diff --git a/engine/src/flutter/impeller/compositor/allocator.h b/engine/src/flutter/impeller/compositor/allocator.h index 9f306180b8e..4b3222026eb 100644 --- a/engine/src/flutter/impeller/compositor/allocator.h +++ b/engine/src/flutter/impeller/compositor/allocator.h @@ -10,6 +10,7 @@ #include "flutter/fml/macros.h" #include "flutter/fml/mapping.h" +#include "impeller/compositor/texture_descriptor.h" namespace impeller { @@ -46,6 +47,7 @@ enum class StorageMode { class Context; class DeviceBuffer; +class Texture; class Allocator { public: @@ -55,6 +57,9 @@ class Allocator { std::shared_ptr CreateBuffer(StorageMode mode, size_t length); + std::shared_ptr CreateTexture(StorageMode mode, + const TextureDescriptor& desc); + std::shared_ptr CreateBufferWithCopy(const uint8_t* buffer, size_t length); diff --git a/engine/src/flutter/impeller/compositor/allocator.mm b/engine/src/flutter/impeller/compositor/allocator.mm index a94d171d9f2..99cb0c1c1e1 100644 --- a/engine/src/flutter/impeller/compositor/allocator.mm +++ b/engine/src/flutter/impeller/compositor/allocator.mm @@ -8,6 +8,7 @@ #include "flutter/fml/logging.h" #include "impeller/compositor/buffer.h" #include "impeller/compositor/device_buffer.h" +#include "impeller/compositor/formats_metal.h" namespace impeller { @@ -26,11 +27,11 @@ bool Allocator::IsValid() const { return is_valid_; } -static MTLResourceOptions ResourceOptionsFromStorageType(StorageMode type) { +static MTLResourceOptions ToMTLResourceOptions(StorageMode type) { switch (type) { case StorageMode::kHostVisible: #if OS_IOS - return MTLStorageModeShared; + return MTLResourceStorageModeShared; #else return MTLResourceStorageModeManaged; #endif @@ -38,11 +39,33 @@ static MTLResourceOptions ResourceOptionsFromStorageType(StorageMode type) { return MTLResourceStorageModePrivate; case StorageMode::kDeviceTransient: #if OS_IOS - return MTLStorageModeMemoryless; + 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) { @@ -59,6 +82,16 @@ bool Allocator::RequiresExplicitHostSynchronization(StorageMode mode) { #endif } +std::shared_ptr Allocator::CreateBuffer(StorageMode mode, + size_t length) { + auto buffer = [device_ newBufferWithLength:length + options:ToMTLResourceOptions(mode)]; + if (!buffer) { + return nullptr; + } + return std::shared_ptr(new DeviceBuffer(buffer, length, mode)); +} + std::shared_ptr Allocator::CreateBufferWithCopy( const uint8_t* buffer, size_t length) { @@ -82,15 +115,20 @@ std::shared_ptr Allocator::CreateBufferWithCopy( return CreateBufferWithCopy(mapping.GetMapping(), mapping.GetSize()); } -std::shared_ptr Allocator::CreateBuffer(StorageMode mode, - size_t length) { - auto buffer = - [device_ newBufferWithLength:length - options:ResourceOptionsFromStorageType(mode)]; - if (!buffer) { +std::shared_ptr Allocator::CreateTexture( + StorageMode mode, + const TextureDescriptor& desc) { + if (!IsValid()) { return nullptr; } - return std::shared_ptr(new DeviceBuffer(buffer, length, mode)); + + auto mtl_texture_desc = ToMTLTextureDescriptor(desc); + mtl_texture_desc.storageMode = ToMTLStorageMode(mode); + auto texture = [device_ newTextureWithDescriptor:mtl_texture_desc]; + if (!texture) { + return nullptr; + } + return std::make_shared(desc, texture); } } // namespace impeller diff --git a/engine/src/flutter/impeller/compositor/device_buffer.mm b/engine/src/flutter/impeller/compositor/device_buffer.mm index cbc84aa0768..ceb8c17f7de 100644 --- a/engine/src/flutter/impeller/compositor/device_buffer.mm +++ b/engine/src/flutter/impeller/compositor/device_buffer.mm @@ -30,20 +30,14 @@ std::shared_ptr DeviceBuffer::MakeTexture(TextureDescriptor desc, return nullptr; } - 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; - - auto texture = [buffer_ newTextureWithDescriptor:mtl_desc + auto texture = [buffer_ newTextureWithDescriptor:ToMTLTextureDescriptor(desc) offset:offset bytesPerRow:desc.GetBytesPerRow()]; if (!texture) { return nullptr; } - return std::make_shared(texture); + return std::make_shared(desc, texture); } [[nodiscard]] bool DeviceBuffer::CopyHostBuffer(const uint8_t* source, diff --git a/engine/src/flutter/impeller/compositor/formats_metal.h b/engine/src/flutter/impeller/compositor/formats_metal.h index 08aa2a8fadc..cea758a5b7c 100644 --- a/engine/src/flutter/impeller/compositor/formats_metal.h +++ b/engine/src/flutter/impeller/compositor/formats_metal.h @@ -10,6 +10,7 @@ #include "flutter/fml/macros.h" #include "impeller/compositor/formats.h" +#include "impeller/compositor/texture_descriptor.h" #include "impeller/geometry/color.h" namespace impeller { @@ -244,8 +245,6 @@ constexpr MTLClearColor ToMTLClearColor(const Color& color) { return MTLClearColorMake(color.red, color.green, color.blue, color.alpha); } -RenderPassDescriptor FromMTLRenderPassDescriptor(MTLRenderPassDescriptor*); - MTLRenderPipelineColorAttachmentDescriptor* ToMTLRenderPipelineColorAttachmentDescriptor( ColorAttachmentDescriptor descriptor); @@ -255,4 +254,6 @@ MTLDepthStencilDescriptor* ToMTLDepthStencilDescriptor( std::optional front, std::optional back); +MTLTextureDescriptor* ToMTLTextureDescriptor(const TextureDescriptor& desc); + } // namespace impeller diff --git a/engine/src/flutter/impeller/compositor/formats_metal.mm b/engine/src/flutter/impeller/compositor/formats_metal.mm index 1e9ea463f88..cef3c06ba67 100644 --- a/engine/src/flutter/impeller/compositor/formats_metal.mm +++ b/engine/src/flutter/impeller/compositor/formats_metal.mm @@ -77,61 +77,13 @@ MTLDepthStencilDescriptor* ToMTLDepthStencilDescriptor( return des; } -static bool ConfigureRenderPassAttachment( - RenderPassAttachment& attachment, - MTLRenderPassAttachmentDescriptor* desc) { - attachment.texture = std::make_shared(desc.texture); - attachment.load_action = FromMTLLoadAction(desc.loadAction); - attachment.store_action = FromMTLStoreAction(desc.storeAction); - return attachment; -} - -static ColorRenderPassAttachment FromMTLRenderPassColorAttachmentDescriptor( - MTLRenderPassColorAttachmentDescriptor* desc) { - ColorRenderPassAttachment attachment; - ConfigureRenderPassAttachment(attachment, desc); - auto clear = desc.clearColor; - attachment.clear_color = - Color{static_cast(clear.red), static_cast(clear.green), - static_cast(clear.blue), static_cast(clear.alpha)}; - return attachment; -} - -static DepthRenderPassAttachment FromMTLRenderPassDepthAttachmentDescriptor( - MTLRenderPassDepthAttachmentDescriptor* desc) { - DepthRenderPassAttachment attachment; - ConfigureRenderPassAttachment(attachment, desc); - attachment.clear_depth = desc.clearDepth; - return attachment; -} - -static StencilRenderPassAttachment FromMTLRenderPassStencilAttachmentDescriptor( - MTLRenderPassStencilAttachmentDescriptor* desc) { - StencilRenderPassAttachment attachment; - ConfigureRenderPassAttachment(attachment, desc); - attachment.clear_stencil = desc.clearStencil; - return attachment; -} - -RenderPassDescriptor FromMTLRenderPassDescriptor( - MTLRenderPassDescriptor* desc) { - RenderPassDescriptor result; - if (!desc) { - return result; - } - - // From https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf - constexpr size_t kMaxPossibleColorAttachments = 8u; - for (size_t i = 0; i < kMaxPossibleColorAttachments; i++) { - result.SetColorAttachment( - FromMTLRenderPassColorAttachmentDescriptor(desc.colorAttachments[i]), - i); - } - result.SetDepthAttachment( - FromMTLRenderPassDepthAttachmentDescriptor(desc.depthAttachment)); - result.SetStencilAttachment( - FromMTLRenderPassStencilAttachmentDescriptor(desc.stencilAttachment)); - return result; +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; + return mtl_desc; } } // namespace impeller diff --git a/engine/src/flutter/impeller/compositor/render_pass.h b/engine/src/flutter/impeller/compositor/render_pass.h index 7c0a089760e..70688bc3548 100644 --- a/engine/src/flutter/impeller/compositor/render_pass.h +++ b/engine/src/flutter/impeller/compositor/render_pass.h @@ -49,7 +49,7 @@ class RenderPassDescriptor { bool HasColorAttachment(size_t index) const; - std::optional GetColorAttachmentSize(size_t index) const; + std::optional GetColorAttachmentSize(size_t index) const; RenderPassDescriptor& SetColorAttachment(ColorRenderPassAttachment attachment, size_t index); diff --git a/engine/src/flutter/impeller/compositor/render_pass.mm b/engine/src/flutter/impeller/compositor/render_pass.mm index 5e77e885450..206aecab551 100644 --- a/engine/src/flutter/impeller/compositor/render_pass.mm +++ b/engine/src/flutter/impeller/compositor/render_pass.mm @@ -25,7 +25,7 @@ bool RenderPassDescriptor::HasColorAttachment(size_t index) const { return false; } -std::optional RenderPassDescriptor::GetColorAttachmentSize( +std::optional RenderPassDescriptor::GetColorAttachmentSize( size_t index) const { auto found = colors_.find(index); diff --git a/engine/src/flutter/impeller/compositor/surface.h b/engine/src/flutter/impeller/compositor/surface.h index edb0e50a132..b71b209602d 100644 --- a/engine/src/flutter/impeller/compositor/surface.h +++ b/engine/src/flutter/impeller/compositor/surface.h @@ -21,7 +21,7 @@ class Surface { ~Surface(); - const Size& GetSize() const; + const ISize& GetSize() const; bool IsValid() const; @@ -29,7 +29,7 @@ class Surface { private: RenderPassDescriptor desc_; - Size size_; + ISize size_; bool is_valid_ = false; diff --git a/engine/src/flutter/impeller/compositor/surface.mm b/engine/src/flutter/impeller/compositor/surface.mm index dfcd330d315..6e16d21cf25 100644 --- a/engine/src/flutter/impeller/compositor/surface.mm +++ b/engine/src/flutter/impeller/compositor/surface.mm @@ -21,7 +21,7 @@ Surface::Surface(RenderPassDescriptor target_desc) Surface::~Surface() = default; -const Size& Surface::GetSize() const { +const ISize& Surface::GetSize() const { return size_; } diff --git a/engine/src/flutter/impeller/compositor/texture.h b/engine/src/flutter/impeller/compositor/texture.h index f1767b90fb5..a4fe87f818a 100644 --- a/engine/src/flutter/impeller/compositor/texture.h +++ b/engine/src/flutter/impeller/compositor/texture.h @@ -4,6 +4,8 @@ #pragma once +#include + #include #include "flutter/fml/macros.h" @@ -15,18 +17,26 @@ namespace impeller { class Texture { public: - Texture(id texture); + Texture(TextureDescriptor desc, id texture); ~Texture(); + void SetLabel(const std::string_view& label); + + [[nodiscard]] bool SetContents(const uint8_t* contents, + size_t length, + size_t mip_level = 0u); + bool IsValid() const; - Size GetSize() const; + ISize GetSize() const; id GetMTLTexture() const; private: - id texture_; + const TextureDescriptor desc_; + id texture_ = nullptr; + bool is_valid_ = false; FML_DISALLOW_COPY_AND_ASSIGN(Texture); }; diff --git a/engine/src/flutter/impeller/compositor/texture.mm b/engine/src/flutter/impeller/compositor/texture.mm index eca5825930e..b1dff469be8 100644 --- a/engine/src/flutter/impeller/compositor/texture.mm +++ b/engine/src/flutter/impeller/compositor/texture.mm @@ -6,13 +6,39 @@ namespace impeller { -Texture::Texture(id texture) : texture_(texture) {} +Texture::Texture(TextureDescriptor desc, id texture) + : desc_(std::move(desc)), texture_(texture) { + if (!desc_.IsValid() || !texture_) { + return; + } + + is_valid_ = true; +} Texture::~Texture() = default; -Size Texture::GetSize() const { - return {static_cast(texture_.width), - static_cast(texture_.height)}; +bool Texture::SetContents(const uint8_t* contents, + size_t length, + size_t mip_level) { + if (!IsValid() || !contents) { + return false; + } + + FML_CHECK(false); + return false; + + // MTLRegionMake2D(NSUInteger x, NSUInteger y, NSUInteger width, + // NSUInteger height) + + // [texture_ replaceRegion:(MTLRegion) + // mipmapLevel:(NSUInteger)withBytes:(nonnull const + // void*)bytesPerRow + // :(NSUInteger)]; +} + +ISize Texture::GetSize() const { + return {static_cast(texture_.width), + static_cast(texture_.height)}; } id Texture::GetMTLTexture() const { @@ -20,7 +46,7 @@ id Texture::GetMTLTexture() const { } bool Texture::IsValid() const { - return texture_; + return is_valid_; } } // namespace impeller diff --git a/engine/src/flutter/impeller/geometry/matrix.h b/engine/src/flutter/impeller/geometry/matrix.h index c2c5310acb6..e90cdb594e6 100644 --- a/engine/src/flutter/impeller/geometry/matrix.h +++ b/engine/src/flutter/impeller/geometry/matrix.h @@ -269,9 +269,9 @@ struct Matrix { Matrix operator+(const Matrix& m) const; - static constexpr Matrix MakeOrthographic(const Size& size) { + static constexpr Matrix MakeOrthographic(Scalar width, Scalar height) { // Per assumptions about NDC documented above. - const auto scale = MakeScale({1.0f / size.width, -1.0f / size.height, 1.0}); + const auto scale = MakeScale({1.0f / width, -1.0f / height, 1.0}); const auto translate = MakeTranslation({-1.0, 1.0, 0.5}); return translate * scale; } diff --git a/engine/src/flutter/impeller/playground/playground.mm b/engine/src/flutter/impeller/playground/playground.mm index 2fe879e8b8c..387beb894a3 100644 --- a/engine/src/flutter/impeller/playground/playground.mm +++ b/engine/src/flutter/impeller/playground/playground.mm @@ -7,6 +7,7 @@ #include "flutter/fml/paths.h" #include "flutter/testing/testing.h" #include "impeller/compositor/context.h" +#include "impeller/compositor/formats_metal.h" #include "impeller/compositor/render_pass.h" #include "impeller/compositor/renderer.h" #include "impeller/compositor/surface.h" @@ -108,8 +109,15 @@ bool Playground::OpenPlaygroundHere(Renderer::RenderCallback render_callback) { return false; } + TextureDescriptor color0_desc; + color0_desc.format = PixelFormat::kPixelFormat_B8G8R8A8_UNormInt; + color0_desc.size = { + static_cast(current_drawable.texture.width), + static_cast(current_drawable.texture.height)}; + ColorRenderPassAttachment color0; - color0.texture = std::make_shared(current_drawable.texture); + color0.texture = + std::make_shared(color0_desc, current_drawable.texture); color0.clear_color = Color::SkyBlue(); color0.load_action = LoadAction::kClear; color0.store_action = StoreAction::kStore; diff --git a/engine/src/flutter/impeller/primitives/primitives_unittests.mm b/engine/src/flutter/impeller/primitives/primitives_unittests.mm index a87b9b19f0f..2715cd39384 100644 --- a/engine/src/flutter/impeller/primitives/primitives_unittests.mm +++ b/engine/src/flutter/impeller/primitives/primitives_unittests.mm @@ -50,23 +50,20 @@ TEST_F(PrimitivesTest, CanCreateBoxPrimitive) { Image image(flutter::testing::OpenFixtureAsMapping("image.png")); auto result = image.Decode(); ASSERT_TRUE(result.IsValid()); - auto device_image_allocation = - context->GetPermanentsAllocator()->CreateBufferWithCopy( - *result.GetAllocation()); - device_image_allocation->SetLabel("Bay Bridge"); - ASSERT_TRUE(device_image_allocation); auto texture_descriptor = TextureDescriptor::MakeFromImageResult(result); ASSERT_TRUE(texture_descriptor.has_value()); - auto texture = - device_image_allocation->MakeTexture(texture_descriptor.value()); + auto texture = context->GetPermanentsAllocator()->CreateTexture( + StorageMode::kHostVisible, texture_descriptor.value()); ASSERT_TRUE(texture); + auto uploaded = texture->SetContents(result.GetAllocation()->GetMapping(), + result.GetAllocation()->GetSize()); + ASSERT_TRUE(uploaded); Renderer::RenderCallback callback = [&](const Surface& surface, RenderPass& pass) { BoxVertexShader::UniformBuffer uniforms; - - uniforms.mvp = Matrix::MakeOrthographic(surface.GetSize()); - + uniforms.mvp = Matrix::MakeOrthographic(surface.GetSize().width, + surface.GetSize().height); Command cmd; cmd.label = "Box"; cmd.pipeline = box_pipeline;