Start getting rid of ObjC TU's from core library.

This commit is contained in:
Chinmay Garde 2021-10-25 14:08:02 -07:00 committed by Dan Field
parent 1401218afc
commit e129fbaba1
89 changed files with 1961 additions and 1862 deletions

View File

@ -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<ContextMTL>(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;

View File

@ -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 = [

View File

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

View File

@ -4,8 +4,6 @@
#pragma once
#include <Metal/Metal.h>
#include <string>
#include "flutter/fml/macros.h"
@ -51,35 +49,30 @@ class Texture;
class Allocator {
public:
~Allocator();
virtual ~Allocator();
bool IsValid() const;
std::shared_ptr<DeviceBuffer> CreateBuffer(StorageMode mode, size_t length);
virtual std::shared_ptr<DeviceBuffer> CreateBuffer(StorageMode mode,
size_t length) = 0;
std::shared_ptr<Texture> CreateTexture(StorageMode mode,
const TextureDescriptor& desc);
virtual std::shared_ptr<Texture> CreateTexture(
StorageMode mode,
const TextureDescriptor& desc) = 0;
std::shared_ptr<DeviceBuffer> CreateBufferWithCopy(const uint8_t* buffer,
size_t length);
virtual std::shared_ptr<DeviceBuffer> CreateBufferWithCopy(
const uint8_t* buffer,
size_t length) = 0;
std::shared_ptr<DeviceBuffer> CreateBufferWithCopy(
const fml::Mapping& mapping);
virtual std::shared_ptr<DeviceBuffer> 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<MTLDevice> device_;
std::string allocator_label_;
bool is_valid_ = false;
Allocator(id<MTLDevice> device, std::string label);
FML_DISALLOW_COPY_AND_ASSIGN(Allocator);
};

View File

@ -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<MTLDevice> 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<DeviceBuffer> Allocator::CreateBuffer(StorageMode mode,
size_t length) {
auto buffer = [device_ newBufferWithLength:length
options:ToMTLResourceOptions(mode)];
if (!buffer) {
return nullptr;
}
return std::shared_ptr<DeviceBuffer>(new DeviceBuffer(buffer, length, mode));
}
std::shared_ptr<DeviceBuffer> 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<DeviceBuffer> Allocator::CreateBufferWithCopy(
const fml::Mapping& mapping) {
return CreateBufferWithCopy(mapping.GetMapping(), mapping.GetSize());
}
std::shared_ptr<Texture> 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<Texture>(desc, texture);
}
} // namespace impeller

View File

@ -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 = []
}

View File

@ -4,6 +4,8 @@
#pragma once
#include <Metal/Metal.h>
#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<MTLDevice> device_;
std::string allocator_label_;
bool is_valid_ = false;
AllocatorMTL(id<MTLDevice> device, std::string label);
// |Allocator|
bool IsValid() const;
// |Allocator|
std::shared_ptr<DeviceBuffer> CreateBuffer(StorageMode mode,
size_t length) override;
// |Allocator|
std::shared_ptr<Texture> CreateTexture(
StorageMode mode,
const TextureDescriptor& desc) override;
// |Allocator|
std::shared_ptr<DeviceBuffer> CreateBufferWithCopy(const uint8_t* buffer,
size_t length) override;
// |Allocator|
std::shared_ptr<DeviceBuffer> CreateBufferWithCopy(
const fml::Mapping& mapping) override;
FML_DISALLOW_COPY_AND_ASSIGN(AllocatorMTL);
};

View File

@ -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<MTLDevice> 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<DeviceBuffer> AllocatorMTL::CreateBuffer(StorageMode mode,
size_t length) {
auto buffer = [device_ newBufferWithLength:length
options:ToMTLResourceOptions(mode)];
if (!buffer) {
return nullptr;
}
return std::shared_ptr<DeviceBufferMTL>(
new DeviceBufferMTL(buffer, length, mode));
}
std::shared_ptr<DeviceBuffer> 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<DeviceBuffer> AllocatorMTL::CreateBufferWithCopy(
const fml::Mapping& mapping) {
return CreateBufferWithCopy(mapping.GetMapping(), mapping.GetSize());
}
std::shared_ptr<Texture> 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<Texture>(desc, texture);
}
} // namespace impeller

View File

@ -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 Sub, class Base>
class BackendCast {
public:
RendererMTL();
static Sub& Cast(Base& base) { return reinterpret_cast<Sub&>(base); }
~RendererMTL() override;
private:
FML_DISALLOW_COPY_AND_ASSIGN(RendererMTL);
static const Sub& Cast(const Base& base) {
return reinterpret_cast<const Sub&>(base);
}
};
} // namespace impeller

View File

@ -4,19 +4,39 @@
#pragma once
#include <Metal/Metal.h>
#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<MTLCommandBuffer> buffer_ = nullptr;
bool is_valid_ = false;
CommandBufferMTL(id<MTLCommandQueue> queue);
// |CommandBuffer|
bool IsValid() const override;
// |CommandBuffer|
void Commit(CommitCallback callback) override;
// |CommandBuffer|
std::shared_ptr<RenderPass> CreateRenderPass(
const RenderPassDescriptor& desc) const override;
FML_DISALLOW_COPY_AND_ASSIGN(CommandBufferMTL);
};
} // namespace impeller

View File

@ -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<MTLCommandQueue> 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<MTLCommandBuffer> buffer) {
callback(ToCommitResult(buffer.status));
}];
[buffer_ commit];
buffer_ = nil;
}
std::shared_ptr<RenderPass> CommandBufferMTL::CreateRenderPass(
const RenderPassDescriptor& desc) const {
if (!buffer_) {
return nullptr;
}
auto pass = std::shared_ptr<RenderPassMTL>(new RenderPassMTL(buffer_, desc));
if (!pass->IsValid()) {
return nullptr;
}
return pass;
}
} // namespace impeller

