| 120 | } |
| 121 | |
| 122 | void VulkanTexture::UploadData(ref_ptr<dp::GraphicsContext> context, uint32_t x, uint32_t y, uint32_t width, |
| 123 | uint32_t height, ref_ptr<void> data) |
| 124 | { |
| 125 | CHECK(m_isMutable, ("Upload data is avaivable only for mutable textures.")); |
| 126 | CHECK(m_creationStagingBuffer == nullptr, ()); |
| 127 | CHECK(m_objectManager != nullptr, ()); |
| 128 | CHECK(data != nullptr, ()); |
| 129 | |
| 130 | ref_ptr<dp::vulkan::VulkanBaseContext> vulkanContext = context; |
| 131 | VkCommandBuffer commandBuffer = vulkanContext->GetCurrentMemoryCommandBuffer(); |
| 132 | CHECK(commandBuffer != nullptr, ()); |
| 133 | |
| 134 | Bind(context); |
| 135 | |
| 136 | auto const sizeInBytes = GetBytesPerPixel(GetFormat()) * width * height; |
| 137 | |
| 138 | VkBuffer sb; |
| 139 | uint32_t offset; |
| 140 | auto stagingBuffer = vulkanContext->GetDefaultStagingBuffer(); |
| 141 | if (stagingBuffer->HasEnoughSpace(sizeInBytes)) |
| 142 | { |
| 143 | auto staging = stagingBuffer->Reserve(sizeInBytes); |
| 144 | memcpy(staging.m_pointer, data.get(), sizeInBytes); |
| 145 | sb = staging.m_stagingBuffer; |
| 146 | offset = staging.m_offset; |
| 147 | } |
| 148 | else |
| 149 | { |
| 150 | // Here we use temporary staging object, which will be destroyed after the nearest |
| 151 | // command queue submitting. |
| 152 | VulkanStagingBuffer tempStagingBuffer(m_objectManager, sizeInBytes); |
| 153 | CHECK(tempStagingBuffer.HasEnoughSpace(sizeInBytes), ()); |
| 154 | auto staging = tempStagingBuffer.Reserve(sizeInBytes); |
| 155 | memcpy(staging.m_pointer, data.get(), sizeInBytes); |
| 156 | tempStagingBuffer.Flush(); |
| 157 | sb = staging.m_stagingBuffer; |
| 158 | offset = staging.m_offset; |
| 159 | } |
| 160 | |
| 161 | // Here we use VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, because we also read textures |
| 162 | // in vertex shaders. |
| 163 | MakeImageLayoutTransition( |
| 164 | commandBuffer, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, |
| 165 | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, |
| 166 | VK_PIPELINE_STAGE_TRANSFER_BIT); |
| 167 | |
| 168 | auto bufferCopyRegion = BufferCopyRegion(x, y, width, height, offset); |
| 169 | vkCmdCopyBufferToImage(commandBuffer, sb, m_textureObject.m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, |
| 170 | &bufferCopyRegion); |
| 171 | |
| 172 | MakeImageLayoutTransition(commandBuffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, |
| 173 | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); |
| 174 | } |
| 175 | |
| 176 | void VulkanTexture::Bind(ref_ptr<dp::GraphicsContext> context) const |
| 177 | { |