diff --git a/ci/licenses_golden/excluded_files b/ci/licenses_golden/excluded_files index 211c6df6be377..272a0cf629132 100644 --- a/ci/licenses_golden/excluded_files +++ b/ci/licenses_golden/excluded_files @@ -138,6 +138,7 @@ ../../../flutter/impeller/entity/contents/filters/inputs/filter_input_unittests.cc ../../../flutter/impeller/entity/contents/test ../../../flutter/impeller/entity/contents/vertices_contents_unittests.cc +../../../flutter/impeller/entity/entity_pass_target_unittests.cc ../../../flutter/impeller/entity/entity_unittests.cc ../../../flutter/impeller/entity/geometry/geometry_unittests.cc ../../../flutter/impeller/entity/render_target_cache_unittests.cc diff --git a/impeller/BUILD.gn b/impeller/BUILD.gn index 3df283d93de75..2eaab0e2b76a8 100644 --- a/impeller/BUILD.gn +++ b/impeller/BUILD.gn @@ -98,7 +98,6 @@ impeller_component("impeller_unittests") { "aiks:aiks_unittests", "display_list:display_list_unittests", "entity:entity_unittests", - "entity:render_target_cache_unittests", "fixtures", "geometry:geometry_unittests", "image:image_unittests", diff --git a/impeller/core/texture.h b/impeller/core/texture.h index 95b21876afd97..8c6e3238b6448 100644 --- a/impeller/core/texture.h +++ b/impeller/core/texture.h @@ -6,7 +6,6 @@ #include -#include "flutter/fml/macros.h" #include "flutter/fml/mapping.h" #include "impeller/core/formats.h" #include "impeller/core/texture_descriptor.h" diff --git a/impeller/entity/BUILD.gn b/impeller/entity/BUILD.gn index bf4c88139c141..51e23460302df 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -282,10 +282,12 @@ impeller_component("entity_unittests") { "contents/checkerboard_contents_unittests.cc", "contents/filters/inputs/filter_input_unittests.cc", "contents/vertices_contents_unittests.cc", + "entity_pass_target_unittests.cc", "entity_playground.cc", "entity_playground.h", "entity_unittests.cc", "geometry/geometry_unittests.cc", + "render_target_cache_unittests.cc", ] deps = [ @@ -296,14 +298,3 @@ impeller_component("entity_unittests") { "//flutter/impeller/typographer/backends/skia:typographer_skia_backend", ] } - -impeller_component("render_target_cache_unittests") { - testonly = true - - sources = [ "render_target_cache_unittests.cc" ] - - deps = [ - ":entity", - "//flutter/testing:testing_lib", - ] -} diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc index f37bb4d4c1c3e..c6c39a6416f7a 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -286,7 +286,8 @@ static EntityPassTarget CreateRenderTarget(ContentContext& renderer, } return EntityPassTarget( - target, renderer.GetDeviceCapabilities().SupportsReadFromResolve()); + target, renderer.GetDeviceCapabilities().SupportsReadFromResolve(), + renderer.GetDeviceCapabilities().SupportsImplicitResolvingMSAA()); } uint32_t EntityPass::GetTotalPassReads(ContentContext& renderer) const { @@ -397,7 +398,10 @@ bool EntityPass::Render(ContentContext& renderer, entity.SetContents(contents); entity.SetBlendMode(BlendMode::kSource); - entity.Render(renderer, *render_pass); + if (!entity.Render(renderer, *render_pass)) { + VALIDATION_LOG << "Failed to render EntityPass root blit."; + return false; + } } if (!render_pass->EncodeCommands()) { @@ -455,7 +459,8 @@ bool EntityPass::Render(ContentContext& renderer, EntityPassTarget pass_target( root_render_target, - renderer.GetDeviceCapabilities().SupportsReadFromResolve()); + renderer.GetDeviceCapabilities().SupportsReadFromResolve(), + renderer.GetDeviceCapabilities().SupportsImplicitResolvingMSAA()); return OnRender( // renderer, // renderer diff --git a/impeller/entity/entity_pass_target.cc b/impeller/entity/entity_pass_target.cc index 46e7e47b4ffb3..d2a63bc43542c 100644 --- a/impeller/entity/entity_pass_target.cc +++ b/impeller/entity/entity_pass_target.cc @@ -11,9 +11,11 @@ namespace impeller { EntityPassTarget::EntityPassTarget(const RenderTarget& render_target, - bool supports_read_from_resolve) + bool supports_read_from_resolve, + bool supports_implicit_msaa) : target_(render_target), - supports_read_from_resolve_(supports_read_from_resolve) {} + supports_read_from_resolve_(supports_read_from_resolve), + supports_implicit_msaa_(supports_implicit_msaa) {} std::shared_ptr EntityPassTarget::Flip(Allocator& allocator) { auto color0 = target_.GetColorAttachments().find(0)->second; @@ -45,7 +47,16 @@ std::shared_ptr EntityPassTarget::Flip(Allocator& allocator) { } } - std::swap(color0.resolve_texture, secondary_color_texture_); + // If the color0 resolve texture is the same as the texture, then we're + // running on the GLES backend with implicit resolve. + if (supports_implicit_msaa_) { + auto new_secondary = color0.resolve_texture; + color0.resolve_texture = secondary_color_texture_; + color0.texture = secondary_color_texture_; + secondary_color_texture_ = new_secondary; + } else { + std::swap(color0.resolve_texture, secondary_color_texture_); + } target_.SetColorAttachment(color0, 0); diff --git a/impeller/entity/entity_pass_target.h b/impeller/entity/entity_pass_target.h index edb40b25f1b7b..76e90ece6f083 100644 --- a/impeller/entity/entity_pass_target.h +++ b/impeller/entity/entity_pass_target.h @@ -14,7 +14,8 @@ class InlinePassContext; class EntityPassTarget { public: explicit EntityPassTarget(const RenderTarget& render_target, - bool supports_read_from_resolve); + bool supports_read_from_resolve, + bool supports_implicit_msaa); /// @brief Flips the backdrop and returns a readable texture that can be /// bound/sampled to restore the previous pass. @@ -34,6 +35,7 @@ class EntityPassTarget { std::shared_ptr secondary_color_texture_; bool supports_read_from_resolve_; + bool supports_implicit_msaa_; friend InlinePassContext; diff --git a/impeller/entity/entity_pass_target_unittests.cc b/impeller/entity/entity_pass_target_unittests.cc new file mode 100644 index 0000000000000..390f7929913f7 --- /dev/null +++ b/impeller/entity/entity_pass_target_unittests.cc @@ -0,0 +1,114 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include + +#include "flutter/testing/testing.h" +#include "gtest/gtest.h" +#include "impeller/core/formats.h" +#include "impeller/entity/entity_pass_target.h" +#include "impeller/entity/entity_playground.h" + +namespace impeller { +namespace testing { + +using EntityPassTargetTest = EntityPlayground; +INSTANTIATE_PLAYGROUND_SUITE(EntityPassTargetTest); + +TEST_P(EntityPassTargetTest, SwapWithMSAATexture) { + if (GetContentContext() + ->GetDeviceCapabilities() + .SupportsImplicitResolvingMSAA()) { + GTEST_SKIP() << "Implicit MSAA is used on this device."; + } + auto content_context = GetContentContext(); + auto buffer = content_context->GetContext()->CreateCommandBuffer(); + auto render_target = RenderTarget::CreateOffscreenMSAA( + *content_context->GetContext(), + *GetContentContext()->GetRenderTargetCache(), {100, 100}); + + auto entity_pass_target = EntityPassTarget(render_target, false, false); + + auto color0 = entity_pass_target.GetRenderTarget() + .GetColorAttachments() + .find(0u) + ->second; + auto msaa_tex = color0.texture; + auto resolve_tex = color0.resolve_texture; + + entity_pass_target.Flip( + *content_context->GetContext()->GetResourceAllocator()); + + color0 = entity_pass_target.GetRenderTarget() + .GetColorAttachments() + .find(0u) + ->second; + + ASSERT_EQ(msaa_tex, color0.texture); + ASSERT_NE(resolve_tex, color0.resolve_texture); +} + +TEST_P(EntityPassTargetTest, SwapWithMSAAImplicitResolve) { + auto content_context = GetContentContext(); + auto buffer = content_context->GetContext()->CreateCommandBuffer(); + auto context = content_context->GetContext(); + auto& allocator = *context->GetResourceAllocator(); + + // Emulate implicit MSAA resolve by making color resolve and msaa texture the + // same. + RenderTarget render_target; + { + PixelFormat pixel_format = + context->GetCapabilities()->GetDefaultColorFormat(); + + // Create MSAA color texture. + + TextureDescriptor color0_tex_desc; + color0_tex_desc.storage_mode = StorageMode::kDevicePrivate; + color0_tex_desc.type = TextureType::kTexture2DMultisample; + color0_tex_desc.sample_count = SampleCount::kCount4; + color0_tex_desc.format = pixel_format; + color0_tex_desc.size = ISize{100, 100}; + color0_tex_desc.usage = static_cast(TextureUsage::kRenderTarget); + + auto color0_msaa_tex = allocator.CreateTexture(color0_tex_desc); + + // Color attachment. + + ColorAttachment color0; + color0.load_action = LoadAction::kDontCare; + color0.store_action = StoreAction::kStoreAndMultisampleResolve; + color0.texture = color0_msaa_tex; + color0.resolve_texture = color0_msaa_tex; + + render_target.SetColorAttachment(color0, 0u); + render_target.SetStencilAttachment(std::nullopt); + } + + auto entity_pass_target = EntityPassTarget(render_target, false, true); + + auto color0 = entity_pass_target.GetRenderTarget() + .GetColorAttachments() + .find(0u) + ->second; + auto msaa_tex = color0.texture; + auto resolve_tex = color0.resolve_texture; + + ASSERT_EQ(msaa_tex, resolve_tex); + + entity_pass_target.Flip( + *content_context->GetContext()->GetResourceAllocator()); + + color0 = entity_pass_target.GetRenderTarget() + .GetColorAttachments() + .find(0u) + ->second; + + ASSERT_NE(msaa_tex, color0.texture); + ASSERT_NE(resolve_tex, color0.resolve_texture); + ASSERT_EQ(color0.texture, color0.resolve_texture); +} + +} // namespace testing +} // namespace impeller