diff --git a/impeller/compiler/code_gen_template.h b/impeller/compiler/code_gen_template.h index 61f442d824dd4..1e73aee4a885a 100644 --- a/impeller/compiler/code_gen_template.h +++ b/impeller/compiler/code_gen_template.h @@ -173,7 +173,14 @@ std::move({{ arg.argument_name }}){% if not loop.is_last %}, {% endif %} // =========================================================================== // Metadata for Vulkan ======================================================= // =========================================================================== - static constexpr std::array kDescriptorSetLayouts{ + static constexpr std::array kDescriptorSetLayouts{ +{% for subpass_input in subpass_inputs %} + DescriptorSetLayout{ + {{subpass_input.binding}}, // binding = {{subpass_input.binding}} + {{subpass_input.descriptor_type}}, // descriptor_type = {{subpass_input.descriptor_type}} + {{to_shader_stage(shader_stage)}}, // shader_stage = {{to_shader_stage(shader_stage)}} + }, +{% endfor %} {% for buffer in buffers %} DescriptorSetLayout{ {{buffer.binding}}, // binding = {{buffer.binding}} diff --git a/impeller/compiler/reflector.cc b/impeller/compiler/reflector.cc index 4f9f9b1a76aa7..50903b1b5ce97 100644 --- a/impeller/compiler/reflector.cc +++ b/impeller/compiler/reflector.cc @@ -188,6 +188,21 @@ std::optional Reflector::GenerateTemplateArguments() const { const auto shader_resources = compiler_->get_shader_resources(); + // Subpass Inputs. + { + auto& subpass_inputs = root["subpass_inputs"] = nlohmann::json::array_t{}; + if (auto subpass_inputs_json = + ReflectResources(shader_resources.subpass_inputs); + subpass_inputs_json.has_value()) { + for (auto subpass_input : subpass_inputs_json.value()) { + subpass_input["descriptor_type"] = "DescriptorType::kInputAttachment"; + subpass_inputs.emplace_back(std::move(subpass_input)); + } + } else { + return std::nullopt; + } + } + // Uniform and storage buffers. { auto& buffers = root["buffers"] = nlohmann::json::array_t{}; diff --git a/impeller/core/shader_types.h b/impeller/core/shader_types.h index 786759aca03f1..425792d1ac7c0 100644 --- a/impeller/core/shader_types.h +++ b/impeller/core/shader_types.h @@ -163,6 +163,7 @@ enum class DescriptorType { kSampledImage, kImage, kSampler, + kInputAttachment, }; struct DescriptorSetLayout { diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index 00a674a1c07e9..d76131fd400a2 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -221,49 +221,64 @@ ContentContext::ContentContext( if (context_->GetCapabilities()->SupportsFramebufferFetch()) { framebuffer_blend_color_pipelines_.CreateDefault( *context_, options_trianglestrip, - {static_cast(BlendSelectValues::kColor), supports_decal}); + {static_cast(BlendSelectValues::kColor), supports_decal}, + UseSubpassInput::kYes); framebuffer_blend_colorburn_pipelines_.CreateDefault( *context_, options_trianglestrip, - {static_cast(BlendSelectValues::kColorBurn), supports_decal}); + {static_cast(BlendSelectValues::kColorBurn), supports_decal}, + UseSubpassInput::kYes); framebuffer_blend_colordodge_pipelines_.CreateDefault( *context_, options_trianglestrip, - {static_cast(BlendSelectValues::kColorDodge), supports_decal}); + {static_cast(BlendSelectValues::kColorDodge), supports_decal}, + UseSubpassInput::kYes); framebuffer_blend_darken_pipelines_.CreateDefault( *context_, options_trianglestrip, - {static_cast(BlendSelectValues::kDarken), supports_decal}); + {static_cast(BlendSelectValues::kDarken), supports_decal}, + UseSubpassInput::kYes); framebuffer_blend_difference_pipelines_.CreateDefault( *context_, options_trianglestrip, - {static_cast(BlendSelectValues::kDifference), supports_decal}); + {static_cast(BlendSelectValues::kDifference), supports_decal}, + UseSubpassInput::kYes); framebuffer_blend_exclusion_pipelines_.CreateDefault( *context_, options_trianglestrip, - {static_cast(BlendSelectValues::kExclusion), supports_decal}); + {static_cast(BlendSelectValues::kExclusion), supports_decal}, + UseSubpassInput::kYes); framebuffer_blend_hardlight_pipelines_.CreateDefault( *context_, options_trianglestrip, - {static_cast(BlendSelectValues::kHardLight), supports_decal}); + {static_cast(BlendSelectValues::kHardLight), supports_decal}, + UseSubpassInput::kYes); framebuffer_blend_hue_pipelines_.CreateDefault( *context_, options_trianglestrip, - {static_cast(BlendSelectValues::kHue), supports_decal}); + {static_cast(BlendSelectValues::kHue), supports_decal}, + UseSubpassInput::kYes); framebuffer_blend_lighten_pipelines_.CreateDefault( *context_, options_trianglestrip, - {static_cast(BlendSelectValues::kLighten), supports_decal}); + {static_cast(BlendSelectValues::kLighten), supports_decal}, + UseSubpassInput::kYes); framebuffer_blend_luminosity_pipelines_.CreateDefault( *context_, options_trianglestrip, - {static_cast(BlendSelectValues::kLuminosity), supports_decal}); + {static_cast(BlendSelectValues::kLuminosity), supports_decal}, + UseSubpassInput::kYes); framebuffer_blend_multiply_pipelines_.CreateDefault( *context_, options_trianglestrip, - {static_cast(BlendSelectValues::kMultiply), supports_decal}); + {static_cast(BlendSelectValues::kMultiply), supports_decal}, + UseSubpassInput::kYes); framebuffer_blend_overlay_pipelines_.CreateDefault( *context_, options_trianglestrip, - {static_cast(BlendSelectValues::kOverlay), supports_decal}); + {static_cast(BlendSelectValues::kOverlay), supports_decal}, + UseSubpassInput::kYes); framebuffer_blend_saturation_pipelines_.CreateDefault( *context_, options_trianglestrip, - {static_cast(BlendSelectValues::kSaturation), supports_decal}); + {static_cast(BlendSelectValues::kSaturation), supports_decal}, + UseSubpassInput::kYes); framebuffer_blend_screen_pipelines_.CreateDefault( *context_, options_trianglestrip, - {static_cast(BlendSelectValues::kScreen), supports_decal}); + {static_cast(BlendSelectValues::kScreen), supports_decal}, + UseSubpassInput::kYes); framebuffer_blend_softlight_pipelines_.CreateDefault( *context_, options_trianglestrip, - {static_cast(BlendSelectValues::kSoftLight), supports_decal}); + {static_cast(BlendSelectValues::kSoftLight), supports_decal}, + UseSubpassInput::kYes); } blend_color_pipelines_.CreateDefault( diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h index 44d8d8afacc3f..e23ddcc1c06f1 100644 --- a/impeller/entity/contents/content_context.h +++ b/impeller/entity/contents/content_context.h @@ -18,6 +18,7 @@ #include "impeller/entity/entity.h" #include "impeller/renderer/capabilities.h" #include "impeller/renderer/pipeline.h" +#include "impeller/renderer/pipeline_descriptor.h" #include "impeller/renderer/render_target.h" #include "impeller/typographer/typographer_context.h" @@ -713,13 +714,15 @@ class ContentContext { void CreateDefault(const Context& context, const ContentContextOptions& options, - const std::initializer_list& constants = {}) { + const std::initializer_list& constants = {}, + UseSubpassInput subpass_input = UseSubpassInput::kNo) { auto desc = PipelineT::Builder::MakeDefaultPipelineDescriptor(context, constants); if (!desc.has_value()) { VALIDATION_LOG << "Failed to create default pipeline."; return; } + desc->SetUseSubpassInput(subpass_input); options.ApplyToPipelineDescriptor(*desc); SetDefault(options, std::make_unique(context, desc)); } diff --git a/impeller/entity/entity_unittests.cc b/impeller/entity/entity_unittests.cc index ad2f7c8c662b4..520f7a1c203b2 100644 --- a/impeller/entity/entity_unittests.cc +++ b/impeller/entity/entity_unittests.cc @@ -10,10 +10,12 @@ #include "fml/logging.h" #include "gtest/gtest.h" +#include "impeller/core/formats.h" #include "impeller/core/texture_descriptor.h" #include "impeller/entity/contents/atlas_contents.h" #include "impeller/entity/contents/clip_contents.h" #include "impeller/entity/contents/conical_gradient_contents.h" +#include "impeller/entity/contents/content_context.h" #include "impeller/entity/contents/contents.h" #include "impeller/entity/contents/filters/color_filter_contents.h" #include "impeller/entity/contents/filters/filter_contents.h" @@ -41,6 +43,7 @@ #include "impeller/playground/playground.h" #include "impeller/playground/widgets.h" #include "impeller/renderer/command.h" +#include "impeller/renderer/pipeline_descriptor.h" #include "impeller/renderer/render_pass.h" #include "impeller/renderer/vertex_buffer_builder.h" #include "impeller/typographer/backends/skia/text_frame_skia.h" @@ -2527,6 +2530,63 @@ TEST_P(EntityTest, DecalSpecializationAppliedToMorphologyFilter) { expected_constants); } +TEST_P(EntityTest, FramebufferFetchPipelinesDeclareUsage) { + auto content_context = + ContentContext(GetContext(), TypographerContextSkia::Make()); + if (!content_context.GetDeviceCapabilities().SupportsFramebufferFetch()) { + GTEST_SKIP() << "Framebuffer fetch not supported."; + } + + ContentContextOptions options; + options.color_attachment_pixel_format = PixelFormat::kR8G8B8A8UNormInt; + auto color_burn = + content_context.GetFramebufferBlendColorBurnPipeline(options); + + EXPECT_TRUE(color_burn->GetDescriptor().UsesSubpassInput()); +} + +TEST_P(EntityTest, PipelineDescriptorEqAndHash) { + auto desc_1 = std::make_shared(); + auto desc_2 = std::make_shared(); + + EXPECT_TRUE(desc_1->IsEqual(*desc_2)); + EXPECT_EQ(desc_1->GetHash(), desc_2->GetHash()); + + desc_1->SetUseSubpassInput(UseSubpassInput::kYes); + + EXPECT_FALSE(desc_1->IsEqual(*desc_2)); + EXPECT_NE(desc_1->GetHash(), desc_2->GetHash()); + + desc_2->SetUseSubpassInput(UseSubpassInput::kYes); + + EXPECT_TRUE(desc_1->IsEqual(*desc_2)); + EXPECT_EQ(desc_1->GetHash(), desc_2->GetHash()); +} + +#ifdef FML_OS_LINUX +TEST_P(EntityTest, FramebufferFetchVulkanBindingOffsetIsTheSame) { + // Using framebuffer fetch on Vulkan requires that we maintain a subpass input + // binding that we don't have a good route for configuring with the current + // metadata approach. This test verifies that the binding value doesn't change + // from the expected constant. + // See also: + // * impeller/renderer/backend/vulkan/binding_helpers_vk.cc + // * impeller/entity/shaders/blending/framebuffer_blend.frag + // This test only works on Linux because macOS hosts incorrectly populate the + // Vulkan descriptor sets based on the MSL compiler settings. + + bool expected_layout = false; + for (const DescriptorSetLayout& layout : FramebufferBlendColorBurnPipeline:: + FragmentShader::kDescriptorSetLayouts) { + if (layout.binding == 64 && + layout.descriptor_type == DescriptorType::kInputAttachment) { + expected_layout = true; + } + } + EXPECT_TRUE(expected_layout); +} +#endif + } // namespace testing } // namespace impeller diff --git a/impeller/entity/shaders/blending/framebuffer_blend.frag b/impeller/entity/shaders/blending/framebuffer_blend.frag index b031dd7f5e365..4ad3650fd0721 100644 --- a/impeller/entity/shaders/blending/framebuffer_blend.frag +++ b/impeller/entity/shaders/blending/framebuffer_blend.frag @@ -10,9 +10,23 @@ #include #include "blend_select.glsl" -layout(constant_id = 0) const float blend_type = 0.0; -layout(constant_id = 1) const float supports_decal = 1.0; +// Warning: if any of the constant values or layouts are changed in this +// file, then the hard-coded constant value in +// impeller/renderer/backend/vulkan/binding_helpers_vk.cc +layout(constant_id = 0) const float blend_type = 0; +layout(constant_id = 1) const float supports_decal = 1; +#ifdef IMPELLER_TARGET_VULKAN +layout(set = 0, + binding = 0, + input_attachment_index = 0) uniform subpassInputMS uSub; + +vec4 ReadDestination() { + return (subpassLoad(uSub, 0) + subpassLoad(uSub, 1) + subpassLoad(uSub, 2) + + subpassLoad(uSub, 3)) / + vec4(4.0); +} +#else layout(set = 0, binding = 0, input_attachment_index = 0) uniform subpassInput uSub; @@ -20,6 +34,7 @@ layout(set = 0, vec4 ReadDestination() { return subpassLoad(uSub); } +#endif // IMPELLER_TARGET_VULKAN uniform sampler2D texture_sampler_src; diff --git a/impeller/entity/shaders/blending/framebuffer_blend.vert b/impeller/entity/shaders/blending/framebuffer_blend.vert index 234d1e0c0b3e6..362362e4e3f8f 100644 --- a/impeller/entity/shaders/blending/framebuffer_blend.vert +++ b/impeller/entity/shaders/blending/framebuffer_blend.vert @@ -5,6 +5,9 @@ #include #include +// Warning: if any of the constant values or layouts are changed in this +// file, then the hard-coded constant value in +// impeller/renderer/backend/vulkan/binding_helpers_vk.cc uniform FrameInfo { mat4 mvp; float src_y_coord_scale; diff --git a/impeller/playground/backend/vulkan/playground_impl_vk.cc b/impeller/playground/backend/vulkan/playground_impl_vk.cc index 675558f6e53d8..e74541fcfdaf8 100644 --- a/impeller/playground/backend/vulkan/playground_impl_vk.cc +++ b/impeller/playground/backend/vulkan/playground_impl_vk.cc @@ -13,6 +13,7 @@ #include "flutter/fml/logging.h" #include "flutter/fml/mapping.h" #include "impeller/entity/vk/entity_shaders_vk.h" +#include "impeller/entity/vk/framebuffer_blend_shaders_vk.h" #include "impeller/entity/vk/modern_shaders_vk.h" #include "impeller/fixtures/vk/fixtures_shaders_vk.h" #include "impeller/playground/imgui/vk/imgui_shaders_vk.h" @@ -33,6 +34,9 @@ ShaderLibraryMappingsForPlayground() { impeller_entity_shaders_vk_length), std::make_shared(impeller_modern_shaders_vk_data, impeller_modern_shaders_vk_length), + std::make_shared( + impeller_framebuffer_blend_shaders_vk_data, + impeller_framebuffer_blend_shaders_vk_length), std::make_shared( impeller_fixtures_shaders_vk_data, impeller_fixtures_shaders_vk_length), diff --git a/impeller/renderer/backend/vulkan/allocator_vk.cc b/impeller/renderer/backend/vulkan/allocator_vk.cc index 1e8fffe995d81..a5dd9b7f14b00 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.cc +++ b/impeller/renderer/backend/vulkan/allocator_vk.cc @@ -12,6 +12,7 @@ #include "impeller/renderer/backend/vulkan/device_buffer_vk.h" #include "impeller/renderer/backend/vulkan/formats_vk.h" #include "impeller/renderer/backend/vulkan/texture_vk.h" +#include "vulkan/vulkan_enums.hpp" namespace impeller { @@ -148,6 +149,7 @@ AllocatorVK::AllocatorVK(std::weak_ptr context, allocator_.reset(allocator); supports_memoryless_textures_ = capabilities.SupportsDeviceTransientTextures(); + supports_framebuffer_fetch_ = capabilities.SupportsFramebufferFetch(); is_valid_ = true; } @@ -167,7 +169,8 @@ static constexpr vk::ImageUsageFlags ToVKImageUsageFlags( PixelFormat format, TextureUsageMask usage, StorageMode mode, - bool supports_memoryless_textures) { + bool supports_memoryless_textures, + bool supports_framebuffer_fetch) { vk::ImageUsageFlags vk_usage; switch (mode) { @@ -187,6 +190,9 @@ static constexpr vk::ImageUsageFlags ToVKImageUsageFlags( } else { vk_usage |= vk::ImageUsageFlagBits::eColorAttachment; } + if (supports_framebuffer_fetch) { + vk_usage |= vk::ImageUsageFlagBits::eInputAttachment; + } } if (usage & static_cast(TextureUsage::kShaderRead)) { @@ -263,7 +269,8 @@ class AllocatedTextureSourceVK final : public TextureSourceVK { const TextureDescriptor& desc, VmaAllocator allocator, vk::Device device, - bool supports_memoryless_textures) + bool supports_memoryless_textures, + bool supports_framebuffer_fetch) : TextureSourceVK(desc), resource_(std::move(resource_manager)) { FML_DCHECK(desc.format != PixelFormat::kUnknown); TRACE_EVENT0("impeller", "CreateDeviceTexture"); @@ -281,9 +288,9 @@ class AllocatedTextureSourceVK final : public TextureSourceVK { image_info.arrayLayers = ToArrayLayerCount(desc.type); image_info.tiling = vk::ImageTiling::eOptimal; image_info.initialLayout = vk::ImageLayout::eUndefined; - image_info.usage = - ToVKImageUsageFlags(desc.format, desc.usage, desc.storage_mode, - supports_memoryless_textures); + image_info.usage = ToVKImageUsageFlags( + desc.format, desc.usage, desc.storage_mode, + supports_memoryless_textures, supports_framebuffer_fetch); image_info.sharingMode = vk::SharingMode::eExclusive; VmaAllocationCreateInfo alloc_nfo = {}; @@ -412,7 +419,8 @@ std::shared_ptr AllocatorVK::OnCreateTexture( desc, // allocator_.get(), // device_holder->GetDevice(), // - supports_memoryless_textures_ // + supports_memoryless_textures_, // + supports_framebuffer_fetch_ // ); if (!source->IsValid()) { return nullptr; diff --git a/impeller/renderer/backend/vulkan/allocator_vk.h b/impeller/renderer/backend/vulkan/allocator_vk.h index a22369462d8b7..1977b79115358 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.h +++ b/impeller/renderer/backend/vulkan/allocator_vk.h @@ -33,6 +33,7 @@ class AllocatorVK final : public Allocator { ISize max_texture_size_; bool is_valid_ = false; bool supports_memoryless_textures_ = false; + bool supports_framebuffer_fetch_ = false; // TODO(jonahwilliams): figure out why CI can't create these buffer pools. bool created_buffer_pool_ = true; uint32_t frame_count_ = 0; diff --git a/impeller/renderer/backend/vulkan/binding_helpers_vk.cc b/impeller/renderer/backend/vulkan/binding_helpers_vk.cc index e331ee7e8e7fa..d029a76f6d137 100644 --- a/impeller/renderer/backend/vulkan/binding_helpers_vk.cc +++ b/impeller/renderer/backend/vulkan/binding_helpers_vk.cc @@ -11,12 +11,17 @@ #include "impeller/renderer/backend/vulkan/context_vk.h" #include "impeller/renderer/backend/vulkan/sampler_vk.h" #include "impeller/renderer/backend/vulkan/texture_vk.h" -#include "impeller/renderer/backend/vulkan/vk.h" #include "impeller/renderer/command.h" #include "impeller/renderer/compute_command.h" +#include "vulkan/vulkan_core.h" namespace impeller { +// Warning: if any of the constant values or layouts are changed in the +// framebuffer fetch shader, then this input binding may need to be +// manually changed. +static constexpr size_t kMagicSubpassInputBinding = 64; + static bool BindImages(const Bindings& bindings, Allocator& allocator, const std::shared_ptr& encoder, @@ -117,7 +122,8 @@ static bool BindBuffers(const Bindings& bindings, fml::StatusOr> AllocateAndBindDescriptorSets( const ContextVK& context, const std::shared_ptr& encoder, - const std::vector& commands) { + const std::vector& commands, + const TextureVK& input_attachment) { if (commands.empty()) { return std::vector{}; } @@ -127,6 +133,7 @@ fml::StatusOr> AllocateAndBindDescriptorSets( // to allocate a correctly sized descriptor pool. size_t buffer_count = 0; size_t samplers_count = 0; + size_t subpass_count = 0; std::vector layouts; layouts.reserve(commands.size()); @@ -134,12 +141,14 @@ fml::StatusOr> AllocateAndBindDescriptorSets( buffer_count += command.vertex_bindings.buffers.size(); buffer_count += command.fragment_bindings.buffers.size(); samplers_count += command.fragment_bindings.sampled_images.size(); + subpass_count += + command.pipeline->GetDescriptor().UsesSubpassInput() ? 1 : 0; layouts.emplace_back( PipelineVK::Cast(*command.pipeline).GetDescriptorSetLayout()); } - auto descriptor_result = - encoder->AllocateDescriptorSets(buffer_count, samplers_count, layouts); + auto descriptor_result = encoder->AllocateDescriptorSets( + buffer_count, samplers_count, subpass_count, layouts); if (!descriptor_result.ok()) { return descriptor_result.status(); } @@ -153,9 +162,9 @@ fml::StatusOr> AllocateAndBindDescriptorSets( std::vector images; std::vector buffers; std::vector writes; - images.reserve(samplers_count); + images.reserve(samplers_count + subpass_count); buffers.reserve(buffer_count); - writes.reserve(samplers_count + buffer_count); + writes.reserve(samplers_count + buffer_count + subpass_count); auto& allocator = *context.GetResourceAllocator(); auto desc_index = 0u; @@ -173,6 +182,23 @@ fml::StatusOr> AllocateAndBindDescriptorSets( return fml::Status(fml::StatusCode::kUnknown, "Failed to bind texture or buffer."); } + + if (command.pipeline->GetDescriptor().UsesSubpassInput()) { + vk::DescriptorImageInfo image_info; + image_info.imageLayout = vk::ImageLayout::eGeneral; + image_info.sampler = VK_NULL_HANDLE; + image_info.imageView = input_attachment.GetImageView(); + images.push_back(image_info); + + vk::WriteDescriptorSet write_set; + write_set.dstSet = descriptor_sets[desc_index]; + write_set.dstBinding = kMagicSubpassInputBinding; + write_set.descriptorCount = 1u; + write_set.descriptorType = vk::DescriptorType::eInputAttachment; + write_set.pImageInfo = &images.back(); + + writes.push_back(write_set); + } desc_index += 1; } @@ -203,7 +229,7 @@ fml::StatusOr> AllocateAndBindDescriptorSets( ComputePipelineVK::Cast(*command.pipeline).GetDescriptorSetLayout()); } auto descriptor_result = - encoder->AllocateDescriptorSets(buffer_count, samplers_count, layouts); + encoder->AllocateDescriptorSets(buffer_count, samplers_count, 0, layouts); if (!descriptor_result.ok()) { return descriptor_result.status(); } diff --git a/impeller/renderer/backend/vulkan/binding_helpers_vk.h b/impeller/renderer/backend/vulkan/binding_helpers_vk.h index 588e2a7cbacaa..14d3145a8d26b 100644 --- a/impeller/renderer/backend/vulkan/binding_helpers_vk.h +++ b/impeller/renderer/backend/vulkan/binding_helpers_vk.h @@ -8,6 +8,7 @@ #include "fml/status_or.h" #include "impeller/renderer/backend/vulkan/context_vk.h" +#include "impeller/renderer/backend/vulkan/texture_vk.h" #include "impeller/renderer/command.h" #include "impeller/renderer/compute_command.h" @@ -16,7 +17,8 @@ namespace impeller { fml::StatusOr> AllocateAndBindDescriptorSets( const ContextVK& context, const std::shared_ptr& encoder, - const std::vector& commands); + const std::vector& commands, + const TextureVK& input_attachment); fml::StatusOr> AllocateAndBindDescriptorSets( const ContextVK& context, diff --git a/impeller/renderer/backend/vulkan/capabilities_vk.cc b/impeller/renderer/backend/vulkan/capabilities_vk.cc index 8af5a31f0b3ca..4d83152795af7 100644 --- a/impeller/renderer/backend/vulkan/capabilities_vk.cc +++ b/impeller/renderer/backend/vulkan/capabilities_vk.cc @@ -9,6 +9,7 @@ #include "impeller/base/validation.h" #include "impeller/core/formats.h" #include "impeller/renderer/backend/vulkan/vk.h" +#include "vulkan/vulkan_core.h" namespace impeller { @@ -156,6 +157,10 @@ static const char* GetDeviceExtensionName(OptionalDeviceExtensionVK ext) { switch (ext) { case OptionalDeviceExtensionVK::kEXTPipelineCreationFeedback: return VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME; + case OptionalDeviceExtensionVK::kARMRasterizationOrderAttachmentAccess: + return VK_ARM_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME; + case OptionalDeviceExtensionVK::kEXTRasterizationOrderAttachmentAccess: + return VK_EXT_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME; case OptionalDeviceExtensionVK::kLast: return "Unknown"; } @@ -401,6 +406,18 @@ bool CapabilitiesVK::SetPhysicalDevice(const vk::PhysicalDevice& device) { }); } + { + supports_framebuffer_fetch_ = + (optional_device_extensions_.find( + OptionalDeviceExtensionVK:: + kARMRasterizationOrderAttachmentAccess) != + optional_device_extensions_.end() || + optional_device_extensions_.find( + OptionalDeviceExtensionVK:: + kEXTRasterizationOrderAttachmentAccess) != + optional_device_extensions_.end()); + } + return true; } @@ -431,7 +448,7 @@ bool CapabilitiesVK::SupportsTextureToTextureBlits() const { // |Capabilities| bool CapabilitiesVK::SupportsFramebufferFetch() const { - return false; + return supports_framebuffer_fetch_; } // |Capabilities| diff --git a/impeller/renderer/backend/vulkan/capabilities_vk.h b/impeller/renderer/backend/vulkan/capabilities_vk.h index f7ffd2232fc7c..eb9eb08a6f7a0 100644 --- a/impeller/renderer/backend/vulkan/capabilities_vk.h +++ b/impeller/renderer/backend/vulkan/capabilities_vk.h @@ -10,7 +10,6 @@ #include #include -#include "flutter/fml/macros.h" #include "impeller/base/backend_cast.h" #include "impeller/renderer/backend/vulkan/vk.h" #include "impeller/renderer/capabilities.h" @@ -22,6 +21,8 @@ class ContextVK; enum class OptionalDeviceExtensionVK : uint32_t { // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_pipeline_creation_feedback.html kEXTPipelineCreationFeedback, + kARMRasterizationOrderAttachmentAccess, + kEXTRasterizationOrderAttachmentAccess, kLast, }; @@ -110,6 +111,7 @@ class CapabilitiesVK final : public Capabilities, vk::PhysicalDeviceProperties device_properties_; bool supports_compute_subgroups_ = false; bool supports_device_transient_textures_ = false; + bool supports_framebuffer_fetch_ = false; bool is_valid_ = false; bool HasExtension(const std::string& ext) const; diff --git a/impeller/renderer/backend/vulkan/command_encoder_vk.cc b/impeller/renderer/backend/vulkan/command_encoder_vk.cc index 4aeedf67d74ee..31ab804027da9 100644 --- a/impeller/renderer/backend/vulkan/command_encoder_vk.cc +++ b/impeller/renderer/backend/vulkan/command_encoder_vk.cc @@ -298,13 +298,14 @@ fml::StatusOr> CommandEncoderVK::AllocateDescriptorSets( uint32_t buffer_count, uint32_t sampler_count, + uint32_t subpass_count, const std::vector& layouts) { if (!IsValid()) { return fml::Status(fml::StatusCode::kUnknown, "command encoder invalid"); } return tracked_objects_->GetDescriptorPool().AllocateDescriptorSets( - buffer_count, sampler_count, layouts); + buffer_count, sampler_count, subpass_count, layouts); } void CommandEncoderVK::PushDebugGroup(const char* label) const { diff --git a/impeller/renderer/backend/vulkan/command_encoder_vk.h b/impeller/renderer/backend/vulkan/command_encoder_vk.h index 6b4cd076cc7d6..5455647b74221 100644 --- a/impeller/renderer/backend/vulkan/command_encoder_vk.h +++ b/impeller/renderer/backend/vulkan/command_encoder_vk.h @@ -84,6 +84,7 @@ class CommandEncoderVK { fml::StatusOr> AllocateDescriptorSets( uint32_t buffer_count, uint32_t sampler_count, + uint32_t subpass_count, const std::vector& layouts); private: diff --git a/impeller/renderer/backend/vulkan/descriptor_pool_vk.cc b/impeller/renderer/backend/vulkan/descriptor_pool_vk.cc index 347bd5b738f8e..d0700c67bf47f 100644 --- a/impeller/renderer/backend/vulkan/descriptor_pool_vk.cc +++ b/impeller/renderer/backend/vulkan/descriptor_pool_vk.cc @@ -9,6 +9,7 @@ #include "impeller/base/allocation.h" #include "impeller/base/validation.h" #include "impeller/renderer/backend/vulkan/resource_manager_vk.h" +#include "vulkan/vulkan_enums.hpp" #include "vulkan/vulkan_handles.hpp" namespace impeller { @@ -82,12 +83,14 @@ fml::StatusOr> DescriptorPoolVK::AllocateDescriptorSets( uint32_t buffer_count, uint32_t sampler_count, + uint32_t subpass_count, const std::vector& layouts) { std::shared_ptr strong_context = context_.lock(); if (!strong_context) { return fml::Status(fml::StatusCode::kUnknown, "No device"); } - auto minimum_capacity = std::max(sampler_count, buffer_count); + auto minimum_capacity = + std::max(std::max(sampler_count, buffer_count), subpass_count); auto [new_pool, capacity] = strong_context->GetDescriptorPoolRecycler()->Get(minimum_capacity); if (!new_pool) { @@ -185,6 +188,8 @@ DescriptorPoolAndSize DescriptorPoolRecyclerVK::Create( vk::DescriptorPoolSize{vk::DescriptorType::eUniformBuffer, minimum_capacity}, vk::DescriptorPoolSize{vk::DescriptorType::eStorageBuffer, + minimum_capacity}, + vk::DescriptorPoolSize{vk::DescriptorType::eInputAttachment, minimum_capacity}}; vk::DescriptorPoolCreateInfo pool_info; pool_info.setMaxSets(minimum_capacity + minimum_capacity); diff --git a/impeller/renderer/backend/vulkan/descriptor_pool_vk.h b/impeller/renderer/backend/vulkan/descriptor_pool_vk.h index e8a3e440c4695..8d2fb7c45ccb2 100644 --- a/impeller/renderer/backend/vulkan/descriptor_pool_vk.h +++ b/impeller/renderer/backend/vulkan/descriptor_pool_vk.h @@ -32,6 +32,7 @@ class DescriptorPoolVK { fml::StatusOr> AllocateDescriptorSets( uint32_t buffer_count, uint32_t sampler_count, + uint32_t subpass_count, const std::vector& layouts); private: diff --git a/impeller/renderer/backend/vulkan/descriptor_pool_vk_unittests.cc b/impeller/renderer/backend/vulkan/descriptor_pool_vk_unittests.cc index c7f3cc3ee6b5c..8749f52af4daa 100644 --- a/impeller/renderer/backend/vulkan/descriptor_pool_vk_unittests.cc +++ b/impeller/renderer/backend/vulkan/descriptor_pool_vk_unittests.cc @@ -66,7 +66,7 @@ TEST(DescriptorPoolRecyclerVKTest, ReclaimMakesDescriptorPoolAvailable) { { // Fetch a pool (which will be created). auto pool = DescriptorPoolVK(context); - pool.AllocateDescriptorSets(1024, 1024, {}); + pool.AllocateDescriptorSets(1024, 1024, 1024, {}); } // There is a chance that the first death rattle item below is destroyed in @@ -106,7 +106,7 @@ TEST(DescriptorPoolRecyclerVKTest, ReclaimDropsDescriptorPoolIfSizeIsExceeded) { std::vector> pools; for (auto i = 0u; i < 33; i++) { auto pool = std::make_unique(context); - pool->AllocateDescriptorSets(1024, 1024, {}); + pool->AllocateDescriptorSets(1024, 1024, 1024, {}); pools.push_back(std::move(pool)); } } @@ -135,7 +135,7 @@ TEST(DescriptorPoolRecyclerVKTest, ReclaimDropsDescriptorPoolIfSizeIsExceeded) { std::vector> pools; for (auto i = 0u; i < 33; i++) { auto pool = std::make_unique(context); - pool->AllocateDescriptorSets(1024, 1024, {}); + pool->AllocateDescriptorSets(1024, 1024, 1024, {}); pools.push_back(std::move(pool)); } } diff --git a/impeller/renderer/backend/vulkan/formats_vk.h b/impeller/renderer/backend/vulkan/formats_vk.h index f7d4c9d989c92..42fca4f9a6094 100644 --- a/impeller/renderer/backend/vulkan/formats_vk.h +++ b/impeller/renderer/backend/vulkan/formats_vk.h @@ -11,6 +11,7 @@ #include "impeller/core/formats.h" #include "impeller/core/shader_types.h" #include "impeller/renderer/backend/vulkan/vk.h" +#include "vulkan/vulkan_enums.hpp" namespace impeller { @@ -281,6 +282,8 @@ constexpr vk::DescriptorType ToVKDescriptorType(DescriptorType type) { case DescriptorType::kSampler: return vk::DescriptorType::eSampler; break; + case DescriptorType::kInputAttachment: + return vk::DescriptorType::eInputAttachment; } FML_UNREACHABLE(); @@ -427,7 +430,8 @@ constexpr vk::AttachmentDescription CreateAttachmentDescription( SampleCount sample_count, LoadAction load_action, StoreAction store_action, - vk::ImageLayout current_layout) { + vk::ImageLayout current_layout, + bool supports_framebuffer_fetch) { vk::AttachmentDescription vk_attachment; vk_attachment.format = ToVKImageFormat(format); @@ -466,7 +470,11 @@ constexpr vk::AttachmentDescription CreateAttachmentDescription( switch (kind) { case AttachmentKind::kColor: vk_attachment.initialLayout = current_layout; - vk_attachment.finalLayout = vk::ImageLayout::eColorAttachmentOptimal; + if (supports_framebuffer_fetch) { + vk_attachment.finalLayout = vk::ImageLayout::eGeneral; + } else { + vk_attachment.finalLayout = vk::ImageLayout::eColorAttachmentOptimal; + } break; case AttachmentKind::kDepth: case AttachmentKind::kStencil: diff --git a/impeller/renderer/backend/vulkan/pipeline_library_vk.cc b/impeller/renderer/backend/vulkan/pipeline_library_vk.cc index 9342061db7f3e..5149158a6904a 100644 --- a/impeller/renderer/backend/vulkan/pipeline_library_vk.cc +++ b/impeller/renderer/backend/vulkan/pipeline_library_vk.cc @@ -19,6 +19,8 @@ #include "impeller/renderer/backend/vulkan/pipeline_vk.h" #include "impeller/renderer/backend/vulkan/shader_function_vk.h" #include "impeller/renderer/backend/vulkan/vertex_descriptor_vk.h" +#include "vulkan/vulkan_core.h" +#include "vulkan/vulkan_enums.hpp" namespace impeller { @@ -28,6 +30,7 @@ PipelineLibraryVK::PipelineLibraryVK( fml::UniqueFD cache_directory, std::shared_ptr worker_task_runner) : device_holder_(device_holder), + supports_framebuffer_fetch_(caps->SupportsFramebufferFetch()), pso_cache_(std::make_shared(std::move(caps), device_holder, std::move(cache_directory))), @@ -60,11 +63,12 @@ static vk::AttachmentDescription CreatePlaceholderAttachmentDescription( SampleCount sample_count) { // Load store ops are immaterial for pass compatibility. The right ops will be // picked up when the pass associated with framebuffer. - return CreateAttachmentDescription(format, // - sample_count, // - LoadAction::kDontCare, // - StoreAction::kDontCare, // - vk::ImageLayout::eUndefined // + return CreateAttachmentDescription(format, // + sample_count, // + LoadAction::kDontCare, // + StoreAction::kDontCare, // + vk::ImageLayout::eUndefined, // + false // ); } @@ -78,10 +82,12 @@ static vk::AttachmentDescription CreatePlaceholderAttachmentDescription( /// static vk::UniqueRenderPass CreateCompatRenderPassForPipeline( const vk::Device& device, - const PipelineDescriptor& desc) { + const PipelineDescriptor& desc, + bool supports_framebuffer_fetch) { std::vector attachments; std::vector color_refs; + std::vector subpass_color_ref; vk::AttachmentReference depth_stencil_ref = kUnusedAttachmentReference; color_refs.resize(desc.GetMaxColorAttacmentBindIndex() + 1, @@ -96,6 +102,8 @@ static vk::UniqueRenderPass CreateCompatRenderPassForPipeline( attachments.emplace_back( CreatePlaceholderAttachmentDescription(color.format, sample_count)); } + subpass_color_ref.push_back(vk::AttachmentReference{ + static_cast(0), vk::ImageLayout::eColorAttachmentOptimal}); if (auto depth = desc.GetDepthStencilAttachmentDescriptor(); depth.has_value()) { @@ -115,6 +123,17 @@ static vk::UniqueRenderPass CreateCompatRenderPassForPipeline( vk::SubpassDescription subpass_desc; subpass_desc.pipelineBindPoint = vk::PipelineBindPoint::eGraphics; + + // If the device supports framebuffer fetch, compatibility pipelines are + // always created with the self reference and rasterization order flag. This + // ensures that all compiled pipelines are compatible with a render pass that + // contains a framebuffer fetch shader (advanced blends). + std::vector subpass_dependencies; + if (supports_framebuffer_fetch) { + subpass_desc.setFlags(vk::SubpassDescriptionFlagBits:: + eRasterizationOrderAttachmentColorAccessARM); + subpass_desc.setInputAttachments(subpass_color_ref); + } subpass_desc.setColorAttachments(color_refs); subpass_desc.setPDepthStencilAttachment(&depth_stencil_ref); @@ -122,6 +141,7 @@ static vk::UniqueRenderPass CreateCompatRenderPassForPipeline( render_pass_desc.setAttachments(attachments); render_pass_desc.setPSubpasses(&subpass_desc); render_pass_desc.setSubpassCount(1u); + render_pass_desc.setDependencies(subpass_dependencies); auto [result, pass] = device.createRenderPassUnique(render_pass_desc); if (result != vk::Result::eSuccess) { @@ -368,8 +388,8 @@ std::unique_ptr PipelineLibraryVK::CreatePipeline( return nullptr; } - auto render_pass = - CreateCompatRenderPassForPipeline(strong_device->GetDevice(), desc); + auto render_pass = CreateCompatRenderPassForPipeline( + strong_device->GetDevice(), desc, supports_framebuffer_fetch_); if (render_pass) { pipeline_info.setBasePipelineHandle(VK_NULL_HANDLE); pipeline_info.setSubpass(0); diff --git a/impeller/renderer/backend/vulkan/pipeline_library_vk.h b/impeller/renderer/backend/vulkan/pipeline_library_vk.h index 9a5fce5976e9b..923dad397a731 100644 --- a/impeller/renderer/backend/vulkan/pipeline_library_vk.h +++ b/impeller/renderer/backend/vulkan/pipeline_library_vk.h @@ -35,6 +35,7 @@ class PipelineLibraryVK final friend ContextVK; std::weak_ptr device_holder_; + bool supports_framebuffer_fetch_ = false; std::shared_ptr pso_cache_; std::shared_ptr worker_task_runner_; Mutex pipelines_mutex_; diff --git a/impeller/renderer/backend/vulkan/pipeline_vk.h b/impeller/renderer/backend/vulkan/pipeline_vk.h index 5d92afaf6c25b..0b6b3b6e036e4 100644 --- a/impeller/renderer/backend/vulkan/pipeline_vk.h +++ b/impeller/renderer/backend/vulkan/pipeline_vk.h @@ -6,7 +6,6 @@ #include -#include "flutter/fml/macros.h" #include "impeller/base/backend_cast.h" #include "impeller/renderer/backend/vulkan/device_holder.h" #include "impeller/renderer/backend/vulkan/vk.h" diff --git a/impeller/renderer/backend/vulkan/render_pass_vk.cc b/impeller/renderer/backend/vulkan/render_pass_vk.cc index d720b8abf2330..e5d313748881f 100644 --- a/impeller/renderer/backend/vulkan/render_pass_vk.cc +++ b/impeller/renderer/backend/vulkan/render_pass_vk.cc @@ -21,6 +21,7 @@ #include "impeller/renderer/backend/vulkan/pipeline_vk.h" #include "impeller/renderer/backend/vulkan/shared_object_vk.h" #include "impeller/renderer/backend/vulkan/texture_vk.h" +#include "vulkan/vulkan_enums.hpp" #include "vulkan/vulkan_handles.hpp" #include "vulkan/vulkan_to_string.hpp" @@ -28,7 +29,8 @@ namespace impeller { static vk::AttachmentDescription CreateAttachmentDescription( const Attachment& attachment, - const std::shared_ptr Attachment::*texture_ptr) { + const std::shared_ptr Attachment::*texture_ptr, + bool supports_framebuffer_fetch) { const auto& texture = attachment.*texture_ptr; if (!texture) { return {}; @@ -50,6 +52,7 @@ static vk::AttachmentDescription CreateAttachmentDescription( store_action = StoreAction::kStore; } + // Always insert a barrier to transition to color attachment optimal. if (current_layout != vk::ImageLayout::ePresentSrcKHR && current_layout != vk::ImageLayout::eUndefined) { // Note: This should incur a barrier. @@ -60,7 +63,8 @@ static vk::AttachmentDescription CreateAttachmentDescription( desc.sample_count, // load_action, // store_action, // - current_layout // + current_layout, + supports_framebuffer_fetch // ); } @@ -96,7 +100,8 @@ static void SetTextureLayout( SharedHandleVK RenderPassVK::CreateVKRenderPass( const ContextVK& context, - const std::shared_ptr& command_buffer) const { + const std::shared_ptr& command_buffer, + bool supports_framebuffer_fetch) const { std::vector attachments; std::vector color_refs; @@ -117,18 +122,22 @@ SharedHandleVK RenderPassVK::CreateVKRenderPass( kUnusedAttachmentReference); for (const auto& [bind_point, color] : render_target_.GetColorAttachments()) { - color_refs[bind_point] = - vk::AttachmentReference{static_cast(attachments.size()), - vk::ImageLayout::eColorAttachmentOptimal}; - attachments.emplace_back( - CreateAttachmentDescription(color, &Attachment::texture)); + color_refs[bind_point] = vk::AttachmentReference{ + static_cast(attachments.size()), + supports_framebuffer_fetch ? vk::ImageLayout::eGeneral + : vk::ImageLayout::eColorAttachmentOptimal}; + attachments.emplace_back(CreateAttachmentDescription( + color, &Attachment::texture, supports_framebuffer_fetch)); SetTextureLayout(color, attachments.back(), command_buffer, &Attachment::texture); if (color.resolve_texture) { resolve_refs[bind_point] = vk::AttachmentReference{ - static_cast(attachments.size()), vk::ImageLayout::eGeneral}; - attachments.emplace_back( - CreateAttachmentDescription(color, &Attachment::resolve_texture)); + static_cast(attachments.size()), + supports_framebuffer_fetch + ? vk::ImageLayout::eGeneral + : vk::ImageLayout::eColorAttachmentOptimal}; + attachments.emplace_back(CreateAttachmentDescription( + color, &Attachment::resolve_texture, supports_framebuffer_fetch)); SetTextureLayout(color, attachments.back(), command_buffer, &Attachment::resolve_texture); } @@ -138,8 +147,8 @@ SharedHandleVK RenderPassVK::CreateVKRenderPass( depth_stencil_ref = vk::AttachmentReference{ static_cast(attachments.size()), vk::ImageLayout::eDepthStencilAttachmentOptimal}; - attachments.emplace_back( - CreateAttachmentDescription(depth.value(), &Attachment::texture)); + attachments.emplace_back(CreateAttachmentDescription( + depth.value(), &Attachment::texture, supports_framebuffer_fetch)); SetTextureLayout(depth.value(), attachments.back(), command_buffer, &Attachment::texture); } @@ -149,8 +158,8 @@ SharedHandleVK RenderPassVK::CreateVKRenderPass( depth_stencil_ref = vk::AttachmentReference{ static_cast(attachments.size()), vk::ImageLayout::eDepthStencilAttachmentOptimal}; - attachments.emplace_back( - CreateAttachmentDescription(stencil.value(), &Attachment::texture)); + attachments.emplace_back(CreateAttachmentDescription( + stencil.value(), &Attachment::texture, supports_framebuffer_fetch)); SetTextureLayout(stencil.value(), attachments.back(), command_buffer, &Attachment::texture); } @@ -161,6 +170,16 @@ SharedHandleVK RenderPassVK::CreateVKRenderPass( subpass_desc.setResolveAttachments(resolve_refs); subpass_desc.setPDepthStencilAttachment(&depth_stencil_ref); + std::vector subpass_dependencies; + std::vector subpass_color_ref; + subpass_color_ref.push_back(vk::AttachmentReference{ + static_cast(0), vk::ImageLayout::eColorAttachmentOptimal}); + if (supports_framebuffer_fetch) { + subpass_desc.setFlags(vk::SubpassDescriptionFlagBits:: + eRasterizationOrderAttachmentColorAccessARM); + subpass_desc.setInputAttachments(subpass_color_ref); + } + vk::RenderPassCreateInfo render_pass_desc; render_pass_desc.setAttachments(attachments); render_pass_desc.setPSubpasses(&subpass_desc); @@ -245,7 +264,6 @@ SharedHandleVK RenderPassVK::CreateVKFramebuffer( const auto target_size = render_target_.GetRenderTargetSize(); fb_info.width = target_size.width; fb_info.height = target_size.height; - fb_info.layers = 1u; std::vector attachments; @@ -490,7 +508,9 @@ bool RenderPassVK::OnEncodeCommands(const Context& context) const { const auto& target_size = render_target_.GetRenderTargetSize(); - auto render_pass = CreateVKRenderPass(vk_context, command_buffer); + auto render_pass = CreateVKRenderPass( + vk_context, command_buffer, + vk_context.GetCapabilities()->SupportsFramebufferFetch()); if (!render_pass) { VALIDATION_LOG << "Could not create renderpass."; return false; @@ -516,8 +536,10 @@ bool RenderPassVK::OnEncodeCommands(const Context& context) const { static_cast(target_size.height); pass_info.setClearValues(clear_values); - auto desc_sets_result = - AllocateAndBindDescriptorSets(vk_context, encoder, commands_); + const auto& color_image_vk = TextureVK::Cast( + *render_target_.GetColorAttachments().find(0u)->second.texture); + auto desc_sets_result = AllocateAndBindDescriptorSets( + vk_context, encoder, commands_, color_image_vk); if (!desc_sets_result.ok()) { return false; } diff --git a/impeller/renderer/backend/vulkan/render_pass_vk.h b/impeller/renderer/backend/vulkan/render_pass_vk.h index 3411b9628fbae..b7164d9d6c1f0 100644 --- a/impeller/renderer/backend/vulkan/render_pass_vk.h +++ b/impeller/renderer/backend/vulkan/render_pass_vk.h @@ -43,7 +43,8 @@ class RenderPassVK final : public RenderPass { SharedHandleVK CreateVKRenderPass( const ContextVK& context, - const std::shared_ptr& command_buffer) const; + const std::shared_ptr& command_buffer, + bool has_subpass_dependency) const; SharedHandleVK CreateVKFramebuffer( const ContextVK& context, diff --git a/impeller/renderer/pipeline.h b/impeller/renderer/pipeline.h index 4426a8984406d..1c761c0a6ff03 100644 --- a/impeller/renderer/pipeline.h +++ b/impeller/renderer/pipeline.h @@ -7,7 +7,6 @@ #include #include "compute_pipeline_descriptor.h" -#include "flutter/fml/macros.h" #include "impeller/renderer/compute_pipeline_builder.h" #include "impeller/renderer/compute_pipeline_descriptor.h" #include "impeller/renderer/context.h" diff --git a/impeller/renderer/pipeline_descriptor.cc b/impeller/renderer/pipeline_descriptor.cc index 9ae6710426f63..8b9dcf8fef7ae 100644 --- a/impeller/renderer/pipeline_descriptor.cc +++ b/impeller/renderer/pipeline_descriptor.cc @@ -45,6 +45,7 @@ std::size_t PipelineDescriptor::GetHash() const { fml::HashCombineSeed(seed, cull_mode_); fml::HashCombineSeed(seed, primitive_type_); fml::HashCombineSeed(seed, polygon_mode_); + fml::HashCombineSeed(seed, use_subpass_input_); return seed; } @@ -65,7 +66,8 @@ bool PipelineDescriptor::IsEqual(const PipelineDescriptor& other) const { cull_mode_ == other.cull_mode_ && primitive_type_ == other.primitive_type_ && polygon_mode_ == other.polygon_mode_ && - specialization_constants_ == other.specialization_constants_; + specialization_constants_ == other.specialization_constants_ && + use_subpass_input_ == other.use_subpass_input_; } PipelineDescriptor& PipelineDescriptor::SetLabel(std::string label) { diff --git a/impeller/renderer/pipeline_descriptor.h b/impeller/renderer/pipeline_descriptor.h index 6231fd97289bc..30149a0524420 100644 --- a/impeller/renderer/pipeline_descriptor.h +++ b/impeller/renderer/pipeline_descriptor.h @@ -20,6 +20,11 @@ class VertexDescriptor; template class Pipeline; +enum class UseSubpassInput { + kYes, + kNo, +}; + class PipelineDescriptor final : public Comparable { public: PipelineDescriptor(); @@ -128,6 +133,17 @@ class PipelineDescriptor final : public Comparable { const std::vector& GetSpecializationConstants() const; + void SetUseSubpassInput(UseSubpassInput value) { use_subpass_input_ = value; } + + bool UsesSubpassInput() const { + switch (use_subpass_input_) { + case UseSubpassInput::kYes: + return true; + case UseSubpassInput::kNo: + return false; + } + } + private: std::string label_; SampleCount sample_count_ = SampleCount::kCount1; @@ -146,6 +162,7 @@ class PipelineDescriptor final : public Comparable { back_stencil_attachment_descriptor_; PrimitiveType primitive_type_ = PrimitiveType::kTriangle; PolygonMode polygon_mode_ = PolygonMode::kFill; + UseSubpassInput use_subpass_input_ = UseSubpassInput::kNo; std::vector specialization_constants_; }; diff --git a/shell/platform/android/android_context_vulkan_impeller.cc b/shell/platform/android/android_context_vulkan_impeller.cc index d9521c35b2b89..c40f997924e07 100644 --- a/shell/platform/android/android_context_vulkan_impeller.cc +++ b/shell/platform/android/android_context_vulkan_impeller.cc @@ -6,6 +6,7 @@ #include "flutter/fml/paths.h" #include "flutter/impeller/entity/vk/entity_shaders_vk.h" +#include "flutter/impeller/entity/vk/framebuffer_blend_shaders_vk.h" #include "flutter/impeller/entity/vk/modern_shaders_vk.h" #include "flutter/impeller/renderer/backend/vulkan/context_vk.h" @@ -19,14 +20,17 @@ static std::shared_ptr CreateImpellerContext( const fml::RefPtr& proc_table, bool enable_vulkan_validation) { std::vector> shader_mappings = { - std::make_shared(impeller_entity_shaders_vk_data, - impeller_entity_shaders_vk_length), + std::make_shared(impeller_entity_shaders_vk_data, + impeller_entity_shaders_vk_length), + std::make_shared( + impeller_framebuffer_blend_shaders_vk_data, + impeller_framebuffer_blend_shaders_vk_length), #if IMPELLER_ENABLE_3D - std::make_shared(impeller_scene_shaders_vk_data, - impeller_scene_shaders_vk_length), + std::make_shared(impeller_scene_shaders_vk_data, + impeller_scene_shaders_vk_length), #endif - std::make_shared(impeller_modern_shaders_vk_data, - impeller_modern_shaders_vk_length), + std::make_shared(impeller_modern_shaders_vk_data, + impeller_modern_shaders_vk_length), }; PFN_vkGetInstanceProcAddr instance_proc_addr = diff --git a/shell/testing/tester_main.cc b/shell/testing/tester_main.cc index f04cbde7f9700..7fa3cc7537820 100644 --- a/shell/testing/tester_main.cc +++ b/shell/testing/tester_main.cc @@ -37,6 +37,7 @@ #include "flutter/vulkan/procs/vulkan_proc_table.h" // nogncheck #include "flutter/vulkan/swiftshader_path.h" // nogncheck #include "impeller/entity/vk/entity_shaders_vk.h" // nogncheck +#include "impeller/entity/vk/framebuffer_blend_shaders_vk.h" // nogncheck #include "impeller/entity/vk/modern_shaders_vk.h" // nogncheck #include "impeller/renderer/backend/vulkan/context_vk.h" // nogncheck #include "impeller/renderer/backend/vulkan/surface_context_vk.h" // nogncheck @@ -53,6 +54,9 @@ static std::vector> ShaderLibraryMappings() { impeller_entity_shaders_vk_length), std::make_shared(impeller_modern_shaders_vk_data, impeller_modern_shaders_vk_length), + std::make_shared( + impeller_framebuffer_blend_shaders_vk_data, + impeller_framebuffer_blend_shaders_vk_length), #if IMPELLER_ENABLE_3D std::make_shared(impeller_scene_shaders_vk_data, impeller_scene_shaders_vk_length),