[Impeller Scene] Command encoding (#37977)
diff --git a/impeller/scene/geometry.cc b/impeller/scene/geometry.cc
index 47ed75f..8a7bf01 100644
--- a/impeller/scene/geometry.cc
+++ b/impeller/scene/geometry.cc
@@ -6,6 +6,12 @@
#include <memory>
+#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 @@
size_ = size;
}
-VertexBuffer CuboidGeometry::GetVertexBuffer(
- std::shared_ptr<Allocator>& allocator) const {
- return {};
+VertexBuffer CuboidGeometry::GetVertexBuffer(Allocator& allocator) const {
+ VertexBufferBuilder<GeometryVertexShader::PerVertexData, uint16_t> 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/impeller/scene/geometry.h b/impeller/scene/geometry.h
index f0e7e47..92c90d1 100644
--- a/impeller/scene/geometry.h
+++ b/impeller/scene/geometry.h
@@ -19,19 +19,16 @@
public:
static std::shared_ptr<CuboidGeometry> MakeCuboid(Vector3 size);
- private:
- virtual VertexBuffer GetVertexBuffer(
- std::shared_ptr<Allocator>& 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>& allocator) const override;
+ VertexBuffer GetVertexBuffer(Allocator& allocator) const override;
+ private:
Vector3 size_;
};
diff --git a/impeller/scene/material.cc b/impeller/scene/material.cc
index a38a14a..a37b2bf 100644
--- a/impeller/scene/material.cc
+++ b/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 <memory>
@@ -33,6 +38,11 @@
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 @@
color_ = color;
}
+void UnlitMaterial::SetColorTexture(std::shared_ptr<Texture> color_texture) {
+ color_texture_ = std::move(color_texture);
+}
+
+// |Material|
+std::shared_ptr<Pipeline<PipelineDescriptor>> 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 @@
environment_map_ = std::move(environment_map);
}
+// |Material|
+std::shared_ptr<Pipeline<PipelineDescriptor>> 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/impeller/scene/material.h b/impeller/scene/material.h
index a9e0be7..a579467 100644
--- a/impeller/scene/material.h
+++ b/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 @@
void SetTranslucent(bool is_translucent);
+ virtual std::shared_ptr<Pipeline<PipelineDescriptor>> 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 @@
public:
void SetColor(Color color);
+ void SetColorTexture(std::shared_ptr<Texture> color_texture);
+
+ // |Material|
+ std::shared_ptr<Pipeline<PipelineDescriptor>> 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<Texture> color_texture_;
};
class StandardMaterial final : public Material {
@@ -67,8 +94,18 @@
void SetEnvironmentMap(std::shared_ptr<Texture> environment_map);
+ // |Material|
+ std::shared_ptr<Pipeline<PipelineDescriptor>> 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/impeller/scene/scene.cc b/impeller/scene/scene.cc
index 6fbd0e6..ee4fa8c 100644
--- a/impeller/scene/scene.cc
+++ b/impeller/scene/scene.cc
@@ -32,9 +32,9 @@
}
// Encode the commands.
+
std::shared_ptr<CommandBuffer> command_buffer =
- encoder.BuildSceneCommandBuffer(*scene_context_->GetContext(),
- render_target);
+ encoder.BuildSceneCommandBuffer(*scene_context_, render_target);
// TODO(bdero): Do post processing.
diff --git a/impeller/scene/scene_context.cc b/impeller/scene/scene_context.cc
index 006b13c..dcf1ce8 100644
--- a/impeller/scene/scene_context.cc
+++ b/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 @@
unlit_pipeline_[{}] = CreateDefaultPipeline<UnlitPipeline>(*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 @@
return context_;
}
+std::shared_ptr<Texture> SceneContext::GetPlaceholderTexture() const {
+ return placeholder_texture_;
+}
+
} // namespace scene
} // namespace impeller
diff --git a/impeller/scene/scene_context.h b/impeller/scene/scene_context.h
index 0b13e48..1e1a2a6 100644
--- a/impeller/scene/scene_context.h
+++ b/impeller/scene/scene_context.h
@@ -4,6 +4,8 @@
#pragma once
+#include <memory>
+
#include "impeller/renderer/context.h"
#include "impeller/renderer/pipeline_descriptor.h"
#include "impeller/scene/shaders/geometry.vert.h"
@@ -46,22 +48,19 @@
std::shared_ptr<Context> GetContext() const;
+ std::shared_ptr<Texture> GetPlaceholderTexture() const;
+
std::shared_ptr<Pipeline<PipelineDescriptor>> GetUnlitPipeline(
SceneContextOptions opts) const {
return GetPipeline(unlit_pipeline_, opts);
}
private:
- std::shared_ptr<Context> context_;
-
template <class T>
using Variants = std::unordered_map<SceneContextOptions,
std::unique_ptr<T>,
SceneContextOptions::Hash,
SceneContextOptions::Equal>;
-
- mutable Variants<UnlitPipeline> unlit_pipeline_;
-
template <class TypedPipeline>
std::shared_ptr<Pipeline<PipelineDescriptor>> GetPipeline(
Variants<TypedPipeline>& container,
@@ -91,7 +90,13 @@
return variant_pipeline;
}
+ std::shared_ptr<Context> context_;
+ mutable Variants<UnlitPipeline> 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<Texture> placeholder_texture_;
FML_DISALLOW_COPY_AND_ASSIGN(SceneContext);
};
diff --git a/impeller/scene/scene_encoder.cc b/impeller/scene/scene_encoder.cc
index 456a86d..fbf7e49 100644
--- a/impeller/scene/scene_encoder.cc
+++ b/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<CommandBuffer> 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/impeller/scene/scene_encoder.h b/impeller/scene/scene_encoder.h
index 2b8f15c..e09be57 100644
--- a/impeller/scene/scene_encoder.h
+++ b/impeller/scene/scene_encoder.h
@@ -5,24 +5,39 @@
#pragma once
#include <memory>
+#include <string>
+#include <vector>
#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<CommandBuffer> BuildSceneCommandBuffer(
- Context& context,
+ const SceneContext& scene_context,
const RenderTarget& render_target) const;
+ std::vector<SceneCommand> commands_;
+
friend Scene;
FML_DISALLOW_COPY_AND_ASSIGN(SceneEncoder);
diff --git a/impeller/scene/static_mesh_entity.cc b/impeller/scene/static_mesh_entity.cc
index 493d342..e234e95 100644
--- a/impeller/scene/static_mesh_entity.cc
+++ b/impeller/scene/static_mesh_entity.cc
@@ -3,8 +3,11 @@
// found in the LICENSE file.
#include "impeller/scene/static_mesh_entity.h"
+
#include <memory>
+
#include "impeller/scene/material.h"
+#include "impeller/scene/scene_encoder.h"
namespace impeller {
namespace scene {
@@ -23,6 +26,13 @@
// |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;
}