diff --git a/engine/src/flutter/impeller/compiler/compiler.cc b/engine/src/flutter/impeller/compiler/compiler.cc index 0ee15159f517a..22855798be214 100644 --- a/engine/src/flutter/impeller/compiler/compiler.cc +++ b/engine/src/flutter/impeller/compiler/compiler.cc @@ -34,6 +34,67 @@ constexpr const char* kEGLImageExternalExtension = "GL_OES_EGL_image_external"; constexpr const char* kEGLImageExternalExtension300 = "GL_OES_EGL_image_external_essl3"; constexpr int kVerboseErrorLineThreshold = 6; + +// Set per pass by RenderPassGLES: +1.0 swapchain, -1.0 offscreen FBO. See +// flutter/flutter#186554. +constexpr const char* kYFlipUniformName = "_impeller_y_flip"; +constexpr const char* kUserMainName = "_impeller_user_main"; + +bool IsGLTargetPlatform(TargetPlatform platform) { + return platform == TargetPlatform::kOpenGLES || + platform == TargetPlatform::kOpenGLDesktop || + platform == TargetPlatform::kRuntimeStageGLES || + platform == TargetPlatform::kRuntimeStageGLES3; +} + +// Wraps the SPIRV-Cross-emitted entry point so `gl_Position.y *= +// _impeller_y_flip;` runs on every exit, including early returns. Renames +// `void main(` to `void _impeller_user_main(` and appends a wrapper that +// calls it then applies the flip. +std::string InjectYFlipForGLESVertexShader(std::string source) { + // Anchor on leading newline; spirv-cross emits the entry point at file + // scope, so the match is unambiguous in its comment-free output. + constexpr std::string_view kMainPattern = "\nvoid main("; + const size_t main_pos = source.find(kMainPattern); + if (main_pos == std::string::npos) { + return source; + } + const std::string user_main_decl = + std::string("\nvoid ") + kUserMainName + "("; + source.replace(main_pos, kMainPattern.size(), user_main_decl); + + std::string wrapper = "\nvoid main() {\n "; + wrapper += kUserMainName; + wrapper += "();\n gl_Position.y *= "; + wrapper += kYFlipUniformName; + wrapper += ";\n}\n"; + source.append(wrapper); + + // Declare the uniform after the last `precision` directive, falling + // back to right after `#version`, falling back to the top. + const std::string declaration = + std::string("\nuniform float ") + kYFlipUniformName + ";\n"; + size_t inject_at = std::string::npos; + for (size_t pos = source.find("\nprecision "); pos != std::string::npos; + pos = source.find("\nprecision ", pos + 1)) { + const size_t eol = source.find('\n', pos + 1); + if (eol == std::string::npos) { + break; + } + inject_at = eol; + } + if (inject_at == std::string::npos) { + const size_t version_pos = source.find("#version"); + if (version_pos != std::string::npos) { + inject_at = source.find('\n', version_pos); + } + } + if (inject_at == std::string::npos) { + inject_at = 0; + } + source.insert(inject_at, declaration); + return source; +} } // namespace // This value should be <= 7372. UBOs can be larger on some devices but a @@ -499,6 +560,15 @@ Compiler::Compiler(const std::shared_ptr& source_mapping, // for Vulkan. The reflector needs information that is only valid after a // successful compilation call. auto sl_compilation_result_str = sl_compiler.GetCompiler()->compile(); + + // GL vertex shaders get a y-flip epilogue; see + // https://github.com/flutter/flutter/issues/186554. + if (IsGLTargetPlatform(source_options.target_platform) && + source_options.type == SourceType::kVertexShader) { + sl_compilation_result_str = + InjectYFlipForGLESVertexShader(std::move(sl_compilation_result_str)); + } + auto sl_compilation_result = CreateMappingWithString(sl_compilation_result_str); diff --git a/engine/src/flutter/impeller/compiler/compiler_unittests.cc b/engine/src/flutter/impeller/compiler/compiler_unittests.cc index 95c2fa0cbdc45..c83362addab36 100644 --- a/engine/src/flutter/impeller/compiler/compiler_unittests.cc +++ b/engine/src/flutter/impeller/compiler/compiler_unittests.cc @@ -79,6 +79,106 @@ TEST(CompilerTest, Defines) { EXPECT_NE(compiler_2.GetSPIRVAssembly(), nullptr); } +TEST(CompilerTest, YFlipInjectionForGLESVertexShaders) { + // Compiles `fixture_name` for `platform` and returns the generated SL + // source. See https://github.com/flutter/flutter/issues/186554. + auto compile = [](const char* fixture_name, SourceType type, + TargetPlatform platform) -> std::string { + std::shared_ptr fixture = + flutter::testing::OpenFixtureAsMapping(fixture_name); + FML_CHECK(fixture); + + SourceOptions options(fixture_name, type); + options.source_language = SourceLanguage::kGLSL; + options.target_platform = platform; + options.working_directory = std::make_shared( + flutter::testing::OpenFixturesDirectory()); + options.entry_point_name = "main"; + + Reflector::Options reflector_options; + reflector_options.target_platform = platform; + reflector_options.header_file_name = "y_flip_injection.h"; + reflector_options.shader_name = "shader"; + + Compiler compiler(fixture, options, reflector_options); + if (!compiler.IsValid()) { + return ""; + } + auto sl = compiler.GetSLShaderSource(); + if (!sl || !sl->GetMapping()) { + return ""; + } + return std::string(reinterpret_cast(sl->GetMapping()), + sl->GetSize()); + }; + + // GL vertex shader: gets both the declaration and the epilogue. + const std::string gl_vert = compile("sample.vert", SourceType::kVertexShader, + TargetPlatform::kOpenGLES); + EXPECT_NE(gl_vert.find("uniform float _impeller_y_flip"), std::string::npos) + << "GLES vertex shader is missing the y-flip uniform declaration:\n" + << gl_vert; + EXPECT_NE(gl_vert.find("gl_Position.y *= _impeller_y_flip"), + std::string::npos) + << "GLES vertex shader is missing the y-flip epilogue:\n" + << gl_vert; + + // GL fragment shader: not injected. + const std::string gl_frag = compile( + "sample.frag", SourceType::kFragmentShader, TargetPlatform::kOpenGLES); + EXPECT_EQ(gl_frag.find("_impeller_y_flip"), std::string::npos) + << "GLES fragment shader was unexpectedly injected:\n" + << gl_frag; + + // Metal vertex shader: not injected. + const std::string mtl_vert = compile("sample.vert", SourceType::kVertexShader, + TargetPlatform::kMetalIOS); + EXPECT_EQ(mtl_vert.find("_impeller_y_flip"), std::string::npos) + << "Metal vertex shader was unexpectedly injected:\n" + << mtl_vert; +} + +TEST(CompilerTest, YFlipInjectionHandlesEarlyReturnsInGLESVertexShader) { + // `y_flip_early_return.vert` has an early `return` before main's implicit + // exit; the wrap-main injection must flip on both paths. + std::shared_ptr fixture = + flutter::testing::OpenFixtureAsMapping("y_flip_early_return.vert"); + FML_CHECK(fixture); + + SourceOptions options("y_flip_early_return.vert", SourceType::kVertexShader); + options.source_language = SourceLanguage::kGLSL; + options.target_platform = TargetPlatform::kOpenGLES; + options.working_directory = std::make_shared( + flutter::testing::OpenFixturesDirectory()); + options.entry_point_name = "main"; + + Reflector::Options reflector_options; + reflector_options.target_platform = TargetPlatform::kOpenGLES; + reflector_options.header_file_name = "y_flip_early_return.h"; + reflector_options.shader_name = "shader"; + + Compiler compiler(fixture, options, reflector_options); + ASSERT_TRUE(compiler.IsValid()); + auto sl = compiler.GetSLShaderSource(); + ASSERT_TRUE(sl && sl->GetMapping()); + const std::string gl_vert(reinterpret_cast(sl->GetMapping()), + sl->GetSize()); + + EXPECT_NE(gl_vert.find("void _impeller_user_main("), std::string::npos) + << gl_vert; + EXPECT_NE(gl_vert.find("_impeller_user_main();"), std::string::npos) + << gl_vert; + EXPECT_NE(gl_vert.find("gl_Position.y *= _impeller_y_flip"), + std::string::npos) + << gl_vert; + + // Only the wrapper's `void main(` should remain after the rename. + const size_t first_main = gl_vert.find("\nvoid main("); + ASSERT_NE(first_main, std::string::npos); + EXPECT_EQ(gl_vert.find("\nvoid main(", first_main + 1), std::string::npos) + << gl_vert; +} + TEST(CompilerTest, ShaderKindMatchingIsSuccessful) { ASSERT_EQ(SourceTypeFromFileName("hello.vert"), SourceType::kVertexShader); ASSERT_EQ(SourceTypeFromFileName("hello.frag"), SourceType::kFragmentShader); diff --git a/engine/src/flutter/impeller/fixtures/BUILD.gn b/engine/src/flutter/impeller/fixtures/BUILD.gn index d062f86f0b91c..4b581ce9fb6dd 100644 --- a/engine/src/flutter/impeller/fixtures/BUILD.gn +++ b/engine/src/flutter/impeller/fixtures/BUILD.gn @@ -183,6 +183,7 @@ test_fixtures("file_fixtures") { "wtf.otf", "texture_lookup.frag", "mat2_test.frag", + "y_flip_early_return.vert", ] if (host_os == "mac") { fixtures += [ "/System/Library/Fonts/Apple Color Emoji.ttc" ] diff --git a/engine/src/flutter/impeller/fixtures/runtime_stage_border.frag b/engine/src/flutter/impeller/fixtures/runtime_stage_border.frag index 2d2cdc1676a1f..f1cbef4dbc696 100644 --- a/engine/src/flutter/impeller/fixtures/runtime_stage_border.frag +++ b/engine/src/flutter/impeller/fixtures/runtime_stage_border.frag @@ -13,11 +13,7 @@ void main() { vec2 fragCoord = FlutterFragCoord().xy; vec2 screenUV = vec2(fragCoord.x / uSize.x, fragCoord.y / uSize.y); - vec2 correctedScreenUV = screenUV; -#ifdef IMPELLER_TARGET_OPENGLES - correctedScreenUV.y = 1.0 - screenUV.y; -#endif - vec4 texColor = texture(uTexture, correctedScreenUV); + vec4 texColor = texture(uTexture, screenUV); // Check if we're within 20px of any edge float borderWidth = 20.0; diff --git a/engine/src/flutter/impeller/fixtures/runtime_stage_filter_circle.frag b/engine/src/flutter/impeller/fixtures/runtime_stage_filter_circle.frag index 423e77f9fcd07..ac498ab08043b 100644 --- a/engine/src/flutter/impeller/fixtures/runtime_stage_filter_circle.frag +++ b/engine/src/flutter/impeller/fixtures/runtime_stage_filter_circle.frag @@ -14,15 +14,11 @@ float radius = 30.0; void main() { vec2 uv = FlutterFragCoord().xy / u_size; - vec2 fixed_uv = uv; -#ifdef IMPELLER_TARGET_OPENGLES - fixed_uv.y = 1.0 - fixed_uv.y; -#endif vec2 norm_origin = u_origin / u_size; float norm_radius = radius / max(u_size.x, u_size.y); if (distance(uv, norm_origin) < norm_radius) { frag_color = vec4(1.0, 0.0, 0.0, 1.0); } else { - frag_color = texture(u_texture, fixed_uv); + frag_color = texture(u_texture, uv); } } diff --git a/engine/src/flutter/impeller/fixtures/runtime_stage_filter_warp.frag b/engine/src/flutter/impeller/fixtures/runtime_stage_filter_warp.frag index 7432dea8cb707..e5cc8266bedc1 100644 --- a/engine/src/flutter/impeller/fixtures/runtime_stage_filter_warp.frag +++ b/engine/src/flutter/impeller/fixtures/runtime_stage_filter_warp.frag @@ -12,8 +12,5 @@ out vec4 frag_color; void main() { vec2 uv = FlutterFragCoord().xy / u_size; uv = uv + vec2(0.0, 0.1 * sin(uv.x * 3.14 * 5.0)); -#ifdef IMPELLER_TARGET_OPENGLES - uv.y = 1.0 - uv.y; -#endif frag_color = texture(u_texture, uv); } diff --git a/engine/src/flutter/impeller/fixtures/texture.frag b/engine/src/flutter/impeller/fixtures/texture.frag index 37719781802e5..1e95b0f8f8ade 100644 --- a/engine/src/flutter/impeller/fixtures/texture.frag +++ b/engine/src/flutter/impeller/fixtures/texture.frag @@ -9,9 +9,5 @@ out vec4 frag_color; uniform sampler2D texture_contents; void main() { - vec2 tex_coords = interpolated_texture_coordinates; -#ifdef IMPELLER_TARGET_OPENGLES - tex_coords.y = 1.0 - tex_coords.y; -#endif - frag_color = texture(texture_contents, tex_coords); + frag_color = texture(texture_contents, interpolated_texture_coordinates); } diff --git a/engine/src/flutter/impeller/fixtures/y_flip_early_return.vert b/engine/src/flutter/impeller/fixtures/y_flip_early_return.vert new file mode 100644 index 0000000000000..690648f07f519 --- /dev/null +++ b/engine/src/flutter/impeller/fixtures/y_flip_early_return.vert @@ -0,0 +1,21 @@ +// 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. + +// Vertex shader with an early return; exercises the y-flip wrap-main +// path. See flutter/flutter#186554. + +uniform UniformBufferObject { + float discard_flag; +} +ubo; + +in vec2 inPosition; + +void main() { + if (ubo.discard_flag > 0.5) { + gl_Position = vec4(0.0); + return; + } + gl_Position = vec4(inPosition, 0.0, 1.0); +} diff --git a/engine/src/flutter/impeller/renderer/backend/gles/blit_command_gles.cc b/engine/src/flutter/impeller/renderer/backend/gles/blit_command_gles.cc index 56b50a7a4f3a7..a3fac9edf0f44 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/blit_command_gles.cc +++ b/engine/src/flutter/impeller/renderer/backend/gles/blit_command_gles.cc @@ -17,29 +17,6 @@ namespace impeller { -namespace { -static void FlipImage(uint8_t* buffer, - size_t width, - size_t height, - size_t stride) { - if (buffer == nullptr || stride == 0) { - return; - } - - const auto byte_width = width * stride; - - for (size_t top = 0; top < height; top++) { - size_t bottom = height - top - 1; - if (top >= bottom) { - break; - } - auto* top_row = buffer + byte_width * top; - auto* bottom_row = buffer + byte_width * bottom; - std::swap_ranges(top_row, top_row + byte_width, bottom_row); - } -} -} // namespace - BlitEncodeGLES::~BlitEncodeGLES() = default; static void DeleteFBO(const ProcTableGLES& gl, GLuint fbo, GLenum type) { @@ -288,8 +265,6 @@ bool BlitCopyTextureToBufferCommandGLES::Encode( return false; } - TextureCoordinateSystem coord_system = source->GetCoordinateSystem(); - GLuint read_fbo = GL_NONE; fml::ScopedCleanupClosure delete_fbos( [&gl, &read_fbo]() { DeleteFBO(gl, read_fbo, GL_FRAMEBUFFER); }); @@ -303,27 +278,15 @@ bool BlitCopyTextureToBufferCommandGLES::Encode( } DeviceBufferGLES::Cast(*destination) - .UpdateBufferData( - [&gl, // - this, // - format = gles_format->external_format, // - type = gles_format->type, // - coord_system, // - bytes_per_pixel = BytesPerPixelForPixelFormat(source_format) // + .UpdateBufferData([&gl, // + this, // + format = gles_format->external_format, // + type = gles_format->type // ](uint8_t* data, size_t length) { - gl.ReadPixels(source_region.GetX(), source_region.GetY(), - source_region.GetWidth(), source_region.GetHeight(), - format, type, data + destination_offset); - switch (coord_system) { - case TextureCoordinateSystem::kUploadFromHost: - break; - case TextureCoordinateSystem::kRenderToTexture: - // The texture is upside down, and must be inverted when copying - // byte data out. - FlipImage(data + destination_offset, source_region.GetWidth(), - source_region.GetHeight(), bytes_per_pixel); - } - }); + gl.ReadPixels(source_region.GetX(), source_region.GetY(), + source_region.GetWidth(), source_region.GetHeight(), + format, type, data + destination_offset); + }); return true; }; diff --git a/engine/src/flutter/impeller/renderer/backend/gles/pipeline_gles.cc b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_gles.cc index e173ce167be85..6ac83ecbed7c1 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/pipeline_gles.cc +++ b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_gles.cc @@ -53,6 +53,8 @@ bool PipelineGLES::BuildVertexDescriptor(const ProcTableGLES& gl, if (!vtx_desc->ReadUniformsBindings(gl, program)) { return false; } + // Cache the y-flip uniform; -1 if not declared. + y_flip_uniform_location_ = gl.GetUniformLocation(program, "_impeller_y_flip"); buffer_bindings_ = std::move(vtx_desc); return true; } diff --git a/engine/src/flutter/impeller/renderer/backend/gles/pipeline_gles.h b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_gles.h index ddbebe9ca656b..101a1cb768164 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/pipeline_gles.h +++ b/engine/src/flutter/impeller/renderer/backend/gles/pipeline_gles.h @@ -39,6 +39,10 @@ class PipelineGLES final [[nodiscard]] bool BuildVertexDescriptor(const ProcTableGLES& gl, GLuint program); + // GL location of the `_impeller_y_flip` uniform (flutter/flutter#186554), + // cached at link time. -1 if the shader doesn't declare it. + GLint GetYFlipUniformLocation() const { return y_flip_uniform_location_; } + private: friend PipelineLibraryGLES; friend class testing::RenderPassGLESViewportTest; @@ -46,6 +50,7 @@ class PipelineGLES final std::shared_ptr reactor_; std::shared_ptr handle_; std::unique_ptr buffer_bindings_; + GLint y_flip_uniform_location_ = -1; bool is_valid_ = false; // |Pipeline| diff --git a/engine/src/flutter/impeller/renderer/backend/gles/render_pass_gles.cc b/engine/src/flutter/impeller/renderer/backend/gles/render_pass_gles.cc index f9b501426b0ec..32380fe2a6edf 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/render_pass_gles.cc +++ b/engine/src/flutter/impeller/renderer/backend/gles/render_pass_gles.cc @@ -193,6 +193,7 @@ static void EncodeViewport(const ProcTableGLES& gl, const RenderPassData& pass_data, const std::optional& command_viewport, const ISize& target_size, + bool flip_y, std::optional& current_viewport) { auto new_viewport = command_viewport.value_or(pass_data.viewport); @@ -204,12 +205,15 @@ static void EncodeViewport(const ProcTableGLES& gl, current_viewport = new_viewport; + // FBO passes flip in the vertex shader; swapchain keeps the old + // top-down -> bottom-up viewport conversion. + const auto viewport_y_gl = flip_y ? new_viewport.rect.GetY() + : target_size.height - + new_viewport.rect.GetY() - + new_viewport.rect.GetHeight(); gl.Viewport(new_viewport.rect.GetX(), // x - target_size.height - new_viewport.rect.GetY() - - new_viewport.rect.GetHeight(), // y - new_viewport.rect.GetWidth(), // width - new_viewport.rect.GetHeight() // height - ); + viewport_y_gl, // y + new_viewport.rect.GetWidth(), new_viewport.rect.GetHeight()); if (pass_data.depth_attachment) { if (gl.DepthRangef.IsAvailable()) { gl.DepthRangef(new_viewport.depth_range.z_near, @@ -336,10 +340,16 @@ static void EncodeViewport(const ProcTableGLES& gl, // is bottom left origin, so we convert the coordinates here. ISize target_size = pass_data.color_attachment->GetSize(); + // Offscreen FBO passes flip in the vertex shader (the swapchain is + // left alone); see https://github.com/flutter/flutter/issues/186554. + const bool flip_y = !is_wrapped_fbo; + const float y_flip_value = flip_y ? -1.0f : 1.0f; + std::optional current_viewport; CullMode current_cull_mode = CullMode::kNone; WindingOrder current_winding_order = WindingOrder::kClockwise; - gl.FrontFace(GL_CW); + // Inverted to keep front-facing consistent under the vertex y-flip. + gl.FrontFace(flip_y ? GL_CCW : GL_CW); for (const auto& command : commands) { #ifdef IMPELLER_DEBUG @@ -392,6 +402,7 @@ static void EncodeViewport(const ProcTableGLES& gl, pass_data, // command.viewport, // target_size, // + flip_y, // current_viewport // ); @@ -401,12 +412,13 @@ static void EncodeViewport(const ProcTableGLES& gl, if (command.scissor.has_value()) { const auto& scissor = command.scissor.value(); gl.Enable(GL_SCISSOR_TEST); - gl.Scissor( - scissor.GetX(), // x - target_size.height - scissor.GetY() - scissor.GetHeight(), // y - scissor.GetWidth(), // width - scissor.GetHeight() // height - ); + // Same flip handling as the viewport above. + const auto scissor_y_gl = + flip_y ? scissor.GetY() + : target_size.height - scissor.GetY() - scissor.GetHeight(); + gl.Scissor(scissor.GetX(), // x + scissor_y_gl, // y + scissor.GetWidth(), scissor.GetHeight()); } //-------------------------------------------------------------------------- @@ -431,17 +443,18 @@ static void EncodeViewport(const ProcTableGLES& gl, } //-------------------------------------------------------------------------- - /// Setup winding order. - /// + /// Setup winding order. The pipeline's winding is inverted when + /// `flip_y` is in effect (the vertex flip reverses the rasterizer's + /// view of winding). WindingOrder pipeline_winding_order = pipeline.GetDescriptor().GetWindingOrder(); if (current_winding_order != pipeline_winding_order) { switch (pipeline.GetDescriptor().GetWindingOrder()) { case WindingOrder::kClockwise: - gl.FrontFace(GL_CW); + gl.FrontFace(flip_y ? GL_CCW : GL_CW); break; case WindingOrder::kCounterClockwise: - gl.FrontFace(GL_CCW); + gl.FrontFace(flip_y ? GL_CW : GL_CCW); break; } current_winding_order = pipeline_winding_order; @@ -471,6 +484,13 @@ static void EncodeViewport(const ProcTableGLES& gl, return false; } + //-------------------------------------------------------------------------- + /// Bind the y-flip uniform if the vertex shader declares it. + const GLint y_flip_loc = pipeline.GetYFlipUniformLocation(); + if (y_flip_loc >= 0) { + gl.Uniform1fv(y_flip_loc, 1, &y_flip_value); + } + //-------------------------------------------------------------------------- /// Bind uniform data. /// diff --git a/engine/src/flutter/impeller/renderer/backend/gles/render_pass_gles_unittests.cc b/engine/src/flutter/impeller/renderer/backend/gles/render_pass_gles_unittests.cc index 2a0ccf087683c..32207052db31f 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/render_pass_gles_unittests.cc +++ b/engine/src/flutter/impeller/renderer/backend/gles/render_pass_gles_unittests.cc @@ -311,7 +311,7 @@ TEST_F(RenderPassGLESViewportTest, ViewportCachedAcrossCommands) { // first override. We set a catch-all to 0 to ensure no other calls occur. EXPECT_CALL(mock_gl_impl_ref, Viewport(_, _, _, _)).Times(0); EXPECT_CALL(mock_gl_impl_ref, Viewport(0, 0, 100, 100)).Times(1); - EXPECT_CALL(mock_gl_impl_ref, Viewport(0, 50, 50, 50)).Times(1); + EXPECT_CALL(mock_gl_impl_ref, Viewport(0, 0, 50, 50)).Times(1); EXPECT_TRUE(render_pass->EncodeCommands()); EXPECT_TRUE(reactor->React()); @@ -344,7 +344,7 @@ TEST_F(RenderPassGLESViewportTest, EXPECT_CALL(mock_gl_impl_ref, Viewport(_, _, _, _)).Times(0); EXPECT_CALL(mock_gl_impl_ref, Viewport(0, 0, 100, 100)).Times(2); - EXPECT_CALL(mock_gl_impl_ref, Viewport(0, 50, 50, 50)).Times(1); + EXPECT_CALL(mock_gl_impl_ref, Viewport(0, 0, 50, 50)).Times(1); EXPECT_TRUE(render_pass->EncodeCommands()); EXPECT_TRUE(reactor->React()); diff --git a/engine/src/flutter/impeller/renderer/backend/gles/texture_gles.cc b/engine/src/flutter/impeller/renderer/backend/gles/texture_gles.cc index f54b05d56204d..01a8a9faa7611 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/texture_gles.cc +++ b/engine/src/flutter/impeller/renderer/backend/gles/texture_gles.cc @@ -649,13 +649,10 @@ bool TextureGLES::SetAsFramebufferAttachment(GLenum target, // |Texture| Scalar TextureGLES::GetYCoordScale() const { - switch (GetCoordinateSystem()) { - case TextureCoordinateSystem::kUploadFromHost: - return 1.0; - case TextureCoordinateSystem::kRenderToTexture: - return -1.0; - } - FML_UNREACHABLE(); + // GLES render-to-texture content is stored top-down via the + // vertex-stage y-flip; see + // https://github.com/flutter/flutter/issues/186554. + return 1.0; } bool TextureGLES::IsWrapped() const { diff --git a/engine/src/flutter/impeller/tools/malioc.json b/engine/src/flutter/impeller/tools/malioc.json index 60ba99c740049..80447cdb4484a 100644 --- a/engine/src/flutter/impeller/tools/malioc.json +++ b/engine/src/flutter/impeller/tools/malioc.json @@ -1909,8 +1909,8 @@ "load_store" ], "longest_path_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -1928,8 +1928,8 @@ "load_store" ], "shortest_path_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -1939,8 +1939,8 @@ "load_store" ], "total_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -1949,7 +1949,7 @@ }, "stack_spill_bytes": 0, "thread_occupancy": 100, - "uniform_registers_used": 22, + "uniform_registers_used": 24, "work_registers_used": 32 }, "Varying": { @@ -2302,8 +2302,8 @@ "load_store" ], "longest_path_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -2321,8 +2321,8 @@ "load_store" ], "shortest_path_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -2332,8 +2332,8 @@ "load_store" ], "total_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -2342,7 +2342,7 @@ }, "stack_spill_bytes": 0, "thread_occupancy": 100, - "uniform_registers_used": 20, + "uniform_registers_used": 22, "work_registers_used": 32 }, "Varying": { @@ -2411,7 +2411,7 @@ "load_store" ], "longest_path_cycles": [ - 2.640000104904175, + 2.9700000286102295, 4.0, 0.0 ], @@ -2424,7 +2424,7 @@ "load_store" ], "shortest_path_cycles": [ - 2.640000104904175, + 2.9700000286102295, 4.0, 0.0 ], @@ -2432,13 +2432,13 @@ "load_store" ], "total_cycles": [ - 2.6666667461395264, + 3.0, 4.0, 0.0 ] }, "thread_occupancy": 100, - "uniform_registers_used": 5, + "uniform_registers_used": 6, "work_registers_used": 2 } } @@ -2577,8 +2577,8 @@ "load_store" ], "longest_path_cycles": [ - 0.109375, - 0.109375, + 0.125, + 0.125, 0.0, 0.0, 2.0, @@ -2596,8 +2596,8 @@ "load_store" ], "shortest_path_cycles": [ - 0.109375, - 0.109375, + 0.125, + 0.125, 0.0, 0.0, 2.0, @@ -2607,8 +2607,8 @@ "load_store" ], "total_cycles": [ - 0.109375, - 0.109375, + 0.125, + 0.125, 0.0, 0.0, 2.0, @@ -2617,7 +2617,7 @@ }, "stack_spill_bytes": 0, "thread_occupancy": 100, - "uniform_registers_used": 18, + "uniform_registers_used": 20, "work_registers_used": 32 } } @@ -3856,8 +3856,8 @@ "load_store" ], "longest_path_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -3875,8 +3875,8 @@ "load_store" ], "shortest_path_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -3886,8 +3886,8 @@ "load_store" ], "total_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -3896,7 +3896,7 @@ }, "stack_spill_bytes": 0, "thread_occupancy": 100, - "uniform_registers_used": 20, + "uniform_registers_used": 22, "work_registers_used": 32 }, "Varying": { @@ -3992,7 +3992,7 @@ ] }, "thread_occupancy": 100, - "uniform_registers_used": 5, + "uniform_registers_used": 6, "work_registers_used": 2 } } @@ -4013,8 +4013,8 @@ "load_store" ], "longest_path_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -4032,8 +4032,8 @@ "load_store" ], "shortest_path_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -4043,8 +4043,8 @@ "load_store" ], "total_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -4170,8 +4170,8 @@ "load_store" ], "longest_path_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -4189,8 +4189,8 @@ "load_store" ], "shortest_path_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -4200,8 +4200,8 @@ "load_store" ], "total_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -4566,8 +4566,8 @@ "load_store" ], "longest_path_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -4585,8 +4585,8 @@ "load_store" ], "shortest_path_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -4596,8 +4596,8 @@ "load_store" ], "total_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -4606,7 +4606,7 @@ }, "stack_spill_bytes": 0, "thread_occupancy": 100, - "uniform_registers_used": 20, + "uniform_registers_used": 22, "work_registers_used": 32 }, "Varying": { @@ -4702,7 +4702,7 @@ ] }, "thread_occupancy": 100, - "uniform_registers_used": 5, + "uniform_registers_used": 6, "work_registers_used": 2 } } @@ -4723,8 +4723,8 @@ "load_store" ], "longest_path_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -4742,8 +4742,8 @@ "load_store" ], "shortest_path_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -4753,8 +4753,8 @@ "load_store" ], "total_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -4832,7 +4832,7 @@ "load_store" ], "longest_path_cycles": [ - 3.299999952316284, + 3.630000114440918, 4.0, 0.0 ], @@ -4845,7 +4845,7 @@ "load_store" ], "shortest_path_cycles": [ - 3.299999952316284, + 3.630000114440918, 4.0, 0.0 ], @@ -4853,14 +4853,14 @@ "load_store" ], "total_cycles": [ - 3.3333332538604736, + 3.6666667461395264, 4.0, 0.0 ] }, "thread_occupancy": 100, - "uniform_registers_used": 8, - "work_registers_used": 2 + "uniform_registers_used": 9, + "work_registers_used": 3 } } } @@ -4995,8 +4995,8 @@ "load_store" ], "longest_path_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -5014,8 +5014,8 @@ "load_store" ], "shortest_path_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -5025,8 +5025,8 @@ "load_store" ], "total_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -5035,7 +5035,7 @@ }, "stack_spill_bytes": 0, "thread_occupancy": 100, - "uniform_registers_used": 20, + "uniform_registers_used": 22, "work_registers_used": 32 }, "Varying": { @@ -5104,7 +5104,7 @@ "load_store" ], "longest_path_cycles": [ - 2.640000104904175, + 2.9700000286102295, 12.0, 0.0 ], @@ -5117,7 +5117,7 @@ "load_store" ], "shortest_path_cycles": [ - 2.640000104904175, + 2.9700000286102295, 12.0, 0.0 ], @@ -5125,13 +5125,13 @@ "load_store" ], "total_cycles": [ - 2.6666667461395264, + 3.0, 12.0, 0.0 ] }, "thread_occupancy": 100, - "uniform_registers_used": 5, + "uniform_registers_used": 6, "work_registers_used": 2 } } @@ -5737,8 +5737,8 @@ "load_store" ], "longest_path_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -5756,8 +5756,8 @@ "load_store" ], "shortest_path_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -5767,8 +5767,8 @@ "load_store" ], "total_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -5874,7 +5874,7 @@ }, "thread_occupancy": 100, "uniform_registers_used": 6, - "work_registers_used": 2 + "work_registers_used": 3 } } } @@ -6244,8 +6244,8 @@ "load_store" ], "longest_path_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -6263,8 +6263,8 @@ "load_store" ], "shortest_path_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -6274,8 +6274,8 @@ "load_store" ], "total_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -6284,7 +6284,7 @@ }, "stack_spill_bytes": 0, "thread_occupancy": 100, - "uniform_registers_used": 20, + "uniform_registers_used": 22, "work_registers_used": 32 }, "Varying": { @@ -6353,7 +6353,7 @@ "load_store" ], "longest_path_cycles": [ - 2.640000104904175, + 2.9700000286102295, 4.0, 0.0 ], @@ -6366,7 +6366,7 @@ "load_store" ], "shortest_path_cycles": [ - 2.640000104904175, + 2.9700000286102295, 4.0, 0.0 ], @@ -6374,13 +6374,13 @@ "load_store" ], "total_cycles": [ - 2.6666667461395264, + 3.0, 4.0, 0.0 ] }, "thread_occupancy": 100, - "uniform_registers_used": 5, + "uniform_registers_used": 6, "work_registers_used": 2 } } @@ -6519,8 +6519,8 @@ "load_store" ], "longest_path_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -6538,8 +6538,8 @@ "load_store" ], "shortest_path_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -6549,8 +6549,8 @@ "load_store" ], "total_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -6559,7 +6559,7 @@ }, "stack_spill_bytes": 0, "thread_occupancy": 100, - "uniform_registers_used": 20, + "uniform_registers_used": 22, "work_registers_used": 32 }, "Varying": { @@ -6628,7 +6628,7 @@ "load_store" ], "longest_path_cycles": [ - 2.640000104904175, + 2.9700000286102295, 4.0, 0.0 ], @@ -6641,7 +6641,7 @@ "load_store" ], "shortest_path_cycles": [ - 2.640000104904175, + 2.9700000286102295, 4.0, 0.0 ], @@ -6649,13 +6649,13 @@ "load_store" ], "total_cycles": [ - 2.6666667461395264, + 3.0, 4.0, 0.0 ] }, "thread_occupancy": 100, - "uniform_registers_used": 5, + "uniform_registers_used": 6, "work_registers_used": 2 } } @@ -6794,8 +6794,8 @@ "load_store" ], "longest_path_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -6813,8 +6813,8 @@ "load_store" ], "shortest_path_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -6824,8 +6824,8 @@ "load_store" ], "total_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -6834,7 +6834,7 @@ }, "stack_spill_bytes": 0, "thread_occupancy": 100, - "uniform_registers_used": 20, + "uniform_registers_used": 22, "work_registers_used": 32 }, "Varying": { @@ -6930,7 +6930,7 @@ ] }, "thread_occupancy": 100, - "uniform_registers_used": 5, + "uniform_registers_used": 6, "work_registers_used": 2 } } @@ -7069,8 +7069,8 @@ "load_store" ], "longest_path_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -7088,8 +7088,8 @@ "load_store" ], "shortest_path_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -7099,8 +7099,8 @@ "load_store" ], "total_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -7109,7 +7109,7 @@ }, "stack_spill_bytes": 0, "thread_occupancy": 100, - "uniform_registers_used": 20, + "uniform_registers_used": 22, "work_registers_used": 32 } } @@ -7154,7 +7154,7 @@ ] }, "thread_occupancy": 100, - "uniform_registers_used": 5, + "uniform_registers_used": 6, "work_registers_used": 2 } } @@ -8004,8 +8004,8 @@ "load_store" ], "longest_path_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -8023,8 +8023,8 @@ "load_store" ], "shortest_path_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -8034,8 +8034,8 @@ "load_store" ], "total_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -8285,8 +8285,8 @@ "load_store" ], "longest_path_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -8304,8 +8304,8 @@ "load_store" ], "shortest_path_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -8315,8 +8315,8 @@ "load_store" ], "total_cycles": [ - 0.140625, - 0.140625, + 0.15625, + 0.15625, 0.0, 0.0, 2.0, @@ -12492,4 +12492,4 @@ } } } -} \ No newline at end of file +} diff --git a/engine/src/flutter/lib/ui/fixtures/shaders/general_shaders/texture.frag b/engine/src/flutter/lib/ui/fixtures/shaders/general_shaders/texture.frag index bd8ff339017db..af63f21f58c05 100644 --- a/engine/src/flutter/lib/ui/fixtures/shaders/general_shaders/texture.frag +++ b/engine/src/flutter/lib/ui/fixtures/shaders/general_shaders/texture.frag @@ -13,9 +13,5 @@ uniform sampler2D u_texture; out vec4 frag_color; void main() { - vec2 tex_coords = FlutterFragCoord().xy / u_size; -#ifdef IMPELLER_TARGET_OPENGLES - tex_coords.y = 1.0 - tex_coords.y; -#endif - frag_color = texture(u_texture, tex_coords); + frag_color = texture(u_texture, FlutterFragCoord().xy / u_size); }