View File

@ -4,18 +4,63 @@
#pragma once
#include <Metal/Metal.h>
#include <string>
#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<ContextMTL, Context> {
public:
ContextMTL();
ContextMTL(std::string shaders_directory, std::string main_library_file_name);
// |Context|
~ContextMTL() override;
id<MTLDevice> GetMTLDevice() const;
private:
id<MTLDevice> device_ = nullptr;
id<MTLCommandQueue> render_queue_ = nullptr;
id<MTLCommandQueue> transfer_queue_ = nullptr;
std::shared_ptr<ShaderLibraryMTL> shader_library_;
std::shared_ptr<PipelineLibraryMTL> pipeline_library_;
std::shared_ptr<SamplerLibrary> sampler_library_;
std::shared_ptr<AllocatorMTL> permanents_allocator_;
std::shared_ptr<AllocatorMTL> transients_allocator_;
bool is_valid_ = false;
// |Context|
bool IsValid() const override;
// |Context|
std::shared_ptr<Allocator> GetPermanentsAllocator() const override;
// |Context|
std::shared_ptr<Allocator> GetTransientsAllocator() const override;
// |Context|
std::shared_ptr<ShaderLibrary> GetShaderLibrary() const override;
// |Context|
std::shared_ptr<SamplerLibrary> GetSamplerLibrary() const override;
// |Context|
std::shared_ptr<PipelineLibrary> GetPipelineLibrary() const override;
// |Context|
std::shared_ptr<CommandBuffer> CreateRenderCommandBuffer() const override;
FML_DISALLOW_COPY_AND_ASSIGN(ContextMTL);
};

View File

@ -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<ShaderLibraryMTL>(new ShaderLibraryMTL(library));
}
// Setup the pipeline library.
{ //
pipeline_library_ =
std::shared_ptr<PipelineLibraryMTL>(new PipelineLibraryMTL(device_));
}
// Setup the sampler library.
{ //
sampler_library_ =
std::shared_ptr<SamplerLibraryMTL>(new SamplerLibraryMTL(device_));
}
{
transients_allocator_ = std::shared_ptr<AllocatorMTL>(
new AllocatorMTL(device_, "Impeller Transients Allocator"));
if (!transients_allocator_) {
return;
}
permanents_allocator_ = std::shared_ptr<AllocatorMTL>(
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<ShaderLibrary> ContextMTL::GetShaderLibrary() const {
return shader_library_;
}
std::shared_ptr<PipelineLibrary> ContextMTL::GetPipelineLibrary() const {
return pipeline_library_;
}
std::shared_ptr<SamplerLibrary> ContextMTL::GetSamplerLibrary() const {
return sampler_library_;
}
std::shared_ptr<CommandBuffer> ContextMTL::CreateRenderCommandBuffer() const {
if (!IsValid()) {
return nullptr;
}
auto buffer =
std::shared_ptr<CommandBufferMTL>(new CommandBufferMTL(render_queue_));
if (!buffer->IsValid()) {
return nullptr;
}
return buffer;
}
std::shared_ptr<Allocator> ContextMTL::GetPermanentsAllocator() const {
return permanents_allocator_;
}
std::shared_ptr<Allocator> ContextMTL::GetTransientsAllocator() const {
return transients_allocator_;
}
id<MTLDevice> ContextMTL::GetMTLDevice() const {
return device_;
}
} // namespace impeller

View File

@ -4,18 +4,56 @@
#pragma once
#include <Metal/Metal.h>
#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<DeviceBufferMTL, DeviceBuffer> {
public:
DeviceBufferMTL();
// |DeviceBuffer|
~DeviceBufferMTL() override;
id<MTLBuffer> GetMTLBuffer() const;
private:
friend class AllocatorMTL;
const id<MTLBuffer> buffer_;
const size_t size_;
const StorageMode mode_;
DeviceBufferMTL(id<MTLBuffer> buffer, size_t size, StorageMode mode);
// |DeviceBuffer|
bool CopyHostBuffer(const uint8_t* source,
Range source_range,
size_t offset) override;
// |DeviceBuffer|
std::shared_ptr<Texture> 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<const DeviceBuffer> GetDeviceBuffer(
Allocator& allocator) const override;
FML_DISALLOW_COPY_AND_ASSIGN(DeviceBufferMTL);
};

View File

