diff --git a/engine/src/flutter/impeller/compositor/BUILD.gn b/engine/src/flutter/impeller/compositor/BUILD.gn index 2288e13e964..23bd49504e1 100644 --- a/engine/src/flutter/impeller/compositor/BUILD.gn +++ b/engine/src/flutter/impeller/compositor/BUILD.gn @@ -10,6 +10,8 @@ impeller_component("compositor") { "allocator.mm", "buffer.h", "buffer.mm", + "buffer_view.h", + "buffer_view.mm", "command.h", "command.mm", "command_buffer.h", @@ -18,10 +20,14 @@ impeller_component("compositor") { "comparable.h", "context.h", "context.mm", + "device_buffer.h", + "device_buffer.mm", "formats.cc", "formats.h", "formats_metal.h", "formats_metal.mm", + "host_buffer.h", + "host_buffer.mm", "pipeline.h", "pipeline.mm", "pipeline_descriptor.h", diff --git a/engine/src/flutter/impeller/compositor/allocator.mm b/engine/src/flutter/impeller/compositor/allocator.mm index 496160ef081..27b86c9b211 100644 --- a/engine/src/flutter/impeller/compositor/allocator.mm +++ b/engine/src/flutter/impeller/compositor/allocator.mm @@ -5,6 +5,7 @@ #include "impeller/compositor/allocator.h" #include "impeller/compositor/buffer.h" +#include "impeller/compositor/device_buffer.h" namespace impeller { diff --git a/engine/src/flutter/impeller/compositor/buffer.h b/engine/src/flutter/impeller/compositor/buffer.h index 39f534e61bd..824a96ba375 100644 --- a/engine/src/flutter/impeller/compositor/buffer.h +++ b/engine/src/flutter/impeller/compositor/buffer.h @@ -28,8 +28,6 @@ class BufferView final : public BufferBase { // |BufferBase| ~BufferView() = default; - const BufferBase* GetBuffer() const { return parent_.get(); } - // |BufferBase| uint8_t* GetMapping() const override { return parent_->GetMapping() + range_in_parent_.offset; @@ -48,55 +46,4 @@ class BufferView final : public BufferBase { : parent_(std::move(parent)), range_in_parent_(range_in_parent) {} }; -class Buffer { - public: - ~Buffer(); - - private: - friend class Allocator; - - const id buffer_; - const size_t size_; - const StorageMode mode_; - const std::string label_; - - Buffer(id buffer, - size_t size, - StorageMode mode, - std::string label); - - FML_DISALLOW_COPY_AND_ASSIGN(Buffer); -}; - -class HostBuffer : public std::enable_shared_from_this, - public BufferBase { - public: - std::shared_ptr Create(); - - std::shared_ptr Emplace(size_t length); - - virtual ~HostBuffer(); - - // |BufferBase| - uint8_t* GetMapping() const override { return buffer_; } - - // |BufferBase| - size_t GetLength() const override { return length_; } - - [[nodiscard]] bool Truncate(size_t length); - - private: - uint8_t* buffer_ = nullptr; - size_t length_ = 0; - size_t reserved_ = 0; - - [[nodiscard]] bool Reserve(size_t reserved); - - [[nodiscard]] bool ReserveNPOT(size_t reserved); - - HostBuffer(); - - FML_DISALLOW_COPY_AND_ASSIGN(HostBuffer); -}; - } // namespace impeller diff --git a/engine/src/flutter/impeller/compositor/buffer.mm b/engine/src/flutter/impeller/compositor/buffer.mm index cb9ba12e05a..9e4c11e91a1 100644 --- a/engine/src/flutter/impeller/compositor/buffer.mm +++ b/engine/src/flutter/impeller/compositor/buffer.mm @@ -4,80 +4,8 @@ #include "impeller/compositor/buffer.h" -#include "flutter/fml/logging.h" - namespace impeller { -Buffer::Buffer(id buffer, - size_t size, - StorageMode mode, - std::string label) - : buffer_(buffer), size_(size), mode_(mode), label_(std::move(label)) {} - -Buffer::~Buffer() = default; - -std::shared_ptr HostBuffer::Create() { - return std::shared_ptr(new HostBuffer()); -} - -HostBuffer::HostBuffer() = default; - -HostBuffer::~HostBuffer() { - ::free(buffer_); -} - -std::shared_ptr HostBuffer::Emplace(size_t length) { - auto old_length = length_; - if (!Truncate(length_ + length)) { - return nullptr; - } - return std::shared_ptr( - new BufferView(shared_from_this(), Range{old_length, length})); -} - -bool HostBuffer::Truncate(size_t length) { - if (!ReserveNPOT(length)) { - return false; - } - length_ = length; - return true; -} - -static uint32_t NextPowerOfTwoSize(uint32_t x) { - if (x == 0) { - return 1; - } - - --x; - - x |= x >> 1; - x |= x >> 2; - x |= x >> 4; - x |= x >> 8; - x |= x >> 16; - - return x + 1; -} - -bool HostBuffer::ReserveNPOT(size_t reserved) { - return Reserve(NextPowerOfTwoSize(reserved)); -} - -bool HostBuffer::Reserve(size_t reserved) { - if (reserved == reserved_) { - return true; - } - auto new_allocation = ::realloc(buffer_, reserved); - if (!new_allocation) { - // If new length is zero, a minimum non-zero sized allocation is returned. - // So this check will not trip and this routine will indicate success as - // expected. - FML_LOG(ERROR) << "Allocation failed. Out of memory."; - return false; - } - buffer_ = static_cast(new_allocation); - reserved_ = reserved; - return true; -} +// } // namespace impeller diff --git a/engine/src/flutter/impeller/compositor/buffer_view.h b/engine/src/flutter/impeller/compositor/buffer_view.h new file mode 100644 index 00000000000..e69de29bb2d diff --git a/engine/src/flutter/impeller/compositor/buffer_view.mm b/engine/src/flutter/impeller/compositor/buffer_view.mm new file mode 100644 index 00000000000..e69de29bb2d diff --git a/engine/src/flutter/impeller/compositor/command.h b/engine/src/flutter/impeller/compositor/command.h index 68c10dbc7ae..1def25cd977 100644 --- a/engine/src/flutter/impeller/compositor/command.h +++ b/engine/src/flutter/impeller/compositor/command.h @@ -19,7 +19,7 @@ class Sampler; struct Bindings { std::map buffers; std::map> textures; - std::map> samplers; + std::map> samplers; }; struct Command { @@ -27,6 +27,7 @@ struct Command { Bindings vertex_bindings; Bindings fragment_bindings; BufferView index_buffer; + size_t index_count = 0u; constexpr operator bool() const { return pipeline && pipeline->IsValid(); } }; diff --git a/engine/src/flutter/impeller/compositor/command.mm b/engine/src/flutter/impeller/compositor/command.mm index 95f37c799ff..7170c57f845 100644 --- a/engine/src/flutter/impeller/compositor/command.mm +++ b/engine/src/flutter/impeller/compositor/command.mm @@ -4,4 +4,10 @@ #include "impeller/compositor/command.h" -namespace impeller {} // namespace impeller +#include + +namespace impeller { + +// + +} // namespace impeller diff --git a/engine/src/flutter/impeller/compositor/device_buffer.h b/engine/src/flutter/impeller/compositor/device_buffer.h new file mode 100644 index 00000000000..a5741b752c2 --- /dev/null +++ b/engine/src/flutter/impeller/compositor/device_buffer.h @@ -0,0 +1,36 @@ +// 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 + +#include + +#include "flutter/fml/macros.h" +#include "impeller/compositor/allocator.h" + +namespace impeller { + +class Buffer { + public: + ~Buffer(); + + private: + friend class Allocator; + + const id buffer_; + const size_t size_; + const StorageMode mode_; + const std::string label_; + + Buffer(id buffer, + size_t size, + StorageMode mode, + std::string label); + + FML_DISALLOW_COPY_AND_ASSIGN(Buffer); +}; + +} // namespace impeller diff --git a/engine/src/flutter/impeller/compositor/device_buffer.mm b/engine/src/flutter/impeller/compositor/device_buffer.mm new file mode 100644 index 00000000000..e54cea72fa1 --- /dev/null +++ b/engine/src/flutter/impeller/compositor/device_buffer.mm @@ -0,0 +1,17 @@ +// 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/compositor/device_buffer.h" + +namespace impeller { + +Buffer::Buffer(id buffer, + size_t size, + StorageMode mode, + std::string label) + : buffer_(buffer), size_(size), mode_(mode), label_(std::move(label)) {} + +Buffer::~Buffer() = default; + +} // namespace impeller diff --git a/engine/src/flutter/impeller/compositor/host_buffer.h b/engine/src/flutter/impeller/compositor/host_buffer.h new file mode 100644 index 00000000000..f2a192023c5 --- /dev/null +++ b/engine/src/flutter/impeller/compositor/host_buffer.h @@ -0,0 +1,46 @@ +// 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 + +#include "flutter/fml/macros.h" +#include "impeller/compositor/buffer.h" +#include "impeller/compositor/host_buffer.h" + +namespace impeller { + +class HostBuffer : public std::enable_shared_from_this, + public BufferBase { + public: + std::shared_ptr Create(); + + std::shared_ptr Emplace(size_t length); + + virtual ~HostBuffer(); + + // |BufferBase| + uint8_t* GetMapping() const override { return buffer_; } + + // |BufferBase| + size_t GetLength() const override { return length_; } + + [[nodiscard]] bool Truncate(size_t length); + + private: + uint8_t* buffer_ = nullptr; + size_t length_ = 0; + size_t reserved_ = 0; + + [[nodiscard]] bool Reserve(size_t reserved); + + [[nodiscard]] bool ReserveNPOT(size_t reserved); + + HostBuffer(); + + FML_DISALLOW_COPY_AND_ASSIGN(HostBuffer); +}; + +} // namespace impeller diff --git a/engine/src/flutter/impeller/compositor/host_buffer.mm b/engine/src/flutter/impeller/compositor/host_buffer.mm new file mode 100644 index 00000000000..1925c4a9c4d --- /dev/null +++ b/engine/src/flutter/impeller/compositor/host_buffer.mm @@ -0,0 +1,75 @@ +// 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/compositor/host_buffer.h" + +#include "flutter/fml/logging.h" + +namespace impeller { + +std::shared_ptr HostBuffer::Create() { + return std::shared_ptr(new HostBuffer()); +} + +HostBuffer::HostBuffer() = default; + +HostBuffer::~HostBuffer() { + ::free(buffer_); +} + +std::shared_ptr HostBuffer::Emplace(size_t length) { + auto old_length = length_; + if (!Truncate(length_ + length)) { + return nullptr; + } + return std::shared_ptr( + new BufferView(shared_from_this(), Range{old_length, length})); +} + +bool HostBuffer::Truncate(size_t length) { + if (!ReserveNPOT(length)) { + return false; + } + length_ = length; + return true; +} + +static uint32_t NextPowerOfTwoSize(uint32_t x) { + if (x == 0) { + return 1; + } + + --x; + + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + + return x + 1; +} + +bool HostBuffer::ReserveNPOT(size_t reserved) { + return Reserve(NextPowerOfTwoSize(reserved)); +} + +bool HostBuffer::Reserve(size_t reserved) { + if (reserved == reserved_) { + return true; + } + auto new_allocation = ::realloc(buffer_, reserved); + if (!new_allocation) { + // If new length is zero, a minimum non-zero sized allocation is returned. + // So this check will not trip and this routine will indicate success as + // expected. + FML_LOG(ERROR) << "Allocation failed. Out of memory."; + return false; + } + buffer_ = static_cast(new_allocation); + reserved_ = reserved; + return true; +} + +} // namespace impeller diff --git a/engine/src/flutter/impeller/compositor/pipeline.h b/engine/src/flutter/impeller/compositor/pipeline.h index 0fef90ac03d..af95b464787 100644 --- a/engine/src/flutter/impeller/compositor/pipeline.h +++ b/engine/src/flutter/impeller/compositor/pipeline.h @@ -23,11 +23,15 @@ class Pipeline { bool IsValid() const; + id GetMTLRenderPipelineState() const; + + id GetMTLDepthStencilState() const; + private: friend class PipelineLibrary; Type type_ = Type::kUnknown; - id state_; + id pipeline_state_; id depth_stencil_state_; bool is_valid_ = false; diff --git a/engine/src/flutter/impeller/compositor/pipeline.mm b/engine/src/flutter/impeller/compositor/pipeline.mm index 94954f850a4..00edc742713 100644 --- a/engine/src/flutter/impeller/compositor/pipeline.mm +++ b/engine/src/flutter/impeller/compositor/pipeline.mm @@ -8,8 +8,8 @@ namespace impeller { Pipeline::Pipeline(id state, id depth_stencil_state) - : state_(state), depth_stencil_state_(depth_stencil_state) { - if (!state_) { + : pipeline_state_(state), depth_stencil_state_(depth_stencil_state) { + if (!pipeline_state_) { return; } type_ = Type::kRender; @@ -22,4 +22,12 @@ bool Pipeline::IsValid() const { return is_valid_; } +id Pipeline::GetMTLRenderPipelineState() const { + return pipeline_state_; +} + +id Pipeline::GetMTLDepthStencilState() const { + return depth_stencil_state_; +} + } // namespace impeller diff --git a/engine/src/flutter/impeller/compositor/render_pass.h b/engine/src/flutter/impeller/compositor/render_pass.h index 811e56bb940..54ee77ff905 100644 --- a/engine/src/flutter/impeller/compositor/render_pass.h +++ b/engine/src/flutter/impeller/compositor/render_pass.h @@ -84,6 +84,8 @@ class RenderPass { RenderPass(id buffer, const RenderPassDescriptor& desc); + bool EncodeCommands(id pass) const; + FML_DISALLOW_COPY_AND_ASSIGN(RenderPass); }; diff --git a/engine/src/flutter/impeller/compositor/render_pass.mm b/engine/src/flutter/impeller/compositor/render_pass.mm index e697a9d615e..fe2ad25fb4b 100644 --- a/engine/src/flutter/impeller/compositor/render_pass.mm +++ b/engine/src/flutter/impeller/compositor/render_pass.mm @@ -4,8 +4,10 @@ #include "impeller/compositor/render_pass.h" +#include "flutter/fml/closure.h" #include "flutter/fml/logging.h" #include "impeller/compositor/formats_metal.h" +#include "impeller/shader_glue/shader_types.h" namespace impeller { @@ -136,7 +138,51 @@ bool RenderPass::Encode() const { if (!pass) { return false; } - [pass endEncoding]; + // Success or failure, the pass must end. The buffer can only process one pass + // at a time. + fml::ScopedCleanupClosure auto_end([pass]() { [pass endEncoding]; }); + + return EncodeCommands(pass); +} + +void Bind(ShaderStage stage, const BufferView& view) {} + +void Bind(ShaderStage stage, const Texture& view) {} + +void Bind(ShaderStage stage, const Sampler& view) {} + +bool RenderPass::EncodeCommands(id pass) const { + // There a numerous opportunities here to ensure bindings are not repeated. + // Stuff like setting the vertex buffer bindings over and over when just the + // offsets could be updated (as recommended in best practices). + + auto bind_stage_resources = [](const Bindings& bindings, ShaderStage stage) { + for (const auto buffer : bindings.buffers) { + Bind(stage, buffer.second); + } + for (const auto texture : bindings.textures) { + Bind(stage, *texture.second); + } + for (const auto sampler : bindings.samplers) { + Bind(stage, *sampler.second); + } + }; + for (const auto& command : commands_) { + [pass setRenderPipelineState:command.pipeline->GetMTLRenderPipelineState()]; + [pass setDepthStencilState:command.pipeline->GetMTLDepthStencilState()]; + [pass setFrontFacingWinding:MTLWindingClockwise]; + [pass setCullMode:MTLCullModeBack]; + bind_stage_resources(command.vertex_bindings, ShaderStage::kVertex); + bind_stage_resources(command.fragment_bindings, ShaderStage::kFragment); + // [pass drawIndexedPrimitives:MTLPrimitiveTypeTriangleStrip + // indexCount:command.index_count + // indexType:MTLIndexTypeUInt32 + // indexBuffer:command.index_buffer + // indexBufferOffset:(NSUInteger)indexBufferOffset + // instanceCount:1u + // baseVertex:0u + // baseInstance:0u]; + } return true; }