diff --git a/engine/src/flutter/impeller/playground/playground.mm b/engine/src/flutter/impeller/playground/playground.mm index 95247d2a94c..f9397e1a9fd 100644 --- a/engine/src/flutter/impeller/playground/playground.mm +++ b/engine/src/flutter/impeller/playground/playground.mm @@ -9,6 +9,7 @@ #include "impeller/image/compressed_image.h" #include "impeller/playground/playground.h" #include "impeller/renderer/allocator.h" +#include "impeller/renderer/backend/metal/context_mtl.h" #include "impeller/renderer/context.h" #include "impeller/renderer/formats_metal.h" #include "impeller/renderer/render_pass.h" @@ -34,7 +35,8 @@ static std::string ShaderLibraryDirectory() { } Playground::Playground() - : renderer_(ShaderLibraryDirectory(), "shader_fixtures.metallib") {} + : renderer_(std::make_shared(ShaderLibraryDirectory(), + "shader_fixtures.metallib")) {} Playground::~Playground() = default; @@ -112,7 +114,7 @@ bool Playground::OpenPlaygroundHere(Renderer::RenderCallback render_callback) { NSWindow* cocoa_window = ::glfwGetCocoaWindow(window); CAMetalLayer* layer = [CAMetalLayer layer]; - layer.device = renderer_.GetContext()->GetMTLDevice(); + layer.device = ContextMTL::Cast(*renderer_.GetContext()).GetMTLDevice(); layer.pixelFormat = MTLPixelFormatBGRA8Unorm; cocoa_window.contentView.layer = layer; cocoa_window.contentView.wantsLayer = YES; diff --git a/engine/src/flutter/impeller/renderer/BUILD.gn b/engine/src/flutter/impeller/renderer/BUILD.gn index 2992255101e..ef46bf756be 100644 --- a/engine/src/flutter/impeller/renderer/BUILD.gn +++ b/engine/src/flutter/impeller/renderer/BUILD.gn @@ -5,73 +5,103 @@ import("//flutter/impeller/tools/impeller.gni") impeller_component("renderer") { - sources = [ - "allocator.h", - "allocator.mm", - "buffer.h", - "buffer.mm", - "buffer_view.h", - "buffer_view.mm", - "command.h", - "command.mm", - "command_buffer.h", - "command_buffer.mm", - "comparable.cc", - "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_builder.h", - "pipeline_builder.mm", - "pipeline_descriptor.h", - "pipeline_descriptor.mm", - "pipeline_library.h", - "pipeline_library.mm", - "platform.h", - "platform.mm", - "range.cc", - "range.h", - "render_pass.h", - "render_pass.mm", - "render_pass_descriptor.h", - "render_pass_descriptor.mm", - "renderer.h", - "renderer.mm", - "sampler.h", - "sampler.mm", - "sampler_descriptor.h", - "sampler_descriptor.mm", - "shader_function.h", - "shader_function.mm", - "shader_library.h", - "shader_library.mm", - "shader_types.cc", - "shader_types.h", - "surface.h", - "surface.mm", - "tessellator.cc", - "tessellator.h", - "texture.h", - "texture.mm", - "texture_descriptor.h", - "texture_descriptor.mm", - "vertex_buffer.h", - "vertex_buffer.mm", - "vertex_buffer_builder.h", - "vertex_buffer_builder.mm", - "vertex_descriptor.h", - "vertex_descriptor.mm", + metal_backend_sources = [ + "backend/metal/allocator_mtl.h", + "backend/metal/allocator_mtl.mm", + "backend/metal/backend_cast.h", + "backend/metal/command_buffer_mtl.h", + "backend/metal/command_buffer_mtl.mm", + "backend/metal/context_mtl.h", + "backend/metal/context_mtl.mm", + "backend/metal/device_buffer_mtl.h", + "backend/metal/device_buffer_mtl.mm", + "backend/metal/formats_mtl.h", + "backend/metal/formats_mtl.mm", + "backend/metal/pipeline_library_mtl.h", + "backend/metal/pipeline_library_mtl.mm", + "backend/metal/pipeline_mtl.h", + "backend/metal/pipeline_mtl.mm", + "backend/metal/render_pass_mtl.h", + "backend/metal/render_pass_mtl.mm", + "backend/metal/sampler_library_mtl.h", + "backend/metal/sampler_library_mtl.mm", + "backend/metal/sampler_mtl.h", + "backend/metal/sampler_mtl.mm", + "backend/metal/shader_function_mtl.h", + "backend/metal/shader_function_mtl.mm", + "backend/metal/shader_library_mtl.h", + "backend/metal/shader_library_mtl.mm", + "backend/metal/texture_mtl.h", + "backend/metal/texture_mtl.mm", ] + sources = [ + "allocator.h", + "allocator.cc", + "buffer.h", + "buffer.cc", + "buffer_view.h", + "buffer_view.cc", + "command.h", + "command.cc", + "command_buffer.h", + "command_buffer.cc", + "comparable.cc", + "comparable.h", + "context.h", + "context.cc", + "device_buffer.h", + "device_buffer.cc", + "formats.cc", + "formats.h", + "host_buffer.h", + "host_buffer.cc", + "pipeline.h", + "pipeline.cc", + "pipeline_builder.h", + "pipeline_builder.cc", + "pipeline_descriptor.h", + "pipeline_descriptor.cc", + "pipeline_library.h", + "pipeline_library.cc", + "platform.h", + "platform.cc", + "range.cc", + "range.h", + "render_pass.h", + "render_pass.cc", + "render_pass_descriptor.h", + "render_pass_descriptor.cc", + "renderer.h", + "renderer.mm", + "sampler.h", + "sampler.cc", + "sampler_descriptor.h", + "sampler_descriptor.cc", + "sampler_library.h", + "sampler_library.cc", + "shader_function.h", + "shader_function.cc", + "shader_library.h", + "shader_library.cc", + "shader_types.cc", + "shader_types.h", + "surface.h", + "surface.cc", + "tessellator.cc", + "tessellator.h", + "texture.h", + "texture.cc", + "texture_descriptor.h", + "texture_descriptor.cc", + "vertex_buffer.h", + "vertex_buffer.cc", + "vertex_buffer_builder.h", + "vertex_buffer_builder.cc", + "vertex_descriptor.h", + "vertex_descriptor.cc", + ] + metal_backend_sources + public_deps = [ "../base", "../geometry", @@ -87,9 +117,9 @@ source_set("renderer_unittests") { testonly = true sources = [ - "device_buffer_unittests.mm", - "host_buffer_unittests.mm", - "renderer_unittests.mm", + "device_buffer_unittests.cc", + "host_buffer_unittests.cc", + "renderer_unittests.cc", ] deps = [ diff --git a/engine/src/flutter/impeller/renderer/allocator.cc b/engine/src/flutter/impeller/renderer/allocator.cc new file mode 100644 index 00000000000..5969d220c21 --- /dev/null +++ b/engine/src/flutter/impeller/renderer/allocator.cc @@ -0,0 +1,27 @@ +// 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/renderer/allocator.h" + +namespace impeller { + +Allocator::Allocator() = default; + +Allocator::~Allocator() = default; + +bool Allocator::RequiresExplicitHostSynchronization(StorageMode mode) { + if (mode != StorageMode::kHostVisible) { + return false; + } + +#if OS_IOS + // StorageMode::kHostVisible is MTLStorageModeShared already. + return false; +#else // OS_IOS + // StorageMode::kHostVisible is MTLResourceStorageModeManaged. + return true; +#endif // OS_IOS +} + +} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/allocator.h b/engine/src/flutter/impeller/renderer/allocator.h index 14c37288f1a..d8a81a8abeb 100644 --- a/engine/src/flutter/impeller/renderer/allocator.h +++ b/engine/src/flutter/impeller/renderer/allocator.h @@ -4,8 +4,6 @@ #pragma once -#include - #include #include "flutter/fml/macros.h" @@ -51,35 +49,30 @@ class Texture; class Allocator { public: - ~Allocator(); + virtual ~Allocator(); bool IsValid() const; - std::shared_ptr CreateBuffer(StorageMode mode, size_t length); + virtual std::shared_ptr CreateBuffer(StorageMode mode, + size_t length) = 0; - std::shared_ptr CreateTexture(StorageMode mode, - const TextureDescriptor& desc); + virtual std::shared_ptr CreateTexture( + StorageMode mode, + const TextureDescriptor& desc) = 0; - std::shared_ptr CreateBufferWithCopy(const uint8_t* buffer, - size_t length); + virtual std::shared_ptr CreateBufferWithCopy( + const uint8_t* buffer, + size_t length) = 0; - std::shared_ptr CreateBufferWithCopy( - const fml::Mapping& mapping); + virtual std::shared_ptr CreateBufferWithCopy( + const fml::Mapping& mapping) = 0; static bool RequiresExplicitHostSynchronization(StorageMode mode); + protected: + Allocator(); + private: - friend class Context; - - // In the prototype, we are going to be allocating resources directly with the - // MTLDevice APIs. But, in the future, this could be backed by named heaps - // with specific limits. - id device_; - std::string allocator_label_; - bool is_valid_ = false; - - Allocator(id device, std::string label); - FML_DISALLOW_COPY_AND_ASSIGN(Allocator); }; diff --git a/engine/src/flutter/impeller/renderer/allocator.mm b/engine/src/flutter/impeller/renderer/allocator.mm deleted file mode 100644 index c409871a371..00000000000 --- a/engine/src/flutter/impeller/renderer/allocator.mm +++ /dev/null @@ -1,134 +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/renderer/allocator.h" - -#include "flutter/fml/build_config.h" -#include "flutter/fml/logging.h" -#include "impeller/renderer/buffer.h" -#include "impeller/renderer/device_buffer.h" -#include "impeller/renderer/formats_metal.h" - -namespace impeller { - -Allocator::Allocator(id device, std::string label) - : device_(device), allocator_label_(std::move(label)) { - if (!device_) { - return; - } - - is_valid_ = true; -} - -Allocator::~Allocator() = default; - -bool Allocator::IsValid() const { - return is_valid_; -} - -static MTLResourceOptions ToMTLResourceOptions(StorageMode type) { - switch (type) { - case StorageMode::kHostVisible: -#if OS_IOS - return MTLResourceStorageModeShared; -#else - return MTLResourceStorageModeManaged; -#endif - case StorageMode::kDevicePrivate: - return MTLResourceStorageModePrivate; - case StorageMode::kDeviceTransient: -#if OS_IOS - return MTLResourceStorageModeMemoryless; -#else - return MTLResourceStorageModePrivate; -#endif - } - - return MTLResourceStorageModePrivate; -} - -static MTLStorageMode ToMTLStorageMode(StorageMode mode) { - switch (mode) { - case StorageMode::kHostVisible: -#if OS_IOS - return MTLStorageModeShared; -#else - return MTLStorageModeManaged; -#endif - case StorageMode::kDevicePrivate: - return MTLStorageModePrivate; - case StorageMode::kDeviceTransient: -#if OS_IOS - return MTLStorageModeMemoryless; -#else - return MTLStorageModePrivate; -#endif - } - return MTLStorageModeShared; -} - -bool Allocator::RequiresExplicitHostSynchronization(StorageMode mode) { - if (mode != StorageMode::kHostVisible) { - return false; - } - -#if OS_IOS - // StorageMode::kHostVisible is MTLStorageModeShared already. - return false; -#else - // StorageMode::kHostVisible is MTLResourceStorageModeManaged. - return true; -#endif -} - -std::shared_ptr Allocator::CreateBuffer(StorageMode mode, - size_t length) { - auto buffer = [device_ newBufferWithLength:length - options:ToMTLResourceOptions(mode)]; - if (!buffer) { - return nullptr; - } - return std::shared_ptr(new DeviceBuffer(buffer, length, mode)); -} - -std::shared_ptr Allocator::CreateBufferWithCopy( - const uint8_t* buffer, - size_t length) { - auto new_buffer = CreateBuffer(StorageMode::kHostVisible, length); - - if (!new_buffer) { - return nullptr; - } - - auto entire_range = Range{0, length}; - - if (!new_buffer->CopyHostBuffer(buffer, entire_range)) { - return nullptr; - } - - return new_buffer; -} - -std::shared_ptr Allocator::CreateBufferWithCopy( - const fml::Mapping& mapping) { - return CreateBufferWithCopy(mapping.GetMapping(), mapping.GetSize()); -} - -std::shared_ptr Allocator::CreateTexture( - StorageMode mode, - const TextureDescriptor& desc) { - if (!IsValid()) { - return nullptr; - } - - auto mtl_texture_desc = ToMTLTextureDescriptor(desc); - mtl_texture_desc.storageMode = ToMTLStorageMode(mode); - auto texture = [device_ newTextureWithDescriptor:mtl_texture_desc]; - if (!texture) { - return nullptr; - } - return std::make_shared(desc, texture); -} - -} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/metal/BUILD.gn b/engine/src/flutter/impeller/renderer/backend/metal/BUILD.gn deleted file mode 100644 index aae58285956..00000000000 --- a/engine/src/flutter/impeller/renderer/backend/metal/BUILD.gn +++ /dev/null @@ -1,9 +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. - -import("//flutter/impeller/tools/impeller.gni") - -impeller_component("metal") { - sources = [] -} diff --git a/engine/src/flutter/impeller/renderer/backend/metal/allocator_mtl.h b/engine/src/flutter/impeller/renderer/backend/metal/allocator_mtl.h index 494b6f78a39..fc5d8c170da 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/allocator_mtl.h +++ b/engine/src/flutter/impeller/renderer/backend/metal/allocator_mtl.h @@ -4,6 +4,8 @@ #pragma once +#include + #include "flutter/fml/macros.h" #include "impeller/renderer/allocator.h" @@ -13,9 +15,41 @@ class AllocatorMTL final : public Allocator { public: AllocatorMTL(); + // |Allocator| ~AllocatorMTL() override; private: + friend class ContextMTL; + + // In the prototype, we are going to be allocating resources directly with the + // MTLDevice APIs. But, in the future, this could be backed by named heaps + // with specific limits. + id device_; + std::string allocator_label_; + bool is_valid_ = false; + + AllocatorMTL(id device, std::string label); + + // |Allocator| + bool IsValid() const; + + // |Allocator| + std::shared_ptr CreateBuffer(StorageMode mode, + size_t length) override; + + // |Allocator| + std::shared_ptr CreateTexture( + StorageMode mode, + const TextureDescriptor& desc) override; + + // |Allocator| + std::shared_ptr CreateBufferWithCopy(const uint8_t* buffer, + size_t length) override; + + // |Allocator| + std::shared_ptr CreateBufferWithCopy( + const fml::Mapping& mapping) override; + FML_DISALLOW_COPY_AND_ASSIGN(AllocatorMTL); }; diff --git a/engine/src/flutter/impeller/renderer/backend/metal/allocator_mtl.mm b/engine/src/flutter/impeller/renderer/backend/metal/allocator_mtl.mm index e69de29bb2d..0414bd135d9 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/allocator_mtl.mm +++ b/engine/src/flutter/impeller/renderer/backend/metal/allocator_mtl.mm @@ -0,0 +1,121 @@ +// 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/renderer/backend/metal/allocator_mtl.h" + +#include "flutter/fml/build_config.h" +#include "flutter/fml/logging.h" +#include "impeller/renderer/backend/metal/device_buffer_mtl.h" +#include "impeller/renderer/backend/metal/formats_mtl.h" +#include "impeller/renderer/buffer.h" + +namespace impeller { + +AllocatorMTL::AllocatorMTL(id device, std::string label) + : device_(device), allocator_label_(std::move(label)) { + if (!device_) { + return; + } + + is_valid_ = true; +} + +AllocatorMTL::~AllocatorMTL() = default; + +bool AllocatorMTL::IsValid() const { + return is_valid_; +} + +static MTLResourceOptions ToMTLResourceOptions(StorageMode type) { + switch (type) { + case StorageMode::kHostVisible: +#if OS_IOS + return MTLResourceStorageModeShared; +#else + return MTLResourceStorageModeManaged; +#endif + case StorageMode::kDevicePrivate: + return MTLResourceStorageModePrivate; + case StorageMode::kDeviceTransient: +#if OS_IOS + return MTLResourceStorageModeMemoryless; +#else + return MTLResourceStorageModePrivate; +#endif + } + + return MTLResourceStorageModePrivate; +} + +static MTLStorageMode ToMTLStorageMode(StorageMode mode) { + switch (mode) { + case StorageMode::kHostVisible: +#if OS_IOS + return MTLStorageModeShared; +#else + return MTLStorageModeManaged; +#endif + case StorageMode::kDevicePrivate: + return MTLStorageModePrivate; + case StorageMode::kDeviceTransient: +#if OS_IOS + return MTLStorageModeMemoryless; +#else + return MTLStorageModePrivate; +#endif + } + return MTLStorageModeShared; +} + +std::shared_ptr AllocatorMTL::CreateBuffer(StorageMode mode, + size_t length) { + auto buffer = [device_ newBufferWithLength:length + options:ToMTLResourceOptions(mode)]; + if (!buffer) { + return nullptr; + } + return std::shared_ptr( + new DeviceBufferMTL(buffer, length, mode)); +} + +std::shared_ptr AllocatorMTL::CreateBufferWithCopy( + const uint8_t* buffer, + size_t length) { + auto new_buffer = CreateBuffer(StorageMode::kHostVisible, length); + + if (!new_buffer) { + return nullptr; + } + + auto entire_range = Range{0, length}; + + if (!new_buffer->CopyHostBuffer(buffer, entire_range)) { + return nullptr; + } + + return new_buffer; +} + +std::shared_ptr AllocatorMTL::CreateBufferWithCopy( + const fml::Mapping& mapping) { + return CreateBufferWithCopy(mapping.GetMapping(), mapping.GetSize()); +} + +std::shared_ptr AllocatorMTL::CreateTexture( + StorageMode mode, + const TextureDescriptor& desc) { + if (!IsValid()) { + return nullptr; + } + + auto mtl_texture_desc = ToMTLTextureDescriptor(desc); + mtl_texture_desc.storageMode = ToMTLStorageMode(mode); + auto texture = [device_ newTextureWithDescriptor:mtl_texture_desc]; + if (!texture) { + return nullptr; + } + return std::make_shared(desc, texture); +} + +} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/metal/renderer_mtl.h b/engine/src/flutter/impeller/renderer/backend/metal/backend_cast.h similarity index 55% rename from engine/src/flutter/impeller/renderer/backend/metal/renderer_mtl.h rename to engine/src/flutter/impeller/renderer/backend/metal/backend_cast.h index dbb9f2565b4..a6bf9db9073 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/renderer_mtl.h +++ b/engine/src/flutter/impeller/renderer/backend/metal/backend_cast.h @@ -5,18 +5,17 @@ #pragma once #include "flutter/fml/macros.h" -#include "impeller/renderer/renderer.h" namespace impeller { -class RendererMTL final : public Renderer { +template +class BackendCast { public: - RendererMTL(); + static Sub& Cast(Base& base) { return reinterpret_cast(base); } - ~RendererMTL() override; - - private: - FML_DISALLOW_COPY_AND_ASSIGN(RendererMTL); + static const Sub& Cast(const Base& base) { + return reinterpret_cast(base); + } }; } // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/metal/command_buffer_mtl.h b/engine/src/flutter/impeller/renderer/backend/metal/command_buffer_mtl.h index 2f3f35d424b..bd816dd76ed 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/command_buffer_mtl.h +++ b/engine/src/flutter/impeller/renderer/backend/metal/command_buffer_mtl.h @@ -4,19 +4,39 @@ #pragma once +#include + #include "flutter/fml/macros.h" #include "impeller/renderer/command_buffer.h" namespace impeller { -class CommabdBufferMTL final : public CommabdBuffer { +class CommandBufferMTL final : public CommandBuffer { public: - CommabdBufferMTL(); + CommandBufferMTL(); - ~CommabdBufferMTL() override; + // |CommandBuffer| + ~CommandBufferMTL() override; private: - FML_DISALLOW_COPY_AND_ASSIGN(CommabdBufferMTL); + friend class ContextMTL; + + id buffer_ = nullptr; + bool is_valid_ = false; + + CommandBufferMTL(id queue); + + // |CommandBuffer| + bool IsValid() const override; + + // |CommandBuffer| + void Commit(CommitCallback callback) override; + + // |CommandBuffer| + std::shared_ptr CreateRenderPass( + const RenderPassDescriptor& desc) const override; + + FML_DISALLOW_COPY_AND_ASSIGN(CommandBufferMTL); }; } // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/metal/command_buffer_mtl.mm b/engine/src/flutter/impeller/renderer/backend/metal/command_buffer_mtl.mm index e69de29bb2d..bd9f56e9e8c 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/command_buffer_mtl.mm +++ b/engine/src/flutter/impeller/renderer/backend/metal/command_buffer_mtl.mm @@ -0,0 +1,70 @@ +// 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/renderer/backend/metal/command_buffer_mtl.h" + +#include "impeller/renderer/backend/metal/render_pass_mtl.h" + +namespace impeller { + +CommandBufferMTL::CommandBufferMTL(id queue) + : buffer_([queue commandBuffer]) { + if (!buffer_) { + return; + } + is_valid_ = true; +} + +CommandBufferMTL::~CommandBufferMTL() = default; + +bool CommandBufferMTL::IsValid() const { + return is_valid_; +} + +static CommandBuffer::CommitResult ToCommitResult( + MTLCommandBufferStatus status) { + switch (status) { + case MTLCommandBufferStatusCompleted: + return CommandBufferMTL::CommitResult::kCompleted; + case MTLCommandBufferStatusEnqueued: + return CommandBufferMTL::CommitResult::kPending; + default: + break; + } + return CommandBufferMTL::CommitResult::kError; +} + +void CommandBufferMTL::Commit(CommitCallback callback) { + if (!callback) { + callback = [](auto) {}; + } + + if (!buffer_) { + // Already committed. This is caller error. + callback(CommitResult::kError); + return; + } + + [buffer_ addCompletedHandler:^(id buffer) { + callback(ToCommitResult(buffer.status)); + }]; + [buffer_ commit]; + buffer_ = nil; +} + +std::shared_ptr CommandBufferMTL::CreateRenderPass( + const RenderPassDescriptor& desc) const { + if (!buffer_) { + return nullptr; + } + + auto pass = std::shared_ptr(new RenderPassMTL(buffer_, desc)); + if (!pass->IsValid()) { + return nullptr; + } + + return pass; +} + +} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.h b/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.h index aaba0258b63..fd9a0e6c20d 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.h +++ b/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.h @@ -4,18 +4,63 @@ #pragma once +#include + +#include + #include "flutter/fml/macros.h" +#include "impeller/renderer/backend/metal/allocator_mtl.h" +#include "impeller/renderer/backend/metal/backend_cast.h" +#include "impeller/renderer/backend/metal/command_buffer_mtl.h" +#include "impeller/renderer/backend/metal/pipeline_library_mtl.h" +#include "impeller/renderer/backend/metal/shader_library_mtl.h" #include "impeller/renderer/context.h" +#include "impeller/renderer/sampler.h" namespace impeller { -class ContextMTL final : public Context { +class ContextMTL final : public Context, + public BackendCast { public: - ContextMTL(); + ContextMTL(std::string shaders_directory, std::string main_library_file_name); + // |Context| ~ContextMTL() override; + id GetMTLDevice() const; + private: + id device_ = nullptr; + id render_queue_ = nullptr; + id transfer_queue_ = nullptr; + std::shared_ptr shader_library_; + std::shared_ptr pipeline_library_; + std::shared_ptr sampler_library_; + std::shared_ptr permanents_allocator_; + std::shared_ptr transients_allocator_; + bool is_valid_ = false; + + // |Context| + bool IsValid() const override; + + // |Context| + std::shared_ptr GetPermanentsAllocator() const override; + + // |Context| + std::shared_ptr GetTransientsAllocator() const override; + + // |Context| + std::shared_ptr GetShaderLibrary() const override; + + // |Context| + std::shared_ptr GetSamplerLibrary() const override; + + // |Context| + std::shared_ptr GetPipelineLibrary() const override; + + // |Context| + std::shared_ptr CreateRenderCommandBuffer() const override; + FML_DISALLOW_COPY_AND_ASSIGN(ContextMTL); }; diff --git a/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.mm b/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.mm index e69de29bb2d..35efa3b560b 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.mm +++ b/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.mm @@ -0,0 +1,135 @@ +// 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/renderer/backend/metal/context_mtl.h" + +#include "flutter/fml/file.h" +#include "flutter/fml/logging.h" +#include "flutter/fml/paths.h" +#include "impeller/renderer/backend/metal/sampler_library_mtl.h" +#include "impeller/renderer/sampler_descriptor.h" + +namespace impeller { + +ContextMTL::ContextMTL(std::string shaders_directory, + std::string main_library_file_name) + : device_(::MTLCreateSystemDefaultDevice()) { + // Setup device. + if (!device_) { + return; + } + + // Setup command queues. + render_queue_ = device_.newCommandQueue; + transfer_queue_ = device_.newCommandQueue; + + if (!render_queue_ || !transfer_queue_) { + return; + } + + render_queue_.label = @"Impeller Render Queue"; + transfer_queue_.label = @"Impeller Transfer Queue"; + + // Setup the shader library. + { + NSError* shader_library_error = nil; + auto shader_library_path = + fml::paths::JoinPaths({shaders_directory, main_library_file_name}); + + auto library_exists = fml::IsFile(shader_library_path); + + if (!library_exists) { + FML_LOG(ERROR) << "Shader library does not exist at path '" + << shader_library_path + << "'. No piplines can be created in this context."; + } + auto library = + library_exists + ? [device_ newLibraryWithFile:@(shader_library_path.c_str()) + error:&shader_library_error] + : [device_ newDefaultLibrary]; + if (!library && shader_library_error) { + FML_LOG(ERROR) << "Could not create shader library: " + << shader_library_error.localizedDescription.UTF8String; + return; + } + + // std::make_shared disallowed because of private friend ctor. + shader_library_ = + std::shared_ptr(new ShaderLibraryMTL(library)); + } + + // Setup the pipeline library. + { // + pipeline_library_ = + std::shared_ptr(new PipelineLibraryMTL(device_)); + } + + // Setup the sampler library. + { // + sampler_library_ = + std::shared_ptr(new SamplerLibraryMTL(device_)); + } + + { + transients_allocator_ = std::shared_ptr( + new AllocatorMTL(device_, "Impeller Transients Allocator")); + if (!transients_allocator_) { + return; + } + + permanents_allocator_ = std::shared_ptr( + new AllocatorMTL(device_, "Impeller Permanents Allocator")); + if (!permanents_allocator_) { + return; + } + } + + is_valid_ = true; +} + +ContextMTL::~ContextMTL() = default; + +bool ContextMTL::IsValid() const { + return is_valid_; +} + +std::shared_ptr ContextMTL::GetShaderLibrary() const { + return shader_library_; +} + +std::shared_ptr ContextMTL::GetPipelineLibrary() const { + return pipeline_library_; +} + +std::shared_ptr ContextMTL::GetSamplerLibrary() const { + return sampler_library_; +} + +std::shared_ptr ContextMTL::CreateRenderCommandBuffer() const { + if (!IsValid()) { + return nullptr; + } + + auto buffer = + std::shared_ptr(new CommandBufferMTL(render_queue_)); + if (!buffer->IsValid()) { + return nullptr; + } + return buffer; +} + +std::shared_ptr ContextMTL::GetPermanentsAllocator() const { + return permanents_allocator_; +} + +std::shared_ptr ContextMTL::GetTransientsAllocator() const { + return transients_allocator_; +} + +id ContextMTL::GetMTLDevice() const { + return device_; +} + +} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/metal/device_buffer_mtl.h b/engine/src/flutter/impeller/renderer/backend/metal/device_buffer_mtl.h index bc7386c39bb..7523cc4cacd 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/device_buffer_mtl.h +++ b/engine/src/flutter/impeller/renderer/backend/metal/device_buffer_mtl.h @@ -4,18 +4,56 @@ #pragma once +#include + #include "flutter/fml/macros.h" +#include "impeller/renderer/backend/metal/backend_cast.h" #include "impeller/renderer/device_buffer.h" namespace impeller { -class DeviceBufferMTL final : public DeviceBuffer { +class DeviceBufferMTL final + : public DeviceBuffer, + public BackendCast { public: DeviceBufferMTL(); + // |DeviceBuffer| ~DeviceBufferMTL() override; + id GetMTLBuffer() const; + private: + friend class AllocatorMTL; + + const id buffer_; + const size_t size_; + const StorageMode mode_; + + DeviceBufferMTL(id buffer, size_t size, StorageMode mode); + + // |DeviceBuffer| + bool CopyHostBuffer(const uint8_t* source, + Range source_range, + size_t offset) override; + + // |DeviceBuffer| + std::shared_ptr MakeTexture(TextureDescriptor desc, + size_t offset) const override; + + // |DeviceBuffer| + bool SetLabel(const std::string& label) override; + + // |DeviceBuffer| + bool SetLabel(const std::string& label, Range range) override; + + // |DeviceBuffer| + BufferView AsBufferView() const override; + + // |Buffer| + std::shared_ptr GetDeviceBuffer( + Allocator& allocator) const override; + FML_DISALLOW_COPY_AND_ASSIGN(DeviceBufferMTL); }; diff --git a/engine/src/flutter/impeller/renderer/backend/metal/device_buffer_mtl.mm b/engine/src/flutter/impeller/renderer/backend/metal/device_buffer_mtl.mm index e69de29bb2d..4469cc34975 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/device_buffer_mtl.mm +++ b/engine/src/flutter/impeller/renderer/backend/metal/device_buffer_mtl.mm @@ -0,0 +1,105 @@ +// 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/renderer/backend/metal/device_buffer_mtl.h" + +#include "flutter/fml/logging.h" +#include "impeller/renderer/backend/metal/formats_mtl.h" + +namespace impeller { + +DeviceBufferMTL::DeviceBufferMTL(id buffer, + size_t size, + StorageMode mode) + : buffer_(buffer), size_(size), mode_(mode) {} + +DeviceBufferMTL::~DeviceBufferMTL() = default; + +id DeviceBufferMTL::GetMTLBuffer() const { + return buffer_; +} + +std::shared_ptr DeviceBufferMTL::MakeTexture(TextureDescriptor desc, + size_t offset) const { + if (!desc.IsValid() || !buffer_) { + return nullptr; + } + + // Avoid overruns. + if (offset + desc.GetSizeOfBaseMipLevel() > size_) { + FML_DLOG(ERROR) << "Avoiding buffer overrun when creating texture."; + return nullptr; + } + + auto texture = [buffer_ newTextureWithDescriptor:ToMTLTextureDescriptor(desc) + offset:offset + bytesPerRow:desc.GetBytesPerRow()]; + if (!texture) { + return nullptr; + } + + return std::make_shared(desc, texture); +} + +[[nodiscard]] bool DeviceBufferMTL::CopyHostBuffer(const uint8_t* source, + Range source_range, + size_t offset) { + if (mode_ != StorageMode::kHostVisible) { + // One of the storage modes where a transfer queue must be used. + return false; + } + + if (offset + source_range.length > size_) { + // Out of bounds of this buffer. + return false; + } + + auto dest = static_cast(buffer_.contents); + + if (!dest) { + return false; + } + + if (source) { + ::memmove(dest + offset, source + source_range.offset, source_range.length); + } + + if (Allocator::RequiresExplicitHostSynchronization(mode_)) { + [buffer_ didModifyRange:NSMakeRange(offset, source_range.length)]; + } + + return true; +} + +// |Buffer| +std::shared_ptr DeviceBufferMTL::GetDeviceBuffer( + Allocator& allocator) const { + return shared_from_this(); +} + +bool DeviceBufferMTL::SetLabel(const std::string& label) { + if (label.empty()) { + return false; + } + [buffer_ setLabel:@(label.c_str())]; + return true; +} + +bool DeviceBufferMTL::SetLabel(const std::string& label, Range range) { + if (label.empty()) { + return false; + } + [buffer_ addDebugMarker:@(label.c_str()) + range:NSMakeRange(range.offset, range.length)]; + return true; +} + +BufferView DeviceBufferMTL::AsBufferView() const { + BufferView view; + view.buffer = shared_from_this(); + view.range = {0u, size_}; + return view; +} + +} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/metal/formats_metal.h b/engine/src/flutter/impeller/renderer/backend/metal/formats_metal.h deleted file mode 100644 index 10e536e31f0..00000000000 --- a/engine/src/flutter/impeller/renderer/backend/metal/formats_metal.h +++ /dev/null @@ -1,263 +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. - -#pragma once - -#include - -#include - -#include "flutter/fml/macros.h" -#include "impeller/geometry/color.h" -#include "impeller/renderer/formats.h" -#include "impeller/renderer/texture_descriptor.h" - -namespace impeller { - -class RenderPassDescriptor; - -constexpr MTLPixelFormat ToMTLPixelFormat(PixelFormat format) { - switch (format) { - case PixelFormat::kUnknown: - return MTLPixelFormatInvalid; - case PixelFormat::kB8G8R8A8UNormInt: - return MTLPixelFormatBGRA8Unorm; - case PixelFormat::kB8G8R8A8UNormIntSRGB: - return MTLPixelFormatBGRA8Unorm_sRGB; - case PixelFormat::kD32FloatS8UNormInt: - return MTLPixelFormatDepth32Float_Stencil8; - case PixelFormat::kR8G8B8A8UNormInt: - return MTLPixelFormatRGBA8Unorm; - case PixelFormat::kR8G8B8A8UNormIntSRGB: - return MTLPixelFormatRGBA8Unorm_sRGB; - } - return MTLPixelFormatInvalid; -}; - -constexpr MTLBlendFactor ToMTLBlendFactor(BlendFactor type) { - switch (type) { - case BlendFactor::kZero: - return MTLBlendFactorZero; - case BlendFactor::kOne: - return MTLBlendFactorOne; - case BlendFactor::kSourceColor: - return MTLBlendFactorSourceColor; - case BlendFactor::kOneMinusSourceColor: - return MTLBlendFactorOneMinusSourceColor; - case BlendFactor::kSourceAlpha: - return MTLBlendFactorSourceAlpha; - case BlendFactor::kOneMinusSourceAlpha: - return MTLBlendFactorOneMinusSourceAlpha; - case BlendFactor::kDestinationColor: - return MTLBlendFactorDestinationColor; - case BlendFactor::kOneMinusDestinationColor: - return MTLBlendFactorOneMinusDestinationColor; - case BlendFactor::kDestinationAlpha: - return MTLBlendFactorDestinationAlpha; - case BlendFactor::kOneMinusDestinationAlpha: - return MTLBlendFactorOneMinusDestinationAlpha; - case BlendFactor::kSourceAlphaSaturated: - return MTLBlendFactorSourceAlphaSaturated; - case BlendFactor::kBlendColor: - return MTLBlendFactorBlendColor; - case BlendFactor::kOneMinusBlendColor: - return MTLBlendFactorOneMinusBlendColor; - case BlendFactor::kBlendAlpha: - return MTLBlendFactorBlendAlpha; - case BlendFactor::kOneMinusBlendAlpha: - return MTLBlendFactorOneMinusBlendAlpha; - } - return MTLBlendFactorZero; -}; - -constexpr MTLPrimitiveType ToMTLPrimitiveType(PrimitiveType type) { - switch (type) { - case PrimitiveType::kTriangle: - return MTLPrimitiveTypeTriangle; - case PrimitiveType::kTriangleStrip: - return MTLPrimitiveTypeTriangleStrip; - case PrimitiveType::kLine: - return MTLPrimitiveTypeLine; - case PrimitiveType::kLineStrip: - return MTLPrimitiveTypeLineStrip; - case PrimitiveType::kPoint: - return MTLPrimitiveTypePoint; - } - return MTLPrimitiveTypePoint; -} - -constexpr MTLBlendOperation ToMTLBlendOperation(BlendOperation type) { - switch (type) { - case BlendOperation::kAdd: - return MTLBlendOperationAdd; - case BlendOperation::kSubtract: - return MTLBlendOperationSubtract; - case BlendOperation::kReverseSubtract: - return MTLBlendOperationReverseSubtract; - case BlendOperation::kMin: - return MTLBlendOperationMin; - case BlendOperation::kMax: - return MTLBlendOperationMax; - } - return MTLBlendOperationAdd; -}; - -constexpr MTLColorWriteMask ToMTLColorWriteMask( - std::underlying_type_t type) { - using UnderlyingType = decltype(type); - - MTLColorWriteMask mask = MTLColorWriteMaskNone; - - if (type & static_cast(ColorWriteMask::kRed)) { - mask |= MTLColorWriteMaskRed; - } - - if (type & static_cast(ColorWriteMask::kGreen)) { - mask |= MTLColorWriteMaskGreen; - } - - if (type & static_cast(ColorWriteMask::kBlue)) { - mask |= MTLColorWriteMaskBlue; - } - - if (type & static_cast(ColorWriteMask::kAlpha)) { - mask |= MTLColorWriteMaskAlpha; - } - - return mask; -}; - -constexpr MTLCompareFunction ToMTLCompareFunction(CompareFunction func) { - switch (func) { - case CompareFunction::kNever: - return MTLCompareFunctionNever; - case CompareFunction::kLess: - return MTLCompareFunctionLess; - case CompareFunction::kEqual: - return MTLCompareFunctionEqual; - case CompareFunction::kLessEqual: - return MTLCompareFunctionLessEqual; - case CompareFunction::kGreater: - return MTLCompareFunctionGreater; - case CompareFunction::kNotEqual: - return MTLCompareFunctionNotEqual; - case CompareFunction::kGreaterEqual: - return MTLCompareFunctionGreaterEqual; - case CompareFunction::kAlways: - return MTLCompareFunctionAlways; - } - return MTLCompareFunctionAlways; -}; - -constexpr MTLStencilOperation ToMTLStencilOperation(StencilOperation op) { - switch (op) { - case StencilOperation::kKeep: - return MTLStencilOperationKeep; - case StencilOperation::kZero: - return MTLStencilOperationZero; - case StencilOperation::kSetToReferneceValue: - return MTLStencilOperationReplace; - case StencilOperation::kIncrementClamp: - return MTLStencilOperationIncrementClamp; - case StencilOperation::kDecrementClamp: - return MTLStencilOperationDecrementClamp; - case StencilOperation::kInvert: - return MTLStencilOperationInvert; - case StencilOperation::kIncrementWrap: - return MTLStencilOperationIncrementWrap; - case StencilOperation::kDecrementWrap: - return MTLStencilOperationDecrementWrap; - } - return MTLStencilOperationKeep; -}; - -constexpr MTLLoadAction ToMTLLoadAction(LoadAction action) { - switch (action) { - case LoadAction::kDontCare: - return MTLLoadActionDontCare; - case LoadAction::kLoad: - return MTLLoadActionLoad; - case LoadAction::kClear: - return MTLLoadActionClear; - } - - return MTLLoadActionDontCare; -} - -constexpr LoadAction FromMTLLoadAction(MTLLoadAction action) { - switch (action) { - case MTLLoadActionDontCare: - return LoadAction::kDontCare; - case MTLLoadActionLoad: - return LoadAction::kLoad; - case MTLLoadActionClear: - return LoadAction::kClear; - default: - break; - } - - return LoadAction::kDontCare; -} - -constexpr MTLStoreAction ToMTLStoreAction(StoreAction action) { - switch (action) { - case StoreAction::kDontCare: - return MTLStoreActionDontCare; - case StoreAction::kStore: - return MTLStoreActionStore; - } - return MTLStoreActionDontCare; -} - -constexpr StoreAction FromMTLStoreAction(MTLStoreAction action) { - switch (action) { - case MTLStoreActionDontCare: - return StoreAction::kDontCare; - case MTLStoreActionStore: - return StoreAction::kStore; - default: - break; - } - return StoreAction::kDontCare; -} - -constexpr MTLSamplerMinMagFilter ToMTLSamplerMinMagFilter(MinMagFilter filter) { - switch (filter) { - case MinMagFilter::kNearest: - return MTLSamplerMinMagFilterNearest; - case MinMagFilter::kLinear: - return MTLSamplerMinMagFilterLinear; - } - return MTLSamplerMinMagFilterNearest; -} - -constexpr MTLSamplerAddressMode ToMTLSamplerAddressMode( - SamplerAddressMode mode) { - switch (mode) { - case SamplerAddressMode::kClampToEdge: - return MTLSamplerAddressModeClampToEdge; - case SamplerAddressMode::kRepeat: - return MTLSamplerAddressModeRepeat; - case SamplerAddressMode::kMirror: - return MTLSamplerAddressModeMirrorRepeat; - } - return MTLSamplerAddressModeClampToEdge; -} - -constexpr MTLClearColor ToMTLClearColor(const Color& color) { - return MTLClearColorMake(color.red, color.green, color.blue, color.alpha); -} - -MTLRenderPipelineColorAttachmentDescriptor* -ToMTLRenderPipelineColorAttachmentDescriptor( - PipelineColorAttachment descriptor); - -MTLDepthStencilDescriptor* ToMTLDepthStencilDescriptor( - std::optional depth, - std::optional front, - std::optional back); - -MTLTextureDescriptor* ToMTLTextureDescriptor(const TextureDescriptor& desc); - -} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/formats_metal.h b/engine/src/flutter/impeller/renderer/backend/metal/formats_mtl.h similarity index 100% rename from engine/src/flutter/impeller/renderer/formats_metal.h rename to engine/src/flutter/impeller/renderer/backend/metal/formats_mtl.h index 10e536e31f0..6b3f6e25c3d 100644 --- a/engine/src/flutter/impeller/renderer/formats_metal.h +++ b/engine/src/flutter/impeller/renderer/backend/metal/formats_mtl.h @@ -4,10 +4,10 @@ #pragma once -#include - #include +#include + #include "flutter/fml/macros.h" #include "impeller/geometry/color.h" #include "impeller/renderer/formats.h" diff --git a/engine/src/flutter/impeller/renderer/backend/metal/formats_metal.mm b/engine/src/flutter/impeller/renderer/backend/metal/formats_mtl.mm similarity index 100% rename from engine/src/flutter/impeller/renderer/backend/metal/formats_metal.mm rename to engine/src/flutter/impeller/renderer/backend/metal/formats_mtl.mm diff --git a/engine/src/flutter/impeller/renderer/backend/metal/pipeline_library_mtl.h b/engine/src/flutter/impeller/renderer/backend/metal/pipeline_library_mtl.h index ef5ccbaadaf..612a95a1de6 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/pipeline_library_mtl.h +++ b/engine/src/flutter/impeller/renderer/backend/metal/pipeline_library_mtl.h @@ -4,18 +4,43 @@ #pragma once +#include + +#include +#include + #include "flutter/fml/macros.h" #include "impeller/renderer/pipeline_library.h" namespace impeller { +class ContextMTL; + class PipelineLibraryMTL final : public PipelineLibrary { public: PipelineLibraryMTL(); + // |PipelineLibrary| ~PipelineLibraryMTL() override; private: + friend ContextMTL; + + using Pipelines = std::unordered_map, + ComparableHash, + ComparableEqual>; + id device_ = nullptr; + Pipelines pipelines_; + + PipelineLibraryMTL(id device); + + void SavePipeline(PipelineDescriptor descriptor, + std::shared_ptr pipeline); + + // |PipelineLibrary| + PipelineFuture GetRenderPipeline(PipelineDescriptor descriptor) override; + FML_DISALLOW_COPY_AND_ASSIGN(PipelineLibraryMTL); }; diff --git a/engine/src/flutter/impeller/renderer/backend/metal/pipeline_library_mtl.mm b/engine/src/flutter/impeller/renderer/backend/metal/pipeline_library_mtl.mm index e69de29bb2d..73d0f26e725 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/pipeline_library_mtl.mm +++ b/engine/src/flutter/impeller/renderer/backend/metal/pipeline_library_mtl.mm @@ -0,0 +1,103 @@ +// 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/renderer/backend/metal/pipeline_library_mtl.h" + +#include "impeller/renderer/backend/metal/formats_mtl.h" +#include "impeller/renderer/backend/metal/pipeline_mtl.h" +#include "impeller/renderer/backend/metal/shader_function_mtl.h" + +namespace impeller { + +PipelineLibraryMTL::PipelineLibraryMTL(id device) + : device_(device) {} + +PipelineLibraryMTL::~PipelineLibraryMTL() = default; + +// TODO(csg): Make PipelineDescriptor a struct and move this to formats_mtl. +static MTLRenderPipelineDescriptor* GetMTLRenderPipelineDescriptor( + const PipelineDescriptor& desc) { + auto descriptor = [[MTLRenderPipelineDescriptor alloc] init]; + descriptor.label = @(desc.GetLabel().c_str()); + descriptor.sampleCount = desc.GetSampleCount(); + + for (const auto& entry : desc.GetStageEntrypoints()) { + if (entry.first == ShaderStage::kVertex) { + descriptor.vertexFunction = + ShaderFunctionMTL::Cast(*entry.second).GetMTLFunction(); + } + if (entry.first == ShaderStage::kFragment) { + descriptor.fragmentFunction = + ShaderFunctionMTL::Cast(*entry.second).GetMTLFunction(); + } + } + + if (const auto& vertex_descriptor = desc.GetVertexDescriptor()) { + descriptor.vertexDescriptor = vertex_descriptor->GetMTLVertexDescriptor(); + } + + for (const auto& item : desc.GetColorAttachmentDescriptors()) { + descriptor.colorAttachments[item.first] = + ToMTLRenderPipelineColorAttachmentDescriptor(item.second); + } + + descriptor.depthAttachmentPixelFormat = + ToMTLPixelFormat(desc.GetDepthPixelFormat()); + descriptor.stencilAttachmentPixelFormat = + ToMTLPixelFormat(desc.GetStencilPixelFormat()); + + return descriptor; +} + +// TODO(csg): Make PipelineDescriptor a struct and move this to formats_mtl. +static id CreateDepthStencilDescriptor( + const PipelineDescriptor& desc, + id device) { + auto descriptor = ToMTLDepthStencilDescriptor( + desc.GetDepthStencilAttachmentDescriptor(), // + desc.GetFrontStencilAttachmentDescriptor(), // + desc.GetBackStencilAttachmentDescriptor() // + ); + return [device newDepthStencilStateWithDescriptor:descriptor]; +} + +std::future> PipelineLibraryMTL::GetRenderPipeline( + PipelineDescriptor descriptor) { + auto promise = std::make_shared>>(); + auto future = promise->get_future(); + if (auto found = pipelines_.find(descriptor); found != pipelines_.end()) { + promise->set_value(nullptr); + return future; + } + + auto thiz = shared_from_this(); + + auto completion_handler = + ^(id _Nullable render_pipeline_state, + NSError* _Nullable error) { + if (error != nil) { + FML_LOG(ERROR) << "Could not create render pipeline: " + << error.localizedDescription.UTF8String; + promise->set_value(nullptr); + } else { + auto new_pipeline = std::shared_ptr(new PipelineMTL( + render_pipeline_state, + CreateDepthStencilDescriptor(descriptor, device_))); + promise->set_value(new_pipeline); + this->SavePipeline(descriptor, new_pipeline); + } + }; + [device_ newRenderPipelineStateWithDescriptor:GetMTLRenderPipelineDescriptor( + descriptor) + completionHandler:completion_handler]; + return future; +} + +void PipelineLibraryMTL::SavePipeline( + PipelineDescriptor descriptor, + std::shared_ptr pipeline) { + pipelines_[descriptor] = std::move(pipeline); +} + +} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/metal/pipeline_mtl.h b/engine/src/flutter/impeller/renderer/backend/metal/pipeline_mtl.h index 7ef22a2b0e7..c115880b0ac 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/pipeline_mtl.h +++ b/engine/src/flutter/impeller/renderer/backend/metal/pipeline_mtl.h @@ -4,18 +4,38 @@ #pragma once +#include + #include "flutter/fml/macros.h" +#include "impeller/renderer/backend/metal/backend_cast.h" #include "impeller/renderer/pipeline.h" namespace impeller { -class PipelineMTL final : public Pipeline { +class PipelineMTL final : public Pipeline, + public BackendCast { public: - PipelineMTL(); - + // |PipelineMTL| ~PipelineMTL() override; + id GetMTLRenderPipelineState() const; + + id GetMTLDepthStencilState() const; + private: + friend class PipelineLibraryMTL; + + Type type_ = Type::kUnknown; + id pipeline_state_; + id depth_stencil_state_; + bool is_valid_ = false; + + PipelineMTL(id state, + id depth_stencil_state); + + // |PipelineMTL| + bool IsValid() const override; + FML_DISALLOW_COPY_AND_ASSIGN(PipelineMTL); }; diff --git a/engine/src/flutter/impeller/renderer/backend/metal/pipeline_mtl.mm b/engine/src/flutter/impeller/renderer/backend/metal/pipeline_mtl.mm index e69de29bb2d..9ff5627697f 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/pipeline_mtl.mm +++ b/engine/src/flutter/impeller/renderer/backend/metal/pipeline_mtl.mm @@ -0,0 +1,33 @@ +// 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/renderer/backend/metal/pipeline_mtl.h" + +namespace impeller { + +PipelineMTL::PipelineMTL(id state, + id depth_stencil_state) + : pipeline_state_(state), depth_stencil_state_(depth_stencil_state) { + if (!pipeline_state_) { + return; + } + type_ = Type::kRender; + is_valid_ = true; +} + +PipelineMTL::~PipelineMTL() = default; + +bool PipelineMTL::IsValid() const { + return is_valid_; +} + +id PipelineMTL::GetMTLRenderPipelineState() const { + return pipeline_state_; +} + +id PipelineMTL::GetMTLDepthStencilState() const { + return depth_stencil_state_; +} + +} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/metal/render_pass_mtl.h b/engine/src/flutter/impeller/renderer/backend/metal/render_pass_mtl.h index b11658c19da..0726dca9620 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/render_pass_mtl.h +++ b/engine/src/flutter/impeller/renderer/backend/metal/render_pass_mtl.h @@ -4,18 +4,49 @@ #pragma once +#include + #include "flutter/fml/macros.h" #include "impeller/renderer/render_pass.h" +#include "impeller/renderer/render_pass_descriptor.h" namespace impeller { class RenderPassMTL final : public RenderPass { public: - RenderPassMTL(); - + // |RenderPass| ~RenderPassMTL() override; private: + friend class CommandBufferMTL; + + id buffer_ = nil; + MTLRenderPassDescriptor* desc_ = nil; + std::vector commands_; + std::shared_ptr transients_buffer_; + std::string label_; + bool is_valid_ = false; + + RenderPassMTL(id buffer, const RenderPassDescriptor& desc); + + // |RenderPass| + bool IsValid() const override; + + // |RenderPass| + void SetLabel(std::string label) override; + + // |RenderPass| + HostBuffer& GetTransientsBuffer() override; + + // |RenderPass| + bool RecordCommand(Command command) override; + + // |RenderPass| + bool Commit(Allocator& transients_allocator) const override; + + bool EncodeCommands(Allocator& transients_allocator, + id pass) const; + FML_DISALLOW_COPY_AND_ASSIGN(RenderPassMTL); }; diff --git a/engine/src/flutter/impeller/renderer/backend/metal/render_pass_mtl.mm b/engine/src/flutter/impeller/renderer/backend/metal/render_pass_mtl.mm index e69de29bb2d..29d02f81d3d 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/render_pass_mtl.mm +++ b/engine/src/flutter/impeller/renderer/backend/metal/render_pass_mtl.mm @@ -0,0 +1,411 @@ +// 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/renderer/backend/metal/render_pass_mtl.h" + +#include "flutter/fml/closure.h" +#include "flutter/fml/logging.h" +#include "impeller/base/base.h" +#include "impeller/renderer/backend/metal/device_buffer_mtl.h" +#include "impeller/renderer/backend/metal/formats_mtl.h" +#include "impeller/renderer/backend/metal/pipeline_mtl.h" +#include "impeller/renderer/backend/metal/sampler_mtl.h" +#include "impeller/renderer/backend/metal/texture_mtl.h" +#include "impeller/renderer/host_buffer.h" +#include "impeller/renderer/shader_types.h" + +namespace impeller { + +static bool ConfigureAttachment(const RenderPassAttachment& desc, + MTLRenderPassAttachmentDescriptor* attachment) { + if (!desc.texture) { + return false; + } + + attachment.texture = TextureMTL::Cast(*desc.texture).GetMTLTexture(); + attachment.loadAction = ToMTLLoadAction(desc.load_action); + attachment.storeAction = ToMTLStoreAction(desc.store_action); + return true; +} + +static bool ConfigureColorAttachment( + const RenderPassColorAttachment& desc, + MTLRenderPassColorAttachmentDescriptor* attachment) { + if (!ConfigureAttachment(desc, attachment)) { + return false; + } + attachment.clearColor = ToMTLClearColor(desc.clear_color); + return true; +} + +static bool ConfigureDepthAttachment( + const RenderPassDepthAttachment& desc, + MTLRenderPassDepthAttachmentDescriptor* attachment) { + if (!ConfigureAttachment(desc, attachment)) { + return false; + } + attachment.clearDepth = desc.clear_depth; + return true; +} + +static bool ConfigureStencilAttachment( + const RenderPassStencilAttachment& desc, + MTLRenderPassStencilAttachmentDescriptor* attachment) { + if (!ConfigureAttachment(desc, attachment)) { + return false; + } + attachment.clearStencil = desc.clear_stencil; + return true; +} + +MTLRenderPassDescriptor* RenderPassDescriptor::ToMTLRenderPassDescriptor() + const { + auto result = [MTLRenderPassDescriptor renderPassDescriptor]; + + for (const auto& color : colors_) { + if (!ConfigureColorAttachment(color.second, + result.colorAttachments[color.first])) { + FML_LOG(ERROR) << "Could not configure color attachment at index " + << color.first; + return nil; + } + } + + if (depth_.has_value() && + !ConfigureDepthAttachment(depth_.value(), result.depthAttachment)) { + return nil; + } + + if (stencil_.has_value() && + !ConfigureStencilAttachment(stencil_.value(), result.stencilAttachment)) { + return nil; + } + + return result; +} + +RenderPassMTL::RenderPassMTL(id buffer, + const RenderPassDescriptor& desc) + : buffer_(buffer), + desc_(desc.ToMTLRenderPassDescriptor()), + transients_buffer_(HostBuffer::Create()) { + if (!buffer_ || !desc_) { + return; + } + is_valid_ = true; +} + +RenderPassMTL::~RenderPassMTL() = default; + +HostBuffer& RenderPassMTL::GetTransientsBuffer() { + return *transients_buffer_; +} + +bool RenderPassMTL::IsValid() const { + return is_valid_; +} + +void RenderPassMTL::SetLabel(std::string label) { + label_ = std::move(label); + transients_buffer_->SetLabel(SPrintF("%s Transients", label_.c_str())); +} + +bool RenderPassMTL::Commit(Allocator& transients_allocator) const { + if (!IsValid()) { + return false; + } + auto pass = [buffer_ renderCommandEncoderWithDescriptor:desc_]; + + if (!pass) { + return false; + } + + if (!label_.empty()) { + [pass setLabel:@(label_.c_str())]; + } + + // 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(transients_allocator, pass); +} + +//----------------------------------------------------------------------------- +/// @brief Ensures that bindings on the pass are not redundantly set or +/// updated. Avoids making the driver do additional checks and makes +/// the frame insights during profiling and instrumentation not +/// complain about the same. +/// +/// There should be no change to rendering if this caching was +/// absent. +/// +struct PassBindingsCache { + PassBindingsCache(id pass) : pass_(pass) {} + + PassBindingsCache(const PassBindingsCache&) = delete; + + PassBindingsCache(PassBindingsCache&&) = delete; + + void SetRenderPipelineState(id pipeline) { + if (pipeline == pipeline_) { + return; + } + pipeline_ = pipeline; + [pass_ setRenderPipelineState:pipeline_]; + } + + void SetDepthStencilState(id depth_stencil) { + if (depth_stencil_ == depth_stencil) { + return; + } + depth_stencil_ = depth_stencil; + [pass_ setDepthStencilState:depth_stencil_]; + } + + bool SetBuffer(ShaderStage stage, + uint64_t index, + uint64_t offset, + id buffer) { + auto& buffers_map = buffers_[stage]; + auto found = buffers_map.find(index); + if (found != buffers_map.end() && found->second.buffer == buffer) { + // The right buffer is bound. Check if its offset needs to be updated. + if (found->second.offset == offset) { + // Buffer and its offset is identical. Nothing to do. + return true; + } + + // Only the offset needs to be updated. + found->second.offset = offset; + + switch (stage) { + case ShaderStage::kVertex: + [pass_ setVertexBufferOffset:offset atIndex:index]; + return true; + case ShaderStage::kFragment: + [pass_ setFragmentBufferOffset:offset atIndex:index]; + return true; + default: + FML_DCHECK(false) + << "Cannot update buffer offset of an unknown stage."; + return false; + } + return true; + } + buffers_map[index] = {buffer, offset}; + switch (stage) { + case ShaderStage::kVertex: + [pass_ setVertexBuffer:buffer offset:offset atIndex:index]; + return true; + case ShaderStage::kFragment: + [pass_ setFragmentBuffer:buffer offset:offset atIndex:index]; + return true; + default: + FML_DCHECK(false) << "Cannot bind buffer to unknown shader stage."; + return false; + } + return false; + } + + bool SetTexture(ShaderStage stage, uint64_t index, id texture) { + auto& texture_map = textures_[stage]; + auto found = texture_map.find(index); + if (found != texture_map.end() && found->second == texture) { + // Already bound. + return true; + } + texture_map[index] = texture; + switch (stage) { + case ShaderStage::kVertex: + [pass_ setVertexTexture:texture atIndex:index]; + return true; + case ShaderStage::kFragment: + [pass_ setFragmentTexture:texture atIndex:index]; + return true; + default: + FML_DCHECK(false) << "Cannot bind buffer to unknown shader stage."; + return false; + } + return false; + } + + bool SetSampler(ShaderStage stage, + uint64_t index, + id sampler) { + auto& sampler_map = samplers_[stage]; + auto found = sampler_map.find(index); + if (found != sampler_map.end() && found->second == sampler) { + // Already bound. + return true; + } + sampler_map[index] = sampler; + switch (stage) { + case ShaderStage::kVertex: + [pass_ setVertexSamplerState:sampler atIndex:index]; + return true; + case ShaderStage::kFragment: + [pass_ setFragmentSamplerState:sampler atIndex:index]; + return true; + default: + FML_DCHECK(false) << "Cannot bind buffer to unknown shader stage."; + return false; + } + return false; + } + + private: + struct BufferOffsetPair { + id buffer = nullptr; + size_t offset = 0u; + }; + using BufferMap = std::map; + using TextureMap = std::map>; + using SamplerMap = std::map>; + + const id pass_; + id pipeline_ = nullptr; + id depth_stencil_ = nullptr; + std::map buffers_; + std::map textures_; + std::map samplers_; +}; + +static bool Bind(PassBindingsCache& pass, + Allocator& allocator, + ShaderStage stage, + size_t bind_index, + const BufferView& view) { + if (!view.buffer) { + return false; + } + + auto device_buffer = view.buffer->GetDeviceBuffer(allocator); + if (!device_buffer) { + return false; + } + + auto buffer = DeviceBufferMTL::Cast(*device_buffer).GetMTLBuffer(); + // The Metal call is a void return and we don't want to make it on nil. + if (!buffer) { + return false; + } + + return pass.SetBuffer(stage, bind_index, view.range.offset, buffer); +} + +static bool Bind(PassBindingsCache& pass, + ShaderStage stage, + size_t bind_index, + const Texture& texture) { + if (!texture.IsValid()) { + return false; + } + + return pass.SetTexture(stage, bind_index, + TextureMTL::Cast(texture).GetMTLTexture()); +} + +static bool Bind(PassBindingsCache& pass, + ShaderStage stage, + size_t bind_index, + const Sampler& sampler) { + if (!sampler.IsValid()) { + return false; + } + + return pass.SetSampler(stage, bind_index, + SamplerMTL::Cast(sampler).GetMTLSamplerState()); +} + +bool RenderPassMTL::EncodeCommands(Allocator& allocator, + id pass) const { + PassBindingsCache pass_bindings(pass); + auto bind_stage_resources = [&allocator, &pass_bindings]( + const Bindings& bindings, + ShaderStage stage) -> bool { + for (const auto buffer : bindings.buffers) { + if (!Bind(pass_bindings, allocator, stage, buffer.first, buffer.second)) { + return false; + } + } + for (const auto texture : bindings.textures) { + if (!Bind(pass_bindings, stage, texture.first, *texture.second)) { + return false; + } + } + for (const auto sampler : bindings.samplers) { + if (!Bind(pass_bindings, stage, sampler.first, *sampler.second)) { + return false; + } + } + return true; + }; + + fml::closure pop_debug_marker = [pass]() { [pass popDebugGroup]; }; + for (const auto& command : commands_) { + if (command.index_count == 0u) { + FML_DLOG(ERROR) << "Zero index count in render pass command."; + continue; + } + + fml::ScopedCleanupClosure auto_pop_debug_marker(pop_debug_marker); + if (!command.label.empty()) { + [pass pushDebugGroup:@(command.label.c_str())]; + } else { + auto_pop_debug_marker.Release(); + } + pass_bindings.SetRenderPipelineState( + PipelineMTL::Cast(*command.pipeline).GetMTLRenderPipelineState()); + pass_bindings.SetDepthStencilState( + PipelineMTL::Cast(*command.pipeline).GetMTLDepthStencilState()); + [pass setFrontFacingWinding:command.winding == WindingOrder::kClockwise + ? MTLWindingClockwise + : MTLWindingCounterClockwise]; + [pass setCullMode:MTLCullModeNone]; + if (!bind_stage_resources(command.vertex_bindings, ShaderStage::kVertex)) { + return false; + } + if (!bind_stage_resources(command.fragment_bindings, + ShaderStage::kFragment)) { + return false; + } + auto index_buffer = command.index_buffer.buffer; + if (!index_buffer) { + return false; + } + auto device_buffer = index_buffer->GetDeviceBuffer(allocator); + if (!device_buffer) { + return false; + } + auto mtl_index_buffer = + DeviceBufferMTL::Cast(*device_buffer).GetMTLBuffer(); + if (!mtl_index_buffer) { + return false; + } + FML_DCHECK(command.index_count * sizeof(uint32_t) == + command.index_buffer.range.length); + // Returns void. All error checking must be done by this point. + [pass drawIndexedPrimitives:ToMTLPrimitiveType(command.primitive_type) + indexCount:command.index_count + indexType:MTLIndexTypeUInt32 + indexBuffer:mtl_index_buffer + indexBufferOffset:command.index_buffer.range.offset + instanceCount:1u + baseVertex:0u + baseInstance:0u]; + } + return true; +} + +bool RenderPassMTL::RecordCommand(Command command) { + if (!command) { + return false; + } + + commands_.emplace_back(std::move(command)); + return true; +} + +} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/metal/renderer_mtl.mm b/engine/src/flutter/impeller/renderer/backend/metal/renderer_mtl.mm deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/engine/src/flutter/impeller/renderer/backend/metal/sampler_library_mtl.h b/engine/src/flutter/impeller/renderer/backend/metal/sampler_library_mtl.h new file mode 100644 index 00000000000..71b8acb5631 --- /dev/null +++ b/engine/src/flutter/impeller/renderer/backend/metal/sampler_library_mtl.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 +#include + +#include "flutter/fml/macros.h" +#include "impeller/renderer/backend/metal/backend_cast.h" +#include "impeller/renderer/comparable.h" +#include "impeller/renderer/sampler_descriptor.h" +#include "impeller/renderer/sampler_library.h" + +namespace impeller { + +class SamplerLibraryMTL final + : public SamplerLibrary, + public BackendCast { + public: + // |SamplerLibrary| + ~SamplerLibraryMTL() override; + + private: + friend class ContextMTL; + + using CachedSamplers = std::unordered_map, + ComparableHash, + ComparableEqual>; + id device_ = nullptr; + CachedSamplers samplers_; + + SamplerLibraryMTL(id device); + + // |SamplerLibrary| + std::shared_ptr GetSampler( + SamplerDescriptor descriptor) override; + + FML_DISALLOW_COPY_AND_ASSIGN(SamplerLibraryMTL); +}; + +} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/sampler_descriptor.mm b/engine/src/flutter/impeller/renderer/backend/metal/sampler_library_mtl.mm similarity index 69% rename from engine/src/flutter/impeller/renderer/sampler_descriptor.mm rename to engine/src/flutter/impeller/renderer/backend/metal/sampler_library_mtl.mm index 72d7509c2cc..313e6709710 100644 --- a/engine/src/flutter/impeller/renderer/sampler_descriptor.mm +++ b/engine/src/flutter/impeller/renderer/backend/metal/sampler_library_mtl.mm @@ -2,18 +2,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "impeller/renderer/sampler_descriptor.h" +#include "impeller/renderer/backend/metal/sampler_library_mtl.h" -#include "impeller/renderer/formats_metal.h" -#include "impeller/renderer/sampler.h" +#include "impeller/renderer/backend/metal/formats_mtl.h" +#include "impeller/renderer/backend/metal/sampler_mtl.h" namespace impeller { -SamplerLibrary::SamplerLibrary(id device) : device_(device) {} +SamplerLibraryMTL::SamplerLibraryMTL(id device) : device_(device) {} -SamplerLibrary::~SamplerLibrary() = default; +SamplerLibraryMTL::~SamplerLibraryMTL() = default; -std::shared_ptr SamplerLibrary::GetSampler( +std::shared_ptr SamplerLibraryMTL::GetSampler( SamplerDescriptor descriptor) { auto found = samplers_.find(descriptor); if (found != samplers_.end()) { @@ -32,7 +32,7 @@ std::shared_ptr SamplerLibrary::GetSampler( if (!mtl_sampler) { return nullptr; } - auto sampler = std::shared_ptr(new Sampler(mtl_sampler)); + auto sampler = std::shared_ptr(new SamplerMTL(mtl_sampler)); if (!sampler->IsValid()) { return nullptr; } diff --git a/engine/src/flutter/impeller/renderer/backend/metal/sampler_mtl.h b/engine/src/flutter/impeller/renderer/backend/metal/sampler_mtl.h index 9a80eb8d8ae..de80442942a 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/sampler_mtl.h +++ b/engine/src/flutter/impeller/renderer/backend/metal/sampler_mtl.h @@ -4,18 +4,36 @@ #pragma once +#include + #include "flutter/fml/macros.h" +#include "impeller/renderer/backend/metal/backend_cast.h" #include "impeller/renderer/sampler.h" namespace impeller { -class SamplerMTL final : public Sampler { +class SamplerLibraryMTL; + +class SamplerMTL final : public Sampler, + public BackendCast { public: SamplerMTL(); + // |Sampler| ~SamplerMTL() override; + id GetMTLSamplerState() const; + private: + friend SamplerLibraryMTL; + + id state_ = nullptr; + + SamplerMTL(id state); + + // |Sampler| + bool IsValid() const override; + FML_DISALLOW_COPY_AND_ASSIGN(SamplerMTL); }; diff --git a/engine/src/flutter/impeller/renderer/backend/metal/sampler_mtl.mm b/engine/src/flutter/impeller/renderer/backend/metal/sampler_mtl.mm index e69de29bb2d..a66c5473bd3 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/sampler_mtl.mm +++ b/engine/src/flutter/impeller/renderer/backend/metal/sampler_mtl.mm @@ -0,0 +1,21 @@ +// 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/renderer/backend/metal/sampler_mtl.h" + +namespace impeller { + +SamplerMTL::SamplerMTL(id state) : state_(state) {} + +SamplerMTL::~SamplerMTL() = default; + +bool SamplerMTL::IsValid() const { + return state_; +} + +id SamplerMTL::GetMTLSamplerState() const { + return state_; +} + +} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/metal/shader_function_mtl.h b/engine/src/flutter/impeller/renderer/backend/metal/shader_function_mtl.h index f48b64a9f3c..6dc35b248e8 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/shader_function_mtl.h +++ b/engine/src/flutter/impeller/renderer/backend/metal/shader_function_mtl.h @@ -4,18 +4,33 @@ #pragma once +#include + #include "flutter/fml/macros.h" +#include "impeller/renderer/backend/metal/backend_cast.h" #include "impeller/renderer/shader_function.h" namespace impeller { -class ShaderFunctionMTL final : public ShaderFunction { +class ShaderFunctionMTL final + : public ShaderFunction, + public BackendCast { public: - ShaderFunctionMTL(); - + // |ShaderFunction| ~ShaderFunctionMTL() override; + id GetMTLFunction() const; + private: + friend class ShaderLibraryMTL; + + id function_ = nullptr; + + ShaderFunctionMTL(UniqueID parent_library_id, + id function, + std::string name, + ShaderStage stage); + FML_DISALLOW_COPY_AND_ASSIGN(ShaderFunctionMTL); }; diff --git a/engine/src/flutter/impeller/renderer/backend/metal/shader_function_mtl.mm b/engine/src/flutter/impeller/renderer/backend/metal/shader_function_mtl.mm index e69de29bb2d..55c7e06b19c 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/shader_function_mtl.mm +++ b/engine/src/flutter/impeller/renderer/backend/metal/shader_function_mtl.mm @@ -0,0 +1,22 @@ +// 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/renderer/backend/metal/shader_function_mtl.h" + +namespace impeller { + +ShaderFunctionMTL::ShaderFunctionMTL(UniqueID parent_library_id, + id function, + std::string name, + ShaderStage stage) + : ShaderFunction(std::move(parent_library_id), std::move(name), stage), + function_(function) {} + +ShaderFunctionMTL::~ShaderFunctionMTL() = default; + +id ShaderFunctionMTL::GetMTLFunction() const { + return function_; +} + +} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/metal/shader_library_mtl.h b/engine/src/flutter/impeller/renderer/backend/metal/shader_library_mtl.h index 7ea6beeebe8..fe10dfd657b 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/shader_library_mtl.h +++ b/engine/src/flutter/impeller/renderer/backend/metal/shader_library_mtl.h @@ -4,7 +4,14 @@ #pragma once +#include + +#include +#include +#include + #include "flutter/fml/macros.h" +#include "impeller/renderer/comparable.h" #include "impeller/renderer/shader_library.h" namespace impeller { @@ -13,9 +20,49 @@ class ShaderLibraryMTL final : public ShaderLibrary { public: ShaderLibraryMTL(); + // |ShaderLibrary| ~ShaderLibraryMTL() override; private: + friend class ContextMTL; + + struct ShaderKey { + std::string name; + ShaderStage stage = ShaderStage::kUnknown; + + ShaderKey(const std::string_view& p_name, ShaderStage p_stage) + : name({p_name.data(), p_name.size()}), stage(p_stage) {} + + struct Hash { + size_t operator()(const ShaderKey& key) const { + return fml::HashCombine(key.name, key.stage); + } + }; + + struct Equal { + constexpr bool operator()(const ShaderKey& k1, + const ShaderKey& k2) const { + return k1.stage == k2.stage && k1.name == k2.name; + } + }; + }; + + using Functions = std::unordered_map, + ShaderKey::Hash, + ShaderKey::Equal>; + + UniqueID library_id_; + id library_ = nullptr; + Functions functions_; + + ShaderLibraryMTL(id library); + + // |ShaderLibrary| + std::shared_ptr GetFunction( + const std::string_view& name, + ShaderStage stage) override; + FML_DISALLOW_COPY_AND_ASSIGN(ShaderLibraryMTL); }; diff --git a/engine/src/flutter/impeller/renderer/backend/metal/shader_library_mtl.mm b/engine/src/flutter/impeller/renderer/backend/metal/shader_library_mtl.mm index e69de29bb2d..5167e4cb7cd 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/shader_library_mtl.mm +++ b/engine/src/flutter/impeller/renderer/backend/metal/shader_library_mtl.mm @@ -0,0 +1,40 @@ +// 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/renderer/backend/metal/shader_library_mtl.h" + +#include "impeller/renderer/backend/metal/shader_function_mtl.h" + +namespace impeller { + +ShaderLibraryMTL::ShaderLibraryMTL(id library) + : library_(library) {} + +ShaderLibraryMTL::~ShaderLibraryMTL() = default; + +std::shared_ptr ShaderLibraryMTL::GetFunction( + const std::string_view& name, + ShaderStage stage) { + if (!library_) { + return nullptr; + } + + ShaderKey key(name, stage); + + if (auto found = functions_.find(key); found != functions_.end()) { + return found->second; + } + + auto function = [library_ newFunctionWithName:@(name.data())]; + if (!function) { + return nullptr; + } + + auto func = std::shared_ptr(new ShaderFunctionMTL( + library_id_, function, {name.data(), name.size()}, stage)); + functions_[key] = func; + return func; +} + +} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/metal/texture_mtl.h b/engine/src/flutter/impeller/renderer/backend/metal/texture_mtl.h index 33d516d8ae3..4ffeb9761c1 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/texture_mtl.h +++ b/engine/src/flutter/impeller/renderer/backend/metal/texture_mtl.h @@ -4,18 +4,37 @@ #pragma once +#include + #include "flutter/fml/macros.h" +#include "impeller/renderer/backend/metal/backend_cast.h" #include "impeller/renderer/texture.h" namespace impeller { -class TextureMTL final : public Texture { +class TextureMTL final : public Texture, + public BackendCast { public: - TextureMTL(); - + // |Texture| ~TextureMTL() override; + void SetLabel(const std::string_view& label) override; + + [[nodiscard]] bool SetContents(const uint8_t* contents, + size_t length) override; + + bool IsValid() const override; + + ISize GetSize() const override; + + id GetMTLTexture() const; + private: + id texture_ = nullptr; + bool is_valid_ = false; + + TextureMTL(TextureDescriptor desc, id texture); + FML_DISALLOW_COPY_AND_ASSIGN(TextureMTL); }; diff --git a/engine/src/flutter/impeller/renderer/backend/metal/texture_mtl.mm b/engine/src/flutter/impeller/renderer/backend/metal/texture_mtl.mm index e69de29bb2d..8d1f42575fa 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/texture_mtl.mm +++ b/engine/src/flutter/impeller/renderer/backend/metal/texture_mtl.mm @@ -0,0 +1,72 @@ +// 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/renderer/backend/metal/texture_mtl.h" + +namespace impeller { + +TextureMTL::TextureMTL(TextureDescriptor p_desc, id texture) + : Texture(std::move(p_desc)), texture_(texture) { + const auto& desc = GetTextureDescriptor(); + + if (!desc.IsValid() || !texture_) { + return; + } + + if (desc.size != GetSize()) { + FML_DLOG(ERROR) + << "The texture and its descriptor disagree about its size."; + return; + } + + is_valid_ = true; +} + +TextureMTL::~TextureMTL() = default; + +void TextureMTL::SetLabel(const std::string_view& label) { + [texture_ setLabel:@(label.data())]; +} + +bool TextureMTL::SetContents(const uint8_t* contents, size_t length) { + if (!IsValid() || !contents) { + return false; + } + + const auto& desc = GetTextureDescriptor(); + + // Out of bounds access. + if (length != desc.GetSizeOfBaseMipLevel()) { + return false; + } + + // TODO(csg): Perhaps the storage mode should be added to the texture + // descriptor so that invalid region replacements on potentially non-host + // visible textures are disallowed. The annoying bit about the API below is + // that there seems to be no error handling guidance. + const auto region = + MTLRegionMake2D(0u, 0u, desc.size.width, desc.size.height); + [texture_ replaceRegion:region // + mipmapLevel:0u // + withBytes:contents // + bytesPerRow:desc.GetBytesPerRow() // + ]; + + return true; +} + +ISize TextureMTL::GetSize() const { + return {static_cast(texture_.width), + static_cast(texture_.height)}; +} + +id TextureMTL::GetMTLTexture() const { + return texture_; +} + +bool TextureMTL::IsValid() const { + return is_valid_; +} + +} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/buffer.mm b/engine/src/flutter/impeller/renderer/buffer.cc similarity index 100% rename from engine/src/flutter/impeller/renderer/buffer.mm rename to engine/src/flutter/impeller/renderer/buffer.cc diff --git a/engine/src/flutter/impeller/renderer/buffer_view.mm b/engine/src/flutter/impeller/renderer/buffer_view.cc similarity index 100% rename from engine/src/flutter/impeller/renderer/buffer_view.mm rename to engine/src/flutter/impeller/renderer/buffer_view.cc diff --git a/engine/src/flutter/impeller/renderer/command.mm b/engine/src/flutter/impeller/renderer/command.cc similarity index 99% rename from engine/src/flutter/impeller/renderer/command.mm rename to engine/src/flutter/impeller/renderer/command.cc index e4a457b0438..bc18314d7c9 100644 --- a/engine/src/flutter/impeller/renderer/command.mm +++ b/engine/src/flutter/impeller/renderer/command.cc @@ -4,8 +4,6 @@ #include "impeller/renderer/command.h" -#include - #include "impeller/renderer/vertex_descriptor.h" namespace impeller { diff --git a/engine/src/flutter/impeller/renderer/command_buffer.cc b/engine/src/flutter/impeller/renderer/command_buffer.cc new file mode 100644 index 00000000000..9398bc6822b --- /dev/null +++ b/engine/src/flutter/impeller/renderer/command_buffer.cc @@ -0,0 +1,13 @@ +// 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/renderer/command_buffer.h" + +namespace impeller { + +CommandBuffer::CommandBuffer() = default; + +CommandBuffer::~CommandBuffer() = default; + +} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/command_buffer.h b/engine/src/flutter/impeller/renderer/command_buffer.h index 7c7c58eb27e..2d7f6be2601 100644 --- a/engine/src/flutter/impeller/renderer/command_buffer.h +++ b/engine/src/flutter/impeller/renderer/command_buffer.h @@ -4,24 +4,19 @@ #pragma once -#include - #include #include #include "flutter/fml/macros.h" -#include "impeller/renderer/render_pass.h" namespace impeller { class Context; +class RenderPass; +class RenderPassDescriptor; class CommandBuffer { public: - ~CommandBuffer(); - - bool IsValid() const; - enum class CommitResult { kPending, kError, @@ -29,19 +24,20 @@ class CommandBuffer { }; using CommitCallback = std::function; - void Commit(CommitCallback callback); - std::shared_ptr CreateRenderPass( - const RenderPassDescriptor& desc) const; + virtual ~CommandBuffer(); + + virtual bool IsValid() const = 0; + + virtual void Commit(CommitCallback callback) = 0; + + virtual std::shared_ptr CreateRenderPass( + const RenderPassDescriptor& desc) const = 0; + + protected: + CommandBuffer(); private: - friend class Context; - - id buffer_ = nullptr; - bool is_valid_ = false; - - CommandBuffer(id queue); - FML_DISALLOW_COPY_AND_ASSIGN(CommandBuffer); }; diff --git a/engine/src/flutter/impeller/renderer/command_buffer.mm b/engine/src/flutter/impeller/renderer/command_buffer.mm deleted file mode 100644 index 43d3f8afe81..00000000000 --- a/engine/src/flutter/impeller/renderer/command_buffer.mm +++ /dev/null @@ -1,67 +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/renderer/command_buffer.h" - -namespace impeller { - -CommandBuffer::CommandBuffer(id queue) - : buffer_([queue commandBuffer]) { - if (!buffer_) { - return; - } - is_valid_ = true; -} - -CommandBuffer::~CommandBuffer() = default; - -bool CommandBuffer::IsValid() const { - return is_valid_; -} - -static CommandBuffer::CommitResult ToCommitResult( - MTLCommandBufferStatus status) { - switch (status) { - case MTLCommandBufferStatusCompleted: - return CommandBuffer::CommitResult::kCompleted; - case MTLCommandBufferStatusEnqueued: - return CommandBuffer::CommitResult::kPending; - default: - break; - } - return CommandBuffer::CommitResult::kError; -} - -void CommandBuffer::Commit(CommitCallback callback) { - if (!callback) { - callback = [](auto) {}; - } - - if (!buffer_) { - callback(CommitResult::kError); - return; - } - - [buffer_ addCompletedHandler:^(id buffer) { - callback(ToCommitResult(buffer.status)); - }]; - [buffer_ commit]; - buffer_ = nil; -} - -std::shared_ptr CommandBuffer::CreateRenderPass( - const RenderPassDescriptor& desc) const { - if (!buffer_) { - return nullptr; - } - - auto pass = std::shared_ptr(new RenderPass(buffer_, desc)); - if (!pass->IsValid()) { - return nullptr; - } - - return pass; -} - -} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/context.cc b/engine/src/flutter/impeller/renderer/context.cc new file mode 100644 index 00000000000..542d04ee14d --- /dev/null +++ b/engine/src/flutter/impeller/renderer/context.cc @@ -0,0 +1,13 @@ +// 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/renderer/context.h" + +namespace impeller { + +Context::~Context() = default; + +Context::Context() = default; + +} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/context.h b/engine/src/flutter/impeller/renderer/context.h index 0da2ce6da01..bb19ac45810 100644 --- a/engine/src/flutter/impeller/renderer/context.h +++ b/engine/src/flutter/impeller/renderer/context.h @@ -4,8 +4,6 @@ #pragma once -#include - #include #include @@ -21,45 +19,34 @@ class Allocator; class Context { public: - Context(std::string shaders_directory, std::string main_library_file_name); + virtual ~Context(); - ~Context(); - - bool IsValid() const; + virtual bool IsValid() const = 0; //---------------------------------------------------------------------------- /// @return An allocator suitable for allocations that persist between /// frames. /// - std::shared_ptr GetPermanentsAllocator() const; + virtual std::shared_ptr GetPermanentsAllocator() const = 0; //---------------------------------------------------------------------------- /// @return An allocator suitable for allocations that used only for one /// frame or render pass. /// - std::shared_ptr GetTransientsAllocator() const; + virtual std::shared_ptr GetTransientsAllocator() const = 0; - std::shared_ptr GetShaderLibrary() const; + virtual std::shared_ptr GetShaderLibrary() const = 0; - std::shared_ptr GetSamplerLibrary() const; + virtual std::shared_ptr GetSamplerLibrary() const = 0; - std::shared_ptr GetPipelineLibrary() const; + virtual std::shared_ptr GetPipelineLibrary() const = 0; - std::shared_ptr CreateRenderCommandBuffer() const; + virtual std::shared_ptr CreateRenderCommandBuffer() const = 0; - id GetMTLDevice() const; + protected: + Context(); private: - id device_ = nullptr; - id render_queue_ = nullptr; - id transfer_queue_ = nullptr; - std::shared_ptr shader_library_; - std::shared_ptr pipeline_library_; - std::shared_ptr sampler_library_; - std::shared_ptr permanents_allocator_; - std::shared_ptr transients_allocator_; - bool is_valid_ = false; - FML_DISALLOW_COPY_AND_ASSIGN(Context); }; diff --git a/engine/src/flutter/impeller/renderer/context.mm b/engine/src/flutter/impeller/renderer/context.mm deleted file mode 100644 index b1203398b11..00000000000 --- a/engine/src/flutter/impeller/renderer/context.mm +++ /dev/null @@ -1,138 +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 "context.h" - -#include "flutter/fml/file.h" -#include "flutter/fml/logging.h" -#include "flutter/fml/paths.h" -#include "impeller/renderer/allocator.h" -#include "impeller/renderer/command_buffer.h" -#include "impeller/renderer/pipeline_library.h" -#include "impeller/renderer/sampler_descriptor.h" -#include "impeller/renderer/shader_library.h" - -namespace impeller { - -Context::Context(std::string shaders_directory, - std::string main_library_file_name) - : device_(::MTLCreateSystemDefaultDevice()) { - // Setup device. - if (!device_) { - return; - } - - // Setup command queues. - render_queue_ = device_.newCommandQueue; - transfer_queue_ = device_.newCommandQueue; - - if (!render_queue_ || !transfer_queue_) { - return; - } - - render_queue_.label = @"Impeller Render Queue"; - transfer_queue_.label = @"Impeller Transfer Queue"; - - // Setup the shader library. - { - NSError* shader_library_error = nil; - auto shader_library_path = - fml::paths::JoinPaths({shaders_directory, main_library_file_name}); - - auto library_exists = fml::IsFile(shader_library_path); - - if (!library_exists) { - FML_LOG(ERROR) << "Shader library does not exist at path '" - << shader_library_path - << "'. No piplines can be created in this context."; - } - auto library = - library_exists - ? [device_ newLibraryWithFile:@(shader_library_path.c_str()) - error:&shader_library_error] - : [device_ newDefaultLibrary]; - if (!library && shader_library_error) { - FML_LOG(ERROR) << "Could not create shader library: " - << shader_library_error.localizedDescription.UTF8String; - return; - } - - // std::make_shared disallowed because of private friend ctor. - shader_library_ = - std::shared_ptr(new ShaderLibrary(library)); - } - - // Setup the pipeline library. - { // - pipeline_library_ = - std::shared_ptr(new PipelineLibrary(device_)); - } - - // Setup the sampler library. - { // - sampler_library_ = - std::shared_ptr(new SamplerLibrary(device_)); - } - - { - transients_allocator_ = std::shared_ptr( - new Allocator(device_, "Impeller Transients Allocator")); - if (!transients_allocator_) { - return; - } - - permanents_allocator_ = std::shared_ptr( - new Allocator(device_, "Impeller Permanents Allocator")); - if (!permanents_allocator_) { - return; - } - } - - is_valid_ = true; -} - -Context::~Context() = default; - -bool Context::IsValid() const { - return is_valid_; -} - -std::shared_ptr Context::GetShaderLibrary() const { - return shader_library_; -} - -std::shared_ptr Context::GetPipelineLibrary() const { - return pipeline_library_; -} - -std::shared_ptr Context::GetSamplerLibrary() const { - return sampler_library_; -} - -std::shared_ptr Context::CreateRenderCommandBuffer() const { - if (!IsValid()) { - return nullptr; - } - - auto buffer = - std::shared_ptr(new CommandBuffer(render_queue_)); - if (!buffer->IsValid()) { - return nullptr; - } - return buffer; -} - -std::shared_ptr Context::GetPermanentsAllocator() const { - return permanents_allocator_; -} - -std::shared_ptr Context::GetTransientsAllocator() const { - return transients_allocator_; -} - -id Context::GetMTLDevice() const { - return device_; -} - -} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/device_buffer.cc b/engine/src/flutter/impeller/renderer/device_buffer.cc new file mode 100644 index 00000000000..7fd7e74cfc0 --- /dev/null +++ b/engine/src/flutter/impeller/renderer/device_buffer.cc @@ -0,0 +1,13 @@ +// 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/renderer/device_buffer.h" + +namespace impeller { + +DeviceBuffer::DeviceBuffer() = default; + +DeviceBuffer::~DeviceBuffer() = default; + +} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/device_buffer.h b/engine/src/flutter/impeller/renderer/device_buffer.h index 91e2a385b58..e9d11302006 100644 --- a/engine/src/flutter/impeller/renderer/device_buffer.h +++ b/engine/src/flutter/impeller/renderer/device_buffer.h @@ -4,8 +4,6 @@ #pragma once -#include - #include #include @@ -18,14 +16,14 @@ namespace impeller { -class DeviceBuffer final : public Buffer, - public std::enable_shared_from_this { +class DeviceBuffer : public Buffer, + public std::enable_shared_from_this { public: - ~DeviceBuffer(); + virtual ~DeviceBuffer(); - [[nodiscard]] bool CopyHostBuffer(const uint8_t* source, - Range source_range, - size_t offset = 0u); + [[nodiscard]] virtual bool CopyHostBuffer(const uint8_t* source, + Range source_range, + size_t offset = 0u) = 0; //---------------------------------------------------------------------------- /// @brief Create a texture whose contents are the same as that of this @@ -39,30 +37,19 @@ class DeviceBuffer final : public Buffer, /// @return The texture whose contents are backed by (a part of) this /// buffer. /// - std::shared_ptr MakeTexture(TextureDescriptor desc, - size_t offset = 0u) const; + virtual std::shared_ptr MakeTexture(TextureDescriptor desc, + size_t offset = 0u) const = 0; - id GetMTLBuffer() const; + virtual bool SetLabel(const std::string& label) = 0; - bool SetLabel(const std::string& label); + virtual bool SetLabel(const std::string& label, Range range) = 0; - bool SetLabel(const std::string& label, Range range); + virtual BufferView AsBufferView() const = 0; - BufferView AsBufferView() const; + protected: + DeviceBuffer(); private: - friend class Allocator; - - const id buffer_; - const size_t size_; - const StorageMode mode_; - - DeviceBuffer(id buffer, size_t size, StorageMode mode); - - // |Buffer| - std::shared_ptr GetDeviceBuffer( - Allocator& allocator) const override; - FML_DISALLOW_COPY_AND_ASSIGN(DeviceBuffer); }; diff --git a/engine/src/flutter/impeller/renderer/device_buffer.mm b/engine/src/flutter/impeller/renderer/device_buffer.mm deleted file mode 100644 index 4bc26264c00..00000000000 --- a/engine/src/flutter/impeller/renderer/device_buffer.mm +++ /dev/null @@ -1,103 +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/renderer/device_buffer.h" - -#include "flutter/fml/logging.h" -#include "impeller/renderer/formats_metal.h" - -namespace impeller { - -DeviceBuffer::DeviceBuffer(id buffer, size_t size, StorageMode mode) - : buffer_(buffer), size_(size), mode_(mode) {} - -DeviceBuffer::~DeviceBuffer() = default; - -id DeviceBuffer::GetMTLBuffer() const { - return buffer_; -} - -std::shared_ptr DeviceBuffer::MakeTexture(TextureDescriptor desc, - size_t offset) const { - if (!desc.IsValid() || !buffer_) { - return nullptr; - } - - // Avoid overruns. - if (offset + desc.GetSizeOfBaseMipLevel() > size_) { - FML_DLOG(ERROR) << "Avoiding buffer overrun when creating texture."; - return nullptr; - } - - auto texture = [buffer_ newTextureWithDescriptor:ToMTLTextureDescriptor(desc) - offset:offset - bytesPerRow:desc.GetBytesPerRow()]; - if (!texture) { - return nullptr; - } - - return std::make_shared(desc, texture); -} - -[[nodiscard]] bool DeviceBuffer::CopyHostBuffer(const uint8_t* source, - Range source_range, - size_t offset) { - if (mode_ != StorageMode::kHostVisible) { - // One of the storage modes where a transfer queue must be used. - return false; - } - - if (offset + source_range.length > size_) { - // Out of bounds of this buffer. - return false; - } - - auto dest = static_cast(buffer_.contents); - - if (!dest) { - return false; - } - - if (source) { - ::memmove(dest + offset, source + source_range.offset, source_range.length); - } - - if (Allocator::RequiresExplicitHostSynchronization(mode_)) { - [buffer_ didModifyRange:NSMakeRange(offset, source_range.length)]; - } - - return true; -} - -// |Buffer| -std::shared_ptr DeviceBuffer::GetDeviceBuffer( - Allocator& allocator) const { - return shared_from_this(); -} - -bool DeviceBuffer::SetLabel(const std::string& label) { - if (label.empty()) { - return false; - } - [buffer_ setLabel:@(label.c_str())]; - return true; -} - -bool DeviceBuffer::SetLabel(const std::string& label, Range range) { - if (label.empty()) { - return false; - } - [buffer_ addDebugMarker:@(label.c_str()) - range:NSMakeRange(range.offset, range.length)]; - return true; -} - -BufferView DeviceBuffer::AsBufferView() const { - BufferView view; - view.buffer = shared_from_this(); - view.range = {0u, size_}; - return view; -} - -} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/device_buffer_unittests.mm b/engine/src/flutter/impeller/renderer/device_buffer_unittests.cc similarity index 100% rename from engine/src/flutter/impeller/renderer/device_buffer_unittests.mm rename to engine/src/flutter/impeller/renderer/device_buffer_unittests.cc diff --git a/engine/src/flutter/impeller/renderer/formats_metal.mm b/engine/src/flutter/impeller/renderer/formats_metal.mm deleted file mode 100644 index ba23493979d..00000000000 --- a/engine/src/flutter/impeller/renderer/formats_metal.mm +++ /dev/null @@ -1,102 +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/renderer/formats_metal.h" - -#include - -#include "impeller/renderer/render_pass.h" - -namespace impeller { - -MTLRenderPipelineColorAttachmentDescriptor* -ToMTLRenderPipelineColorAttachmentDescriptor( - PipelineColorAttachment descriptor) { - auto des = [[MTLRenderPipelineColorAttachmentDescriptor alloc] init]; - des.pixelFormat = ToMTLPixelFormat(descriptor.format); - - des.blendingEnabled = descriptor.blending_enabled; - - des.sourceRGBBlendFactor = - ToMTLBlendFactor(descriptor.src_color_blend_factor); - des.rgbBlendOperation = ToMTLBlendOperation(descriptor.color_blend_op); - des.destinationRGBBlendFactor = - ToMTLBlendFactor(descriptor.dst_color_blend_factor); - - des.sourceAlphaBlendFactor = - ToMTLBlendFactor(descriptor.src_alpha_blend_factor); - des.alphaBlendOperation = ToMTLBlendOperation(descriptor.alpha_blend_op); - des.destinationAlphaBlendFactor = - ToMTLBlendFactor(descriptor.dst_alpha_blend_factor); - - des.writeMask = ToMTLColorWriteMask(descriptor.write_mask); - return des; -} - -MTLStencilDescriptor* ToMTLStencilDescriptor( - const PipelineStencilAttachment& descriptor) { - auto des = [[MTLStencilDescriptor alloc] init]; - des.stencilCompareFunction = ToMTLCompareFunction(descriptor.stencil_compare); - des.stencilFailureOperation = - ToMTLStencilOperation(descriptor.stencil_failure); - des.depthFailureOperation = ToMTLStencilOperation(descriptor.depth_failure); - des.depthStencilPassOperation = - ToMTLStencilOperation(descriptor.depth_stencil_pass); - - des.readMask = descriptor.read_mask; - des.writeMask = descriptor.write_mask; - - return des; -} - -MTLDepthStencilDescriptor* ToMTLDepthStencilDescriptor( - std::optional depth, - std::optional front, - std::optional back) { - if (!depth) { - depth = PipelineDepthAttachment{ - // Always pass the depth test. - .depth_compare = CompareFunction::kAlways, - .depth_write_enabled = false, - }; - } - - auto des = [[MTLDepthStencilDescriptor alloc] init]; - - des.depthCompareFunction = ToMTLCompareFunction(depth->depth_compare); - des.depthWriteEnabled = depth->depth_write_enabled; - - if (front.has_value()) { - des.frontFaceStencil = ToMTLStencilDescriptor(front.value()); - } - if (back.has_value()) { - des.backFaceStencil = ToMTLStencilDescriptor(back.value()); - } - - return des; -} - -MTLTextureDescriptor* ToMTLTextureDescriptor(const TextureDescriptor& desc) { - auto mtl_desc = [[MTLTextureDescriptor alloc] init]; - mtl_desc.pixelFormat = ToMTLPixelFormat(desc.format); - mtl_desc.width = desc.size.width; - mtl_desc.height = desc.size.height; - mtl_desc.mipmapLevelCount = desc.mip_count; - mtl_desc.usage = MTLTextureUsageUnknown; - if (desc.usage & static_cast(TextureUsage::kUnknown)) { - mtl_desc.usage |= MTLTextureUsageUnknown; - } - if (desc.usage & static_cast(TextureUsage::kShaderRead)) { - mtl_desc.usage |= MTLTextureUsageShaderRead; - } - if (desc.usage & static_cast(TextureUsage::kShaderWrite)) { - mtl_desc.usage |= MTLTextureUsageShaderWrite; - } - if (desc.usage & static_cast(TextureUsage::kRenderTarget)) { - mtl_desc.usage |= MTLTextureUsageRenderTarget; - } - return mtl_desc; -} - -} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/host_buffer.mm b/engine/src/flutter/impeller/renderer/host_buffer.cc similarity index 100% rename from engine/src/flutter/impeller/renderer/host_buffer.mm rename to engine/src/flutter/impeller/renderer/host_buffer.cc diff --git a/engine/src/flutter/impeller/renderer/host_buffer_unittests.mm b/engine/src/flutter/impeller/renderer/host_buffer_unittests.cc similarity index 100% rename from engine/src/flutter/impeller/renderer/host_buffer_unittests.mm rename to engine/src/flutter/impeller/renderer/host_buffer_unittests.cc diff --git a/engine/src/flutter/impeller/renderer/pipeline.mm b/engine/src/flutter/impeller/renderer/pipeline.cc similarity index 58% rename from engine/src/flutter/impeller/renderer/pipeline.mm rename to engine/src/flutter/impeller/renderer/pipeline.cc index a5fc33aa937..6badd53ab2e 100644 --- a/engine/src/flutter/impeller/renderer/pipeline.mm +++ b/engine/src/flutter/impeller/renderer/pipeline.cc @@ -9,30 +9,10 @@ namespace impeller { -Pipeline::Pipeline(id state, - id depth_stencil_state) - : pipeline_state_(state), depth_stencil_state_(depth_stencil_state) { - if (!pipeline_state_) { - return; - } - type_ = Type::kRender; - is_valid_ = true; -} +Pipeline::Pipeline() = default; Pipeline::~Pipeline() = default; -bool Pipeline::IsValid() const { - return is_valid_; -} - -id Pipeline::GetMTLRenderPipelineState() const { - return pipeline_state_; -} - -id Pipeline::GetMTLDepthStencilState() const { - return depth_stencil_state_; -} - PipelineFuture CreatePipelineFuture(const Context& context, std::optional desc) { if (!context.IsValid()) { diff --git a/engine/src/flutter/impeller/renderer/pipeline.h b/engine/src/flutter/impeller/renderer/pipeline.h index 1c979e17bc8..bfb0f649e38 100644 --- a/engine/src/flutter/impeller/renderer/pipeline.h +++ b/engine/src/flutter/impeller/renderer/pipeline.h @@ -4,8 +4,6 @@ #pragma once -#include - #include #include "flutter/fml/macros.h" @@ -26,25 +24,14 @@ class Pipeline { kRender, }; - ~Pipeline(); + virtual ~Pipeline(); - bool IsValid() const; + virtual bool IsValid() const = 0; - id GetMTLRenderPipelineState() const; - - id GetMTLDepthStencilState() const; + protected: + Pipeline(); private: - friend class PipelineLibrary; - - Type type_ = Type::kUnknown; - id pipeline_state_; - id depth_stencil_state_; - bool is_valid_ = false; - - Pipeline(id state, - id depth_stencil_state); - FML_DISALLOW_COPY_AND_ASSIGN(Pipeline); }; diff --git a/engine/src/flutter/impeller/renderer/pipeline_builder.mm b/engine/src/flutter/impeller/renderer/pipeline_builder.cc similarity index 100% rename from engine/src/flutter/impeller/renderer/pipeline_builder.mm rename to engine/src/flutter/impeller/renderer/pipeline_builder.cc diff --git a/engine/src/flutter/impeller/renderer/pipeline_descriptor.mm b/engine/src/flutter/impeller/renderer/pipeline_descriptor.cc similarity index 73% rename from engine/src/flutter/impeller/renderer/pipeline_descriptor.mm rename to engine/src/flutter/impeller/renderer/pipeline_descriptor.cc index fee3a9faa0c..25484f06bf6 100644 --- a/engine/src/flutter/impeller/renderer/pipeline_descriptor.mm +++ b/engine/src/flutter/impeller/renderer/pipeline_descriptor.cc @@ -5,6 +5,7 @@ #include "impeller/renderer/pipeline_descriptor.h" #include "impeller/renderer/formats_metal.h" +#include "impeller/renderer/shader_function.h" #include "impeller/renderer/shader_library.h" #include "impeller/renderer/vertex_descriptor.h" @@ -55,9 +56,8 @@ bool PipelineDescriptor::IsEqual(const PipelineDescriptor& other) const { other.back_stencil_attachment_descriptor_; } -PipelineDescriptor& PipelineDescriptor::SetLabel( - const std::string_view& label) { - label_ = {label.data(), label.size()}; +PipelineDescriptor& PipelineDescriptor::SetLabel(std::string label) { + label_ = std::move(label); return *this; } @@ -132,45 +132,4 @@ PipelineDescriptor& PipelineDescriptor::SetStencilAttachmentDescriptors( return *this; } -MTLRenderPipelineDescriptor* -PipelineDescriptor::GetMTLRenderPipelineDescriptor() const { - auto descriptor = [[MTLRenderPipelineDescriptor alloc] init]; - descriptor.label = @(label_.c_str()); - descriptor.sampleCount = sample_count_; - - for (const auto& entry : entrypoints_) { - if (entry.first == ShaderStage::kVertex) { - descriptor.vertexFunction = entry.second->GetMTLFunction(); - } - if (entry.first == ShaderStage::kFragment) { - descriptor.fragmentFunction = entry.second->GetMTLFunction(); - } - } - - if (vertex_descriptor_) { - descriptor.vertexDescriptor = vertex_descriptor_->GetMTLVertexDescriptor(); - } - - for (const auto& item : color_attachment_descriptors_) { - descriptor.colorAttachments[item.first] = - ToMTLRenderPipelineColorAttachmentDescriptor(item.second); - } - - descriptor.depthAttachmentPixelFormat = ToMTLPixelFormat(depth_pixel_format_); - descriptor.stencilAttachmentPixelFormat = - ToMTLPixelFormat(stencil_pixel_format_); - - return descriptor; -} - -id PipelineDescriptor::CreateDepthStencilDescriptor( - id device) const { - auto descriptor = - ToMTLDepthStencilDescriptor(depth_attachment_descriptor_, // - front_stencil_attachment_descriptor_, // - back_stencil_attachment_descriptor_ // - ); - return [device newDepthStencilStateWithDescriptor:descriptor]; -} - } // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/pipeline_descriptor.h b/engine/src/flutter/impeller/renderer/pipeline_descriptor.h index 840a074a5fb..678bbe23c90 100644 --- a/engine/src/flutter/impeller/renderer/pipeline_descriptor.h +++ b/engine/src/flutter/impeller/renderer/pipeline_descriptor.h @@ -4,8 +4,6 @@ #pragma once -#include - #include #include #include @@ -30,16 +28,29 @@ class PipelineDescriptor final : public Comparable { ~PipelineDescriptor(); - PipelineDescriptor& SetLabel(const std::string_view& label); + PipelineDescriptor& SetLabel(std::string label); + + const std::string& GetLabel() const { return label_; } PipelineDescriptor& SetSampleCount(size_t samples); + size_t GetSampleCount() const { return sample_count_; } + PipelineDescriptor& AddStageEntrypoint( std::shared_ptr function); + const std::map>& + GetStageEntrypoints() const { + return entrypoints_; + } + PipelineDescriptor& SetVertexDescriptor( std::shared_ptr vertex_descriptor); + const std::shared_ptr& GetVertexDescriptor() const { + return vertex_descriptor_; + } + PipelineDescriptor& SetColorAttachmentDescriptor( size_t index, PipelineColorAttachment desc); @@ -47,9 +58,19 @@ class PipelineDescriptor final : public Comparable { const PipelineColorAttachment* GetColorAttachmentDescriptor( size_t index) const; + const std::map + GetColorAttachmentDescriptors() const { + return color_attachment_descriptors_; + } + PipelineDescriptor& SetDepthStencilAttachmentDescriptor( PipelineDepthAttachment desc); + std::optional GetDepthStencilAttachmentDescriptor() + const { + return depth_attachment_descriptor_; + } + PipelineDescriptor& SetStencilAttachmentDescriptors( PipelineStencilAttachment front_and_back); @@ -57,14 +78,23 @@ class PipelineDescriptor final : public Comparable { PipelineStencilAttachment front, PipelineStencilAttachment back); + std::optional GetFrontStencilAttachmentDescriptor() + const { + return front_stencil_attachment_descriptor_; + } + + std::optional GetBackStencilAttachmentDescriptor() + const { + return back_stencil_attachment_descriptor_; + } + PipelineDescriptor& SetDepthPixelFormat(PixelFormat format); + PixelFormat GetDepthPixelFormat() const { return depth_pixel_format_; } + PipelineDescriptor& SetStencilPixelFormat(PixelFormat format); - MTLRenderPipelineDescriptor* GetMTLRenderPipelineDescriptor() const; - - id CreateDepthStencilDescriptor( - id device) const; + PixelFormat GetStencilPixelFormat() const { return stencil_pixel_format_; } // Comparable std::size_t GetHash() const override; @@ -76,7 +106,8 @@ class PipelineDescriptor final : public Comparable { std::string label_; size_t sample_count_ = 1; std::map> entrypoints_; - std::map color_attachment_descriptors_; + std::map + color_attachment_descriptors_; std::shared_ptr vertex_descriptor_; PixelFormat depth_pixel_format_ = PixelFormat::kUnknown; PixelFormat stencil_pixel_format_ = PixelFormat::kUnknown; diff --git a/engine/src/flutter/impeller/renderer/pipeline_library.cc b/engine/src/flutter/impeller/renderer/pipeline_library.cc new file mode 100644 index 00000000000..10bb194bf41 --- /dev/null +++ b/engine/src/flutter/impeller/renderer/pipeline_library.cc @@ -0,0 +1,23 @@ +// 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/renderer/pipeline_library.h" + +namespace impeller { + +PipelineLibrary::PipelineLibrary() = default; + +PipelineLibrary::~PipelineLibrary() = default; + +PipelineFuture PipelineLibrary::GetRenderPipeline( + std::optional descriptor) { + if (descriptor.has_value()) { + return GetRenderPipeline(std::move(descriptor.value())); + } + auto promise = std::make_shared>>(); + promise->set_value(nullptr); + return promise->get_future(); +} + +} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/pipeline_library.h b/engine/src/flutter/impeller/renderer/pipeline_library.h index b161b2e8d82..67fc8efdc6d 100644 --- a/engine/src/flutter/impeller/renderer/pipeline_library.h +++ b/engine/src/flutter/impeller/renderer/pipeline_library.h @@ -4,10 +4,7 @@ #pragma once -#include - -#include -#include +#include #include "flutter/fml/macros.h" #include "impeller/renderer/pipeline.h" @@ -19,28 +16,17 @@ class Context; class PipelineLibrary : public std::enable_shared_from_this { public: - ~PipelineLibrary(); + virtual ~PipelineLibrary(); PipelineFuture GetRenderPipeline( std::optional descriptor); - PipelineFuture GetRenderPipeline(PipelineDescriptor descriptor); + virtual PipelineFuture GetRenderPipeline(PipelineDescriptor descriptor) = 0; + + protected: + PipelineLibrary(); private: - friend Context; - - using Pipelines = std::unordered_map, - ComparableHash, - ComparableEqual>; - id device_ = nullptr; - Pipelines pipelines_; - - PipelineLibrary(id device); - - void SavePipeline(PipelineDescriptor descriptor, - std::shared_ptr pipeline); - FML_DISALLOW_COPY_AND_ASSIGN(PipelineLibrary); }; diff --git a/engine/src/flutter/impeller/renderer/pipeline_library.mm b/engine/src/flutter/impeller/renderer/pipeline_library.mm deleted file mode 100644 index 931e9428c93..00000000000 --- a/engine/src/flutter/impeller/renderer/pipeline_library.mm +++ /dev/null @@ -1,65 +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/renderer/pipeline_library.h" - -#include - -#include "flutter/fml/logging.h" - -namespace impeller { - -PipelineLibrary::PipelineLibrary(id device) : device_(device) {} - -PipelineLibrary::~PipelineLibrary() = default; - -std::future> PipelineLibrary::GetRenderPipeline( - std::optional descriptor) { - if (descriptor.has_value()) { - return GetRenderPipeline(std::move(descriptor.value())); - } - auto promise = std::make_shared>>(); - promise->set_value(nullptr); - return promise->get_future(); -} - -std::future> PipelineLibrary::GetRenderPipeline( - PipelineDescriptor descriptor) { - auto promise = std::make_shared>>(); - auto future = promise->get_future(); - if (auto found = pipelines_.find(descriptor); found != pipelines_.end()) { - promise->set_value(nullptr); - return future; - } - - auto thiz = shared_from_this(); - - auto completion_handler = - ^(id _Nullable render_pipeline_state, - NSError* _Nullable error) { - if (error != nil) { - FML_LOG(ERROR) << "Could not create render pipeline: " - << error.localizedDescription.UTF8String; - promise->set_value(nullptr); - } else { - auto new_pipeline = std::shared_ptr( - new Pipeline(render_pipeline_state, - descriptor.CreateDepthStencilDescriptor(device_))); - promise->set_value(new_pipeline); - this->SavePipeline(descriptor, new_pipeline); - } - }; - [device_ - newRenderPipelineStateWithDescriptor:descriptor - .GetMTLRenderPipelineDescriptor() - completionHandler:completion_handler]; - return future; -} - -void PipelineLibrary::SavePipeline(PipelineDescriptor descriptor, - std::shared_ptr pipeline) { - pipelines_[descriptor] = std::move(pipeline); -} - -} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/platform.mm b/engine/src/flutter/impeller/renderer/platform.cc similarity index 100% rename from engine/src/flutter/impeller/renderer/platform.mm rename to engine/src/flutter/impeller/renderer/platform.cc diff --git a/engine/src/flutter/impeller/renderer/render_pass.cc b/engine/src/flutter/impeller/renderer/render_pass.cc new file mode 100644 index 00000000000..93c4ead3bf6 --- /dev/null +++ b/engine/src/flutter/impeller/renderer/render_pass.cc @@ -0,0 +1,13 @@ +// 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/renderer/render_pass.h" + +namespace impeller { + +RenderPass::RenderPass() = default; + +RenderPass::~RenderPass() = default; + +} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/render_pass.h b/engine/src/flutter/impeller/renderer/render_pass.h index 289bd182c7d..c61f16cc2ed 100644 --- a/engine/src/flutter/impeller/renderer/render_pass.h +++ b/engine/src/flutter/impeller/renderer/render_pass.h @@ -4,35 +4,26 @@ #pragma once -#include +#include -#include -#include - -#include "flutter/fml/macros.h" -#include "impeller/geometry/color.h" -#include "impeller/geometry/size.h" #include "impeller/renderer/command.h" -#include "impeller/renderer/formats.h" -#include "impeller/renderer/host_buffer.h" -#include "impeller/renderer/render_pass_descriptor.h" -#include "impeller/renderer/texture.h" namespace impeller { -class CommandBuffer; +class HostBuffer; +class Allocator; class RenderPass { public: - ~RenderPass(); + virtual ~RenderPass(); - bool IsValid() const; + virtual bool IsValid() const = 0; - void SetLabel(std::string label); + virtual void SetLabel(std::string label) = 0; - HostBuffer& GetTransientsBuffer(); + virtual HostBuffer& GetTransientsBuffer() = 0; - [[nodiscard]] bool RecordCommand(Command command); + [[nodiscard]] virtual bool RecordCommand(Command command) = 0; //---------------------------------------------------------------------------- /// @brief Commit the recorded commands to the underlying command buffer. @@ -44,23 +35,12 @@ class RenderPass { /// @return If the commands were committed to the underlying command /// buffer. /// - [[nodiscard]] bool Commit(Allocator& transients_allocator) const; + [[nodiscard]] virtual bool Commit(Allocator& transients_allocator) const = 0; + + protected: + RenderPass(); private: - friend class CommandBuffer; - - id buffer_ = nil; - MTLRenderPassDescriptor* desc_ = nil; - std::vector commands_; - std::shared_ptr transients_buffer_; - std::string label_; - bool is_valid_ = false; - - RenderPass(id buffer, const RenderPassDescriptor& desc); - - bool EncodeCommands(Allocator& transients_allocator, - id pass) const; - FML_DISALLOW_COPY_AND_ASSIGN(RenderPass); }; diff --git a/engine/src/flutter/impeller/renderer/render_pass.mm b/engine/src/flutter/impeller/renderer/render_pass.mm deleted file mode 100644 index a136864b85e..00000000000 --- a/engine/src/flutter/impeller/renderer/render_pass.mm +++ /dev/null @@ -1,408 +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/renderer/render_pass.h" - -#include -#include - -#include "flutter/fml/closure.h" -#include "flutter/fml/logging.h" -#include "impeller/base/base.h" -#include "impeller/renderer/device_buffer.h" -#include "impeller/renderer/formats_metal.h" -#include "impeller/renderer/sampler.h" -#include "impeller/renderer/shader_types.h" - -namespace impeller { - -static bool ConfigureAttachment(const RenderPassAttachment& desc, - MTLRenderPassAttachmentDescriptor* attachment) { - if (!desc.texture) { - return false; - } - - attachment.texture = desc.texture->GetMTLTexture(); - attachment.loadAction = ToMTLLoadAction(desc.load_action); - attachment.storeAction = ToMTLStoreAction(desc.store_action); - return true; -} - -static bool ConfigureColorAttachment( - const RenderPassColorAttachment& desc, - MTLRenderPassColorAttachmentDescriptor* attachment) { - if (!ConfigureAttachment(desc, attachment)) { - return false; - } - attachment.clearColor = ToMTLClearColor(desc.clear_color); - return true; -} - -static bool ConfigureDepthAttachment( - const RenderPassDepthAttachment& desc, - MTLRenderPassDepthAttachmentDescriptor* attachment) { - if (!ConfigureAttachment(desc, attachment)) { - return false; - } - attachment.clearDepth = desc.clear_depth; - return true; -} - -static bool ConfigureStencilAttachment( - const RenderPassStencilAttachment& desc, - MTLRenderPassStencilAttachmentDescriptor* attachment) { - if (!ConfigureAttachment(desc, attachment)) { - return false; - } - attachment.clearStencil = desc.clear_stencil; - return true; -} - -MTLRenderPassDescriptor* RenderPassDescriptor::ToMTLRenderPassDescriptor() - const { - auto result = [MTLRenderPassDescriptor renderPassDescriptor]; - - for (const auto& color : colors_) { - if (!ConfigureColorAttachment(color.second, - result.colorAttachments[color.first])) { - FML_LOG(ERROR) << "Could not configure color attachment at index " - << color.first; - return nil; - } - } - - if (depth_.has_value() && - !ConfigureDepthAttachment(depth_.value(), result.depthAttachment)) { - return nil; - } - - if (stencil_.has_value() && - !ConfigureStencilAttachment(stencil_.value(), result.stencilAttachment)) { - return nil; - } - - return result; -} - -RenderPass::RenderPass(id buffer, - const RenderPassDescriptor& desc) - : buffer_(buffer), - desc_(desc.ToMTLRenderPassDescriptor()), - transients_buffer_(HostBuffer::Create()) { - if (!buffer_ || !desc_) { - return; - } - is_valid_ = true; -} - -RenderPass::~RenderPass() = default; - -HostBuffer& RenderPass::GetTransientsBuffer() { - return *transients_buffer_; -} - -bool RenderPass::IsValid() const { - return is_valid_; -} - -void RenderPass::SetLabel(std::string label) { - label_ = std::move(label); - transients_buffer_->SetLabel(SPrintF("%s Transients", label_.c_str())); -} - -bool RenderPass::Commit(Allocator& transients_allocator) const { - if (!IsValid()) { - return false; - } - auto pass = [buffer_ renderCommandEncoderWithDescriptor:desc_]; - - if (!pass) { - return false; - } - - if (!label_.empty()) { - [pass setLabel:@(label_.c_str())]; - } - - // 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(transients_allocator, pass); -} - -//----------------------------------------------------------------------------- -/// @brief Ensures that bindings on the pass are not redundantly set or -/// updated. Avoids making the driver do additional checks and makes -/// the frame insights during profiling and instrumentation not -/// complain about the same. -/// -/// There should be no change to rendering if this caching was -/// absent. -/// -struct PassBindingsCache { - PassBindingsCache(id pass) : pass_(pass) {} - - PassBindingsCache(const PassBindingsCache&) = delete; - - PassBindingsCache(PassBindingsCache&&) = delete; - - void SetRenderPipelineState(id pipeline) { - if (pipeline == pipeline_) { - return; - } - pipeline_ = pipeline; - [pass_ setRenderPipelineState:pipeline_]; - } - - void SetDepthStencilState(id depth_stencil) { - if (depth_stencil_ == depth_stencil) { - return; - } - depth_stencil_ = depth_stencil; - [pass_ setDepthStencilState:depth_stencil_]; - } - - bool SetBuffer(ShaderStage stage, - uint64_t index, - uint64_t offset, - id buffer) { - auto& buffers_map = buffers_[stage]; - auto found = buffers_map.find(index); - if (found != buffers_map.end() && found->second.buffer == buffer) { - // The right buffer is bound. Check if its offset needs to be updated. - if (found->second.offset == offset) { - // Buffer and its offset is identical. Nothing to do. - return true; - } - - // Only the offset needs to be updated. - found->second.offset = offset; - - switch (stage) { - case ShaderStage::kVertex: - [pass_ setVertexBufferOffset:offset atIndex:index]; - return true; - case ShaderStage::kFragment: - [pass_ setFragmentBufferOffset:offset atIndex:index]; - return true; - default: - FML_DCHECK(false) - << "Cannot update buffer offset of an unknown stage."; - return false; - } - return true; - } - buffers_map[index] = {buffer, offset}; - switch (stage) { - case ShaderStage::kVertex: - [pass_ setVertexBuffer:buffer offset:offset atIndex:index]; - return true; - case ShaderStage::kFragment: - [pass_ setFragmentBuffer:buffer offset:offset atIndex:index]; - return true; - default: - FML_DCHECK(false) << "Cannot bind buffer to unknown shader stage."; - return false; - } - return false; - } - - bool SetTexture(ShaderStage stage, uint64_t index, id texture) { - auto& texture_map = textures_[stage]; - auto found = texture_map.find(index); - if (found != texture_map.end() && found->second == texture) { - // Already bound. - return true; - } - texture_map[index] = texture; - switch (stage) { - case ShaderStage::kVertex: - [pass_ setVertexTexture:texture atIndex:index]; - return true; - case ShaderStage::kFragment: - [pass_ setFragmentTexture:texture atIndex:index]; - return true; - default: - FML_DCHECK(false) << "Cannot bind buffer to unknown shader stage."; - return false; - } - return false; - } - - bool SetSampler(ShaderStage stage, - uint64_t index, - id sampler) { - auto& sampler_map = samplers_[stage]; - auto found = sampler_map.find(index); - if (found != sampler_map.end() && found->second == sampler) { - // Already bound. - return true; - } - sampler_map[index] = sampler; - switch (stage) { - case ShaderStage::kVertex: - [pass_ setVertexSamplerState:sampler atIndex:index]; - return true; - case ShaderStage::kFragment: - [pass_ setFragmentSamplerState:sampler atIndex:index]; - return true; - default: - FML_DCHECK(false) << "Cannot bind buffer to unknown shader stage."; - return false; - } - return false; - } - - private: - struct BufferOffsetPair { - id buffer = nullptr; - size_t offset = 0u; - }; - using BufferMap = std::map; - using TextureMap = std::map>; - using SamplerMap = std::map>; - - const id pass_; - id pipeline_ = nullptr; - id depth_stencil_ = nullptr; - std::map buffers_; - std::map textures_; - std::map samplers_; -}; - -static bool Bind(PassBindingsCache& pass, - Allocator& allocator, - ShaderStage stage, - size_t bind_index, - const BufferView& view) { - if (!view.buffer) { - return false; - } - - auto device_buffer = view.buffer->GetDeviceBuffer(allocator); - if (!device_buffer) { - return false; - } - - auto buffer = device_buffer->GetMTLBuffer(); - // The Metal call is a void return and we don't want to make it on nil. - if (!buffer) { - return false; - } - - return pass.SetBuffer(stage, bind_index, view.range.offset, buffer); -} - -static bool Bind(PassBindingsCache& pass, - ShaderStage stage, - size_t bind_index, - const Texture& texture) { - if (!texture.IsValid()) { - return false; - } - - return pass.SetTexture(stage, bind_index, texture.GetMTLTexture()); -} - -static bool Bind(PassBindingsCache& pass, - ShaderStage stage, - size_t bind_index, - const Sampler& sampler) { - if (!sampler.IsValid()) { - return false; - } - - return pass.SetSampler(stage, bind_index, sampler.GetMTLSamplerState()); -} - -bool RenderPass::EncodeCommands(Allocator& allocator, - id pass) const { - PassBindingsCache pass_bindings(pass); - auto bind_stage_resources = [&allocator, &pass_bindings]( - const Bindings& bindings, - ShaderStage stage) -> bool { - for (const auto buffer : bindings.buffers) { - if (!Bind(pass_bindings, allocator, stage, buffer.first, buffer.second)) { - return false; - } - } - for (const auto texture : bindings.textures) { - if (!Bind(pass_bindings, stage, texture.first, *texture.second)) { - return false; - } - } - for (const auto sampler : bindings.samplers) { - if (!Bind(pass_bindings, stage, sampler.first, *sampler.second)) { - return false; - } - } - return true; - }; - - fml::closure pop_debug_marker = [pass]() { [pass popDebugGroup]; }; - for (const auto& command : commands_) { - if (command.index_count == 0u) { - FML_DLOG(ERROR) << "Zero index count in render pass command."; - continue; - } - - fml::ScopedCleanupClosure auto_pop_debug_marker(pop_debug_marker); - if (!command.label.empty()) { - [pass pushDebugGroup:@(command.label.c_str())]; - } else { - auto_pop_debug_marker.Release(); - } - pass_bindings.SetRenderPipelineState( - command.pipeline->GetMTLRenderPipelineState()); - pass_bindings.SetDepthStencilState( - command.pipeline->GetMTLDepthStencilState()); - [pass setFrontFacingWinding:command.winding == WindingOrder::kClockwise - ? MTLWindingClockwise - : MTLWindingCounterClockwise]; - [pass setCullMode:MTLCullModeNone]; - if (!bind_stage_resources(command.vertex_bindings, ShaderStage::kVertex)) { - return false; - } - if (!bind_stage_resources(command.fragment_bindings, - ShaderStage::kFragment)) { - return false; - } - auto index_buffer = command.index_buffer.buffer; - if (!index_buffer) { - return false; - } - auto device_buffer = index_buffer->GetDeviceBuffer(allocator); - if (!device_buffer) { - return false; - } - auto mtl_index_buffer = device_buffer->GetMTLBuffer(); - if (!mtl_index_buffer) { - return false; - } - FML_DCHECK(command.index_count * sizeof(uint32_t) == - command.index_buffer.range.length); - // Returns void. All error checking must be done by this point. - [pass drawIndexedPrimitives:ToMTLPrimitiveType(command.primitive_type) - indexCount:command.index_count - indexType:MTLIndexTypeUInt32 - indexBuffer:mtl_index_buffer - indexBufferOffset:command.index_buffer.range.offset - instanceCount:1u - baseVertex:0u - baseInstance:0u]; - } - return true; -} - -bool RenderPass::RecordCommand(Command command) { - if (!command) { - return false; - } - - commands_.emplace_back(std::move(command)); - return true; -} - -} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/render_pass_descriptor.mm b/engine/src/flutter/impeller/renderer/render_pass_descriptor.cc similarity index 100% rename from engine/src/flutter/impeller/renderer/render_pass_descriptor.mm rename to engine/src/flutter/impeller/renderer/render_pass_descriptor.cc diff --git a/engine/src/flutter/impeller/renderer/render_pass_descriptor.h b/engine/src/flutter/impeller/renderer/render_pass_descriptor.h index 1c68781f0ea..df4a2a35f96 100644 --- a/engine/src/flutter/impeller/renderer/render_pass_descriptor.h +++ b/engine/src/flutter/impeller/renderer/render_pass_descriptor.h @@ -7,8 +7,6 @@ #include #include -#include - #include "flutter/fml/macros.h" #include "impeller/geometry/size.h" #include "impeller/renderer/formats.h" @@ -34,8 +32,6 @@ class RenderPassDescriptor { RenderPassDescriptor& SetStencilAttachment( RenderPassStencilAttachment attachment); - MTLRenderPassDescriptor* ToMTLRenderPassDescriptor() const; - private: std::map colors_; std::optional depth_; diff --git a/engine/src/flutter/impeller/renderer/renderer.h b/engine/src/flutter/impeller/renderer/renderer.h index c3c8b56f3bb..529ccb3c78d 100644 --- a/engine/src/flutter/impeller/renderer/renderer.h +++ b/engine/src/flutter/impeller/renderer/renderer.h @@ -23,7 +23,7 @@ class Renderer { using RenderCallback = std::function; - Renderer(std::string shaders_directory, std::string main_library_file); + Renderer(std::shared_ptr context); ~Renderer(); diff --git a/engine/src/flutter/impeller/renderer/renderer.mm b/engine/src/flutter/impeller/renderer/renderer.mm index 43a38e8f354..461deb0c4cd 100644 --- a/engine/src/flutter/impeller/renderer/renderer.mm +++ b/engine/src/flutter/impeller/renderer/renderer.mm @@ -12,10 +12,9 @@ namespace impeller { constexpr size_t kMaxFramesInFlight = 3u; -Renderer::Renderer(std::string shaders_directory, std::string main_library_file) +Renderer::Renderer(std::shared_ptr context) : frames_in_flight_sema_(::dispatch_semaphore_create(kMaxFramesInFlight)), - context_(std::make_shared(std::move(shaders_directory), - std::move(main_library_file))) { + context_(std::move(context)) { if (!context_->IsValid()) { return; } diff --git a/engine/src/flutter/impeller/renderer/renderer_unittests.mm b/engine/src/flutter/impeller/renderer/renderer_unittests.cc similarity index 99% rename from engine/src/flutter/impeller/renderer/renderer_unittests.mm rename to engine/src/flutter/impeller/renderer/renderer_unittests.cc index f037087f3d8..0d5117f68ca 100644 --- a/engine/src/flutter/impeller/renderer/renderer_unittests.mm +++ b/engine/src/flutter/impeller/renderer/renderer_unittests.cc @@ -15,7 +15,9 @@ #include "impeller/renderer/pipeline_builder.h" #include "impeller/renderer/pipeline_library.h" #include "impeller/renderer/renderer.h" +#include "impeller/renderer/sampler.h" #include "impeller/renderer/sampler_descriptor.h" +#include "impeller/renderer/sampler_library.h" #include "impeller/renderer/surface.h" #include "impeller/renderer/tessellator.h" #include "impeller/renderer/vertex_buffer_builder.h" diff --git a/engine/src/flutter/impeller/renderer/sampler.mm b/engine/src/flutter/impeller/renderer/sampler.cc similarity index 59% rename from engine/src/flutter/impeller/renderer/sampler.mm rename to engine/src/flutter/impeller/renderer/sampler.cc index 63e4a7404cc..67f818689a7 100644 --- a/engine/src/flutter/impeller/renderer/sampler.mm +++ b/engine/src/flutter/impeller/renderer/sampler.cc @@ -6,16 +6,8 @@ namespace impeller { -Sampler::Sampler(id state) : state_(state) {} +Sampler::Sampler() = default; Sampler::~Sampler() = default; -bool Sampler::IsValid() const { - return state_; -} - -id Sampler::GetMTLSamplerState() const { - return state_; -} - } // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/sampler.h b/engine/src/flutter/impeller/renderer/sampler.h index da7fdd37f52..81609ad16df 100644 --- a/engine/src/flutter/impeller/renderer/sampler.h +++ b/engine/src/flutter/impeller/renderer/sampler.h @@ -4,29 +4,20 @@ #pragma once -#include - #include "flutter/fml/macros.h" namespace impeller { -class SamplerLibrary; - class Sampler { public: - bool IsValid() const; + virtual ~Sampler(); - ~Sampler(); + virtual bool IsValid() const = 0; - id GetMTLSamplerState() const; + protected: + Sampler(); private: - friend SamplerLibrary; - - id state_ = nullptr; - - Sampler(id state); - FML_DISALLOW_COPY_AND_ASSIGN(Sampler); }; diff --git a/engine/src/flutter/impeller/renderer/sampler_descriptor.cc b/engine/src/flutter/impeller/renderer/sampler_descriptor.cc new file mode 100644 index 00000000000..35251848bc7 --- /dev/null +++ b/engine/src/flutter/impeller/renderer/sampler_descriptor.cc @@ -0,0 +1,11 @@ +// 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/renderer/sampler_descriptor.h" + +namespace impeller { + +// + +} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/sampler_descriptor.h b/engine/src/flutter/impeller/renderer/sampler_descriptor.h index ab1d169884d..6b0eb69c58d 100644 --- a/engine/src/flutter/impeller/renderer/sampler_descriptor.h +++ b/engine/src/flutter/impeller/renderer/sampler_descriptor.h @@ -4,10 +4,6 @@ #pragma once -#include - -#include - #include "flutter/fml/macros.h" #include "impeller/renderer/comparable.h" #include "impeller/renderer/formats.h" @@ -40,25 +36,4 @@ struct SamplerDescriptor final : public Comparable { } }; -class SamplerLibrary { - public: - ~SamplerLibrary(); - - std::shared_ptr GetSampler(SamplerDescriptor descriptor); - - private: - friend Context; - - using Samplers = std::unordered_map, - ComparableHash, - ComparableEqual>; - id device_ = nullptr; - Samplers samplers_; - - SamplerLibrary(id device); - - FML_DISALLOW_COPY_AND_ASSIGN(SamplerLibrary); -}; - } // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/sampler_library.cc b/engine/src/flutter/impeller/renderer/sampler_library.cc new file mode 100644 index 00000000000..7aae0f779f8 --- /dev/null +++ b/engine/src/flutter/impeller/renderer/sampler_library.cc @@ -0,0 +1,13 @@ +// 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/renderer/sampler_library.h" + +namespace impeller { + +SamplerLibrary::SamplerLibrary() = default; + +SamplerLibrary::~SamplerLibrary() = default; + +} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/sampler_library.h b/engine/src/flutter/impeller/renderer/sampler_library.h new file mode 100644 index 00000000000..e515b6facab --- /dev/null +++ b/engine/src/flutter/impeller/renderer/sampler_library.h @@ -0,0 +1,28 @@ +// 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/renderer/sampler_descriptor.h" + +namespace impeller { + +class SamplerLibrary { + public: + virtual ~SamplerLibrary(); + + virtual std::shared_ptr GetSampler( + SamplerDescriptor descriptor) = 0; + + protected: + SamplerLibrary(); + + private: + FML_DISALLOW_COPY_AND_ASSIGN(SamplerLibrary); +}; + +} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/shader_function.mm b/engine/src/flutter/impeller/renderer/shader_function.cc similarity index 85% rename from engine/src/flutter/impeller/renderer/shader_function.mm rename to engine/src/flutter/impeller/renderer/shader_function.cc index bed9c729fd2..b51a4888d00 100644 --- a/engine/src/flutter/impeller/renderer/shader_function.mm +++ b/engine/src/flutter/impeller/renderer/shader_function.cc @@ -7,20 +7,14 @@ namespace impeller { ShaderFunction::ShaderFunction(UniqueID parent_library_id, - id function, std::string name, ShaderStage stage) : parent_library_id_(parent_library_id), - function_(function), name_(std::move(name)), stage_(stage) {} ShaderFunction::~ShaderFunction() = default; -id ShaderFunction::GetMTLFunction() const { - return function_; -} - ShaderStage ShaderFunction::GetStage() const { return stage_; } diff --git a/engine/src/flutter/impeller/renderer/shader_function.h b/engine/src/flutter/impeller/renderer/shader_function.h index 04e4f573b93..682a67e21ee 100644 --- a/engine/src/flutter/impeller/renderer/shader_function.h +++ b/engine/src/flutter/impeller/renderer/shader_function.h @@ -4,8 +4,6 @@ #pragma once -#include - #include "flutter/fml/hash_combine.h" #include "flutter/fml/macros.h" #include "impeller/renderer/comparable.h" @@ -15,31 +13,27 @@ namespace impeller { class ShaderFunction : public Comparable { public: + // |Comparable| virtual ~ShaderFunction(); ShaderStage GetStage() const; - id GetMTLFunction() const; - // |Comparable| std::size_t GetHash() const override; // |Comparable| bool IsEqual(const ShaderFunction& other) const override; - private: - friend class ShaderLibrary; - - UniqueID parent_library_id_; - id function_ = nullptr; - std::string name_; - ShaderStage stage_; - + protected: ShaderFunction(UniqueID parent_library_id, - id function, std::string name, ShaderStage stage); + private: + UniqueID parent_library_id_; + std::string name_; + ShaderStage stage_; + FML_DISALLOW_COPY_AND_ASSIGN(ShaderFunction); }; diff --git a/engine/src/flutter/impeller/renderer/shader_library.cc b/engine/src/flutter/impeller/renderer/shader_library.cc new file mode 100644 index 00000000000..0c7b445501a --- /dev/null +++ b/engine/src/flutter/impeller/renderer/shader_library.cc @@ -0,0 +1,13 @@ +// 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/renderer/shader_library.h" + +namespace impeller { + +ShaderLibrary::ShaderLibrary() = default; + +ShaderLibrary::~ShaderLibrary() = default; + +} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/shader_library.h b/engine/src/flutter/impeller/renderer/shader_library.h index 4d28a690ac7..357be584cfc 100644 --- a/engine/src/flutter/impeller/renderer/shader_library.h +++ b/engine/src/flutter/impeller/renderer/shader_library.h @@ -4,64 +4,29 @@ #pragma once -#include - #include -#include #include -#include #include "flutter/fml/macros.h" -#include "impeller/renderer/comparable.h" -#include "impeller/renderer/shader_function.h" +#include "impeller/renderer/shader_types.h" namespace impeller { class Context; +class ShaderFunction; class ShaderLibrary { public: - ~ShaderLibrary(); + virtual ~ShaderLibrary(); - std::shared_ptr GetFunction( + virtual std::shared_ptr GetFunction( const std::string_view& name, - ShaderStage stage); + ShaderStage stage) = 0; + + protected: + ShaderLibrary(); private: - friend class Context; - - struct ShaderKey { - std::string name; - ShaderStage stage = ShaderStage::kUnknown; - - ShaderKey(const std::string_view& p_name, ShaderStage p_stage) - : name({p_name.data(), p_name.size()}), stage(p_stage) {} - - struct Hash { - size_t operator()(const ShaderKey& key) const { - return fml::HashCombine(key.name, key.stage); - } - }; - - struct Equal { - constexpr bool operator()(const ShaderKey& k1, - const ShaderKey& k2) const { - return k1.stage == k2.stage && k1.name == k2.name; - } - }; - }; - - using Functions = std::unordered_map, - ShaderKey::Hash, - ShaderKey::Equal>; - - UniqueID library_id_; - id library_ = nullptr; - Functions functions_; - - ShaderLibrary(id library); - FML_DISALLOW_COPY_AND_ASSIGN(ShaderLibrary); }; diff --git a/engine/src/flutter/impeller/renderer/shader_library.mm b/engine/src/flutter/impeller/renderer/shader_library.mm deleted file mode 100644 index baeb0fac0a2..00000000000 --- a/engine/src/flutter/impeller/renderer/shader_library.mm +++ /dev/null @@ -1,37 +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/renderer/shader_library.h" - -namespace impeller { - -ShaderLibrary::ShaderLibrary(id library) : library_(library) {} - -ShaderLibrary::~ShaderLibrary() = default; - -std::shared_ptr ShaderLibrary::GetFunction( - const std::string_view& name, - ShaderStage stage) { - if (!library_) { - return nullptr; - } - - ShaderKey key(name, stage); - - if (auto found = functions_.find(key); found != functions_.end()) { - return found->second; - } - - auto function = [library_ newFunctionWithName:@(name.data())]; - if (!function) { - return nullptr; - } - - auto func = std::shared_ptr(new ShaderFunction( - library_id_, function, {name.data(), name.size()}, stage)); - functions_[key] = func; - return func; -} - -} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/surface.mm b/engine/src/flutter/impeller/renderer/surface.cc similarity index 100% rename from engine/src/flutter/impeller/renderer/surface.mm rename to engine/src/flutter/impeller/renderer/surface.cc diff --git a/engine/src/flutter/impeller/renderer/surface.h b/engine/src/flutter/impeller/renderer/surface.h index 231d89e424a..2fb2d85a821 100644 --- a/engine/src/flutter/impeller/renderer/surface.h +++ b/engine/src/flutter/impeller/renderer/surface.h @@ -4,14 +4,13 @@ #pragma once -#include - #include #include #include "flutter/fml/macros.h" #include "impeller/renderer/context.h" #include "impeller/renderer/render_pass.h" +#include "impeller/renderer/render_pass_descriptor.h" namespace impeller { diff --git a/engine/src/flutter/impeller/renderer/texture.cc b/engine/src/flutter/impeller/renderer/texture.cc new file mode 100644 index 00000000000..1d29828e938 --- /dev/null +++ b/engine/src/flutter/impeller/renderer/texture.cc @@ -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/renderer/texture.h" + +namespace impeller { + +Texture::Texture(TextureDescriptor desc) : desc_(std::move(desc)) {} + +Texture::~Texture() = default; + +const TextureDescriptor& Texture::GetTextureDescriptor() const { + return desc_; +} + +} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/texture.h b/engine/src/flutter/impeller/renderer/texture.h index d3067498e61..a698820432b 100644 --- a/engine/src/flutter/impeller/renderer/texture.h +++ b/engine/src/flutter/impeller/renderer/texture.h @@ -6,8 +6,6 @@ #include -#include - #include "flutter/fml/macros.h" #include "impeller/geometry/size.h" #include "impeller/renderer/formats.h" @@ -17,24 +15,24 @@ namespace impeller { class Texture { public: - Texture(TextureDescriptor desc, id texture); + virtual ~Texture(); - ~Texture(); + virtual void SetLabel(const std::string_view& label) = 0; - void SetLabel(const std::string_view& label); + [[nodiscard]] virtual bool SetContents(const uint8_t* contents, + size_t length) = 0; - [[nodiscard]] bool SetContents(const uint8_t* contents, size_t length); + virtual bool IsValid() const = 0; - bool IsValid() const; + virtual ISize GetSize() const = 0; - ISize GetSize() const; + const TextureDescriptor& GetTextureDescriptor() const; - id GetMTLTexture() const; + protected: + Texture(TextureDescriptor desc); private: const TextureDescriptor desc_; - id texture_ = nullptr; - bool is_valid_ = false; FML_DISALLOW_COPY_AND_ASSIGN(Texture); }; diff --git a/engine/src/flutter/impeller/renderer/texture.mm b/engine/src/flutter/impeller/renderer/texture.mm deleted file mode 100644 index 591ceb12024..00000000000 --- a/engine/src/flutter/impeller/renderer/texture.mm +++ /dev/null @@ -1,68 +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/renderer/texture.h" - -namespace impeller { - -Texture::Texture(TextureDescriptor desc, id texture) - : desc_(std::move(desc)), texture_(texture) { - if (!desc_.IsValid() || !texture_) { - return; - } - - if (desc_.size != GetSize()) { - FML_DLOG(ERROR) - << "The texture and its descriptor disagree about its size."; - return; - } - - is_valid_ = true; -} - -Texture::~Texture() = default; - -void Texture::SetLabel(const std::string_view& label) { - [texture_ setLabel:@(label.data())]; -} - -bool Texture::SetContents(const uint8_t* contents, size_t length) { - if (!IsValid() || !contents) { - return false; - } - - // Out of bounds access. - if (length != desc_.GetSizeOfBaseMipLevel()) { - return false; - } - - // TODO(csg): Perhaps the storage mode should be added to the texture - // descriptor so that invalid region replacements on potentially non-host - // visible textures are disallowed. The annoying bit about the API below is - // that there seems to be no error handling guidance. - const auto region = - MTLRegionMake2D(0u, 0u, desc_.size.width, desc_.size.height); - [texture_ replaceRegion:region // - mipmapLevel:0u // - withBytes:contents // - bytesPerRow:desc_.GetBytesPerRow() // - ]; - - return true; -} - -ISize Texture::GetSize() const { - return {static_cast(texture_.width), - static_cast(texture_.height)}; -} - -id Texture::GetMTLTexture() const { - return texture_; -} - -bool Texture::IsValid() const { - return is_valid_; -} - -} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/texture_descriptor.mm b/engine/src/flutter/impeller/renderer/texture_descriptor.cc similarity index 100% rename from engine/src/flutter/impeller/renderer/texture_descriptor.mm rename to engine/src/flutter/impeller/renderer/texture_descriptor.cc diff --git a/engine/src/flutter/impeller/renderer/vertex_buffer.mm b/engine/src/flutter/impeller/renderer/vertex_buffer.cc similarity index 100% rename from engine/src/flutter/impeller/renderer/vertex_buffer.mm rename to engine/src/flutter/impeller/renderer/vertex_buffer.cc diff --git a/engine/src/flutter/impeller/renderer/vertex_buffer_builder.mm b/engine/src/flutter/impeller/renderer/vertex_buffer_builder.cc similarity index 100% rename from engine/src/flutter/impeller/renderer/vertex_buffer_builder.mm rename to engine/src/flutter/impeller/renderer/vertex_buffer_builder.cc diff --git a/engine/src/flutter/impeller/renderer/vertex_descriptor.mm b/engine/src/flutter/impeller/renderer/vertex_descriptor.cc similarity index 100% rename from engine/src/flutter/impeller/renderer/vertex_descriptor.mm rename to engine/src/flutter/impeller/renderer/vertex_descriptor.cc diff --git a/engine/src/flutter/impeller/renderer/vertex_descriptor.h b/engine/src/flutter/impeller/renderer/vertex_descriptor.h index 26e63be373b..09f7c20dbcb 100644 --- a/engine/src/flutter/impeller/renderer/vertex_descriptor.h +++ b/engine/src/flutter/impeller/renderer/vertex_descriptor.h @@ -4,8 +4,6 @@ #pragma once -#include - #include #include "flutter/fml/macros.h"