@ -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<MTLBuffer> buffer,
size_t size,
StorageMode mode)
: buffer_(buffer), size_(size), mode_(mode) {}
DeviceBufferMTL::~DeviceBufferMTL() = default;
id<MTLBuffer> DeviceBufferMTL::GetMTLBuffer() const {
return buffer_;
}
std::shared_ptr<Texture> 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<Texture>(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<uint8_t*>(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<const DeviceBuffer> 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

View File

@ -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 <optional>
#include <Metal/Metal.h>
#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<ColorWriteMask> type) {
using UnderlyingType = decltype(type);
MTLColorWriteMask mask = MTLColorWriteMaskNone;
if (type & static_cast<UnderlyingType>(ColorWriteMask::kRed)) {
mask |= MTLColorWriteMaskRed;
}
if (type & static_cast<UnderlyingType>(ColorWriteMask::kGreen)) {
mask |= MTLColorWriteMaskGreen;
}
if (type & static_cast<UnderlyingType>(ColorWriteMask::kBlue)) {
mask |= MTLColorWriteMaskBlue;
}
if (type & static_cast<UnderlyingType>(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<PipelineDepthAttachment> depth,
std::optional<PipelineStencilAttachment> front,
std::optional<PipelineStencilAttachment> back);
MTLTextureDescriptor* ToMTLTextureDescriptor(const TextureDescriptor& desc);
} // namespace impeller

View File

@ -4,10 +4,10 @@
#pragma once
#include <optional>
#include <Metal/Metal.h>
#include <optional>
#include "flutter/fml/macros.h"
#include "impeller/geometry/color.h"
#include "impeller/renderer/formats.h"

View File

@ -4,18 +4,43 @@
#pragma once
#include <Metal/Metal.h>
#include <memory>
#include <unordered_map>
#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<PipelineDescriptor,
std::shared_ptr<const Pipeline>,
ComparableHash<PipelineDescriptor>,
ComparableEqual<PipelineDescriptor>>;
id<MTLDevice> device_ = nullptr;
Pipelines pipelines_;
PipelineLibraryMTL(id<MTLDevice> device);
void SavePipeline(PipelineDescriptor descriptor,
std::shared_ptr<const Pipeline> pipeline);
// |PipelineLibrary|
PipelineFuture GetRenderPipeline(PipelineDescriptor descriptor) override;
FML_DISALLOW_COPY_AND_ASSIGN(PipelineLibraryMTL);
};

View File

@ -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<MTLDevice> 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<MTLDepthStencilState> CreateDepthStencilDescriptor(
const PipelineDescriptor& desc,
id<MTLDevice> device) {
auto descriptor = ToMTLDepthStencilDescriptor(
desc.GetDepthStencilAttachmentDescriptor(), //
desc.GetFrontStencilAttachmentDescriptor(), //
desc.GetBackStencilAttachmentDescriptor() //
);
return [device newDepthStencilStateWithDescriptor:descriptor];
}
std::future<std::shared_ptr<Pipeline>> PipelineLibraryMTL::GetRenderPipeline(
PipelineDescriptor descriptor) {
auto promise = std::make_shared<std::promise<std::shared_ptr<Pipeline>>>();
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<MTLRenderPipelineState> _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<PipelineMTL>(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<const Pipeline> pipeline) {
pipelines_[descriptor] = std::move(pipeline);
}
} // namespace impeller

View File

@ -4,18 +4,38 @@
#pragma once
#include <Metal/Metal.h>
#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<PipelineMTL, Pipeline> {
public:
PipelineMTL();
// |PipelineMTL|
~PipelineMTL() override;
id<MTLRenderPipelineState> GetMTLRenderPipelineState() const;
id<MTLDepthStencilState> GetMTLDepthStencilState() const;
private:
friend class PipelineLibraryMTL;
Type type_ = Type::kUnknown;
id<MTLRenderPipelineState> pipeline_state_;
id<MTLDepthStencilState> depth_stencil_state_;
bool is_valid_ = false;
PipelineMTL(id<MTLRenderPipelineState> state,
id<MTLDepthStencilState> depth_stencil_state);
// |PipelineMTL|
bool IsValid() const override;
FML_DISALLOW_COPY_AND_ASSIGN(PipelineMTL);
};

View File

@ -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<MTLRenderPipelineState> state,
id<MTLDepthStencilState> 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<MTLRenderPipelineState> PipelineMTL::GetMTLRenderPipelineState() const {
return pipeline_state_;
}
id<MTLDepthStencilState> PipelineMTL::GetMTLDepthStencilState() const {
return depth_stencil_state_;
}
} // namespace impeller

View File

@ -4,18 +4,49 @@
#pragma once
#include <Metal/Metal.h>
#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<MTLCommandBuffer> buffer_ = nil;
MTLRenderPassDescriptor* desc_ = nil;
std::vector<Command> commands_;
std::shared_ptr<HostBuffer> transients_buffer_;
std::string label_;
bool is_valid_ = false;
RenderPassMTL(id<MTLCommandBuffer> 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<MTLRenderCommandEncoder> pass) const;
FML_DISALLOW_COPY_AND_ASSIGN(RenderPassMTL);
};

View File

@ -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<MTLCommandBuffer> 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<MTLRenderCommandEncoder> pass) : pass_(pass) {}
PassBindingsCache(const PassBindingsCache&) = delete;
PassBindingsCache(PassBindingsCache&&) = delete;
void SetRenderPipelineState(id<MTLRenderPipelineState> pipeline) {
if (pipeline == pipeline_) {
return;
}
pipeline_ = pipeline;
[pass_ setRenderPipelineState:pipeline_];
}
void SetDepthStencilState(id<MTLDepthStencilState> 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<MTLBuffer> 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<MTLTexture> 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<MTLSamplerState> 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<MTLBuffer> buffer = nullptr;
size_t offset = 0u;
};
using BufferMap = std::map<uint64_t, BufferOffsetPair>;
using TextureMap = std::map<uint64_t, id<MTLTexture>>;
using SamplerMap = std::map<uint64_t, id<MTLSamplerState>>;
const id<MTLRenderCommandEncoder> pass_;
id<MTLRenderPipelineState> pipeline_ = nullptr;
id<MTLDepthStencilState> depth_stencil_ = nullptr;
std::map<ShaderStage, BufferMap> buffers_;
std::map<ShaderStage, TextureMap> textures_;
std::map<ShaderStage, SamplerMap> 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<MTLRenderCommandEncoder> 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

View File

@ -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 <Metal/Metal.h>
#include <memory>
#include <unordered_map>
#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<SamplerLibraryMTL, SamplerLibrary> {
public:
// |SamplerLibrary|
~SamplerLibraryMTL() override;
private:
friend class ContextMTL;
using CachedSamplers = std::unordered_map<SamplerDescriptor,
std::shared_ptr<const Sampler>,
ComparableHash<SamplerDescriptor>,
ComparableEqual<SamplerDescriptor>>;
id<MTLDevice> device_ = nullptr;
CachedSamplers samplers_;
SamplerLibraryMTL(id<MTLDevice> device);
// |SamplerLibrary|
std::shared_ptr<const Sampler> GetSampler(
SamplerDescriptor descriptor) override;
FML_DISALLOW_COPY_AND_ASSIGN(SamplerLibraryMTL);
};
} // namespace impeller

