[Impeller] store GLES bindings on render pass w/ offsets instead of per-command. (flutter/engine#56910)
To reduce heap fragmentation from tons of little vectors.
This commit is contained in:
parent
4453a2b85b
commit
7b1b6d13f2
@ -229,8 +229,6 @@ impeller_component("entity_test_helpers") {
|
||||
testonly = true
|
||||
|
||||
sources = [
|
||||
"contents/test/contents_test_helpers.cc",
|
||||
"contents/test/contents_test_helpers.h",
|
||||
"contents/test/recording_render_pass.cc",
|
||||
"contents/test/recording_render_pass.h",
|
||||
]
|
||||
|
@ -24,6 +24,38 @@
|
||||
|
||||
namespace impeller {
|
||||
|
||||
namespace {
|
||||
constexpr char kPaddingType = 0;
|
||||
constexpr char kFloatType = 1;
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
BufferView RuntimeEffectContents::EmplaceVulkanUniform(
|
||||
const std::shared_ptr<const std::vector<uint8_t>>& input_data,
|
||||
HostBuffer& host_buffer,
|
||||
const RuntimeUniformDescription& uniform) {
|
||||
// TODO(jonahwilliams): rewrite this to emplace directly into
|
||||
// HostBuffer.
|
||||
std::vector<float> uniform_buffer;
|
||||
uniform_buffer.reserve(uniform.struct_layout.size());
|
||||
size_t uniform_byte_index = 0u;
|
||||
for (char byte_type : uniform.struct_layout) {
|
||||
if (byte_type == kPaddingType) {
|
||||
uniform_buffer.push_back(0.f);
|
||||
} else {
|
||||
FML_DCHECK(byte_type == kFloatType);
|
||||
uniform_buffer.push_back(reinterpret_cast<const float*>(
|
||||
input_data->data())[uniform_byte_index++]);
|
||||
}
|
||||
}
|
||||
size_t alignment = std::max(sizeof(float) * uniform_buffer.size(),
|
||||
DefaultUniformAlignment());
|
||||
|
||||
return host_buffer.Emplace(
|
||||
reinterpret_cast<const void*>(uniform_buffer.data()),
|
||||
sizeof(float) * uniform_buffer.size(), alignment);
|
||||
}
|
||||
|
||||
void RuntimeEffectContents::SetRuntimeStage(
|
||||
std::shared_ptr<RuntimeStage> runtime_stage) {
|
||||
runtime_stage_ = std::move(runtime_stage);
|
||||
@ -251,30 +283,11 @@ bool RuntimeEffectContents::Render(const ContentContext& renderer,
|
||||
uniform_slot.binding = uniform.location;
|
||||
uniform_slot.name = uniform.name.c_str();
|
||||
|
||||
// TODO(jonahwilliams): rewrite this to emplace directly into
|
||||
// HostBuffer.
|
||||
std::vector<float> uniform_buffer;
|
||||
uniform_buffer.reserve(uniform.struct_layout.size());
|
||||
size_t uniform_byte_index = 0u;
|
||||
for (const auto& byte_type : uniform.struct_layout) {
|
||||
if (byte_type == 0) {
|
||||
uniform_buffer.push_back(0.f);
|
||||
} else if (byte_type == 1) {
|
||||
uniform_buffer.push_back(reinterpret_cast<float*>(
|
||||
uniform_data_->data())[uniform_byte_index++]);
|
||||
} else {
|
||||
FML_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
size_t alignment = std::max(sizeof(float) * uniform_buffer.size(),
|
||||
DefaultUniformAlignment());
|
||||
|
||||
BufferView buffer_view = renderer.GetTransientsBuffer().Emplace(
|
||||
reinterpret_cast<const void*>(uniform_buffer.data()),
|
||||
sizeof(float) * uniform_buffer.size(), alignment);
|
||||
pass.BindResource(ShaderStage::kFragment,
|
||||
DescriptorType::kUniformBuffer, uniform_slot,
|
||||
nullptr, std::move(buffer_view));
|
||||
pass.BindResource(
|
||||
ShaderStage::kFragment, DescriptorType::kUniformBuffer,
|
||||
uniform_slot, nullptr,
|
||||
EmplaceVulkanUniform(uniform_data_,
|
||||
renderer.GetTransientsBuffer(), uniform));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "impeller/core/host_buffer.h"
|
||||
#include "impeller/core/sampler_descriptor.h"
|
||||
#include "impeller/entity/contents/color_source_contents.h"
|
||||
#include "impeller/runtime_stage/runtime_stage.h"
|
||||
@ -35,6 +36,12 @@ class RuntimeEffectContents final : public ColorSourceContents {
|
||||
/// Load the runtime effect and ensure a default PSO is initialized.
|
||||
bool BootstrapShader(const ContentContext& renderer) const;
|
||||
|
||||
// Visible for testing
|
||||
static BufferView EmplaceVulkanUniform(
|
||||
const std::shared_ptr<const std::vector<uint8_t>>& input_data,
|
||||
HostBuffer& host_buffer,
|
||||
const RuntimeUniformDescription& uniform);
|
||||
|
||||
private:
|
||||
bool RegisterShader(const ContentContext& renderer) const;
|
||||
|
||||
|
@ -1,11 +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/contents/test/contents_test_helpers.h"
|
||||
|
||||
namespace impeller::testing {
|
||||
|
||||
//
|
||||
|
||||
} // namespace impeller::testing
|
@ -1,49 +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.
|
||||
|
||||
#ifndef FLUTTER_IMPELLER_ENTITY_CONTENTS_TEST_CONTENTS_TEST_HELPERS_H_
|
||||
#define FLUTTER_IMPELLER_ENTITY_CONTENTS_TEST_CONTENTS_TEST_HELPERS_H_
|
||||
|
||||
#include "impeller/renderer/command.h"
|
||||
|
||||
namespace impeller::testing {
|
||||
|
||||
/// @brief Retrieve the [VertInfo] struct data from the provided [command].
|
||||
template <typename T>
|
||||
typename T::VertInfo* GetVertInfo(const Command& command) {
|
||||
auto resource = std::find_if(command.vertex_bindings.buffers.begin(),
|
||||
command.vertex_bindings.buffers.end(),
|
||||
[](const BufferAndUniformSlot& data) {
|
||||
return data.slot.ext_res_0 == 0u;
|
||||
});
|
||||
if (resource == command.vertex_bindings.buffers.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto data = (resource->view.resource.buffer->OnGetContents() +
|
||||
resource->view.resource.range.offset);
|
||||
return reinterpret_cast<typename T::VertInfo*>(data);
|
||||
}
|
||||
|
||||
/// @brief Retrieve the [FragInfo] struct data from the provided [command].
|
||||
template <typename T>
|
||||
typename T::FragInfo* GetFragInfo(const Command& command) {
|
||||
auto resource = std::find_if(command.fragment_bindings.buffers.begin(),
|
||||
command.fragment_bindings.buffers.end(),
|
||||
[](const BufferAndUniformSlot& data) {
|
||||
return data.slot.ext_res_0 == 0u ||
|
||||
data.slot.binding == 64;
|
||||
});
|
||||
if (resource == command.fragment_bindings.buffers.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto data = (resource->view.resource.buffer->OnGetContents() +
|
||||
resource->view.resource.range.offset);
|
||||
return reinterpret_cast<typename T::FragInfo*>(data);
|
||||
}
|
||||
|
||||
} // namespace impeller::testing
|
||||
|
||||
#endif // FLUTTER_IMPELLER_ENTITY_CONTENTS_TEST_CONTENTS_TEST_HELPERS_H_
|
@ -110,7 +110,6 @@ bool RecordingRenderPass::BindResource(ShaderStage stage,
|
||||
const ShaderUniformSlot& slot,
|
||||
const ShaderMetadata* metadata,
|
||||
BufferView view) {
|
||||
pending_.BindResource(stage, type, slot, metadata, view);
|
||||
if (delegate_) {
|
||||
return delegate_->BindResource(stage, type, slot, metadata, view);
|
||||
}
|
||||
@ -124,7 +123,6 @@ bool RecordingRenderPass::BindDynamicResource(
|
||||
const ShaderUniformSlot& slot,
|
||||
std::unique_ptr<ShaderMetadata> metadata,
|
||||
BufferView view) {
|
||||
pending_.BindResource(stage, type, slot, metadata.get(), view);
|
||||
if (delegate_) {
|
||||
return delegate_->BindDynamicResource(stage, type, slot,
|
||||
std::move(metadata), view);
|
||||
@ -140,7 +138,6 @@ bool RecordingRenderPass::BindDynamicResource(
|
||||
std::unique_ptr<ShaderMetadata> metadata,
|
||||
std::shared_ptr<const Texture> texture,
|
||||
const std::unique_ptr<const Sampler>& sampler) {
|
||||
pending_.BindResource(stage, type, slot, metadata.get(), texture, sampler);
|
||||
if (delegate_) {
|
||||
return delegate_->BindDynamicResource(
|
||||
stage, type, slot, std::move(metadata), texture, sampler);
|
||||
@ -155,7 +152,6 @@ bool RecordingRenderPass::BindResource(
|
||||
const ShaderMetadata* metadata,
|
||||
std::shared_ptr<const Texture> texture,
|
||||
const std::unique_ptr<const Sampler>& sampler) {
|
||||
pending_.BindResource(stage, type, slot, metadata, texture, sampler);
|
||||
if (delegate_) {
|
||||
return delegate_->BindResource(stage, type, slot, metadata, texture,
|
||||
sampler);
|
||||
|
@ -1843,27 +1843,16 @@ TEST_P(EntityTest, RuntimeEffectSetsRightSizeWhenUniformIsStruct) {
|
||||
auto uniform_data = std::make_shared<std::vector<uint8_t>>();
|
||||
uniform_data->resize(sizeof(FragUniforms));
|
||||
memcpy(uniform_data->data(), &frag_uniforms, sizeof(FragUniforms));
|
||||
contents->SetUniformData(uniform_data);
|
||||
|
||||
Entity entity;
|
||||
entity.SetContents(contents);
|
||||
auto buffer_view = RuntimeEffectContents::EmplaceVulkanUniform(
|
||||
uniform_data, GetContentContext()->GetTransientsBuffer(),
|
||||
runtime_stage->GetUniforms()[0]);
|
||||
|
||||
auto context = GetContentContext();
|
||||
RenderTarget target = context->GetRenderTargetCache()->CreateOffscreen(
|
||||
*context->GetContext(), {1, 1}, 1u);
|
||||
|
||||
testing::MockRenderPass pass(GetContext(), target);
|
||||
ASSERT_TRUE(contents->Render(*context, entity, pass));
|
||||
ASSERT_EQ(pass.GetCommands().size(), 1u);
|
||||
const auto& command = pass.GetCommands()[0];
|
||||
ASSERT_EQ(command.fragment_bindings.buffers.size(), 1u);
|
||||
// 16 bytes:
|
||||
// 8 bytes for iResolution
|
||||
// 4 bytes for iTime
|
||||
// 4 bytes padding
|
||||
EXPECT_EQ(
|
||||
command.fragment_bindings.buffers[0].view.resource.GetRange().length,
|
||||
16u);
|
||||
EXPECT_EQ(buffer_view.GetRange().length, 16u);
|
||||
}
|
||||
|
||||
TEST_P(EntityTest, ColorFilterWithForegroundColorAdvancedBlend) {
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "impeller/renderer/backend/gles/formats_gles.h"
|
||||
#include "impeller/renderer/backend/gles/sampler_gles.h"
|
||||
#include "impeller/renderer/backend/gles/texture_gles.h"
|
||||
#include "impeller/renderer/command.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
@ -179,27 +180,23 @@ bool BufferBindingsGLES::BindVertexAttributes(const ProcTableGLES& gl,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BufferBindingsGLES::BindUniformData(const ProcTableGLES& gl,
|
||||
const Bindings& vertex_bindings,
|
||||
const Bindings& fragment_bindings) {
|
||||
for (const auto& buffer : vertex_bindings.buffers) {
|
||||
if (!BindUniformBuffer(gl, buffer.view)) {
|
||||
bool BufferBindingsGLES::BindUniformData(
|
||||
const ProcTableGLES& gl,
|
||||
const std::vector<TextureAndSampler>& bound_textures,
|
||||
const std::vector<BufferResource>& bound_buffers,
|
||||
Range texture_range,
|
||||
Range buffer_range) {
|
||||
for (auto i = 0u; i < buffer_range.length; i++) {
|
||||
if (!BindUniformBuffer(gl, bound_buffers[buffer_range.offset + i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (const auto& buffer : fragment_bindings.buffers) {
|
||||
if (!BindUniformBuffer(gl, buffer.view)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<size_t> next_unit_index =
|
||||
BindTextures(gl, vertex_bindings, ShaderStage::kVertex);
|
||||
BindTextures(gl, bound_textures, texture_range, ShaderStage::kVertex);
|
||||
if (!next_unit_index.has_value()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!BindTextures(gl, fragment_bindings, ShaderStage::kFragment,
|
||||
if (!BindTextures(gl, bound_textures, texture_range, ShaderStage::kFragment,
|
||||
*next_unit_index)
|
||||
.has_value()) {
|
||||
return false;
|
||||
@ -389,11 +386,16 @@ bool BufferBindingsGLES::BindUniformBuffer(const ProcTableGLES& gl,
|
||||
|
||||
std::optional<size_t> BufferBindingsGLES::BindTextures(
|
||||
const ProcTableGLES& gl,
|
||||
const Bindings& bindings,
|
||||
const std::vector<TextureAndSampler>& bound_textures,
|
||||
Range texture_range,
|
||||
ShaderStage stage,
|
||||
size_t unit_start_index) {
|
||||
size_t active_index = unit_start_index;
|
||||
for (const auto& data : bindings.sampled_images) {
|
||||
for (auto i = 0u; i < texture_range.length; i++) {
|
||||
const TextureAndSampler& data = bound_textures[texture_range.offset + i];
|
||||
if (data.stage != stage) {
|
||||
continue;
|
||||
}
|
||||
const auto& texture_gles = TextureGLES::Cast(*data.texture.resource);
|
||||
if (data.texture.GetMetadata() == nullptr) {
|
||||
VALIDATION_LOG << "No metadata found for texture binding.";
|
||||
|
@ -42,8 +42,10 @@ class BufferBindingsGLES {
|
||||
size_t vertex_offset);
|
||||
|
||||
bool BindUniformData(const ProcTableGLES& gl,
|
||||
const Bindings& vertex_bindings,
|
||||
const Bindings& fragment_bindings);
|
||||
const std::vector<TextureAndSampler>& bound_textures,
|
||||
const std::vector<BufferResource>& bound_buffers,
|
||||
Range texture_range,
|
||||
Range buffer_range);
|
||||
|
||||
bool UnbindVertexAttributes(const ProcTableGLES& gl);
|
||||
|
||||
@ -75,8 +77,10 @@ class BufferBindingsGLES {
|
||||
|
||||
bool BindUniformBuffer(const ProcTableGLES& gl, const BufferResource& buffer);
|
||||
|
||||
std::optional<size_t> BindTextures(const ProcTableGLES& gl,
|
||||
const Bindings& bindings,
|
||||
std::optional<size_t> BindTextures(
|
||||
const ProcTableGLES& gl,
|
||||
const std::vector<TextureAndSampler>& bound_textures,
|
||||
Range texture_range,
|
||||
ShaderStage stage,
|
||||
size_t unit_start_index = 0);
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "impeller/renderer/backend/gles/buffer_bindings_gles.h"
|
||||
#include "impeller/renderer/backend/gles/device_buffer_gles.h"
|
||||
#include "impeller/renderer/backend/gles/test/mock_gles.h"
|
||||
#include "impeller/renderer/testing/mocks.h"
|
||||
#include "impeller/renderer/command.h"
|
||||
|
||||
namespace impeller {
|
||||
namespace testing {
|
||||
@ -18,7 +18,8 @@ TEST(BufferBindingsGLESTest, BindUniformData) {
|
||||
uniform_bindings["SHADERMETADATA.FOOBAR"] = 1;
|
||||
bindings.SetUniformBindings(std::move(uniform_bindings));
|
||||
std::shared_ptr<MockGLES> mock_gl = MockGLES::Init();
|
||||
Bindings vertex_bindings;
|
||||
std::vector<BufferResource> bound_buffers;
|
||||
std::vector<TextureAndSampler> bound_textures;
|
||||
|
||||
ShaderMetadata shader_metadata = {
|
||||
.name = "shader_metadata",
|
||||
@ -33,14 +34,11 @@ TEST(BufferBindingsGLESTest, BindUniformData) {
|
||||
DeviceBufferGLES device_buffer(DeviceBufferDescriptor{.size = sizeof(float)},
|
||||
reactor, backing_store);
|
||||
BufferView buffer_view(&device_buffer, Range(0, sizeof(float)));
|
||||
vertex_bindings.buffers.push_back(BufferAndUniformSlot{
|
||||
.slot =
|
||||
ShaderUniformSlot{
|
||||
.name = "foobar", .ext_res_0 = 0, .set = 0, .binding = 0},
|
||||
.view = BufferResource(&shader_metadata, buffer_view)});
|
||||
Bindings fragment_bindings;
|
||||
EXPECT_TRUE(bindings.BindUniformData(mock_gl->GetProcTable(), vertex_bindings,
|
||||
fragment_bindings));
|
||||
bound_buffers.push_back(BufferResource(&shader_metadata, buffer_view));
|
||||
|
||||
EXPECT_TRUE(bindings.BindUniformData(mock_gl->GetProcTable(), bound_textures,
|
||||
bound_buffers, Range{0, 0},
|
||||
Range{0, 1}));
|
||||
std::vector<std::string> captured_calls = mock_gl->GetCapturedCalls();
|
||||
EXPECT_TRUE(std::find(captured_calls.begin(), captured_calls.end(),
|
||||
"glUniform1fv") != captured_calls.end());
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "impeller/renderer/backend/gles/gpu_tracer_gles.h"
|
||||
#include "impeller/renderer/backend/gles/pipeline_gles.h"
|
||||
#include "impeller/renderer/backend/gles/texture_gles.h"
|
||||
#include "impeller/renderer/command.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
@ -188,9 +189,10 @@ void RenderPassGLES::ResetGLState(const ProcTableGLES& gl) {
|
||||
|
||||
[[nodiscard]] bool EncodeCommandsInReactor(
|
||||
const RenderPassData& pass_data,
|
||||
const std::shared_ptr<Allocator>& transients_allocator,
|
||||
const ReactorGLES& reactor,
|
||||
const std::vector<Command>& commands,
|
||||
const std::vector<TextureAndSampler>& bound_textures,
|
||||
const std::vector<BufferResource>& bound_buffers,
|
||||
const std::shared_ptr<GPUTracerGLES>& tracer) {
|
||||
TRACE_EVENT0("impeller", "RenderPassGLES::EncodeCommandsInReactor");
|
||||
|
||||
@ -456,9 +458,12 @@ void RenderPassGLES::ResetGLState(const ProcTableGLES& gl) {
|
||||
//--------------------------------------------------------------------------
|
||||
/// Bind uniform data.
|
||||
///
|
||||
if (!vertex_desc_gles->BindUniformData(gl, //
|
||||
command.vertex_bindings, //
|
||||
command.fragment_bindings //
|
||||
if (!vertex_desc_gles->BindUniformData(
|
||||
gl, //
|
||||
bound_textures, //
|
||||
bound_buffers, //
|
||||
/*texture_range=*/command.bound_textures, //
|
||||
/*buffer_range=*/command.bound_buffers //
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
@ -602,13 +607,18 @@ bool RenderPassGLES::OnEncodeCommands(const Context& context) const {
|
||||
CanDiscardAttachmentWhenDone(stencil0->store_action);
|
||||
}
|
||||
|
||||
std::shared_ptr<const RenderPassGLES> shared_this = shared_from_this();
|
||||
auto tracer = ContextGLES::Cast(context).GetGPUTracer();
|
||||
return reactor_->AddOperation(
|
||||
[pass_data, allocator = context.GetResourceAllocator(),
|
||||
render_pass = std::move(shared_this), tracer](const auto& reactor) {
|
||||
auto result = EncodeCommandsInReactor(*pass_data, allocator, reactor,
|
||||
render_pass->commands_, tracer);
|
||||
[pass_data = std::move(pass_data), render_pass = shared_from_this(),
|
||||
tracer =
|
||||
ContextGLES::Cast(context).GetGPUTracer()](const auto& reactor) {
|
||||
auto result = EncodeCommandsInReactor(
|
||||
/*pass_data=*/*pass_data, //
|
||||
/*reactor=*/reactor, //
|
||||
/*commands=*/render_pass->commands_, //
|
||||
/*bound_textures=*/render_pass->bound_textures_, //
|
||||
/*bound_buffers=*/render_pass->bound_buffers_, //
|
||||
/*tracer=*/tracer //
|
||||
);
|
||||
FML_CHECK(result)
|
||||
<< "Must be able to encode GL commands without error.";
|
||||
},
|
||||
|
@ -48,9 +48,6 @@ class RenderPassMTL final : public RenderPass {
|
||||
const RenderTarget& target,
|
||||
id<MTLCommandBuffer> buffer);
|
||||
|
||||
// |RenderPass|
|
||||
void ReserveCommands(size_t command_count) override {}
|
||||
|
||||
// |RenderPass|
|
||||
bool IsValid() const override;
|
||||
|
||||
|
@ -92,9 +92,6 @@ class RenderPassVK final : public RenderPass {
|
||||
// |RenderPass|
|
||||
fml::Status Draw() override;
|
||||
|
||||
// |RenderPass|
|
||||
void ReserveCommands(size_t command_count) override {}
|
||||
|
||||
// |ResourceBinder|
|
||||
bool BindResource(ShaderStage stage,
|
||||
DescriptorType type,
|
||||
|
@ -4,11 +4,8 @@
|
||||
|
||||
#include "impeller/renderer/command.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "impeller/base/validation.h"
|
||||
#include "impeller/core/formats.h"
|
||||
#include "impeller/renderer/vertex_descriptor.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
@ -26,112 +23,4 @@ bool Command::BindVertices(const VertexBuffer& buffer) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Command::BindResource(ShaderStage stage,
|
||||
DescriptorType type,
|
||||
const ShaderUniformSlot& slot,
|
||||
const ShaderMetadata* metadata,
|
||||
BufferView view) {
|
||||
FML_DCHECK(slot.ext_res_0 != VertexDescriptor::kReservedVertexBufferIndex);
|
||||
if (!view) {
|
||||
return false;
|
||||
}
|
||||
BufferResource resouce = BufferResource(metadata, std::move(view));
|
||||
return BindBuffer(stage, slot, std::move(resouce));
|
||||
}
|
||||
|
||||
bool Command::BindDynamicResource(ShaderStage stage,
|
||||
DescriptorType type,
|
||||
const ShaderUniformSlot& slot,
|
||||
std::unique_ptr<ShaderMetadata> metadata,
|
||||
BufferView view) {
|
||||
FML_DCHECK(slot.ext_res_0 != VertexDescriptor::kReservedVertexBufferIndex);
|
||||
if (!view) {
|
||||
return false;
|
||||
}
|
||||
BufferResource resouce =
|
||||
BufferResource::MakeDynamic(std::move(metadata), std::move(view));
|
||||
|
||||
return BindBuffer(stage, slot, std::move(resouce));
|
||||
}
|
||||
|
||||
bool Command::BindResource(ShaderStage stage,
|
||||
DescriptorType type,
|
||||
const SampledImageSlot& slot,
|
||||
const ShaderMetadata* metadata,
|
||||
std::shared_ptr<const Texture> texture,
|
||||
const std::unique_ptr<const Sampler>& sampler) {
|
||||
if (!sampler) {
|
||||
return false;
|
||||
}
|
||||
if (!texture || !texture->IsValid()) {
|
||||
return false;
|
||||
}
|
||||
TextureResource resource = TextureResource(metadata, std::move(texture));
|
||||
return BindTexture(stage, slot, std::move(resource), sampler);
|
||||
}
|
||||
|
||||
bool Command::BindDynamicResource(
|
||||
ShaderStage stage,
|
||||
DescriptorType type,
|
||||
const SampledImageSlot& slot,
|
||||
std::unique_ptr<ShaderMetadata> metadata,
|
||||
std::shared_ptr<const Texture> texture,
|
||||
const std::unique_ptr<const Sampler>& sampler) {
|
||||
if (!sampler) {
|
||||
return false;
|
||||
}
|
||||
if (!texture || !texture->IsValid()) {
|
||||
return false;
|
||||
}
|
||||
TextureResource resource =
|
||||
TextureResource::MakeDynamic(std::move(metadata), std::move(texture));
|
||||
return BindTexture(stage, slot, std::move(resource), sampler);
|
||||
}
|
||||
|
||||
bool Command::BindBuffer(ShaderStage stage,
|
||||
const ShaderUniformSlot& slot,
|
||||
BufferResource resource) {
|
||||
BufferAndUniformSlot data =
|
||||
BufferAndUniformSlot{.slot = slot, .view = std::move(resource)};
|
||||
|
||||
switch (stage) {
|
||||
case ShaderStage::kVertex:
|
||||
vertex_bindings.buffers.push_back(std::move(data));
|
||||
return true;
|
||||
case ShaderStage::kFragment:
|
||||
fragment_bindings.buffers.push_back(std::move(data));
|
||||
return true;
|
||||
case ShaderStage::kCompute:
|
||||
VALIDATION_LOG << "Use ComputeCommands for compute shader stages.";
|
||||
case ShaderStage::kUnknown:
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Command::BindTexture(ShaderStage stage,
|
||||
const SampledImageSlot& slot,
|
||||
TextureResource resource,
|
||||
const std::unique_ptr<const Sampler>& sampler) {
|
||||
TextureAndSampler data = TextureAndSampler{
|
||||
.slot = slot,
|
||||
.texture = std::move(resource),
|
||||
.sampler = &sampler,
|
||||
};
|
||||
|
||||
switch (stage) {
|
||||
case ShaderStage::kVertex:
|
||||
vertex_bindings.sampled_images.push_back(std::move(data));
|
||||
return true;
|
||||
case ShaderStage::kFragment:
|
||||
fragment_bindings.sampled_images.push_back((std::move(data)));
|
||||
return true;
|
||||
case ShaderStage::kCompute:
|
||||
VALIDATION_LOG << "Use ComputeCommands for compute shader stages.";
|
||||
case ShaderStage::kUnknown:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
|
@ -12,7 +12,6 @@
|
||||
|
||||
#include "impeller/core/buffer_view.h"
|
||||
#include "impeller/core/formats.h"
|
||||
#include "impeller/core/resource_binder.h"
|
||||
#include "impeller/core/sampler.h"
|
||||
#include "impeller/core/shader_types.h"
|
||||
#include "impeller/core/texture.h"
|
||||
@ -22,12 +21,6 @@
|
||||
|
||||
namespace impeller {
|
||||
|
||||
#ifdef IMPELLER_DEBUG
|
||||
#define DEBUG_COMMAND_INFO(obj, arg) obj.label = arg;
|
||||
#else
|
||||
#define DEBUG_COMMAND_INFO(obj, arg)
|
||||
#endif // IMPELLER_DEBUG
|
||||
|
||||
template <class T>
|
||||
class Resource {
|
||||
public:
|
||||
@ -65,21 +58,11 @@ using TextureResource = Resource<std::shared_ptr<const Texture>>;
|
||||
/// @brief combines the texture, sampler and sampler slot information.
|
||||
struct TextureAndSampler {
|
||||
SampledImageSlot slot;
|
||||
ShaderStage stage;
|
||||
TextureResource texture;
|
||||
const std::unique_ptr<const Sampler>* sampler;
|
||||
};
|
||||
|
||||
/// @brief combines the buffer resource and its uniform slot information.
|
||||
struct BufferAndUniformSlot {
|
||||
ShaderUniformSlot slot;
|
||||
BufferResource view;
|
||||
};
|
||||
|
||||
struct Bindings {
|
||||
std::vector<TextureAndSampler> sampled_images;
|
||||
std::vector<BufferAndUniformSlot> buffers;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// @brief An object used to specify work to the GPU along with references
|
||||
/// to resources the GPU will used when doing said work.
|
||||
@ -94,21 +77,16 @@ struct Bindings {
|
||||
/// referenced in commands views into buffers managed by other
|
||||
/// allocators and resource managers.
|
||||
///
|
||||
struct Command : public ResourceBinder {
|
||||
struct Command {
|
||||
//----------------------------------------------------------------------------
|
||||
/// The pipeline to use for this command.
|
||||
///
|
||||
std::shared_ptr<Pipeline<PipelineDescriptor>> pipeline;
|
||||
//----------------------------------------------------------------------------
|
||||
/// The buffer, texture, and sampler bindings used by the vertex pipeline
|
||||
/// stage.
|
||||
///
|
||||
Bindings vertex_bindings;
|
||||
//----------------------------------------------------------------------------
|
||||
/// The buffer, texture, and sampler bindings used by the fragment pipeline
|
||||
/// stage.
|
||||
///
|
||||
Bindings fragment_bindings;
|
||||
|
||||
/// An offset into render pass storage where bound buffers/texture metadata is
|
||||
/// stored.
|
||||
Range bound_buffers = Range{0, 0};
|
||||
Range bound_textures = Range{0, 0};
|
||||
|
||||
#ifdef IMPELLER_DEBUG
|
||||
//----------------------------------------------------------------------------
|
||||
@ -184,45 +162,7 @@ struct Command : public ResourceBinder {
|
||||
///
|
||||
bool BindVertices(const VertexBuffer& buffer);
|
||||
|
||||
// |ResourceBinder|
|
||||
bool BindResource(ShaderStage stage,
|
||||
DescriptorType type,
|
||||
const ShaderUniformSlot& slot,
|
||||
const ShaderMetadata* metadata,
|
||||
BufferView view) override;
|
||||
|
||||
// |ResourceBinder|
|
||||
bool BindResource(ShaderStage stage,
|
||||
DescriptorType type,
|
||||
const SampledImageSlot& slot,
|
||||
const ShaderMetadata* metadata,
|
||||
std::shared_ptr<const Texture> texture,
|
||||
const std::unique_ptr<const Sampler>& sampler) override;
|
||||
|
||||
bool BindDynamicResource(ShaderStage stage,
|
||||
DescriptorType type,
|
||||
const ShaderUniformSlot& slot,
|
||||
std::unique_ptr<ShaderMetadata> metadata,
|
||||
BufferView view);
|
||||
|
||||
bool BindDynamicResource(ShaderStage stage,
|
||||
DescriptorType type,
|
||||
const SampledImageSlot& slot,
|
||||
std::unique_ptr<ShaderMetadata> metadata,
|
||||
std::shared_ptr<const Texture> texture,
|
||||
const std::unique_ptr<const Sampler>& sampler);
|
||||
|
||||
bool IsValid() const { return pipeline && pipeline->IsValid(); }
|
||||
|
||||
private:
|
||||
bool BindBuffer(ShaderStage stage,
|
||||
const ShaderUniformSlot& slot,
|
||||
BufferResource resource);
|
||||
|
||||
bool BindTexture(ShaderStage stage,
|
||||
const SampledImageSlot& slot,
|
||||
TextureResource resource,
|
||||
const std::unique_ptr<const Sampler>& sampler);
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
|
@ -194,8 +194,12 @@ bool RenderPass::ValidateIndexBuffer(const BufferView& index_buffer,
|
||||
}
|
||||
|
||||
fml::Status RenderPass::Draw() {
|
||||
pending_.bound_buffers.offset = bound_buffers_start_.value_or(0u);
|
||||
pending_.bound_textures.offset = bound_textures_start_.value_or(0u);
|
||||
auto result = AddCommand(std::move(pending_));
|
||||
pending_ = Command{};
|
||||
bound_textures_start_ = std::nullopt;
|
||||
bound_buffers_start_ = std::nullopt;
|
||||
if (result) {
|
||||
return fml::Status();
|
||||
}
|
||||
@ -209,7 +213,12 @@ bool RenderPass::BindResource(ShaderStage stage,
|
||||
const ShaderUniformSlot& slot,
|
||||
const ShaderMetadata* metadata,
|
||||
BufferView view) {
|
||||
return pending_.BindResource(stage, type, slot, metadata, view);
|
||||
FML_DCHECK(slot.ext_res_0 != VertexDescriptor::kReservedVertexBufferIndex);
|
||||
if (!view) {
|
||||
return false;
|
||||
}
|
||||
BufferResource resouce = BufferResource(metadata, std::move(view));
|
||||
return BindBuffer(stage, slot, std::move(resouce));
|
||||
}
|
||||
|
||||
// |ResourceBinder|
|
||||
@ -219,8 +228,14 @@ bool RenderPass::BindResource(ShaderStage stage,
|
||||
const ShaderMetadata* metadata,
|
||||
std::shared_ptr<const Texture> texture,
|
||||
const std::unique_ptr<const Sampler>& sampler) {
|
||||
return pending_.BindResource(stage, type, slot, metadata, std::move(texture),
|
||||
sampler);
|
||||
if (!sampler) {
|
||||
return false;
|
||||
}
|
||||
if (!texture || !texture->IsValid()) {
|
||||
return false;
|
||||
}
|
||||
TextureResource resource = TextureResource(metadata, std::move(texture));
|
||||
return BindTexture(stage, slot, std::move(resource), sampler);
|
||||
}
|
||||
|
||||
bool RenderPass::BindDynamicResource(ShaderStage stage,
|
||||
@ -228,8 +243,14 @@ bool RenderPass::BindDynamicResource(ShaderStage stage,
|
||||
const ShaderUniformSlot& slot,
|
||||
std::unique_ptr<ShaderMetadata> metadata,
|
||||
BufferView view) {
|
||||
return pending_.BindDynamicResource(stage, type, slot, std::move(metadata),
|
||||
std::move(view));
|
||||
FML_DCHECK(slot.ext_res_0 != VertexDescriptor::kReservedVertexBufferIndex);
|
||||
if (!view) {
|
||||
return false;
|
||||
}
|
||||
BufferResource resouce =
|
||||
BufferResource::MakeDynamic(std::move(metadata), std::move(view));
|
||||
|
||||
return BindBuffer(stage, slot, std::move(resouce));
|
||||
}
|
||||
|
||||
bool RenderPass::BindDynamicResource(
|
||||
@ -239,8 +260,46 @@ bool RenderPass::BindDynamicResource(
|
||||
std::unique_ptr<ShaderMetadata> metadata,
|
||||
std::shared_ptr<const Texture> texture,
|
||||
const std::unique_ptr<const Sampler>& sampler) {
|
||||
return pending_.BindDynamicResource(stage, type, slot, std::move(metadata),
|
||||
std::move(texture), sampler);
|
||||
if (!sampler) {
|
||||
return false;
|
||||
}
|
||||
if (!texture || !texture->IsValid()) {
|
||||
return false;
|
||||
}
|
||||
TextureResource resource =
|
||||
TextureResource::MakeDynamic(std::move(metadata), std::move(texture));
|
||||
return BindTexture(stage, slot, std::move(resource), sampler);
|
||||
}
|
||||
|
||||
bool RenderPass::BindBuffer(ShaderStage stage,
|
||||
const ShaderUniformSlot& slot,
|
||||
BufferResource resource) {
|
||||
if (!bound_buffers_start_.has_value()) {
|
||||
bound_buffers_start_ = bound_buffers_.size();
|
||||
}
|
||||
|
||||
pending_.bound_buffers.length++;
|
||||
bound_buffers_.push_back(std::move(resource));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RenderPass::BindTexture(ShaderStage stage,
|
||||
const SampledImageSlot& slot,
|
||||
TextureResource resource,
|
||||
const std::unique_ptr<const Sampler>& sampler) {
|
||||
TextureAndSampler data = TextureAndSampler{
|
||||
.stage = stage,
|
||||
.texture = std::move(resource),
|
||||
.sampler = &sampler,
|
||||
};
|
||||
|
||||
if (!bound_textures_start_.has_value()) {
|
||||
bound_textures_start_ = bound_textures_.size();
|
||||
}
|
||||
|
||||
pending_.bound_textures.length++;
|
||||
bound_textures_.push_back(std::move(data));
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
|
@ -18,9 +18,6 @@
|
||||
|
||||
namespace impeller {
|
||||
|
||||
class HostBuffer;
|
||||
class Allocator;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// @brief Render passes encode render commands directed as one specific
|
||||
/// render target into an underlying command buffer.
|
||||
@ -46,13 +43,6 @@ class RenderPass : public ResourceBinder {
|
||||
|
||||
void SetLabel(std::string_view label);
|
||||
|
||||
/// @brief Reserve [command_count] commands in the HAL command buffer.
|
||||
///
|
||||
/// Note: this is not the native command buffer.
|
||||
virtual void ReserveCommands(size_t command_count) {
|
||||
commands_.reserve(command_count);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// The pipeline to use for this command.
|
||||
virtual void SetPipeline(
|
||||
@ -202,6 +192,7 @@ class RenderPass : public ResourceBinder {
|
||||
std::shared_ptr<const Texture> texture,
|
||||
const std::unique_ptr<const Sampler>& sampler);
|
||||
|
||||
/// @brief Bind with dynamically generated shader metadata.
|
||||
virtual bool BindDynamicResource(ShaderStage stage,
|
||||
DescriptorType type,
|
||||
const ShaderUniformSlot& slot,
|
||||
@ -253,6 +244,8 @@ class RenderPass : public ResourceBinder {
|
||||
const ISize render_target_size_;
|
||||
const RenderTarget render_target_;
|
||||
std::vector<Command> commands_;
|
||||
std::vector<BufferResource> bound_buffers_;
|
||||
std::vector<TextureAndSampler> bound_textures_;
|
||||
const Matrix orthographic_;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@ -284,7 +277,18 @@ class RenderPass : public ResourceBinder {
|
||||
|
||||
RenderPass& operator=(const RenderPass&) = delete;
|
||||
|
||||
bool BindBuffer(ShaderStage stage,
|
||||
const ShaderUniformSlot& slot,
|
||||
BufferResource resource);
|
||||
|
||||
bool BindTexture(ShaderStage stage,
|
||||
const SampledImageSlot& slot,
|
||||
TextureResource resource,
|
||||
const std::unique_ptr<const Sampler>& sampler);
|
||||
|
||||
Command pending_;
|
||||
std::optional<size_t> bound_buffers_start_ = std::nullopt;
|
||||
std::optional<size_t> bound_textures_start_ = std::nullopt;
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
|
@ -417,7 +417,7 @@ static bool BindUniform(
|
||||
|
||||
uniform_map->insert_or_assign(
|
||||
uniform_struct,
|
||||
impeller::BufferAndUniformSlot{
|
||||
flutter::gpu::RenderPass::BufferAndUniformSlot{
|
||||
.slot = uniform_struct->slot,
|
||||
.view = impeller::BufferResource{
|
||||
&uniform_struct->metadata,
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "flutter/lib/ui/dart_wrapper.h"
|
||||
#include "fml/memory/ref_ptr.h"
|
||||
#include "impeller/core/formats.h"
|
||||
#include "impeller/core/shader_types.h"
|
||||
#include "impeller/renderer/command.h"
|
||||
#include "impeller/renderer/render_pass.h"
|
||||
#include "impeller/renderer/render_target.h"
|
||||
@ -56,9 +57,14 @@ class RenderPass : public RefCountedDartWrappable<RenderPass> {
|
||||
|
||||
bool Draw();
|
||||
|
||||
struct BufferAndUniformSlot {
|
||||
impeller::ShaderUniformSlot slot;
|
||||
impeller::BufferResource view;
|
||||
};
|
||||
|
||||
using BufferUniformMap =
|
||||
std::unordered_map<const flutter::gpu::Shader::UniformBinding*,
|
||||
impeller::BufferAndUniformSlot>;
|
||||
BufferAndUniformSlot>;
|
||||
using TextureUniformMap =
|
||||
std::unordered_map<const flutter::gpu::Shader::TextureBinding*,
|
||||
impeller::TextureAndSampler>;
|
||||
|
Loading…
x
Reference in New Issue
Block a user