mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Start getting rid of ObjC TU's from core library.
This commit is contained in:
parent
1401218afc
commit
e129fbaba1
@ -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;
|
||||
|
||||
@ -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 = [
|
||||
|
||||
27
engine/src/flutter/impeller/renderer/allocator.cc
Normal file
27
engine/src/flutter/impeller/renderer/allocator.cc
Normal 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
|
||||
@ -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);
|
||||
};
|
||||
|
||||
|
||||
@ -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
|
||||
@ -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 = []
|
||||
}
|
||||
@ -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);
|
||||
};
|
||||
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
@ -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);
|
||||
};
|
||||
|
||||
|
||||
@ -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
|
||||
@ -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);
|
||||
};
|
||||
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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"
|
||||
@ -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);
|
||||
};
|
||||
|
||||
|
||||
@ -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
|
||||
@ -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);
|
||||
};
|
||||
|
||||
|
||||
@ -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
|
||||
@ -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);
|
||||
};
|
||||
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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;
|
||||
}
|
||||
@ -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);
|
||||
};
|
||||
|
||||
|
||||
@ -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
|
||||
@ -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);
|
||||
};
|
||||
|
||||
|
||||
@ -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
|
||||
@ -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);
|
||||
};
|
||||
|
||||
|
||||
@ -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
|
||||
@ -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);
|
||||
};
|
||||
|
||||
|
||||
@ -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
|
||||
@ -4,8 +4,6 @@
|
||||
|
||||
#include "impeller/renderer/command.h"
|
||||
|
||||
#include <Metal/Metal.h>
|
||||
|
||||
#include "impeller/renderer/vertex_descriptor.h"
|
||||
|
||||
namespace impeller {
|
||||
13
engine/src/flutter/impeller/renderer/command_buffer.cc
Normal file
13
engine/src/flutter/impeller/renderer/command_buffer.cc
Normal 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
|
||||
@ -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);
|
||||
};
|
||||
|
||||
|
||||
@ -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
|
||||
13
engine/src/flutter/impeller/renderer/context.cc
Normal file
13
engine/src/flutter/impeller/renderer/context.cc
Normal 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
|
||||
@ -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);
|
||||
};
|
||||
|
||||
|
||||
@ -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
|
||||
13
engine/src/flutter/impeller/renderer/device_buffer.cc
Normal file
13
engine/src/flutter/impeller/renderer/device_buffer.cc
Normal 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
|
||||
@ -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);
|
||||
};
|
||||
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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()) {
|
||||
@ -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);
|
||||
};
|
||||
|
||||
|
||||
@ -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
|
||||
@ -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;
|
||||
|
||||
23
engine/src/flutter/impeller/renderer/pipeline_library.cc
Normal file
23
engine/src/flutter/impeller/renderer/pipeline_library.cc
Normal 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
|
||||
@ -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);
|
||||
};
|
||||
|
||||
|
||||
@ -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
|
||||
13
engine/src/flutter/impeller/renderer/render_pass.cc
Normal file
13
engine/src/flutter/impeller/renderer/render_pass.cc
Normal 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
|
||||
@ -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);
|
||||
};
|
||||
|
||||
|
||||
@ -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
|
||||
@ -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_;
|
||||
|
||||
@ -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();
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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"
|
||||
@ -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
|
||||
@ -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);
|
||||
};
|
||||
|
||||
|
||||
11
engine/src/flutter/impeller/renderer/sampler_descriptor.cc
Normal file
11
engine/src/flutter/impeller/renderer/sampler_descriptor.cc
Normal 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
|
||||
@ -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
|
||||
|
||||
13
engine/src/flutter/impeller/renderer/sampler_library.cc
Normal file
13
engine/src/flutter/impeller/renderer/sampler_library.cc
Normal 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
|
||||
28
engine/src/flutter/impeller/renderer/sampler_library.h
Normal file
28
engine/src/flutter/impeller/renderer/sampler_library.h
Normal 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
|
||||
@ -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_;
|
||||
}
|
||||
@ -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);
|
||||
};
|
||||
|
||||
|
||||
13
engine/src/flutter/impeller/renderer/shader_library.cc
Normal file
13
engine/src/flutter/impeller/renderer/shader_library.cc
Normal 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
|
||||
@ -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);
|
||||
};
|
||||
|
||||
|
||||
@ -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
|
||||
@ -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 {
|
||||
|
||||
|
||||
17
engine/src/flutter/impeller/renderer/texture.cc
Normal file
17
engine/src/flutter/impeller/renderer/texture.cc
Normal 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
|
||||
@ -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);
|
||||
};
|
||||
|
||||
@ -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
|
||||
@ -4,8 +4,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Metal/Metal.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user