View File

@ -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<MTLDevice> device) : device_(device) {}
SamplerLibraryMTL::SamplerLibraryMTL(id<MTLDevice> device) : device_(device) {}
SamplerLibrary::~SamplerLibrary() = default;
SamplerLibraryMTL::~SamplerLibraryMTL() = default;
std::shared_ptr<const Sampler> SamplerLibrary::GetSampler(
std::shared_ptr<const Sampler> SamplerLibraryMTL::GetSampler(
SamplerDescriptor descriptor) {
auto found = samplers_.find(descriptor);
if (found != samplers_.end()) {
@ -32,7 +32,7 @@ std::shared_ptr<const Sampler> SamplerLibrary::GetSampler(
if (!mtl_sampler) {
return nullptr;
}
auto sampler = std::shared_ptr<Sampler>(new Sampler(mtl_sampler));
auto sampler = std::shared_ptr<SamplerMTL>(new SamplerMTL(mtl_sampler));
if (!sampler->IsValid()) {
return nullptr;
}

View File

@ -4,18 +4,36 @@
#pragma once
#include <Metal/Metal.h>
#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<SamplerMTL, Sampler> {
public:
SamplerMTL();
// |Sampler|
~SamplerMTL() override;
id<MTLSamplerState> GetMTLSamplerState() const;
private:
friend SamplerLibraryMTL;
id<MTLSamplerState> state_ = nullptr;
SamplerMTL(id<MTLSamplerState> state);
// |Sampler|
bool IsValid() const override;
FML_DISALLOW_COPY_AND_ASSIGN(SamplerMTL);
};

View File

@ -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<MTLSamplerState> state) : state_(state) {}
SamplerMTL::~SamplerMTL() = default;
bool SamplerMTL::IsValid() const {
return state_;
}
id<MTLSamplerState> SamplerMTL::GetMTLSamplerState() const {
return state_;
}
} // namespace impeller

View File

@ -4,18 +4,33 @@
#pragma once
#include <Metal/Metal.h>
#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<ShaderFunctionMTL, ShaderFunction> {
public:
ShaderFunctionMTL();
// |ShaderFunction|
~ShaderFunctionMTL() override;
id<MTLFunction> GetMTLFunction() const;
private:
friend class ShaderLibraryMTL;
id<MTLFunction> function_ = nullptr;
ShaderFunctionMTL(UniqueID parent_library_id,
id<MTLFunction> function,
std::string name,
ShaderStage stage);
FML_DISALLOW_COPY_AND_ASSIGN(ShaderFunctionMTL);
};

View File

@ -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<MTLFunction> function,
std::string name,
ShaderStage stage)
: ShaderFunction(std::move(parent_library_id), std::move(name), stage),
function_(function) {}
ShaderFunctionMTL::~ShaderFunctionMTL() = default;
id<MTLFunction> ShaderFunctionMTL::GetMTLFunction() const {
return function_;
}
} // namespace impeller

View File

@ -4,7 +4,14 @@
#pragma once
#include <Metal/Metal.h>
#include <memory>
#include <string>
#include <unordered_map>
#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,
std::shared_ptr<const ShaderFunction>,
ShaderKey::Hash,
ShaderKey::Equal>;
UniqueID library_id_;
id<MTLLibrary> library_ = nullptr;
Functions functions_;
ShaderLibraryMTL(id<MTLLibrary> library);
// |ShaderLibrary|
std::shared_ptr<const ShaderFunction> GetFunction(
const std::string_view& name,
ShaderStage stage) override;
FML_DISALLOW_COPY_AND_ASSIGN(ShaderLibraryMTL);
};

View File

@ -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<MTLLibrary> library)
: library_(library) {}
ShaderLibraryMTL::~ShaderLibraryMTL() = default;
std::shared_ptr<const ShaderFunction> 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<ShaderFunctionMTL>(new ShaderFunctionMTL(
library_id_, function, {name.data(), name.size()}, stage));
functions_[key] = func;
return func;
}
} // namespace impeller

View File

@ -4,18 +4,37 @@
#pragma once
#include <Metal/Metal.h>
#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<TextureMTL, Texture> {
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<MTLTexture> GetMTLTexture() const;
private:
id<MTLTexture> texture_ = nullptr;
bool is_valid_ = false;
TextureMTL(TextureDescriptor desc, id<MTLTexture> texture);
FML_DISALLOW_COPY_AND_ASSIGN(TextureMTL);
};

View File

@ -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<MTLTexture> 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<ISize::Type>(texture_.width),
static_cast<ISize::Type>(texture_.height)};
}
id<MTLTexture> TextureMTL::GetMTLTexture() const {
return texture_;
}
bool TextureMTL::IsValid() const {
return is_valid_;
}
} // namespace impeller

View File

@ -4,8 +4,6 @@
#include "impeller/renderer/command.h"
#include <Metal/Metal.h>
#include "impeller/renderer/vertex_descriptor.h"
namespace impeller {

View File

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

View File

@ -4,24 +4,19 @@
#pragma once
#include <Metal/Metal.h>
#include <functional>
#include <memory>
#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(CommitResult)>;
void Commit(CommitCallback callback);
std::shared_ptr<RenderPass> CreateRenderPass(
const RenderPassDescriptor& desc) const;
virtual ~CommandBuffer();
virtual bool IsValid() const = 0;
virtual void Commit(CommitCallback callback) = 0;
virtual std::shared_ptr<RenderPass> CreateRenderPass(
const RenderPassDescriptor& desc) const = 0;
protected:
CommandBuffer();
private:
friend class Context;
id<MTLCommandBuffer> buffer_ = nullptr;
bool is_valid_ = false;
CommandBuffer(id<MTLCommandQueue> queue);
FML_DISALLOW_COPY_AND_ASSIGN(CommandBuffer);
};

