diff --git a/engine/src/flutter/impeller/compositor/formats.h b/engine/src/flutter/impeller/compositor/formats.h index c970edc1886..0037fd87022 100644 --- a/engine/src/flutter/impeller/compositor/formats.h +++ b/engine/src/flutter/impeller/compositor/formats.h @@ -15,6 +15,7 @@ namespace impeller { enum class PixelFormat { kUnknown, + kPixelFormat_B8G8R8A8_UNormInt, kPixelFormat_B8G8R8A8_UNormInt_SRGB, kPixelFormat_D32_Float_S8_UNormInt, }; diff --git a/engine/src/flutter/impeller/compositor/formats_metal.h b/engine/src/flutter/impeller/compositor/formats_metal.h index 970b1ad5388..08aa2a8fadc 100644 --- a/engine/src/flutter/impeller/compositor/formats_metal.h +++ b/engine/src/flutter/impeller/compositor/formats_metal.h @@ -20,6 +20,8 @@ constexpr MTLPixelFormat ToMTLPixelFormat(PixelFormat format) { switch (format) { case PixelFormat::kUnknown: return MTLPixelFormatInvalid; + case PixelFormat::kPixelFormat_B8G8R8A8_UNormInt: + return MTLPixelFormatBGRA8Unorm; case PixelFormat::kPixelFormat_B8G8R8A8_UNormInt_SRGB: return MTLPixelFormatBGRA8Unorm_sRGB; case PixelFormat::kPixelFormat_D32_Float_S8_UNormInt: diff --git a/engine/src/flutter/impeller/compositor/pipeline_builder.h b/engine/src/flutter/impeller/compositor/pipeline_builder.h index 4191e938ccc..fe973e743fb 100644 --- a/engine/src/flutter/impeller/compositor/pipeline_builder.h +++ b/engine/src/flutter/impeller/compositor/pipeline_builder.h @@ -6,6 +6,7 @@ #include "flutter/fml/logging.h" #include "flutter/fml/macros.h" +#include "impeller/base/base.h" #include "impeller/compositor/context.h" #include "impeller/compositor/pipeline_descriptor.h" #include "impeller/compositor/shader_library.h" @@ -84,7 +85,7 @@ struct PipelineBuilder { // TODO(csg): This can be easily reflected but we are sticking to the // convention that the first stage output is the color output. ColorAttachmentDescriptor color0; - color0.format = PixelFormat::kPixelFormat_B8G8R8A8_UNormInt_SRGB; + color0.format = PixelFormat::kPixelFormat_B8G8R8A8_UNormInt; desc.SetColorAttachmentDescriptor(0u, std::move(color0)); } @@ -94,10 +95,10 @@ struct PipelineBuilder { // TODO(csg): Make this configurable if possible as the D32 component is // wasted. This can even be moved out of the "default" descriptor // construction as a case can be made that this is caller responsibility. - const auto combined_depth_stencil_format = - PixelFormat::kPixelFormat_D32_Float_S8_UNormInt; - desc.SetDepthPixelFormat(combined_depth_stencil_format); - desc.SetStencilPixelFormat(combined_depth_stencil_format); + // const auto combined_depth_stencil_format = + // PixelFormat::kPixelFormat_D32_Float_S8_UNormInt; + // desc.SetDepthPixelFormat(combined_depth_stencil_format); + // desc.SetStencilPixelFormat(combined_depth_stencil_format); } return desc; diff --git a/engine/src/flutter/impeller/compositor/renderer.h b/engine/src/flutter/impeller/compositor/renderer.h index 85b1f9e8130..61a1258c314 100644 --- a/engine/src/flutter/impeller/compositor/renderer.h +++ b/engine/src/flutter/impeller/compositor/renderer.h @@ -6,6 +6,7 @@ #include +#include #include #include "flutter/fml/macros.h" @@ -19,21 +20,19 @@ class RenderPass; class Renderer { public: - virtual ~Renderer(); + using RenderCallback = + std::function; + + Renderer(std::string shaders_directory); + + ~Renderer(); bool IsValid() const; - bool Render(const Surface& surface); + bool Render(const Surface& surface, RenderCallback callback) const; std::shared_ptr GetContext() const; - protected: - Renderer(std::string shaders_directory); - - virtual bool OnIsValid() const = 0; - - virtual bool OnRender(const Surface& surface, RenderPass& pass) = 0; - private: dispatch_semaphore_t frames_in_flight_sema_ = nullptr; std::shared_ptr context_; diff --git a/engine/src/flutter/impeller/compositor/renderer.mm b/engine/src/flutter/impeller/compositor/renderer.mm index b5dfcf82901..8b55e4b7c8a 100644 --- a/engine/src/flutter/impeller/compositor/renderer.mm +++ b/engine/src/flutter/impeller/compositor/renderer.mm @@ -25,10 +25,11 @@ Renderer::Renderer(std::string shaders_directory) Renderer::~Renderer() = default; bool Renderer::IsValid() const { - return is_valid_ && OnIsValid(); + return is_valid_; } -bool Renderer::Render(const Surface& surface) { +bool Renderer::Render(const Surface& surface, + RenderCallback render_callback) const { if (!IsValid()) { return false; } @@ -44,16 +45,12 @@ bool Renderer::Render(const Surface& surface) { } auto render_pass = - command_buffer->CreateRenderPass(surface.GetRenderPassDescriptor()); + command_buffer->CreateRenderPass(surface.GetTargetRenderPassDescriptor()); if (!render_pass) { return false; } - if (!OnRender(surface, *render_pass)) { - return false; - } - - if (!surface.Present()) { + if (render_callback && !render_callback(surface, *render_pass)) { return false; } diff --git a/engine/src/flutter/impeller/compositor/surface.h b/engine/src/flutter/impeller/compositor/surface.h index 7a92188e801..edb0e50a132 100644 --- a/engine/src/flutter/impeller/compositor/surface.h +++ b/engine/src/flutter/impeller/compositor/surface.h @@ -17,22 +17,18 @@ namespace impeller { class Surface { public: - Surface(RenderPassDescriptor desc, - std::function present_callback); + Surface(RenderPassDescriptor target_desc); ~Surface(); const Size& GetSize() const; - bool Present() const; - bool IsValid() const; - const RenderPassDescriptor& GetRenderPassDescriptor() const; + const RenderPassDescriptor& GetTargetRenderPassDescriptor() const; private: RenderPassDescriptor desc_; - std::function present_callback_; Size size_; bool is_valid_ = false; diff --git a/engine/src/flutter/impeller/compositor/surface.mm b/engine/src/flutter/impeller/compositor/surface.mm index a872e8a467f..dfcd330d315 100644 --- a/engine/src/flutter/impeller/compositor/surface.mm +++ b/engine/src/flutter/impeller/compositor/surface.mm @@ -8,9 +8,8 @@ namespace impeller { -Surface::Surface(RenderPassDescriptor desc, - std::function present_callback) - : desc_(std::move(desc)), present_callback_(present_callback) { +Surface::Surface(RenderPassDescriptor target_desc) + : desc_(std::move(target_desc)) { if (auto size = desc_.GetColorAttachmentSize(0u); size.has_value()) { size_ = size.value(); } else { @@ -26,21 +25,11 @@ const Size& Surface::GetSize() const { return size_; } -bool Surface::Present() const { - auto callback = present_callback_; - - if (!callback) { - return false; - } - - return callback(); -} - bool Surface::IsValid() const { return is_valid_; } -const RenderPassDescriptor& Surface::GetRenderPassDescriptor() const { +const RenderPassDescriptor& Surface::GetTargetRenderPassDescriptor() const { return desc_; } diff --git a/engine/src/flutter/impeller/entity/BUILD.gn b/engine/src/flutter/impeller/entity/BUILD.gn index bd19c0ed5ab..a321fa03bb6 100644 --- a/engine/src/flutter/impeller/entity/BUILD.gn +++ b/engine/src/flutter/impeller/entity/BUILD.gn @@ -8,8 +8,6 @@ impeller_component("entity") { sources = [ "entity.cc", "entity.h", - "entity_renderer.h", - "entity_renderer.mm", ] public_deps = [ diff --git a/engine/src/flutter/impeller/entity/entity_renderer.h b/engine/src/flutter/impeller/entity/entity_renderer.h deleted file mode 100644 index cf1cb1beaf8..00000000000 --- a/engine/src/flutter/impeller/entity/entity_renderer.h +++ /dev/null @@ -1,35 +0,0 @@ -// 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. - -#pragma once - -#include "flutter/fml/macros.h" -#include "impeller/compositor/renderer.h" -#include "impeller/compositor/vertex_buffer.h" -#include "impeller/entity/entity.h" - -namespace impeller { - -class EntityRenderer final : public Renderer { - public: - EntityRenderer(std::string shaders_directory); - - ~EntityRenderer() override; - - private: - std::shared_ptr root_; - std::shared_ptr box_pipeline_; - VertexBuffer vertex_buffer_; - bool is_valid_ = false; - - // |Renderer| - bool OnIsValid() const override; - - // |Renderer| - bool OnRender(const Surface& surface, RenderPass& pass) override; - - FML_DISALLOW_COPY_AND_ASSIGN(EntityRenderer); -}; - -} // namespace impeller diff --git a/engine/src/flutter/impeller/entity/entity_renderer.mm b/engine/src/flutter/impeller/entity/entity_renderer.mm deleted file mode 100644 index 2f0c9a1b12c..00000000000 --- a/engine/src/flutter/impeller/entity/entity_renderer.mm +++ /dev/null @@ -1,96 +0,0 @@ -// 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 "impeller/entity/entity_renderer.h" - -#include "flutter/fml/time/time_point.h" -#include "impeller/compositor/command.h" -#include "impeller/compositor/pipeline_builder.h" -#include "impeller/compositor/sampler_descriptor.h" -#include "impeller/compositor/surface.h" -#include "impeller/compositor/vertex_buffer_builder.h" -#include "impeller/primitives/box.frag.h" -#include "impeller/primitives/box.vert.h" - -namespace impeller { - -EntityRenderer::EntityRenderer(std::string shaders_directory) - : Renderer(std::move(shaders_directory)), - root_(std::make_shared()) { - root_->SetBackgroundColor(Color::DarkGray()); - - auto context = GetContext(); - - if (!context) { - return; - } - - using BoxPipelineBuilder = - PipelineBuilder; - auto desc = BoxPipelineBuilder::MakeDefaultPipelineDescriptor(*context); - box_pipeline_ = - context->GetPipelineLibrary()->GetRenderPipeline(std::move(desc)).get(); - - if (!box_pipeline_) { - return; - } - - VertexBufferBuilder vertex_builder; - vertex_builder.SetLabel("Box"); - vertex_builder.AddVertices({ - {{100, 100, 0.0}, {Color::Red()}, {0.0, 0.0}}, // 1 - {{800, 100, 0.0}, {Color::Green()}, {1.0, 0.0}}, // 2 - {{800, 800, 0.0}, {Color::Blue()}, {1.0, 1.0}}, // 3 - - {{100, 100, 0.0}, {Color::Cyan()}, {0.0, 0.0}}, // 1 - {{800, 800, 0.0}, {Color::White()}, {1.0, 1.0}}, // 3 - {{100, 800, 0.0}, {Color::Purple()}, {0.0, 1.0}}, // 4 - }); - - vertex_buffer_ = - vertex_builder.CreateVertexBuffer(*context->GetPermanentsAllocator()); - - if (!vertex_buffer_) { - return; - } - - is_valid_ = true; -} - -EntityRenderer::~EntityRenderer() = default; - -bool EntityRenderer::OnIsValid() const { - return is_valid_; -} - -bool EntityRenderer::OnRender(const Surface& surface, RenderPass& pass) { - pass.SetLabel("EntityRenderer Render Pass"); - - BoxVertexShader::UniformBuffer uniforms; - - uniforms.mvp = Matrix::MakeOrthographic(surface.GetSize()); - - Command cmd; - cmd.label = "Box"; - cmd.pipeline = box_pipeline_; - cmd.vertex_bindings.buffers[VertexDescriptor::kReservedVertexBufferIndex] = - vertex_buffer_.vertex_buffer; - cmd.vertex_bindings.buffers[BoxVertexShader::kUniformUniformBuffer.binding] = - pass.GetTransientsBuffer().EmplaceUniform(uniforms); - cmd.fragment_bindings.samplers[BoxFragmentShader::kInputContents1.binding] = - GetContext()->GetSamplerLibrary()->GetSampler({}); - cmd.fragment_bindings.samplers[BoxFragmentShader::kInputContents2.binding] = - GetContext()->GetSamplerLibrary()->GetSampler({}); - cmd.fragment_bindings.samplers[BoxFragmentShader::kInputContents3.binding] = - GetContext()->GetSamplerLibrary()->GetSampler({}); - cmd.index_buffer = vertex_buffer_.index_buffer; - cmd.index_count = vertex_buffer_.index_count; - cmd.primitive_type = PrimitiveType::kTriange; - if (!pass.RecordCommand(std::move(cmd))) { - return false; - } - return true; -} - -} // namespace impeller diff --git a/engine/src/flutter/impeller/entity/entity_unittests.mm b/engine/src/flutter/impeller/entity/entity_unittests.mm index b53534d35e8..939d907173b 100644 --- a/engine/src/flutter/impeller/entity/entity_unittests.mm +++ b/engine/src/flutter/impeller/entity/entity_unittests.mm @@ -3,14 +3,11 @@ // found in the LICENSE file. #include "flutter/testing/testing.h" -#include "impeller/playground/playground.h" namespace impeller { namespace testing { -TEST_F(Playground, CanCreateEntity) { - OpenPlaygroundHere([]() { return true; }); -} +// } // namespace testing } // namespace impeller diff --git a/engine/src/flutter/impeller/playground/playground.h b/engine/src/flutter/impeller/playground/playground.h index b340f83f48a..081e24a9e91 100644 --- a/engine/src/flutter/impeller/playground/playground.h +++ b/engine/src/flutter/impeller/playground/playground.h @@ -5,6 +5,7 @@ #include "flutter/fml/closure.h" #include "flutter/fml/macros.h" #include "gtest/gtest.h" +#include "impeller/compositor/renderer.h" namespace impeller { @@ -14,9 +15,13 @@ class Playground : public ::testing::Test { ~Playground(); - bool OpenPlaygroundHere(std::function closure); + std::shared_ptr GetContext() const; + + bool OpenPlaygroundHere(Renderer::RenderCallback render_callback); private: + Renderer renderer_; + FML_DISALLOW_COPY_AND_ASSIGN(Playground); }; diff --git a/engine/src/flutter/impeller/playground/playground.mm b/engine/src/flutter/impeller/playground/playground.mm index b87d3a4c9fd..ea7e46f1d43 100644 --- a/engine/src/flutter/impeller/playground/playground.mm +++ b/engine/src/flutter/impeller/playground/playground.mm @@ -3,9 +3,11 @@ // found in the LICENSE file. #include "impeller/playground/playground.h" +#include "flutter/fml/paths.h" #include "flutter/testing/testing.h" #include "impeller/compositor/context.h" #include "impeller/compositor/render_pass.h" +#include "impeller/compositor/renderer.h" #include "impeller/compositor/surface.h" #define GLFW_INCLUDE_NONE @@ -18,10 +20,22 @@ namespace impeller { -Playground::Playground() = default; +static std::string ShaderLibraryDirectory() { + auto path_result = fml::paths::GetExecutableDirectoryPath(); + if (!path_result.first) { + return {}; + } + return fml::paths::JoinPaths({path_result.second, "shaders"}); +} + +Playground::Playground() : renderer_(ShaderLibraryDirectory()) {} Playground::~Playground() = default; +std::shared_ptr Playground::GetContext() const { + return renderer_.IsValid() ? renderer_.GetContext() : nullptr; +} + static void PlaygroundKeyCallback(GLFWwindow* window, int key, int scancode, @@ -32,14 +46,12 @@ static void PlaygroundKeyCallback(GLFWwindow* window, } } -bool Playground::OpenPlaygroundHere(std::function closure) { - if (!closure) { +bool Playground::OpenPlaygroundHere(Renderer::RenderCallback render_callback) { + if (!render_callback) { return true; } - Context context(flutter::testing::GetFixturesPath()); - - if (!context.IsValid()) { + if (!renderer_.IsValid()) { return false; } @@ -50,7 +62,8 @@ bool Playground::OpenPlaygroundHere(std::function closure) { ::glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - auto window = ::glfwCreateWindow(800, 600, "Impeller Playground", NULL, NULL); + auto window = ::glfwCreateWindow( + 800, 600, "Impeller Playground (Press ESC or 'q' to quit)", NULL, NULL); if (!window) { return false; } @@ -63,7 +76,7 @@ bool Playground::OpenPlaygroundHere(std::function closure) { NSWindow* cocoa_window = ::glfwGetCocoaWindow(window); CAMetalLayer* layer = [CAMetalLayer layer]; - layer.device = context.GetMTLDevice(); + layer.device = renderer_.GetContext()->GetMTLDevice(); layer.pixelFormat = MTLPixelFormatBGRA8Unorm; cocoa_window.contentView.layer = layer; cocoa_window.contentView.wantsLayer = YES; @@ -91,23 +104,14 @@ bool Playground::OpenPlaygroundHere(std::function closure) { RenderPassDescriptor desc; desc.SetColorAttachment(color0, 0u); - Surface surface(desc, [current_drawable, closure]() { - if (!closure()) { - return false; - } - [current_drawable present]; - return true; - }); + Surface surface(desc); - if (!surface.IsValid()) { - FML_LOG(ERROR) << "Could not wrap surface to render to into."; + if (!renderer_.Render(surface, render_callback)) { + FML_LOG(ERROR) << "Could not render into the surface."; return false; } - if (!surface.Present()) { - FML_LOG(ERROR) << "Could not render into playground surface."; - return false; - } + [current_drawable present]; } return true; diff --git a/engine/src/flutter/impeller/primitives/BUILD.gn b/engine/src/flutter/impeller/primitives/BUILD.gn index a3a046d68c4..18acdaddd64 100644 --- a/engine/src/flutter/impeller/primitives/BUILD.gn +++ b/engine/src/flutter/impeller/primitives/BUILD.gn @@ -25,5 +25,10 @@ impeller_component("primitives") { } impeller_component("primitives_unittests") { + testonly = true sources = [ "primitives_unittests.mm" ] + deps = [ + ":primitives", + "../playground", + ] } diff --git a/engine/src/flutter/impeller/primitives/box.frag b/engine/src/flutter/impeller/primitives/box.frag index 48525081277..0263c965f29 100644 --- a/engine/src/flutter/impeller/primitives/box.frag +++ b/engine/src/flutter/impeller/primitives/box.frag @@ -3,17 +3,9 @@ // found in the LICENSE file. in vec4 color; -in vec2 interpolated_texture_coordinates; - -uniform sampler2D contents1; -uniform sampler2D contents2; -uniform sampler2D contents3; out vec4 frag_color; void main() { - vec4 color1 = texture(contents1, interpolated_texture_coordinates); - vec4 color2 = texture(contents2, interpolated_texture_coordinates); - vec4 color3 = texture(contents3, interpolated_texture_coordinates); - frag_color = color3; + frag_color = color; } diff --git a/engine/src/flutter/impeller/primitives/box.vert b/engine/src/flutter/impeller/primitives/box.vert index e764b6267b5..431c4c04d1f 100644 --- a/engine/src/flutter/impeller/primitives/box.vert +++ b/engine/src/flutter/impeller/primitives/box.vert @@ -8,13 +8,10 @@ uniform UniformBuffer { in vec3 vertex_position; in vec4 vertex_color; -in vec2 texture_coordinates; out vec4 color; -out vec2 interpolated_texture_coordinates; void main() { gl_Position = uniforms.mvp * vec4(vertex_position, 1.0); color = vertex_color; - interpolated_texture_coordinates = texture_coordinates; } diff --git a/engine/src/flutter/impeller/primitives/primitives_unittests.mm b/engine/src/flutter/impeller/primitives/primitives_unittests.mm index e7217c7d7b3..922c7ad8866 100644 --- a/engine/src/flutter/impeller/primitives/primitives_unittests.mm +++ b/engine/src/flutter/impeller/primitives/primitives_unittests.mm @@ -1,3 +1,74 @@ // 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 "flutter/fml/time/time_point.h" +#include "flutter/testing/testing.h" +#include "impeller/compositor/command.h" +#include "impeller/compositor/pipeline_builder.h" +#include "impeller/compositor/renderer.h" +#include "impeller/compositor/sampler_descriptor.h" +#include "impeller/compositor/surface.h" +#include "impeller/compositor/vertex_buffer_builder.h" +#include "impeller/playground/playground.h" +#include "impeller/primitives/box.frag.h" +#include "impeller/primitives/box.vert.h" + +namespace impeller { +namespace testing { + +using PrimitivesTest = Playground; + +TEST_F(PrimitivesTest, CanCreateBoxPrimitive) { + auto context = GetContext(); + ASSERT_TRUE(context); + using BoxPipelineBuilder = + PipelineBuilder; + auto desc = BoxPipelineBuilder::MakeDefaultPipelineDescriptor(*context); + auto box_pipeline = + context->GetPipelineLibrary()->GetRenderPipeline(std::move(desc)).get(); + ASSERT_TRUE(box_pipeline); + + VertexBufferBuilder vertex_builder; + vertex_builder.SetLabel("Box"); + vertex_builder.AddVertices({ + {{100, 100, 0.0}, {Color::Red()}}, // 1 + {{800, 100, 0.0}, {Color::Green()}}, // 2 + {{800, 800, 0.0}, {Color::Blue()}}, // 3 + + {{100, 100, 0.0}, {Color::Cyan()}}, // 1 + {{800, 800, 0.0}, {Color::White()}}, // 3 + {{100, 800, 0.0}, {Color::Purple()}}, // 4 + }); + auto vertex_buffer = + vertex_builder.CreateVertexBuffer(*context->GetPermanentsAllocator()); + ASSERT_TRUE(vertex_buffer); + Renderer::RenderCallback callback = [&](const Surface& surface, + RenderPass& pass) { + pass.SetLabel("EntityRenderer Render Pass"); + + BoxVertexShader::UniformBuffer uniforms; + + uniforms.mvp = Matrix::MakeOrthographic(surface.GetSize()); + + Command cmd; + cmd.label = "Box"; + cmd.pipeline = box_pipeline; + cmd.vertex_bindings.buffers[VertexDescriptor::kReservedVertexBufferIndex] = + vertex_buffer.vertex_buffer; + cmd.vertex_bindings + .buffers[BoxVertexShader::kUniformUniformBuffer.binding] = + pass.GetTransientsBuffer().EmplaceUniform(uniforms); + cmd.index_buffer = vertex_buffer.index_buffer; + cmd.index_count = vertex_buffer.index_count; + cmd.primitive_type = PrimitiveType::kTriange; + if (!pass.RecordCommand(std::move(cmd))) { + return false; + } + return true; + }; + OpenPlaygroundHere(callback); +} + +} // namespace testing +} // namespace impeller