From 0fd45d69a8d0bdf4e255379478abf975472f4f10 Mon Sep 17 00:00:00 2001 From: Kaushik Iska Date: Thu, 6 Oct 2022 15:25:22 -0400 Subject: [PATCH] [Impeller] Wire image sampler descriptors for Vulkan (flutter/engine#36641) --- .../impeller/compiler/code_gen_template.h | 2 + .../renderer/backend/vulkan/allocator_vk.cc | 19 +- .../renderer/backend/vulkan/allocator_vk.h | 1 + .../renderer/backend/vulkan/render_pass_vk.cc | 166 ++++++++++++------ .../renderer/backend/vulkan/render_pass_vk.h | 14 +- .../renderer/backend/vulkan/sampler_vk.cc | 6 +- .../renderer/backend/vulkan/sampler_vk.h | 2 + .../renderer/backend/vulkan/texture_vk.cc | 11 ++ .../renderer/backend/vulkan/texture_vk.h | 3 + .../src/flutter/impeller/renderer/command.cc | 2 + .../src/flutter/impeller/renderer/command.h | 1 + .../flutter/impeller/renderer/shader_types.h | 2 + 12 files changed, 171 insertions(+), 58 deletions(-) diff --git a/engine/src/flutter/impeller/compiler/code_gen_template.h b/engine/src/flutter/impeller/compiler/code_gen_template.h index 2de845d7aa..f399084015 100644 --- a/engine/src/flutter/impeller/compiler/code_gen_template.h +++ b/engine/src/flutter/impeller/compiler/code_gen_template.h @@ -107,6 +107,8 @@ struct {{camel_case(shader_name)}}{{camel_case(shader_stage)}}Shader { "{{sampled_image.name}}", // name {{sampled_image.ext_res_0}}u, // texture {{sampled_image.ext_res_1}}u, // sampler + {{sampled_image.binding}}u, // binding + {{sampled_image.set}}u, // set }; static ShaderMetadata kMetadata{{camel_case(sampled_image.name)}}; {% endfor %} diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/allocator_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/allocator_vk.cc index 720c31021e..de0d3384c8 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/allocator_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/allocator_vk.cc @@ -26,7 +26,7 @@ AllocatorVK::AllocatorVK(ContextVK& context, const vk::Instance& instance, PFN_vkGetInstanceProcAddr get_instance_proc_address, PFN_vkGetDeviceProcAddr get_device_proc_address) - : context_(context) { + : context_(context), device_(logical_device) { VmaVulkanFunctions proc_table = {}; proc_table.vkGetInstanceProcAddr = get_instance_proc_address; proc_table.vkGetDeviceProcAddr = get_device_proc_address; @@ -100,6 +100,22 @@ std::shared_ptr AllocatorVK::OnCreateTexture( return nullptr; } + vk::ImageViewCreateInfo view_create_info = {}; + view_create_info.image = img; + view_create_info.viewType = vk::ImageViewType::e2D; + view_create_info.format = image_create_info.format; + view_create_info.subresourceRange.aspectMask = + vk::ImageAspectFlagBits::eColor; + view_create_info.subresourceRange.levelCount = image_create_info.mipLevels; + view_create_info.subresourceRange.layerCount = image_create_info.arrayLayers; + + auto img_view_res = device_.createImageView(view_create_info); + if (img_view_res.result != vk::Result::eSuccess) { + VALIDATION_LOG << "Unable to create an image view: " + << vk::to_string(img_view_res.result); + return nullptr; + } + auto texture_info = std::make_unique(TextureInfoVK{ .backing_type = TextureBackingTypeVK::kAllocatedTexture, .allocated_texture = @@ -108,6 +124,7 @@ std::shared_ptr AllocatorVK::OnCreateTexture( .allocation = allocation, .allocation_info = allocation_info, .image = img, + .image_view = img_view_res.value, }, }); return std::make_shared(desc, &context_, std::move(texture_info)); diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/allocator_vk.h b/engine/src/flutter/impeller/renderer/backend/vulkan/allocator_vk.h index a5ac44545a..5225845bf7 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/allocator_vk.h +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/allocator_vk.h @@ -23,6 +23,7 @@ class AllocatorVK final : public Allocator { VmaAllocator allocator_ = {}; ContextVK& context_; + vk::Device device_; bool is_valid_ = false; AllocatorVK(ContextVK& context, diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/render_pass_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/render_pass_vk.cc index 4beb8c1741..1179f2deff 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/render_pass_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/render_pass_vk.cc @@ -13,9 +13,13 @@ #include "impeller/renderer/backend/vulkan/device_buffer_vk.h" #include "impeller/renderer/backend/vulkan/formats_vk.h" #include "impeller/renderer/backend/vulkan/pipeline_vk.h" +#include "impeller/renderer/backend/vulkan/sampler_vk.h" #include "impeller/renderer/backend/vulkan/surface_producer_vk.h" #include "impeller/renderer/backend/vulkan/texture_vk.h" +#include "impeller/renderer/sampler.h" #include "impeller/renderer/shader_types.h" +#include "vulkan/vulkan_enums.hpp" +#include "vulkan/vulkan_structs.hpp" namespace impeller { @@ -77,52 +81,10 @@ bool RenderPassVK::OnEncodeCommands(const Context& context) const { const uint32_t frame_num = tex_info.frame_num; // layout transition. - { - auto pool = command_buffer_.getPool(); - vk::CommandBufferAllocateInfo alloc_info = - vk::CommandBufferAllocateInfo() - .setCommandPool(pool) - .setLevel(vk::CommandBufferLevel::ePrimary) - .setCommandBufferCount(1); - auto cmd_buf_res = device_.allocateCommandBuffersUnique(alloc_info); - if (cmd_buf_res.result != vk::Result::eSuccess) { - VALIDATION_LOG << "Failed to allocate command buffer: " - << vk::to_string(cmd_buf_res.result); - return false; - } - auto transition_cmd = std::move(cmd_buf_res.value[0]); - - vk::CommandBufferBeginInfo begin_info; - auto res = transition_cmd->begin(begin_info); - - vk::ImageMemoryBarrier barrier = - vk::ImageMemoryBarrier() - .setSrcAccessMask(vk::AccessFlagBits::eColorAttachmentRead) - .setDstAccessMask(vk::AccessFlagBits::eColorAttachmentWrite) - .setOldLayout(vk::ImageLayout::eUndefined) - .setNewLayout(vk::ImageLayout::eColorAttachmentOptimal) - .setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED) - .setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED) - .setImage(tex_info.swapchain_image->GetImage()) - .setSubresourceRange( - vk::ImageSubresourceRange() - .setAspectMask(vk::ImageAspectFlagBits::eColor) - .setBaseMipLevel(0) - .setLevelCount(1) - .setBaseArrayLayer(0) - .setLayerCount(1)); - transition_cmd->pipelineBarrier( - vk::PipelineStageFlagBits::eColorAttachmentOutput, - vk::PipelineStageFlagBits::eColorAttachmentOutput, {}, nullptr, nullptr, - barrier); - - res = transition_cmd->end(); - if (res != vk::Result::eSuccess) { - VALIDATION_LOG << "Failed to end command buffer: " << vk::to_string(res); - return false; - } - - surface_producer_->QueueCommandBuffer(frame_num, std::move(transition_cmd)); + if (!TransitionImageLayout(frame_num, tex_info.swapchain_image->GetImage(), + vk::ImageLayout::eUndefined, + vk::ImageLayout::eColorAttachmentOptimal)) { + return false; } vk::ClearValue clear_value; @@ -162,7 +124,7 @@ bool RenderPassVK::OnEncodeCommands(const Context& context) const { continue; } - if (!EncodeCommand(context, command)) { + if (!EncodeCommand(frame_num, context, command)) { return false; } } @@ -188,14 +150,16 @@ bool RenderPassVK::EndCommandBuffer(uint32_t frame_num) { return false; } -bool RenderPassVK::EncodeCommand(const Context& context, +bool RenderPassVK::EncodeCommand(uint32_t frame_num, + const Context& context, const Command& command) const { SetViewportAndScissor(command); auto& pipeline_vk = PipelineVK::Cast(*command.pipeline); PipelineCreateInfoVK* pipeline_create_info = pipeline_vk.GetCreateInfo(); - if (!AllocateAndBindDescriptorSets(context, command, pipeline_create_info)) { + if (!AllocateAndBindDescriptorSets(frame_num, context, command, + pipeline_create_info)) { return false; } @@ -243,6 +207,7 @@ bool RenderPassVK::EncodeCommand(const Context& context, } bool RenderPassVK::AllocateAndBindDescriptorSets( + uint32_t frame_num, const Context& context, const Command& command, PipelineCreateInfoVK* pipeline_create_info) const { @@ -269,13 +234,15 @@ bool RenderPassVK::AllocateAndBindDescriptorSets( } auto desc_sets = desc_sets_res.value; - bool update_vertex_descriptors = UpdateDescriptorSets( - "vertex_bindings", command.vertex_bindings, allocator, desc_sets[0]); + bool update_vertex_descriptors = + UpdateDescriptorSets(frame_num, "vertex_bindings", + command.vertex_bindings, allocator, desc_sets[0]); if (!update_vertex_descriptors) { return false; } - bool update_frag_descriptors = UpdateDescriptorSets( - "fragment_bindings", command.fragment_bindings, allocator, desc_sets[0]); + bool update_frag_descriptors = + UpdateDescriptorSets(frame_num, "fragment_bindings", + command.fragment_bindings, allocator, desc_sets[0]); if (!update_frag_descriptors) { return false; } @@ -285,12 +252,15 @@ bool RenderPassVK::AllocateAndBindDescriptorSets( return true; } -bool RenderPassVK::UpdateDescriptorSets(const char* label, +bool RenderPassVK::UpdateDescriptorSets(uint32_t frame_num, + const char* label, const Bindings& bindings, Allocator& allocator, vk::DescriptorSet desc_set) const { std::vector writes; std::vector buffer_infos; + std::vector image_infos; + for (const auto& [buffer_index, view] : bindings.buffers) { const auto& buffer_view = view.resource.buffer; @@ -330,6 +300,42 @@ bool RenderPassVK::UpdateDescriptorSets(const char* label, writes.push_back(setWrite); } + for (const auto& [index, sampler_handle] : bindings.samplers) { + if (bindings.textures.find(index) == bindings.textures.end()) { + VALIDATION_LOG << "Missing texture for sampler: " << index; + return false; + } + + const auto& texture_vk = + TextureVK::Cast(*bindings.textures.at(index).resource); + + const Sampler& sampler = *sampler_handle.resource; + const SamplerVK& sampler_vk = SamplerVK::Cast(sampler); + + const SampledImageSlot& slot = bindings.sampled_images.at(index); + + if (!TransitionImageLayout(frame_num, texture_vk.GetImage(), + vk::ImageLayout::eUndefined, + vk::ImageLayout::eGeneral)) { + return false; + } + + vk::DescriptorImageInfo desc_image_info; + desc_image_info.setImageLayout(vk::ImageLayout::eGeneral); + desc_image_info.setSampler(sampler_vk.GetSamplerVK()); + desc_image_info.setImageView(texture_vk.GetImageView()); + image_infos.push_back(desc_image_info); + + vk::WriteDescriptorSet setWrite; + setWrite.setDstSet(desc_set); + setWrite.setDstBinding(slot.binding); + setWrite.setDescriptorCount(1); + setWrite.setDescriptorType(vk::DescriptorType::eCombinedImageSampler); + setWrite.setPImageInfo(&image_infos.back()); + + writes.push_back(setWrite); + } + std::array copies; device_.updateDescriptorSets(writes, copies); @@ -374,4 +380,56 @@ vk::Framebuffer RenderPassVK::CreateFrameBuffer( return std::move(res.value); } +bool RenderPassVK::TransitionImageLayout(uint32_t frame_num, + vk::Image image, + vk::ImageLayout layout_old, + vk::ImageLayout layout_new) const { + auto pool = command_buffer_.getPool(); + vk::CommandBufferAllocateInfo alloc_info = + vk::CommandBufferAllocateInfo() + .setCommandPool(pool) + .setLevel(vk::CommandBufferLevel::ePrimary) + .setCommandBufferCount(1); + auto cmd_buf_res = device_.allocateCommandBuffersUnique(alloc_info); + if (cmd_buf_res.result != vk::Result::eSuccess) { + VALIDATION_LOG << "Failed to allocate command buffer: " + << vk::to_string(cmd_buf_res.result); + return false; + } + auto transition_cmd = std::move(cmd_buf_res.value[0]); + + vk::CommandBufferBeginInfo begin_info; + auto res = transition_cmd->begin(begin_info); + + vk::ImageMemoryBarrier barrier = + vk::ImageMemoryBarrier() + .setSrcAccessMask(vk::AccessFlagBits::eColorAttachmentRead) + .setDstAccessMask(vk::AccessFlagBits::eColorAttachmentWrite) + .setOldLayout(layout_old) + .setNewLayout(layout_new) + .setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED) + .setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED) + .setImage(image) + .setSubresourceRange( + vk::ImageSubresourceRange() + .setAspectMask(vk::ImageAspectFlagBits::eColor) + .setBaseMipLevel(0) + .setLevelCount(1) + .setBaseArrayLayer(0) + .setLayerCount(1)); + transition_cmd->pipelineBarrier( + vk::PipelineStageFlagBits::eColorAttachmentOutput, + vk::PipelineStageFlagBits::eColorAttachmentOutput, {}, nullptr, nullptr, + barrier); + + res = transition_cmd->end(); + if (res != vk::Result::eSuccess) { + VALIDATION_LOG << "Failed to end command buffer: " << vk::to_string(res); + return false; + } + + surface_producer_->QueueCommandBuffer(frame_num, std::move(transition_cmd)); + return true; +} + } // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/render_pass_vk.h b/engine/src/flutter/impeller/renderer/backend/vulkan/render_pass_vk.h index c6c551d537..3530cbb706 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/render_pass_vk.h +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/render_pass_vk.h @@ -12,6 +12,7 @@ #include "impeller/renderer/command.h" #include "impeller/renderer/render_pass.h" #include "impeller/renderer/render_target.h" +#include "vulkan/vulkan_enums.hpp" #include "vulkan/vulkan_structs.hpp" namespace impeller { @@ -48,16 +49,20 @@ class RenderPassVK final : public RenderPass { // |RenderPass| bool OnEncodeCommands(const Context& context) const override; - bool EncodeCommand(const Context& context, const Command& command) const; + bool EncodeCommand(uint32_t frame_num, + const Context& context, + const Command& command) const; bool AllocateAndBindDescriptorSets( + uint32_t frame_num, const Context& context, const Command& command, PipelineCreateInfoVK* pipeline_create_info) const; bool EndCommandBuffer(uint32_t frame_num); - bool UpdateDescriptorSets(const char* label, + bool UpdateDescriptorSets(uint32_t frame_num, + const char* label, const Bindings& bindings, Allocator& allocator, vk::DescriptorSet desc_set) const; @@ -67,6 +72,11 @@ class RenderPassVK final : public RenderPass { vk::Framebuffer CreateFrameBuffer( const WrappedTextureInfoVK& wrapped_texture_info) const; + bool TransitionImageLayout(uint32_t frame_num, + vk::Image image, + vk::ImageLayout layout_old, + vk::ImageLayout layout_new) const; + FML_DISALLOW_COPY_AND_ASSIGN(RenderPassVK); }; diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/sampler_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/sampler_vk.cc index 161fa57378..6212bedd2c 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/sampler_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/sampler_vk.cc @@ -7,8 +7,12 @@ namespace impeller { SamplerVK::~SamplerVK() {} +vk::Sampler SamplerVK::GetSamplerVK() const { + return sampler_.get(); +} + SamplerVK::SamplerVK(SamplerDescriptor desc, vk::UniqueSampler sampler) - : Sampler(desc), sampler_(std::move(sampler)) { + : Sampler(std::move(desc)), sampler_(std::move(sampler)) { is_valid_ = true; } diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/sampler_vk.h b/engine/src/flutter/impeller/renderer/backend/vulkan/sampler_vk.h index 15d08205fa..4c11bd3660 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/sampler_vk.h +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/sampler_vk.h @@ -21,6 +21,8 @@ class SamplerVK final : public Sampler, public BackendCast { // |Sampler| ~SamplerVK() override; + vk::Sampler GetSamplerVK() const; + private: friend SamplerLibraryVK; diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/texture_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/texture_vk.cc index 66ad2cf182..829cef6f9f 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/texture_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/texture_vk.cc @@ -81,6 +81,17 @@ bool TextureVK::IsWrapped() const { return texture_info_->backing_type == TextureBackingTypeVK::kWrappedTexture; } +vk::ImageView TextureVK::GetImageView() const { + switch (texture_info_->backing_type) { + case TextureBackingTypeVK::kUnknownType: + return nullptr; + case TextureBackingTypeVK::kAllocatedTexture: + return texture_info_->allocated_texture.image_view; + case TextureBackingTypeVK::kWrappedTexture: + return texture_info_->wrapped_texture.swapchain_image->GetImageView(); + } +} + vk::Image TextureVK::GetImage() const { switch (texture_info_->backing_type) { case TextureBackingTypeVK::kUnknownType: diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/texture_vk.h b/engine/src/flutter/impeller/renderer/backend/vulkan/texture_vk.h index 632e9e738a..918ed5f56b 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/texture_vk.h +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/texture_vk.h @@ -29,6 +29,7 @@ struct AllocatedTextureInfoVK { VmaAllocation allocation = nullptr; VmaAllocationInfo allocation_info = {}; VkImage image = nullptr; + VkImageView image_view = nullptr; }; struct TextureInfoVK { @@ -52,6 +53,8 @@ class TextureVK final : public Texture, public BackendCast { vk::Image GetImage() const; + vk::ImageView GetImageView() const; + TextureInfoVK* GetTextureInfo() const; private: diff --git a/engine/src/flutter/impeller/renderer/command.cc b/engine/src/flutter/impeller/renderer/command.cc index cac510881c..e5380a8357 100644 --- a/engine/src/flutter/impeller/renderer/command.cc +++ b/engine/src/flutter/impeller/renderer/command.cc @@ -108,9 +108,11 @@ bool Command::BindResource(ShaderStage stage, switch (stage) { case ShaderStage::kVertex: vertex_bindings.samplers[slot.sampler_index] = {&metadata, sampler}; + vertex_bindings.sampled_images[slot.sampler_index] = slot; return true; case ShaderStage::kFragment: fragment_bindings.samplers[slot.sampler_index] = {&metadata, sampler}; + fragment_bindings.sampled_images[slot.sampler_index] = slot; return true; case ShaderStage::kCompute: VALIDATION_LOG << "Use ComputeCommands for compute shader stages."; diff --git a/engine/src/flutter/impeller/renderer/command.h b/engine/src/flutter/impeller/renderer/command.h index c804c0e5c2..3b3d1c049b 100644 --- a/engine/src/flutter/impeller/renderer/command.h +++ b/engine/src/flutter/impeller/renderer/command.h @@ -42,6 +42,7 @@ using SamplerResource = Resource>; struct Bindings { std::map uniforms; + std::map sampled_images; std::map buffers; std::map textures; std::map samplers; diff --git a/engine/src/flutter/impeller/renderer/shader_types.h b/engine/src/flutter/impeller/renderer/shader_types.h index 3afb01bf58..3a9bab21ae 100644 --- a/engine/src/flutter/impeller/renderer/shader_types.h +++ b/engine/src/flutter/impeller/renderer/shader_types.h @@ -114,6 +114,8 @@ struct SampledImageSlot { const char* name; size_t texture_index; size_t sampler_index; + size_t binding; + size_t set; constexpr bool HasTexture() const { return texture_index < 32u; }