View File

@ -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<MTLCommandQueue> 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<MTLCommandBuffer> buffer) {
callback(ToCommitResult(buffer.status));
}];
[buffer_ commit];
buffer_ = nil;
}
std::shared_ptr<RenderPass> CommandBuffer::CreateRenderPass(
const RenderPassDescriptor& desc) const {
if (!buffer_) {
return nullptr;
}
auto pass = std::shared_ptr<RenderPass>(new RenderPass(buffer_, desc));
if (!pass->IsValid()) {
return nullptr;
}
return pass;
}
} // namespace impeller

View File

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

View File

@ -4,8 +4,6 @@
#pragma once
#include <Metal/Metal.h>
#include <memory>
#include <string>
@ -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<Allocator> GetPermanentsAllocator() const;
virtual std::shared_ptr<Allocator> GetPermanentsAllocator() const = 0;
//----------------------------------------------------------------------------
/// @return An allocator suitable for allocations that used only for one
/// frame or render pass.
///
std::shared_ptr<Allocator> GetTransientsAllocator() const;
virtual std::shared_ptr<Allocator> GetTransientsAllocator() const = 0;
std::shared_ptr<ShaderLibrary> GetShaderLibrary() const;
virtual std::shared_ptr<ShaderLibrary> GetShaderLibrary() const = 0;
std::shared_ptr<SamplerLibrary> GetSamplerLibrary() const;
virtual std::shared_ptr<SamplerLibrary> GetSamplerLibrary() const = 0;
std::shared_ptr<PipelineLibrary> GetPipelineLibrary() const;
virtual std::shared_ptr<PipelineLibrary> GetPipelineLibrary() const = 0;
std::shared_ptr<CommandBuffer> CreateRenderCommandBuffer() const;
virtual std::shared_ptr<CommandBuffer> CreateRenderCommandBuffer() const = 0;
id<MTLDevice> GetMTLDevice() const;
protected:
Context();
private:
id<MTLDevice> device_ = nullptr;
id<MTLCommandQueue> render_queue_ = nullptr;
id<MTLCommandQueue> transfer_queue_ = nullptr;
std::shared_ptr<ShaderLibrary> shader_library_;
std::shared_ptr<PipelineLibrary> pipeline_library_;
std::shared_ptr<SamplerLibrary> sampler_library_;
std::shared_ptr<Allocator> permanents_allocator_;
std::shared_ptr<Allocator> transients_allocator_;
bool is_valid_ = false;
FML_DISALLOW_COPY_AND_ASSIGN(Context);
};

View File

