| 481 | } |
| 482 | |
| 483 | bool create_texture(Rml::TextureHandle texture_handle, const Rml::byte* source, const Rml::Vector2i& source_dimensions, bool flip_y = false, bool bgra = false) { |
| 484 | std::unique_ptr<plume::RenderTexture> texture = |
| 485 | device_->createTexture(plume::RenderTextureDesc::Texture2D(source_dimensions.x, source_dimensions.y, 1, bgra ? RmlTextureFormatBgra : RmlTextureFormat)); |
| 486 | |
| 487 | if (texture != nullptr) { |
| 488 | uint32_t image_size_bytes = source_dimensions.x * source_dimensions.y * RmlTextureFormatBytesPerPixel; |
| 489 | |
| 490 | // Calculate the texture padding for alignment purposes. |
| 491 | uint32_t row_pitch = source_dimensions.x * RmlTextureFormatBytesPerPixel; |
| 492 | uint32_t row_byte_width, row_byte_padding; |
| 493 | CalculateTextureRowWidthPadding(row_pitch, row_byte_width, row_byte_padding); |
| 494 | uint32_t row_width = row_byte_width / RmlTextureFormatBytesPerPixel; |
| 495 | |
| 496 | // Calculate the real number of bytes to upload including padding. |
| 497 | uint32_t uploaded_size_bytes = row_byte_width * source_dimensions.y; |
| 498 | |
| 499 | // Allocate room in the upload buffer for the uploaded data. |
| 500 | if (uploaded_size_bytes > copy_buffer_size_) { |
| 501 | copy_buffer_size_ = (uploaded_size_bytes * 3) / 2; |
| 502 | copy_buffer_ = device_->createBuffer(plume::RenderBufferDesc::UploadBuffer(copy_buffer_size_)); |
| 503 | } |
| 504 | |
| 505 | // Copy the source data into the upload buffer. |
| 506 | uint8_t* dst_data = (uint8_t *)(copy_buffer_->map()); |
| 507 | if (row_byte_padding == 0) { |
| 508 | // Copy row-by-row if the image is flipped. |
| 509 | if (flip_y) { |
| 510 | for (int row = 0; row < source_dimensions.y; row++) { |
| 511 | memcpy(dst_data + row_byte_width * (source_dimensions.y - row - 1), source + row_byte_width * row, row_byte_width); |
| 512 | } |
| 513 | } |
| 514 | // Directly copy if no padding is needed and the image isn't flipped. |
| 515 | else { |
| 516 | memcpy(dst_data, source, image_size_bytes); |
| 517 | } |
| 518 | } |
| 519 | // Otherwise pad each row as necessary. |
| 520 | else { |
| 521 | const Rml::byte *src_data = flip_y ? source + row_pitch * (source_dimensions.y - 1) : source; |
| 522 | uint32_t src_stride = flip_y ? -row_pitch : row_pitch; |
| 523 | |
| 524 | for (int row = 0; row < source_dimensions.y; row++) { |
| 525 | memcpy(dst_data, src_data, row_pitch); |
| 526 | src_data += src_stride; |
| 527 | dst_data += row_byte_width; |
| 528 | } |
| 529 | } |
| 530 | |
| 531 | copy_buffer_->unmap(); |
| 532 | |
| 533 | // Reset the command list. |
| 534 | copy_command_list_->begin(); |
| 535 | |
| 536 | // Prepare the texture to be a destination for copying. |
| 537 | copy_command_list_->barriers(plume::RenderBarrierStage::COPY, plume::RenderTextureBarrier(texture.get(), plume::RenderTextureLayout::COPY_DEST)); |
| 538 | |
| 539 | // Copy the upload buffer into the texture. |
| 540 | copy_command_list_->copyTextureRegion( |