From 012487f3625349687d3586cbea14207ef87dc23d Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Tue, 29 Nov 2022 23:38:10 -0800 Subject: [PATCH] [Impeller Scene] Command encoding (flutter/engine#37977) --- engine/src/flutter/impeller/scene/geometry.cc | 22 +++++++- engine/src/flutter/impeller/scene/geometry.h | 9 +-- engine/src/flutter/impeller/scene/material.cc | 56 +++++++++++++++++++ engine/src/flutter/impeller/scene/material.h | 41 +++++++++++++- engine/src/flutter/impeller/scene/scene.cc | 4 +- .../flutter/impeller/scene/scene_context.cc | 26 +++++++++ .../flutter/impeller/scene/scene_context.h | 15 +++-- .../flutter/impeller/scene/scene_encoder.cc | 53 +++++++++++++++++- .../flutter/impeller/scene/scene_encoder.h | 19 ++++++- .../impeller/scene/static_mesh_entity.cc | 10 ++++ 10 files changed, 232 insertions(+), 23 deletions(-) diff --git a/engine/src/flutter/impeller/scene/geometry.cc b/engine/src/flutter/impeller/scene/geometry.cc index 47ed75f18b..8a7bf01377 100644 --- a/engine/src/flutter/impeller/scene/geometry.cc +++ b/engine/src/flutter/impeller/scene/geometry.cc @@ -6,6 +6,12 @@ #include +#include "impeller/geometry/point.h" +#include "impeller/geometry/vector.h" +#include "impeller/renderer/formats.h" +#include "impeller/renderer/vertex_buffer_builder.h" +#include "impeller/scene/shaders/geometry.vert.h" + namespace impeller { namespace scene { @@ -27,9 +33,19 @@ void CuboidGeometry::SetSize(Vector3 size) { size_ = size; } -VertexBuffer CuboidGeometry::GetVertexBuffer( - std::shared_ptr& allocator) const { - return {}; +VertexBuffer CuboidGeometry::GetVertexBuffer(Allocator& allocator) const { + VertexBufferBuilder builder; + // Layout: position, normal, tangent, uv + builder.AddVertices({ + // Front. + {Vector3(0, 0, 0), Vector3(0, 0, -1), Vector3(1, 0, 0), Point(0, 0)}, + {Vector3(1, 0, 0), Vector3(0, 0, -1), Vector3(1, 0, 0), Point(1, 0)}, + {Vector3(1, 1, 0), Vector3(0, 0, -1), Vector3(1, 0, 0), Point(1, 1)}, + {Vector3(1, 1, 0), Vector3(0, 0, -1), Vector3(1, 0, 0), Point(1, 1)}, + {Vector3(0, 1, 0), Vector3(0, 0, -1), Vector3(1, 0, 0), Point(0, 1)}, + {Vector3(0, 0, 0), Vector3(0, 0, -1), Vector3(1, 0, 0), Point(0, 0)}, + }); + return builder.CreateVertexBuffer(allocator); } } // namespace scene diff --git a/engine/src/flutter/impeller/scene/geometry.h b/engine/src/flutter/impeller/scene/geometry.h index f0e7e47eb3..92c90d1785 100644 --- a/engine/src/flutter/impeller/scene/geometry.h +++ b/engine/src/flutter/impeller/scene/geometry.h @@ -19,19 +19,16 @@ class Geometry { public: static std::shared_ptr MakeCuboid(Vector3 size); - private: - virtual VertexBuffer GetVertexBuffer( - std::shared_ptr& allocator) const = 0; + virtual VertexBuffer GetVertexBuffer(Allocator& allocator) const = 0; }; class CuboidGeometry final : public Geometry { public: void SetSize(Vector3 size); - private: - VertexBuffer GetVertexBuffer( - std::shared_ptr& allocator) const override; + VertexBuffer GetVertexBuffer(Allocator& allocator) const override; + private: Vector3 size_; }; diff --git a/engine/src/flutter/impeller/scene/material.cc b/engine/src/flutter/impeller/scene/material.cc index a38a14a4f5..a37b2bf51f 100644 --- a/engine/src/flutter/impeller/scene/material.cc +++ b/engine/src/flutter/impeller/scene/material.cc @@ -3,6 +3,11 @@ // found in the LICENSE file. #include "impeller/scene/material.h" +#include "impeller/renderer/formats.h" +#include "impeller/renderer/sampler_descriptor.h" +#include "impeller/renderer/sampler_library.h" +#include "impeller/scene/scene_context.h" +#include "impeller/scene/shaders/unlit.frag.h" #include @@ -33,6 +38,11 @@ void Material::SetTranslucent(bool is_translucent) { is_translucent_ = is_translucent; } +SceneContextOptions Material::GetContextOptions(const RenderPass& pass) const { + // TODO(bdero): Pipeline blend and stencil config. + return {.sample_count = pass.GetRenderTarget().GetSampleCount()}; +} + //------------------------------------------------------------------------------ /// UnlitMaterial /// @@ -41,6 +51,40 @@ void UnlitMaterial::SetColor(Color color) { color_ = color; } +void UnlitMaterial::SetColorTexture(std::shared_ptr color_texture) { + color_texture_ = std::move(color_texture); +} + +// |Material| +std::shared_ptr> UnlitMaterial::GetPipeline( + const SceneContext& scene_context, + const RenderPass& pass) const { + return scene_context.GetUnlitPipeline(GetContextOptions(pass)); +} + +// |Material| +void UnlitMaterial::BindToCommand(const SceneContext& scene_context, + HostBuffer& buffer, + Command& command) const { + // Uniform buffer. + UnlitPipeline::FragmentShader::FragInfo info; + info.color = color_; + UnlitPipeline::FragmentShader::BindFragInfo(command, + buffer.EmplaceUniform(info)); + + // Textures. + SamplerDescriptor sampler_descriptor; + sampler_descriptor.label = "Trilinear"; + sampler_descriptor.min_filter = MinMagFilter::kLinear; + sampler_descriptor.mag_filter = MinMagFilter::kLinear; + sampler_descriptor.mip_filter = MipFilter::kLinear; + UnlitPipeline::FragmentShader::BindBaseColorTexture( + command, + color_texture_ ? color_texture_ : scene_context.GetPlaceholderTexture(), + scene_context.GetContext()->GetSamplerLibrary()->GetSampler( + sampler_descriptor)); +} + //------------------------------------------------------------------------------ /// StandardMaterial /// @@ -78,5 +122,17 @@ void StandardMaterial::SetEnvironmentMap( environment_map_ = std::move(environment_map); } +// |Material| +std::shared_ptr> StandardMaterial::GetPipeline( + const SceneContext& scene_context, + const RenderPass& pass) const { + return nullptr; +} + +// |Material| +void StandardMaterial::BindToCommand(const SceneContext& scene_context, + HostBuffer& buffer, + Command& command) const {} + } // namespace scene } // namespace impeller diff --git a/engine/src/flutter/impeller/scene/material.h b/engine/src/flutter/impeller/scene/material.h index a9e0be7a3b..a579467304 100644 --- a/engine/src/flutter/impeller/scene/material.h +++ b/engine/src/flutter/impeller/scene/material.h @@ -8,11 +8,16 @@ #include "impeller/geometry/scalar.h" #include "impeller/renderer/formats.h" +#include "impeller/renderer/render_pass.h" #include "impeller/renderer/texture.h" namespace impeller { namespace scene { +class SceneContext; +struct SceneContextOptions; +class Geometry; + class UnlitMaterial; class StandardMaterial; @@ -40,7 +45,16 @@ class Material { void SetTranslucent(bool is_translucent); + virtual std::shared_ptr> GetPipeline( + const SceneContext& scene_context, + const RenderPass& pass) const = 0; + virtual void BindToCommand(const SceneContext& scene_context, + HostBuffer& buffer, + Command& command) const = 0; + protected: + SceneContextOptions GetContextOptions(const RenderPass& pass) const; + BlendConfig blend_config_; StencilConfig stencil_config_; bool is_translucent_ = false; @@ -50,8 +64,21 @@ class UnlitMaterial final : public Material { public: void SetColor(Color color); + void SetColorTexture(std::shared_ptr color_texture); + + // |Material| + std::shared_ptr> GetPipeline( + const SceneContext& scene_context, + const RenderPass& pass) const override; + + // |Material| + void BindToCommand(const SceneContext& scene_context, + HostBuffer& buffer, + Command& command) const override; + private: - Color color_; + Color color_ = Color::White(); + std::shared_ptr color_texture_; }; class StandardMaterial final : public Material { @@ -67,8 +94,18 @@ class StandardMaterial final : public Material { void SetEnvironmentMap(std::shared_ptr environment_map); + // |Material| + std::shared_ptr> GetPipeline( + const SceneContext& scene_context, + const RenderPass& pass) const override; + + // |Material| + void BindToCommand(const SceneContext& scene_context, + HostBuffer& buffer, + Command& command) const override; + private: - Color albedo_ = Color::CornflowerBlue(); + Color albedo_ = Color::White(); Scalar roughness_ = 0.5; Scalar metallic_ = 0.5; diff --git a/engine/src/flutter/impeller/scene/scene.cc b/engine/src/flutter/impeller/scene/scene.cc index 6fbd0e6f25..ee4fa8cf8f 100644 --- a/engine/src/flutter/impeller/scene/scene.cc +++ b/engine/src/flutter/impeller/scene/scene.cc @@ -32,9 +32,9 @@ bool Scene::Render(const RenderTarget& render_target, } // Encode the commands. + std::shared_ptr command_buffer = - encoder.BuildSceneCommandBuffer(*scene_context_->GetContext(), - render_target); + encoder.BuildSceneCommandBuffer(*scene_context_, render_target); // TODO(bdero): Do post processing. diff --git a/engine/src/flutter/impeller/scene/scene_context.cc b/engine/src/flutter/impeller/scene/scene_context.cc index 006b13ccc8..dcf1ce81f0 100644 --- a/engine/src/flutter/impeller/scene/scene_context.cc +++ b/engine/src/flutter/impeller/scene/scene_context.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "impeller/scene/scene_context.h" +#include "impeller/renderer/formats.h" namespace impeller { namespace scene { @@ -33,6 +34,27 @@ SceneContext::SceneContext(std::shared_ptr context) unlit_pipeline_[{}] = CreateDefaultPipeline(*context_); + { + impeller::TextureDescriptor texture_descriptor; + texture_descriptor.storage_mode = impeller::StorageMode::kHostVisible; + texture_descriptor.format = PixelFormat::kDefaultColor; + texture_descriptor.size = {1, 1}; + texture_descriptor.mip_count = 1u; + + placeholder_texture_ = + context_->GetResourceAllocator()->CreateTexture(texture_descriptor); + if (!placeholder_texture_) { + FML_DLOG(ERROR) << "Could not create placeholder texture."; + return; + } + + uint8_t pixel[] = {0xFF, 0xFF, 0xFF, 0xFF}; + if (!placeholder_texture_->SetContents(pixel, 4, 0)) { + FML_DLOG(ERROR) << "Could not set contents of placeholder texture."; + return; + } + } + is_valid_ = true; } @@ -46,5 +68,9 @@ std::shared_ptr SceneContext::GetContext() const { return context_; } +std::shared_ptr SceneContext::GetPlaceholderTexture() const { + return placeholder_texture_; +} + } // namespace scene } // namespace impeller diff --git a/engine/src/flutter/impeller/scene/scene_context.h b/engine/src/flutter/impeller/scene/scene_context.h index 0b13e480d0..1e1a2a6b57 100644 --- a/engine/src/flutter/impeller/scene/scene_context.h +++ b/engine/src/flutter/impeller/scene/scene_context.h @@ -4,6 +4,8 @@ #pragma once +#include + #include "impeller/renderer/context.h" #include "impeller/renderer/pipeline_descriptor.h" #include "impeller/scene/shaders/geometry.vert.h" @@ -46,22 +48,19 @@ class SceneContext { std::shared_ptr GetContext() const; + std::shared_ptr GetPlaceholderTexture() const; + std::shared_ptr> GetUnlitPipeline( SceneContextOptions opts) const { return GetPipeline(unlit_pipeline_, opts); } private: - std::shared_ptr context_; - template using Variants = std::unordered_map, SceneContextOptions::Hash, SceneContextOptions::Equal>; - - mutable Variants unlit_pipeline_; - template std::shared_ptr> GetPipeline( Variants& container, @@ -91,7 +90,13 @@ class SceneContext { return variant_pipeline; } + std::shared_ptr context_; + mutable Variants unlit_pipeline_; + bool is_valid_ = false; + // A 1x1 opaque white texture that can be used as a placeholder binding. + // Available for the lifetime of the scene context + std::shared_ptr placeholder_texture_; FML_DISALLOW_COPY_AND_ASSIGN(SceneContext); }; diff --git a/engine/src/flutter/impeller/scene/scene_encoder.cc b/engine/src/flutter/impeller/scene/scene_encoder.cc index 456a86df64..fbf7e4923d 100644 --- a/engine/src/flutter/impeller/scene/scene_encoder.cc +++ b/engine/src/flutter/impeller/scene/scene_encoder.cc @@ -4,24 +4,71 @@ #include "flutter/fml/macros.h" -#include "fml/logging.h" +#include "flutter/fml/logging.h" +#include "impeller/renderer/command.h" #include "impeller/renderer/render_target.h" +#include "impeller/scene/scene_context.h" #include "impeller/scene/scene_encoder.h" +#include "impeller/scene/shaders/geometry.vert.h" namespace impeller { namespace scene { SceneEncoder::SceneEncoder() = default; +void SceneEncoder::Add(const SceneCommand& command) { + // TODO(bdero): Manage multi-pass translucency ordering. + commands_.push_back(command); +} + +static void EncodeCommand(const SceneContext& scene_context, + RenderPass& render_pass, + const SceneCommand& scene_command) { + auto& host_buffer = render_pass.GetTransientsBuffer(); + + Command cmd; + cmd.label = scene_command.label; + cmd.stencil_reference = + 0; // TODO(bdero): Configurable stencil ref per-command. + + cmd.BindVertices(scene_command.geometry->GetVertexBuffer( + *scene_context.GetContext()->GetResourceAllocator())); + + cmd.pipeline = + scene_command.material->GetPipeline(scene_context, render_pass); + scene_command.material->BindToCommand(scene_context, host_buffer, cmd); + + GeometryVertexShader::VertInfo info; + info.mvp = scene_command.transform; + GeometryVertexShader::BindVertInfo(cmd, host_buffer.EmplaceUniform(info)); + + render_pass.AddCommand(std::move(cmd)); +} + std::shared_ptr SceneEncoder::BuildSceneCommandBuffer( - Context& context, + const SceneContext& scene_context, const RenderTarget& render_target) const { - auto command_buffer = context.CreateCommandBuffer(); + auto command_buffer = scene_context.GetContext()->CreateCommandBuffer(); if (!command_buffer) { FML_LOG(ERROR) << "Failed to create command buffer."; return nullptr; } + auto render_pass = command_buffer->CreateRenderPass(render_target); + if (!render_pass) { + FML_LOG(ERROR) << "Failed to create render pass."; + return nullptr; + } + + for (auto& command : commands_) { + EncodeCommand(scene_context, *render_pass, command); + } + + if (!render_pass->EncodeCommands()) { + FML_LOG(ERROR) << "Failed to encode render pass commands."; + return nullptr; + } + return command_buffer; } diff --git a/engine/src/flutter/impeller/scene/scene_encoder.h b/engine/src/flutter/impeller/scene/scene_encoder.h index 2b8f15cab1..e09be574e0 100644 --- a/engine/src/flutter/impeller/scene/scene_encoder.h +++ b/engine/src/flutter/impeller/scene/scene_encoder.h @@ -5,24 +5,39 @@ #pragma once #include +#include +#include #include "flutter/fml/macros.h" - #include "impeller/renderer/command_buffer.h" +#include "impeller/scene/geometry.h" +#include "impeller/scene/material.h" namespace impeller { namespace scene { class Scene; +struct SceneCommand { + std::string label; + Matrix transform; + Geometry* geometry; + Material* material; +}; + class SceneEncoder { + public: + void Add(const SceneCommand& command); + private: SceneEncoder(); std::shared_ptr BuildSceneCommandBuffer( - Context& context, + const SceneContext& scene_context, const RenderTarget& render_target) const; + std::vector commands_; + friend Scene; FML_DISALLOW_COPY_AND_ASSIGN(SceneEncoder); diff --git a/engine/src/flutter/impeller/scene/static_mesh_entity.cc b/engine/src/flutter/impeller/scene/static_mesh_entity.cc index 493d342b87..e234e956ea 100644 --- a/engine/src/flutter/impeller/scene/static_mesh_entity.cc +++ b/engine/src/flutter/impeller/scene/static_mesh_entity.cc @@ -3,8 +3,11 @@ // found in the LICENSE file. #include "impeller/scene/static_mesh_entity.h" + #include + #include "impeller/scene/material.h" +#include "impeller/scene/scene_encoder.h" namespace impeller { namespace scene { @@ -23,6 +26,13 @@ void StaticMeshEntity::SetMaterial(std::shared_ptr material) { // |SceneEntity| bool StaticMeshEntity::OnRender(SceneEncoder& encoder, const Camera& camera) const { + SceneCommand command = { + .label = "Static Mesh", + .transform = GetGlobalTransform(), + .geometry = geometry_.get(), + .material = material_.get(), + }; + encoder.Add(command); return true; }