VK Immediate Drawer: Properly transition texture layouts
Support wrapping of textures not created here
This commit is contained in:
parent
f8d9472872
commit
fd37112db8
|
@ -136,6 +136,46 @@ class LightweightCircularBuffer {
|
|||
|
||||
class VulkanImmediateTexture : public ImmediateTexture {
|
||||
public:
|
||||
VulkanImmediateTexture(VulkanDevice* device, VkDescriptorPool descriptor_pool,
|
||||
VkDescriptorSetLayout descriptor_set_layout,
|
||||
VkImageView image_view, VkSampler sampler,
|
||||
uint32_t width, uint32_t height)
|
||||
: ImmediateTexture(width, height),
|
||||
device_(*device),
|
||||
descriptor_pool_(descriptor_pool),
|
||||
image_view_(image_view),
|
||||
sampler_(sampler) {
|
||||
handle = reinterpret_cast<uintptr_t>(this);
|
||||
|
||||
// Create descriptor set used just for this texture.
|
||||
// It never changes, so we can reuse it and not worry with updates.
|
||||
VkDescriptorSetAllocateInfo set_alloc_info;
|
||||
set_alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||
set_alloc_info.pNext = nullptr;
|
||||
set_alloc_info.descriptorPool = descriptor_pool_;
|
||||
set_alloc_info.descriptorSetCount = 1;
|
||||
set_alloc_info.pSetLayouts = &descriptor_set_layout;
|
||||
auto err =
|
||||
vkAllocateDescriptorSets(device_, &set_alloc_info, &descriptor_set_);
|
||||
CheckResult(err, "vkAllocateDescriptorSets");
|
||||
|
||||
// Initialize descriptor with our texture.
|
||||
VkDescriptorImageInfo texture_info;
|
||||
texture_info.sampler = sampler_;
|
||||
texture_info.imageView = image_view_;
|
||||
texture_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
VkWriteDescriptorSet descriptor_write;
|
||||
descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
descriptor_write.pNext = nullptr;
|
||||
descriptor_write.dstSet = descriptor_set_;
|
||||
descriptor_write.dstBinding = 0;
|
||||
descriptor_write.dstArrayElement = 0;
|
||||
descriptor_write.descriptorCount = 1;
|
||||
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
descriptor_write.pImageInfo = &texture_info;
|
||||
vkUpdateDescriptorSets(device_, 1, &descriptor_write, 0, nullptr);
|
||||
}
|
||||
|
||||
VulkanImmediateTexture(VulkanDevice* device, VkDescriptorPool descriptor_pool,
|
||||
VkDescriptorSetLayout descriptor_set_layout,
|
||||
VkSampler sampler, uint32_t width, uint32_t height)
|
||||
|
@ -161,7 +201,7 @@ class VulkanImmediateTexture : public ImmediateTexture {
|
|||
image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
image_info.queueFamilyIndexCount = 0;
|
||||
image_info.pQueueFamilyIndices = nullptr;
|
||||
image_info.initialLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
image_info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
|
||||
auto err = vkCreateImage(device_, &image_info, nullptr, &image_);
|
||||
CheckResult(err, "vkCreateImage");
|
||||
|
||||
|
@ -221,9 +261,12 @@ class VulkanImmediateTexture : public ImmediateTexture {
|
|||
|
||||
~VulkanImmediateTexture() override {
|
||||
vkFreeDescriptorSets(device_, descriptor_pool_, 1, &descriptor_set_);
|
||||
vkDestroyImageView(device_, image_view_, nullptr);
|
||||
vkDestroyImage(device_, image_, nullptr);
|
||||
vkFreeMemory(device_, device_memory_, nullptr);
|
||||
|
||||
if (device_memory_) {
|
||||
vkDestroyImageView(device_, image_view_, nullptr);
|
||||
vkDestroyImage(device_, image_, nullptr);
|
||||
vkFreeMemory(device_, device_memory_, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void Upload(const uint8_t* src_data) {
|
||||
|
@ -238,25 +281,49 @@ class VulkanImmediateTexture : public ImmediateTexture {
|
|||
vkGetImageSubresourceLayout(device_, image_, &subresource, &layout);
|
||||
|
||||
// Map memory for upload.
|
||||
void* gpu_data = nullptr;
|
||||
auto err =
|
||||
vkMapMemory(device_, device_memory_, 0, layout.size, 0, &gpu_data);
|
||||
uint8_t* gpu_data = nullptr;
|
||||
auto err = vkMapMemory(device_, device_memory_, 0, layout.size, 0,
|
||||
reinterpret_cast<void**>(&gpu_data));
|
||||
CheckResult(err, "vkMapMemory");
|
||||
|
||||
// Copy the entire texture, hoping its layout matches what we expect.
|
||||
std::memcpy(gpu_data, src_data, layout.size);
|
||||
std::memcpy(gpu_data + layout.offset, src_data, layout.size);
|
||||
|
||||
vkUnmapMemory(device_, device_memory_);
|
||||
}
|
||||
|
||||
// Queues a command to transition this texture to a new layout. This assumes
|
||||
// the command buffer WILL be queued and executed by the device.
|
||||
void TransitionLayout(VkCommandBuffer command_buffer,
|
||||
VkImageLayout new_layout) {
|
||||
VkImageMemoryBarrier image_barrier;
|
||||
image_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
image_barrier.pNext = nullptr;
|
||||
image_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
image_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
image_barrier.srcAccessMask = 0;
|
||||
image_barrier.dstAccessMask = 0;
|
||||
image_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
image_barrier.newLayout = new_layout;
|
||||
image_barrier.image = image_;
|
||||
image_barrier.subresourceRange = {0, 0, 1, 0, 1};
|
||||
image_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
image_layout_ = new_layout;
|
||||
|
||||
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0,
|
||||
nullptr, 1, &image_barrier);
|
||||
}
|
||||
|
||||
VkDescriptorSet descriptor_set() const { return descriptor_set_; }
|
||||
VkImageLayout layout() const { return image_layout_; }
|
||||
|
||||
private:
|
||||
VkDevice device_ = nullptr;
|
||||
VkDescriptorPool descriptor_pool_ = nullptr;
|
||||
VkSampler sampler_ = nullptr; // Not owned.
|
||||
VkImage image_ = nullptr;
|
||||
VkImageLayout image_layout_ = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
VkImageLayout image_layout_ = VK_IMAGE_LAYOUT_PREINITIALIZED;
|
||||
VkDeviceMemory device_memory_ = nullptr;
|
||||
VkImageView image_view_ = nullptr;
|
||||
VkDescriptorSet descriptor_set_ = nullptr;
|
||||
|
@ -604,6 +671,14 @@ std::unique_ptr<ImmediateTexture> VulkanImmediateDrawer::CreateTexture(
|
|||
return std::unique_ptr<ImmediateTexture>(texture.release());
|
||||
}
|
||||
|
||||
std::unique_ptr<ImmediateTexture> VulkanImmediateDrawer::WrapTexture(
|
||||
VkImageView image_view, VkSampler sampler, uint32_t width,
|
||||
uint32_t height) {
|
||||
return std::make_unique<VulkanImmediateTexture>(
|
||||
context_->device(), descriptor_pool_, texture_set_layout_, image_view,
|
||||
sampler, width, height);
|
||||
}
|
||||
|
||||
void VulkanImmediateDrawer::UpdateTexture(ImmediateTexture* texture,
|
||||
const uint8_t* data) {
|
||||
static_cast<VulkanImmediateTexture*>(texture)->Upload(data);
|
||||
|
@ -686,6 +761,10 @@ void VulkanImmediateDrawer::Draw(const ImmediateDraw& draw) {
|
|||
// Setup texture binding.
|
||||
auto texture = reinterpret_cast<VulkanImmediateTexture*>(draw.texture_handle);
|
||||
if (texture) {
|
||||
if (texture->layout() != VK_IMAGE_LAYOUT_GENERAL) {
|
||||
texture->TransitionLayout(current_cmd_buffer_, VK_IMAGE_LAYOUT_GENERAL);
|
||||
}
|
||||
|
||||
auto texture_set = texture->descriptor_set();
|
||||
vkCmdBindDescriptorSets(current_cmd_buffer_,
|
||||
VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout_,
|
||||
|
|
|
@ -32,6 +32,10 @@ class VulkanImmediateDrawer : public ImmediateDrawer {
|
|||
ImmediateTextureFilter filter,
|
||||
bool repeat,
|
||||
const uint8_t* data) override;
|
||||
std::unique_ptr<ImmediateTexture> WrapTexture(VkImageView image_view,
|
||||
VkSampler sampler,
|
||||
uint32_t width,
|
||||
uint32_t height);
|
||||
void UpdateTexture(ImmediateTexture* texture, const uint8_t* data) override;
|
||||
|
||||
void Begin(int render_target_width, int render_target_height) override;
|
||||
|
|
Loading…
Reference in New Issue