@ -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<ShaderLibrary>(new ShaderLibrary(library));
}
// Setup the pipeline library.
{ //
pipeline_library_ =
std::shared_ptr<PipelineLibrary>(new PipelineLibrary(device_));
}
// Setup the sampler library.
{ //
sampler_library_ =
std::shared_ptr<SamplerLibrary>(new SamplerLibrary(device_));
}
{
transients_allocator_ = std::shared_ptr<Allocator>(
new Allocator(device_, "Impeller Transients Allocator"));
if (!transients_allocator_) {
return;
}
permanents_allocator_ = std::shared_ptr<Allocator>(
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<ShaderLibrary> Context::GetShaderLibrary() const {
return shader_library_;
}
std::shared_ptr<PipelineLibrary> Context::GetPipelineLibrary() const {
return pipeline_library_;
}
std::shared_ptr<SamplerLibrary> Context::GetSamplerLibrary() const {
return sampler_library_;
}
std::shared_ptr<CommandBuffer> Context::CreateRenderCommandBuffer() const {
if (!IsValid()) {
return nullptr;
}
auto buffer =
std::shared_ptr<CommandBuffer>(new CommandBuffer(render_queue_));
if (!buffer->IsValid()) {
return nullptr;
}
return buffer;
}
std::shared_ptr<Allocator> Context::GetPermanentsAllocator() const {
return permanents_allocator_;
}
std::shared_ptr<Allocator> Context::GetTransientsAllocator() const {
return transients_allocator_;
}
id<MTLDevice> Context::GetMTLDevice() const {
return device_;
}
} // namespace impeller

View File

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

View File

@ -4,8 +4,6 @@
#pragma once
#include <Metal/Metal.h>
#include <memory>
#include <string>
@ -18,14 +16,14 @@
namespace impeller {
class DeviceBuffer final : public Buffer,
public std::enable_shared_from_this<DeviceBuffer> {
class DeviceBuffer : public Buffer,
public std::enable_shared_from_this<DeviceBuffer> {
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<Texture> MakeTexture(TextureDescriptor desc,
size_t offset = 0u) const;
virtual std::shared_ptr<Texture> MakeTexture(TextureDescriptor desc,
size_t offset = 0u) const = 0;
id<MTLBuffer> 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<MTLBuffer> buffer_;
const size_t size_;
const StorageMode mode_;
DeviceBuffer(id<MTLBuffer> buffer, size_t size, StorageMode mode);
// |Buffer|
std::shared_ptr<const DeviceBuffer> GetDeviceBuffer(
Allocator& allocator) const override;
FML_DISALLOW_COPY_AND_ASSIGN(DeviceBuffer);
};

View File

@ -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<MTLBuffer> buffer, size_t size, StorageMode mode)
: buffer_(buffer), size_(size), mode_(mode) {}
DeviceBuffer::~DeviceBuffer() = default;
id<MTLBuffer> DeviceBuffer::GetMTLBuffer() const {
return buffer_;
}
std::shared_ptr<Texture> 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<Texture>(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<uint8_t*>(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<const DeviceBuffer> 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

View File

@ -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 <memory>
#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<PipelineDepthAttachment> depth,
std::optional<PipelineStencilAttachment> front,
std::optional<PipelineStencilAttachment> 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<TextureUsageMask>(TextureUsage::kUnknown)) {
mtl_desc.usage |= MTLTextureUsageUnknown;
}
if (desc.usage & static_cast<TextureUsageMask>(TextureUsage::kShaderRead)) {
mtl_desc.usage |= MTLTextureUsageShaderRead;
}
if (desc.usage & static_cast<TextureUsageMask>(TextureUsage::kShaderWrite)) {
mtl_desc.usage |= MTLTextureUsageShaderWrite;
}
if (desc.usage & static_cast<TextureUsageMask>(TextureUsage::kRenderTarget)) {
mtl_desc.usage |= MTLTextureUsageRenderTarget;
}
return mtl_desc;
}
} // namespace impeller

View File

@ -9,30 +9,10 @@
namespace impeller {
Pipeline::Pipeline(id<MTLRenderPipelineState> state,
id<MTLDepthStencilState> 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<MTLRenderPipelineState> Pipeline::GetMTLRenderPipelineState() const {
return pipeline_state_;
}
id<MTLDepthStencilState> Pipeline::GetMTLDepthStencilState() const {
return depth_stencil_state_;
}
PipelineFuture CreatePipelineFuture(const Context& context,
std::optional<PipelineDescriptor> desc) {
if (!context.IsValid()) {

View File

@ -4,8 +4,6 @@
#pragma once
#include <Metal/Metal.h>
#include <future>
#include "flutter/fml/macros.h"
@ -26,25 +24,14 @@ class Pipeline {
kRender,
};
~Pipeline();
virtual ~Pipeline();
bool IsValid() const;
virtual bool IsValid() const = 0;
id<MTLRenderPipelineState> GetMTLRenderPipelineState() const;
id<MTLDepthStencilState> GetMTLDepthStencilState() const;
protected:
Pipeline();
private:
friend class PipelineLibrary;
Type type_ = Type::kUnknown;
id<MTLRenderPipelineState> pipeline_state_;
id<MTLDepthStencilState> depth_stencil_state_;
bool is_valid_ = false;
Pipeline(id<MTLRenderPipelineState> state,
id<MTLDepthStencilState> depth_stencil_state);
FML_DISALLOW_COPY_AND_ASSIGN(Pipeline);
};

View File

@ -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<MTLDepthStencilState> PipelineDescriptor::CreateDepthStencilDescriptor(
id<MTLDevice> device) const {
auto descriptor =
ToMTLDepthStencilDescriptor(depth_attachment_descriptor_, //
front_stencil_attachment_descriptor_, //
back_stencil_attachment_descriptor_ //
);
return [device newDepthStencilStateWithDescriptor:descriptor];
}
} // namespace impeller

View File

@ -4,8 +4,6 @@
#pragma once
#include <Metal/Metal.h>
#include <functional>
#include <map>
#include <memory>
@ -30,16 +28,29 @@ class PipelineDescriptor final : public Comparable<PipelineDescriptor> {
~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<const ShaderFunction> function);
const std::map<ShaderStage, std::shared_ptr<const ShaderFunction>>&
GetStageEntrypoints() const {
return entrypoints_;
}
PipelineDescriptor& SetVertexDescriptor(
std::shared_ptr<PipelineVertexDescriptor> vertex_descriptor);
const std::shared_ptr<PipelineVertexDescriptor>& GetVertexDescriptor() const {
return vertex_descriptor_;
}
PipelineDescriptor& SetColorAttachmentDescriptor(
size_t index,
PipelineColorAttachment desc);
@ -47,9 +58,19 @@ class PipelineDescriptor final : public Comparable<PipelineDescriptor> {
const PipelineColorAttachment* GetColorAttachmentDescriptor(
size_t index) const;
const std::map<size_t /* index */, PipelineColorAttachment>
GetColorAttachmentDescriptors() const {
return color_attachment_descriptors_;
}
PipelineDescriptor& SetDepthStencilAttachmentDescriptor(
PipelineDepthAttachment desc);
std::optional<PipelineDepthAttachment> GetDepthStencilAttachmentDescriptor()
const {
return depth_attachment_descriptor_;
}
PipelineDescriptor& SetStencilAttachmentDescriptors(
PipelineStencilAttachment front_and_back);
@ -57,14 +78,23 @@ class PipelineDescriptor final : public Comparable<PipelineDescriptor> {
PipelineStencilAttachment front,
PipelineStencilAttachment back);
std::optional<PipelineStencilAttachment> GetFrontStencilAttachmentDescriptor()
const {
return front_stencil_attachment_descriptor_;
}
std::optional<PipelineStencilAttachment> 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<MTLDepthStencilState> CreateDepthStencilDescriptor(
id<MTLDevice> device) const;
PixelFormat GetStencilPixelFormat() const { return stencil_pixel_format_; }
// Comparable<PipelineDescriptor>
std::size_t GetHash() const override;
@ -76,7 +106,8 @@ class PipelineDescriptor final : public Comparable<PipelineDescriptor> {
std::string label_;
size_t sample_count_ = 1;
std::map<ShaderStage, std::shared_ptr<const ShaderFunction>> entrypoints_;
std::map<size_t, PipelineColorAttachment> color_attachment_descriptors_;
std::map<size_t /* index */, PipelineColorAttachment>
color_attachment_descriptors_;
std::shared_ptr<PipelineVertexDescriptor> vertex_descriptor_;
PixelFormat depth_pixel_format_ = PixelFormat::kUnknown;
PixelFormat stencil_pixel_format_ = PixelFormat::kUnknown;

View File

@ -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<PipelineDescriptor> descriptor) {
if (descriptor.has_value()) {
return GetRenderPipeline(std::move(descriptor.value()));
}
auto promise = std::make_shared<std::promise<std::shared_ptr<Pipeline>>>();
promise->set_value(nullptr);
return promise->get_future();
}
} // namespace impeller

View File

@ -4,10 +4,7 @@
#pragma once
#include <Metal/Metal.h>
#include <memory>
#include <unordered_map>
#include <optional>
#include "flutter/fml/macros.h"
#include "impeller/renderer/pipeline.h"
@ -19,28 +16,17 @@ class Context;
class PipelineLibrary : public std::enable_shared_from_this<PipelineLibrary> {
public:
~PipelineLibrary();
virtual ~PipelineLibrary();
PipelineFuture GetRenderPipeline(
std::optional<PipelineDescriptor> descriptor);
PipelineFuture GetRenderPipeline(PipelineDescriptor descriptor);
virtual PipelineFuture GetRenderPipeline(PipelineDescriptor descriptor) = 0;
protected:
PipelineLibrary();
private:
friend Context;
using Pipelines = std::unordered_map<PipelineDescriptor,
std::shared_ptr<const Pipeline>,
ComparableHash<PipelineDescriptor>,
ComparableEqual<PipelineDescriptor>>;
id<MTLDevice> device_ = nullptr;
Pipelines pipelines_;
PipelineLibrary(id<MTLDevice> device);
void SavePipeline(PipelineDescriptor descriptor,
std::shared_ptr<const Pipeline> pipeline);
FML_DISALLOW_COPY_AND_ASSIGN(PipelineLibrary);
};

View File

@ -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 <memory>
#include "flutter/fml/logging.h"
namespace impeller {
PipelineLibrary::PipelineLibrary(id<MTLDevice> device) : device_(device) {}
PipelineLibrary::~PipelineLibrary() = default;
std::future<std::shared_ptr<Pipeline>> PipelineLibrary::GetRenderPipeline(
std::optional<PipelineDescriptor> descriptor) {
if (descriptor.has_value()) {
return GetRenderPipeline(std::move(descriptor.value()));
}
auto promise = std::make_shared<std::promise<std::shared_ptr<Pipeline>>>();
promise->set_value(nullptr);
return promise->get_future();
}
std::future<std::shared_ptr<Pipeline>> PipelineLibrary::GetRenderPipeline(
PipelineDescriptor descriptor) {
auto promise = std::make_shared<std::promise<std::shared_ptr<Pipeline>>>();
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<MTLRenderPipelineState> _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<Pipeline>(
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<const Pipeline> pipeline) {
pipelines_[descriptor] = std::move(pipeline);
}
} // namespace impeller

View File

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

View File

@ -4,35 +4,26 @@
#pragma once
#include <Metal/Metal.h>
#include <string>
#include <map>
#include <vector>
#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<MTLCommandBuffer> buffer_ = nil;
MTLRenderPassDescriptor* desc_ = nil;
std::vector<Command> commands_;
std::shared_ptr<HostBuffer> transients_buffer_;
std::string label_;
bool is_valid_ = false;
RenderPass(id<MTLCommandBuffer> buffer, const RenderPassDescriptor& desc);
bool EncodeCommands(Allocator& transients_allocator,
id<MTLRenderCommandEncoder> pass) const;
FML_DISALLOW_COPY_AND_ASSIGN(RenderPass);
};

View File

@ -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 <map>
#include <set>
#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<MTLCommandBuffer> 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<MTLRenderCommandEncoder> pass) : pass_(pass) {}
PassBindingsCache(const PassBindingsCache&) = delete;
PassBindingsCache(PassBindingsCache&&) = delete;
void SetRenderPipelineState(id<MTLRenderPipelineState> pipeline) {
if (pipeline == pipeline_) {
return;
}
pipeline_ = pipeline;
[pass_ setRenderPipelineState:pipeline_];
}
void SetDepthStencilState(id<MTLDepthStencilState> 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<MTLBuffer> 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<MTLTexture> 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<MTLSamplerState> 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<MTLBuffer> buffer = nullptr;
size_t offset = 0u;
};
using BufferMap = std::map<uint64_t, BufferOffsetPair>;
using TextureMap = std::map<uint64_t, id<MTLTexture>>;
using SamplerMap = std::map<uint64_t, id<MTLSamplerState>>;
const id<MTLRenderCommandEncoder> pass_;
id<MTLRenderPipelineState> pipeline_ = nullptr;
id<MTLDepthStencilState> depth_stencil_ = nullptr;
std::map<ShaderStage, BufferMap> buffers_;
std::map<ShaderStage, TextureMap> textures_;
std::map<ShaderStage, SamplerMap> 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<MTLRenderCommandEncoder> 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

View File

@ -7,8 +7,6 @@
#include <map>
#include <optional>
#include <Metal/Metal.h>
#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<size_t, RenderPassColorAttachment> colors_;
std::optional<RenderPassDepthAttachment> depth_;

View File

@ -23,7 +23,7 @@ class Renderer {
using RenderCallback =
std::function<bool(const Surface& surface, RenderPass& pass)>;
Renderer(std::string shaders_directory, std::string main_library_file);
Renderer(std::shared_ptr<Context> context);
~Renderer();

View File

@ -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> context)
: frames_in_flight_sema_(::dispatch_semaphore_create(kMaxFramesInFlight)),
context_(std::make_shared<Context>(std::move(shaders_directory),
std::move(main_library_file))) {
context_(std::move(context)) {
if (!context_->IsValid()) {
return;
}

View File

@ -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"

View File

@ -6,16 +6,8 @@
namespace impeller {
Sampler::Sampler(id<MTLSamplerState> state) : state_(state) {}
Sampler::Sampler() = default;
Sampler::~Sampler() = default;
bool Sampler::IsValid() const {
return state_;
}
id<MTLSamplerState> Sampler::GetMTLSamplerState() const {
return state_;
}
} // namespace impeller

View File

@ -4,29 +4,20 @@
#pragma once
#include <Metal/Metal.h>
#include "flutter/fml/macros.h"
namespace impeller {
class SamplerLibrary;
class Sampler {
public:
bool IsValid() const;
virtual ~Sampler();
~Sampler();
virtual bool IsValid() const = 0;
id<MTLSamplerState> GetMTLSamplerState() const;
protected:
Sampler();
private:
friend SamplerLibrary;
id<MTLSamplerState> state_ = nullptr;
Sampler(id<MTLSamplerState> state);
FML_DISALLOW_COPY_AND_ASSIGN(Sampler);
};

View File

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

View File

@ -4,10 +4,6 @@
#pragma once
#include <Metal/Metal.h>
#include <unordered_map>
#include "flutter/fml/macros.h"
#include "impeller/renderer/comparable.h"
#include "impeller/renderer/formats.h"
@ -40,25 +36,4 @@ struct SamplerDescriptor final : public Comparable<SamplerDescriptor> {
}
};
class SamplerLibrary {
public:
~SamplerLibrary();
std::shared_ptr<const Sampler> GetSampler(SamplerDescriptor descriptor);
private:
friend Context;
using Samplers = std::unordered_map<SamplerDescriptor,
std::shared_ptr<const Sampler>,
ComparableHash<SamplerDescriptor>,
ComparableEqual<SamplerDescriptor>>;
id<MTLDevice> device_ = nullptr;
Samplers samplers_;
SamplerLibrary(id<MTLDevice> device);
FML_DISALLOW_COPY_AND_ASSIGN(SamplerLibrary);
};
} // namespace impeller

View File

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

View File

@ -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 <unordered_map>
#include "flutter/fml/macros.h"
#include "impeller/renderer/sampler_descriptor.h"
namespace impeller {
class SamplerLibrary {
public:
virtual ~SamplerLibrary();
virtual std::shared_ptr<const Sampler> GetSampler(
SamplerDescriptor descriptor) = 0;
protected:
SamplerLibrary();
private:
FML_DISALLOW_COPY_AND_ASSIGN(SamplerLibrary);
};
} // namespace impeller

View File

@ -7,20 +7,14 @@
namespace impeller {
ShaderFunction::ShaderFunction(UniqueID parent_library_id,
id<MTLFunction> function,
std::string name,
ShaderStage stage)
: parent_library_id_(parent_library_id),
function_(function),
name_(std::move(name)),
stage_(stage) {}
ShaderFunction::~ShaderFunction() = default;
id<MTLFunction> ShaderFunction::GetMTLFunction() const {
return function_;
}
ShaderStage ShaderFunction::GetStage() const {
return stage_;
}

View File

@ -4,8 +4,6 @@
#pragma once
#include <Metal/Metal.h>
#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<ShaderFunction> {
public:
// |Comparable<ShaderFunction>|
virtual ~ShaderFunction();
ShaderStage GetStage() const;
id<MTLFunction> GetMTLFunction() const;
// |Comparable<ShaderFunction>|
std::size_t GetHash() const override;
// |Comparable<ShaderFunction>|
bool IsEqual(const ShaderFunction& other) const override;
private:
friend class ShaderLibrary;
UniqueID parent_library_id_;
id<MTLFunction> function_ = nullptr;
std::string name_;
ShaderStage stage_;
protected:
ShaderFunction(UniqueID parent_library_id,
id<MTLFunction> function,
std::string name,
ShaderStage stage);
private:
UniqueID parent_library_id_;
std::string name_;
ShaderStage stage_;
FML_DISALLOW_COPY_AND_ASSIGN(ShaderFunction);
};

View File

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

View File

@ -4,64 +4,29 @@
#pragma once
#include <Metal/Metal.h>
#include <memory>
#include <string>
#include <string_view>
#include <unordered_map>
#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<const ShaderFunction> GetFunction(
virtual std::shared_ptr<const ShaderFunction> 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,
std::shared_ptr<const ShaderFunction>,
ShaderKey::Hash,
ShaderKey::Equal>;
UniqueID library_id_;
id<MTLLibrary> library_ = nullptr;
Functions functions_;
ShaderLibrary(id<MTLLibrary> library);
FML_DISALLOW_COPY_AND_ASSIGN(ShaderLibrary);
};

View File

@ -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<MTLLibrary> library) : library_(library) {}
ShaderLibrary::~ShaderLibrary() = default;
std::shared_ptr<const ShaderFunction> 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<ShaderFunction>(new ShaderFunction(
library_id_, function, {name.data(), name.size()}, stage));
functions_[key] = func;
return func;
}
} // namespace impeller

View File

@ -4,14 +4,13 @@
#pragma once
#include <Metal/Metal.h>
#include <functional>
#include <memory>
#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 {

View File

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

View File

@ -6,8 +6,6 @@
#include <string_view>
#include <Metal/Metal.h>
#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<MTLTexture> 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<MTLTexture> GetMTLTexture() const;
protected:
Texture(TextureDescriptor desc);
private:
const TextureDescriptor desc_;
id<MTLTexture> texture_ = nullptr;
bool is_valid_ = false;
FML_DISALLOW_COPY_AND_ASSIGN(Texture);
};

View File

@ -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<MTLTexture> 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<ISize::Type>(texture_.width),
static_cast<ISize::Type>(texture_.height)};
}
id<MTLTexture> Texture::GetMTLTexture() const {
return texture_;
}
bool Texture::IsValid() const {
return is_valid_;
}
} // namespace impeller

View File

@ -4,8 +4,6 @@
#pragma once
#include <Metal/Metal.h>
#include <vector>
#include "flutter/fml/macros.h"