[Impeller Scene] Command encoding (flutter/engine#37977)

This commit is contained in:
Brandon DeRosier
2022-11-29 23:38:10 -08:00
committed by GitHub
parent f2580d83ba
commit 012487f362
10 changed files with 232 additions and 23 deletions

View File

@@ -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 @@ void CuboidGeometry::SetSize(Vector3 size) {
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

View File

@@ -19,19 +19,16 @@ class Geometry {
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_;
};

View File

@@ -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 @@ 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<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 @@ void StandardMaterial::SetEnvironmentMap(
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

View File

@@ -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<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 @@ class UnlitMaterial final : public Material {
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 @@ class StandardMaterial final : public Material {
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;

View File

@@ -32,9 +32,9 @@ bool Scene::Render(const RenderTarget& render_target,
}
// 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.

View File

@@ -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> context)
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 @@ std::shared_ptr<Context> SceneContext::GetContext() const {
return context_;
}
std::shared_ptr<Texture> SceneContext::GetPlaceholderTexture() const {
return placeholder_texture_;
}
} // namespace scene
} // namespace impeller

View File

@@ -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 @@ class SceneContext {
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 @@ class SceneContext {
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);
};

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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 @@ void StaticMeshEntity::SetMaterial(std::shared_ptr<Material> 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;
}