diff --git a/impeller/core/formats.h b/impeller/core/formats.h index 071fc3c88457a..d0809defc59d4 100644 --- a/impeller/core/formats.h +++ b/impeller/core/formats.h @@ -502,6 +502,13 @@ struct ColorAttachmentDescriptor { BlendOperation alpha_blend_op = BlendOperation::kAdd; BlendFactor dst_alpha_blend_factor = BlendFactor::kOneMinusSourceAlpha; + /// @brief If the advanced blend override is specified, then all other fields + /// are ignored. + /// + /// This is only valid if the platform has native support for advanced + /// blend modes. + std::optional advanced_blend_override = std::nullopt; + std::underlying_type_t write_mask = static_cast(ColorWriteMask::kAll); @@ -514,14 +521,17 @@ struct ColorAttachmentDescriptor { src_alpha_blend_factor == o.src_alpha_blend_factor && // alpha_blend_op == o.alpha_blend_op && // dst_alpha_blend_factor == o.dst_alpha_blend_factor && // - write_mask == o.write_mask; + write_mask == o.write_mask && // + advanced_blend_override.value_or(BlendMode::kClear) == + o.advanced_blend_override.value_or(BlendMode::kClear); } constexpr size_t Hash() const { - return fml::HashCombine(format, blending_enabled, src_color_blend_factor, - color_blend_op, dst_color_blend_factor, - src_alpha_blend_factor, alpha_blend_op, - dst_alpha_blend_factor, write_mask); + return fml::HashCombine( + format, blending_enabled, src_color_blend_factor, color_blend_op, + dst_color_blend_factor, src_alpha_blend_factor, alpha_blend_op, + dst_alpha_blend_factor, write_mask, + advanced_blend_override.value_or(BlendMode::kClear)); } }; diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index d76131fd400a2..95020f15fdb42 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -9,7 +9,6 @@ #include "impeller/base/strings.h" #include "impeller/core/formats.h" #include "impeller/entity/contents/framebuffer_blend_contents.h" -#include "impeller/entity/entity.h" #include "impeller/entity/render_target_cache.h" #include "impeller/renderer/command_buffer.h" #include "impeller/renderer/pipeline_descriptor.h" @@ -23,14 +22,8 @@ namespace impeller { void ContentContextOptions::ApplyToPipelineDescriptor( PipelineDescriptor& desc) const { auto pipeline_blend = blend_mode; - if (blend_mode > Entity::kLastPipelineBlendMode) { - VALIDATION_LOG << "Cannot use blend mode " << static_cast(blend_mode) - << " as a pipeline blend."; - pipeline_blend = BlendMode::kSourceOver; - } desc.SetSampleCount(sample_count); - ColorAttachmentDescriptor color0 = *desc.GetColorAttachmentDescriptor(0u); color0.format = color_attachment_pixel_format; color0.alpha_blend_op = BlendOperation::kAdd; @@ -132,7 +125,13 @@ void ContentContextOptions::ApplyToPipelineDescriptor( color0.src_color_blend_factor = BlendFactor::kZero; break; default: - FML_UNREACHABLE(); + // This is an advanced blend, set the override. + color0.advanced_blend_override = blend_mode; + color0.dst_alpha_blend_factor = BlendFactor::kOne; + color0.dst_color_blend_factor = BlendFactor::kOne; + color0.src_alpha_blend_factor = BlendFactor::kOne; + color0.src_color_blend_factor = BlendFactor::kOne; + break; } desc.SetColorAttachmentDescriptor(0u, color0); @@ -149,7 +148,6 @@ void ContentContextOptions::ApplyToPipelineDescriptor( } desc.SetPrimitiveType(primitive_type); - desc.SetPolygonMode(wireframe ? PolygonMode::kLine : PolygonMode::kFill); } diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h index e23ddcc1c06f1..5aca5312af0bd 100644 --- a/impeller/entity/contents/content_context.h +++ b/impeller/entity/contents/content_context.h @@ -12,7 +12,6 @@ #include "flutter/fml/build_config.h" #include "flutter/fml/hash_combine.h" #include "flutter/fml/logging.h" -#include "flutter/fml/macros.h" #include "impeller/base/validation.h" #include "impeller/core/formats.h" #include "impeller/entity/entity.h" diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc index 4ac61827c2865..c2facd664d764 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -293,10 +293,12 @@ static EntityPassTarget CreateRenderTarget(ContentContext& renderer, } uint32_t EntityPass::GetTotalPassReads(ContentContext& renderer) const { - return renderer.GetDeviceCapabilities().SupportsFramebufferFetch() - ? backdrop_filter_reads_from_pass_texture_ - : backdrop_filter_reads_from_pass_texture_ + - advanced_blend_reads_from_pass_texture_; + if (renderer.GetDeviceCapabilities().SupportsFramebufferFetch() || + renderer.GetDeviceCapabilities().SupportsNativeAdvancedBlends()) { + return backdrop_filter_reads_from_pass_texture_; + } + return backdrop_filter_reads_from_pass_texture_ + + advanced_blend_reads_from_pass_texture_; } bool EntityPass::Render(ContentContext& renderer, @@ -915,7 +917,10 @@ bool EntityPass::OnRender( /// if (result.entity.GetBlendMode() > Entity::kLastPipelineBlendMode) { - if (renderer.GetDeviceCapabilities().SupportsFramebufferFetch()) { + if (renderer.GetDeviceCapabilities().SupportsNativeAdvancedBlends()) { + // If native support for advanced blends is present, pass the entity + // through as-is. + } else if (renderer.GetDeviceCapabilities().SupportsFramebufferFetch()) { auto src_contents = result.entity.GetContents(); auto contents = std::make_shared(); contents->SetChildContents(src_contents); diff --git a/impeller/renderer/backend/gles/capabilities_gles.cc b/impeller/renderer/backend/gles/capabilities_gles.cc index e832aca15f276..e54ebfb546c3f 100644 --- a/impeller/renderer/backend/gles/capabilities_gles.cc +++ b/impeller/renderer/backend/gles/capabilities_gles.cc @@ -176,6 +176,10 @@ bool CapabilitiesGLES::SupportsDeviceTransientTextures() const { return false; } +bool CapabilitiesGLES::SupportsNativeAdvancedBlends() const { + return false; +} + PixelFormat CapabilitiesGLES::GetDefaultColorFormat() const { return PixelFormat::kR8G8B8A8UNormInt; } diff --git a/impeller/renderer/backend/gles/capabilities_gles.h b/impeller/renderer/backend/gles/capabilities_gles.h index 921d3a4287cac..07843c103a950 100644 --- a/impeller/renderer/backend/gles/capabilities_gles.h +++ b/impeller/renderer/backend/gles/capabilities_gles.h @@ -106,6 +106,9 @@ class CapabilitiesGLES final // |Capabilities| bool SupportsDeviceTransientTextures() const override; + // |Capabilities| + bool SupportsNativeAdvancedBlends() const override; + // |Capabilities| PixelFormat GetDefaultColorFormat() const override; diff --git a/impeller/renderer/backend/gles/proc_table_gles.h b/impeller/renderer/backend/gles/proc_table_gles.h index 03af427d8bacf..fa8ce818bb2fb 100644 --- a/impeller/renderer/backend/gles/proc_table_gles.h +++ b/impeller/renderer/backend/gles/proc_table_gles.h @@ -110,6 +110,7 @@ struct GLProc { PROC(BindTexture); \ PROC(BlendEquationSeparate); \ PROC(BlendFuncSeparate); \ + PROC(BlendEquation); \ PROC(BufferData); \ PROC(CheckFramebufferStatus); \ PROC(Clear); \ diff --git a/impeller/renderer/backend/gles/render_pass_gles.cc b/impeller/renderer/backend/gles/render_pass_gles.cc index efee4d68f6168..f656e7126bfb9 100644 --- a/impeller/renderer/backend/gles/render_pass_gles.cc +++ b/impeller/renderer/backend/gles/render_pass_gles.cc @@ -12,6 +12,7 @@ #include "fml/logging.h" #include "impeller/base/validation.h" #include "impeller/core/texture_descriptor.h" +#include "impeller/geometry/color.h" #include "impeller/renderer/backend/gles/context_gles.h" #include "impeller/renderer/backend/gles/device_buffer_gles.h" #include "impeller/renderer/backend/gles/formats_gles.h" @@ -44,6 +45,7 @@ void RenderPassGLES::OnSetLabel(std::string label) { void ConfigureBlending(const ProcTableGLES& gl, const ColorAttachmentDescriptor* color) { if (color->blending_enabled) { + FML_DCHECK(!color->advanced_blend_override.has_value()); gl.Enable(GL_BLEND); gl.BlendFuncSeparate( ToBlendFactor(color->src_color_blend_factor), // src color diff --git a/impeller/renderer/backend/metal/context_mtl.mm b/impeller/renderer/backend/metal/context_mtl.mm index 3c0055e6b9a9b..3d7b92b5a97de 100644 --- a/impeller/renderer/backend/metal/context_mtl.mm +++ b/impeller/renderer/backend/metal/context_mtl.mm @@ -68,6 +68,7 @@ static bool DeviceSupportsComputeSubgroups(id device) { .SetSupportsComputeSubgroups(DeviceSupportsComputeSubgroups(device)) .SetSupportsReadFromResolve(true) .SetSupportsDeviceTransientTextures(true) + .SetSupportsNativeAdvancedBlends(false) .Build(); } diff --git a/impeller/renderer/backend/vulkan/allocator_vk.cc b/impeller/renderer/backend/vulkan/allocator_vk.cc index a5dd9b7f14b00..dc87901c904fe 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.cc +++ b/impeller/renderer/backend/vulkan/allocator_vk.cc @@ -172,6 +172,7 @@ static constexpr vk::ImageUsageFlags ToVKImageUsageFlags( bool supports_memoryless_textures, bool supports_framebuffer_fetch) { vk::ImageUsageFlags vk_usage; + bool supports_advanced_blends = true; switch (mode) { case StorageMode::kHostVisible: @@ -192,6 +193,8 @@ static constexpr vk::ImageUsageFlags ToVKImageUsageFlags( } if (supports_framebuffer_fetch) { vk_usage |= vk::ImageUsageFlagBits::eInputAttachment; + } else if (supports_advanced_blends) { + vk_usage |= vk::ImageUsageFlagBits::eInputAttachment; } } diff --git a/impeller/renderer/backend/vulkan/capabilities_vk.cc b/impeller/renderer/backend/vulkan/capabilities_vk.cc index 4d83152795af7..e1db66c720030 100644 --- a/impeller/renderer/backend/vulkan/capabilities_vk.cc +++ b/impeller/renderer/backend/vulkan/capabilities_vk.cc @@ -157,6 +157,8 @@ static const char* GetDeviceExtensionName(OptionalDeviceExtensionVK ext) { switch (ext) { case OptionalDeviceExtensionVK::kEXTPipelineCreationFeedback: return VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME; + case OptionalDeviceExtensionVK::kEXTBlendOperationAdvanced: + return VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME; case OptionalDeviceExtensionVK::kARMRasterizationOrderAttachmentAccess: return VK_ARM_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME; case OptionalDeviceExtensionVK::kEXTRasterizationOrderAttachmentAccess: @@ -363,9 +365,9 @@ bool CapabilitiesVK::SetPhysicalDevice(const vk::PhysicalDevice& device) { device_properties_ = device.getProperties(); - auto physical_properties_2 = - device.getProperties2(); + auto physical_properties_2 = device.getProperties2< + vk::PhysicalDeviceProperties2, vk::PhysicalDeviceSubgroupProperties, + vk::PhysicalDeviceBlendOperationAdvancedPropertiesEXT>(); // Currently shaders only want access to arithmetic subgroup features. // If that changes this needs to get updated, and so does Metal (which right @@ -407,6 +409,10 @@ bool CapabilitiesVK::SetPhysicalDevice(const vk::PhysicalDevice& device) { } { + supports_native_advanced_blends_ = + optional_device_extensions_.find( + OptionalDeviceExtensionVK::kEXTBlendOperationAdvanced) != + optional_device_extensions_.end(); supports_framebuffer_fetch_ = (optional_device_extensions_.find( OptionalDeviceExtensionVK:: @@ -472,6 +478,10 @@ bool CapabilitiesVK::SupportsDecalSamplerAddressMode() const { return true; } +bool CapabilitiesVK::SupportsNativeAdvancedBlends() const { + return supports_native_advanced_blends_; +} + // |Capabilities| bool CapabilitiesVK::SupportsDeviceTransientTextures() const { return supports_device_transient_textures_; diff --git a/impeller/renderer/backend/vulkan/capabilities_vk.h b/impeller/renderer/backend/vulkan/capabilities_vk.h index eb9eb08a6f7a0..52c56eb1e7c4f 100644 --- a/impeller/renderer/backend/vulkan/capabilities_vk.h +++ b/impeller/renderer/backend/vulkan/capabilities_vk.h @@ -21,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, + // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_blend_operation_advanced.html + kEXTBlendOperationAdvanced, kARMRasterizationOrderAttachmentAccess, kEXTRasterizationOrderAttachmentAccess, kLast, @@ -92,6 +94,9 @@ class CapabilitiesVK final : public Capabilities, // |Capabilities| bool SupportsDeviceTransientTextures() const override; + // |Capabilities| + bool SupportsNativeAdvancedBlends() const override; + // |Capabilities| PixelFormat GetDefaultColorFormat() const override; @@ -111,6 +116,7 @@ class CapabilitiesVK final : public Capabilities, vk::PhysicalDeviceProperties device_properties_; bool supports_compute_subgroups_ = false; bool supports_device_transient_textures_ = false; + bool supports_native_advanced_blends_ = false; bool supports_framebuffer_fetch_ = false; bool is_valid_ = false; diff --git a/impeller/renderer/backend/vulkan/formats_vk.h b/impeller/renderer/backend/vulkan/formats_vk.h index 42fca4f9a6094..a74e0b9921f1f 100644 --- a/impeller/renderer/backend/vulkan/formats_vk.h +++ b/impeller/renderer/backend/vulkan/formats_vk.h @@ -73,6 +73,45 @@ constexpr vk::BlendOp ToVKBlendOp(BlendOperation op) { FML_UNREACHABLE(); } +constexpr vk::BlendOp ToAdvancedVKBlendOp(BlendMode blend_mode) { + switch (blend_mode) { + case BlendMode::kScreen: + return vk::BlendOp::eScreenEXT; + case BlendMode::kOverlay: + return vk::BlendOp::eOverlayEXT; + case BlendMode::kDarken: + return vk::BlendOp::eDarkenEXT; + case BlendMode::kLighten: + return vk::BlendOp::eLightenEXT; + case BlendMode::kColorDodge: + return vk::BlendOp::eColordodgeEXT; + case BlendMode::kColorBurn: + return vk::BlendOp::eColorburnEXT; + case BlendMode::kHardLight: + return vk::BlendOp::eHardlightEXT; + case BlendMode::kSoftLight: + return vk::BlendOp::eSoftlightEXT; + case BlendMode::kDifference: + return vk::BlendOp::eDifferenceEXT; + case BlendMode::kExclusion: + return vk::BlendOp::eExclusionEXT; + case BlendMode::kMultiply: + return vk::BlendOp::eMultiplyEXT; + case BlendMode::kHue: + return vk::BlendOp::eHslHueEXT; + case BlendMode::kSaturation: + return vk::BlendOp::eHslSaturationEXT; + case BlendMode::kColor: + return vk::BlendOp::eHslColorEXT; + case BlendMode::kLuminosity: + return vk::BlendOp::eHslLuminosityEXT; + break; + default: + break; + } + FML_UNREACHABLE(); +} + constexpr vk::ColorComponentFlags ToVKColorComponentFlags( std::underlying_type_t type) { using UnderlyingType = decltype(type); @@ -105,13 +144,24 @@ ToVKPipelineColorBlendAttachmentState(const ColorAttachmentDescriptor& desc) { res.setBlendEnable(desc.blending_enabled); res.setSrcColorBlendFactor(ToVKBlendFactor(desc.src_color_blend_factor)); - res.setColorBlendOp(ToVKBlendOp(desc.color_blend_op)); - res.setDstColorBlendFactor(ToVKBlendFactor(desc.dst_color_blend_factor)); + if (desc.advanced_blend_override.has_value()) { + res.setColorBlendOp( + ToAdvancedVKBlendOp(desc.advanced_blend_override.value())); + } else { + res.setColorBlendOp(ToVKBlendOp(desc.color_blend_op)); + } + res.setDstColorBlendFactor(ToVKBlendFactor(desc.dst_color_blend_factor)); res.setSrcAlphaBlendFactor(ToVKBlendFactor(desc.src_alpha_blend_factor)); - res.setAlphaBlendOp(ToVKBlendOp(desc.alpha_blend_op)); - res.setDstAlphaBlendFactor(ToVKBlendFactor(desc.dst_alpha_blend_factor)); + if (desc.advanced_blend_override.has_value()) { + res.setAlphaBlendOp( + ToAdvancedVKBlendOp(desc.advanced_blend_override.value())); + } else { + res.setAlphaBlendOp(ToVKBlendOp(desc.alpha_blend_op)); + } + + res.setDstAlphaBlendFactor(ToVKBlendFactor(desc.dst_alpha_blend_factor)); res.setColorWriteMask(ToVKColorComponentFlags(desc.write_mask)); return res; diff --git a/impeller/renderer/backend/vulkan/pipeline_library_vk.cc b/impeller/renderer/backend/vulkan/pipeline_library_vk.cc index 5149158a6904a..2993c8e1a4b8e 100644 --- a/impeller/renderer/backend/vulkan/pipeline_library_vk.cc +++ b/impeller/renderer/backend/vulkan/pipeline_library_vk.cc @@ -86,6 +86,7 @@ static vk::UniqueRenderPass CreateCompatRenderPassForPipeline( bool supports_framebuffer_fetch) { std::vector attachments; + bool supports_advanced_blend = true; std::vector color_refs; std::vector subpass_color_ref; vk::AttachmentReference depth_stencil_ref = kUnusedAttachmentReference; @@ -137,6 +138,24 @@ static vk::UniqueRenderPass CreateCompatRenderPassForPipeline( subpass_desc.setColorAttachments(color_refs); subpass_desc.setPDepthStencilAttachment(&depth_stencil_ref); + // See + // https://github.com/google/angle/blob/46817856888e74d23169e79ac98064600fd00127/src/libANGLE/renderer/vulkan/vk_cache_utils.cpp#L672-L693 + if (supports_advanced_blend) { + vk::SubpassDependency subpass_dependency; + subpass_dependency.setSrcSubpass(0); + subpass_dependency.setDstSubpass(0); + subpass_dependency.dependencyFlags = vk::DependencyFlagBits::eByRegion; + subpass_dependency.srcStageMask = + vk::PipelineStageFlagBits::eColorAttachmentOutput; + subpass_dependency.srcAccessMask = + vk::AccessFlagBits::eColorAttachmentWrite; + subpass_dependency.dstStageMask = + vk::PipelineStageFlagBits::eColorAttachmentOutput; + subpass_dependency.dstAccessMask = + vk::AccessFlagBits::eColorAttachmentReadNoncoherentEXT; + subpass_dependencies.emplace_back(subpass_dependency); + } + vk::RenderPassCreateInfo render_pass_desc; render_pass_desc.setAttachments(attachments); render_pass_desc.setPSubpasses(&subpass_desc); @@ -383,6 +402,15 @@ std::unique_ptr PipelineLibraryVK::CreatePipeline( blend_state.setAttachments(attachment_blend_state); pipeline_info.setPColorBlendState(&blend_state); + // vk::PipelineColorBlendAdvancedStateCreateInfoEXT state; + // if (desc.GetColorAttachmentDescriptors() + // .find(0u) + // ->second.advanced_blend_override.has_value()) { + // state.setBlendOverlap(vk::BlendOverlapEXT::eUncorrelated); // dunno + // state.setSrcPremultiplied(true); // double + // check state.setDstPremultiplied(true); blend_state.pNext = &state; + // } + std::shared_ptr strong_device = device_holder_.lock(); if (!strong_device) { return nullptr; diff --git a/impeller/renderer/backend/vulkan/render_pass_vk.cc b/impeller/renderer/backend/vulkan/render_pass_vk.cc index 615ab1e27617f..2fa4bd0ec125d 100644 --- a/impeller/renderer/backend/vulkan/render_pass_vk.cc +++ b/impeller/renderer/backend/vulkan/render_pass_vk.cc @@ -24,6 +24,7 @@ #include "impeller/renderer/command.h" #include "vulkan/vulkan_enums.hpp" #include "vulkan/vulkan_handles.hpp" +#include "vulkan/vulkan_structs.hpp" #include "vulkan/vulkan_to_string.hpp" namespace impeller { @@ -108,6 +109,7 @@ SharedHandleVK RenderPassVK::CreateVKRenderPass( std::vector color_refs; std::vector resolve_refs; vk::AttachmentReference depth_stencil_ref = kUnusedAttachmentReference; + bool supports_advanced_blend = true; // Spec says: "Each element of the pColorAttachments array corresponds to an // output location in the shader, i.e. if the shader declares an output @@ -123,10 +125,11 @@ SharedHandleVK RenderPassVK::CreateVKRenderPass( kUnusedAttachmentReference); for (const auto& [bind_point, color] : render_target_.GetColorAttachments()) { - color_refs[bind_point] = vk::AttachmentReference{ - static_cast(attachments.size()), - supports_framebuffer_fetch ? vk::ImageLayout::eGeneral - : vk::ImageLayout::eColorAttachmentOptimal}; + 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, @@ -134,7 +137,7 @@ SharedHandleVK RenderPassVK::CreateVKRenderPass( if (color.resolve_texture) { resolve_refs[bind_point] = vk::AttachmentReference{ static_cast(attachments.size()), - supports_framebuffer_fetch + (supports_framebuffer_fetch) ? vk::ImageLayout::eGeneral : vk::ImageLayout::eColorAttachmentOptimal}; attachments.emplace_back(CreateAttachmentDescription( @@ -181,10 +184,27 @@ SharedHandleVK RenderPassVK::CreateVKRenderPass( subpass_desc.setInputAttachments(subpass_color_ref); } + if (supports_advanced_blend) { + vk::SubpassDependency subpass_dependency; + subpass_dependency.setSrcSubpass(0); + subpass_dependency.setDstSubpass(0); + subpass_dependency.dependencyFlags = vk::DependencyFlagBits::eByRegion; + subpass_dependency.srcStageMask = + vk::PipelineStageFlagBits::eColorAttachmentOutput; + subpass_dependency.srcAccessMask = + vk::AccessFlagBits::eColorAttachmentWrite; + subpass_dependency.dstStageMask = + vk::PipelineStageFlagBits::eColorAttachmentOutput; + subpass_dependency.dstAccessMask = + vk::AccessFlagBits::eColorAttachmentReadNoncoherentEXT; + subpass_dependencies.emplace_back(subpass_dependency); + } + vk::RenderPassCreateInfo render_pass_desc; 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] = context.GetDevice().createRenderPassUnique(render_pass_desc); @@ -369,7 +389,8 @@ static bool EncodeCommand(const Context& context, CommandEncoderVK& encoder, PassBindingsCache& command_buffer_cache, const ISize& target_size, - const vk::DescriptorSet vk_desc_set) { + const vk::DescriptorSet vk_desc_set, + const TextureVK& texture) { #ifdef IMPELLER_DEBUG fml::ScopedCleanupClosure pop_marker( [&encoder]() { encoder.PopDebugGroup(); }); @@ -383,6 +404,26 @@ static bool EncodeCommand(const Context& context, const auto& cmd_buffer = encoder.GetCommandBuffer(); const auto& pipeline_vk = PipelineVK::Cast(*command.pipeline); + if (pipeline_vk.GetDescriptor() + .GetColorAttachmentDescriptor(0u) + ->advanced_blend_override.has_value()) { + vk::ImageMemoryBarrier barrier; + barrier.srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite; + barrier.dstAccessMask = + vk::AccessFlagBits::eColorAttachmentReadNoncoherentEXT; + barrier.oldLayout = vk::ImageLayout::eColorAttachmentOptimal; + barrier.newLayout = vk::ImageLayout::eColorAttachmentOptimal; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.image = texture.GetImage(); + barrier.subresourceRange = {vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}; + + cmd_buffer.pipelineBarrier( + vk::PipelineStageFlagBits::eColorAttachmentOutput, + vk::PipelineStageFlagBits::eColorAttachmentOutput, + vk::DependencyFlagBits::eByRegion, nullptr, nullptr, {barrier}); + } + encoder.GetCommandBuffer().bindDescriptorSets( vk::PipelineBindPoint::eGraphics, // bind point pipeline_vk.GetPipelineLayout(), // layout @@ -556,7 +597,7 @@ bool RenderPassVK::OnEncodeCommands(const Context& context) const { auto desc_index = 0u; for (const auto& command : commands_) { if (!EncodeCommand(context, command, *encoder, pass_bindings_cache_, - target_size, desc_sets[desc_index])) { + target_size, desc_sets[desc_index], color_image_vk)) { return false; } desc_index += 1; diff --git a/impeller/renderer/capabilities.cc b/impeller/renderer/capabilities.cc index 4dcda955ab954..7481f2f49f2b0 100644 --- a/impeller/renderer/capabilities.cc +++ b/impeller/renderer/capabilities.cc @@ -78,6 +78,10 @@ class StandardCapabilities final : public Capabilities { return supports_device_transient_textures_; } + bool SupportsNativeAdvancedBlends() const override { + return supports_native_advanced_blends_; + } + private: StandardCapabilities(bool supports_offscreen_msaa, bool supports_ssbo, @@ -89,6 +93,7 @@ class StandardCapabilities final : public Capabilities { bool supports_read_from_resolve, bool supports_decal_sampler_address_mode, bool supports_device_transient_textures, + bool supports_native_advanced_blends, PixelFormat default_color_format, PixelFormat default_stencil_format, PixelFormat default_depth_stencil_format) @@ -103,6 +108,7 @@ class StandardCapabilities final : public Capabilities { supports_decal_sampler_address_mode_( supports_decal_sampler_address_mode), supports_device_transient_textures_(supports_device_transient_textures), + supports_native_advanced_blends_(supports_native_advanced_blends), default_color_format_(default_color_format), default_stencil_format_(default_stencil_format), default_depth_stencil_format_(default_depth_stencil_format) {} @@ -119,6 +125,7 @@ class StandardCapabilities final : public Capabilities { bool supports_read_from_resolve_ = false; bool supports_decal_sampler_address_mode_ = false; bool supports_device_transient_textures_ = false; + bool supports_native_advanced_blends_ = false; PixelFormat default_color_format_ = PixelFormat::kUnknown; PixelFormat default_stencil_format_ = PixelFormat::kUnknown; PixelFormat default_depth_stencil_format_ = PixelFormat::kUnknown; @@ -207,6 +214,12 @@ CapabilitiesBuilder& CapabilitiesBuilder::SetSupportsDeviceTransientTextures( return *this; } +CapabilitiesBuilder& CapabilitiesBuilder::SetSupportsNativeAdvancedBlends( + bool value) { + supports_native_advanced_blends_ = value; + return *this; +} + std::unique_ptr CapabilitiesBuilder::Build() { return std::unique_ptr(new StandardCapabilities( // supports_offscreen_msaa_, // @@ -219,6 +232,7 @@ std::unique_ptr CapabilitiesBuilder::Build() { supports_read_from_resolve_, // supports_decal_sampler_address_mode_, // supports_device_transient_textures_, // + supports_native_advanced_blends_, // default_color_format_.value_or(PixelFormat::kUnknown), // default_stencil_format_.value_or(PixelFormat::kUnknown), // default_depth_stencil_format_.value_or(PixelFormat::kUnknown) // diff --git a/impeller/renderer/capabilities.h b/impeller/renderer/capabilities.h index 48f12a7d2432d..86d26598fba82 100644 --- a/impeller/renderer/capabilities.h +++ b/impeller/renderer/capabilities.h @@ -80,6 +80,10 @@ class Capabilities { /// @brief Whether the context backend supports `SamplerAddressMode::Decal`. virtual bool SupportsDecalSamplerAddressMode() const = 0; + /// @brief Whether the "non-pipeline" advanced blends are supported via + /// Additional blend configuration. + virtual bool SupportsNativeAdvancedBlends() const = 0; + /// @brief Whether the context backend supports allocating /// `StorageMode::kDeviceTransient` (aka "memoryless") textures, which /// are temporary textures kept in tile memory for the duration of the @@ -144,6 +148,8 @@ class CapabilitiesBuilder { CapabilitiesBuilder& SetSupportsDeviceTransientTextures(bool value); + CapabilitiesBuilder& SetSupportsNativeAdvancedBlends(bool value); + std::unique_ptr Build(); private: @@ -157,6 +163,7 @@ class CapabilitiesBuilder { bool supports_read_from_resolve_ = false; bool supports_decal_sampler_address_mode_ = false; bool supports_device_transient_textures_ = false; + bool supports_native_advanced_blends_ = false; std::optional default_color_format_ = std::nullopt; std::optional default_stencil_format_ = std::nullopt; std::optional default_depth_stencil_format_ = std::nullopt;