mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[Impeller] reland: directly encode blit commands for Metal. (flutter/engine#52819)
Fixes bad interaction with render pass clear patch, which potentially created an active blit and render pass encoder at the same time. Make sure that we start/finish the render pass before we start the blit pass.
This commit is contained in:
parent
c16a2409e5
commit
ff5ea29080
@ -42656,8 +42656,6 @@ ORIGIN: ../../../flutter/impeller/renderer/backend/gles/texture_gles.cc + ../../
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/gles/texture_gles.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/allocator_mtl.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/allocator_mtl.mm + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/blit_command_mtl.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/blit_command_mtl.mm + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/blit_pass_mtl.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/blit_pass_mtl.mm + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/command_buffer_mtl.h + ../../../flutter/LICENSE
|
||||
@ -45531,8 +45529,6 @@ FILE: ../../../flutter/impeller/renderer/backend/gles/texture_gles.cc
|
||||
FILE: ../../../flutter/impeller/renderer/backend/gles/texture_gles.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/metal/allocator_mtl.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/metal/allocator_mtl.mm
|
||||
FILE: ../../../flutter/impeller/renderer/backend/metal/blit_command_mtl.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/metal/blit_command_mtl.mm
|
||||
FILE: ../../../flutter/impeller/renderer/backend/metal/blit_pass_mtl.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/metal/blit_pass_mtl.mm
|
||||
FILE: ../../../flutter/impeller/renderer/backend/metal/command_buffer_mtl.h
|
||||
|
||||
@ -8,8 +8,6 @@ impeller_component("metal") {
|
||||
sources = [
|
||||
"allocator_mtl.h",
|
||||
"allocator_mtl.mm",
|
||||
"blit_command_mtl.h",
|
||||
"blit_command_mtl.mm",
|
||||
"blit_pass_mtl.h",
|
||||
"blit_pass_mtl.mm",
|
||||
"command_buffer_mtl.h",
|
||||
|
||||
@ -1,66 +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.
|
||||
|
||||
#ifndef FLUTTER_IMPELLER_RENDERER_BACKEND_METAL_BLIT_COMMAND_MTL_H_
|
||||
#define FLUTTER_IMPELLER_RENDERER_BACKEND_METAL_BLIT_COMMAND_MTL_H_
|
||||
|
||||
#include <Metal/Metal.h>
|
||||
|
||||
#include "impeller/base/backend_cast.h"
|
||||
#include "impeller/renderer/blit_command.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
/// Mixin for dispatching Metal commands.
|
||||
struct BlitEncodeMTL : BackendCast<BlitEncodeMTL, BlitCommand> {
|
||||
virtual ~BlitEncodeMTL();
|
||||
|
||||
virtual std::string GetLabel() const = 0;
|
||||
|
||||
[[nodiscard]] virtual bool Encode(
|
||||
id<MTLBlitCommandEncoder> encoder) const = 0;
|
||||
};
|
||||
|
||||
struct BlitCopyTextureToTextureCommandMTL
|
||||
: public BlitCopyTextureToTextureCommand,
|
||||
public BlitEncodeMTL {
|
||||
~BlitCopyTextureToTextureCommandMTL() override;
|
||||
|
||||
std::string GetLabel() const override;
|
||||
|
||||
[[nodiscard]] bool Encode(id<MTLBlitCommandEncoder> encoder) const override;
|
||||
};
|
||||
|
||||
struct BlitCopyTextureToBufferCommandMTL
|
||||
: public BlitCopyTextureToBufferCommand,
|
||||
public BlitEncodeMTL {
|
||||
~BlitCopyTextureToBufferCommandMTL() override;
|
||||
|
||||
std::string GetLabel() const override;
|
||||
|
||||
[[nodiscard]] bool Encode(id<MTLBlitCommandEncoder> encoder) const override;
|
||||
};
|
||||
|
||||
struct BlitGenerateMipmapCommandMTL : public BlitGenerateMipmapCommand,
|
||||
public BlitEncodeMTL {
|
||||
~BlitGenerateMipmapCommandMTL() override;
|
||||
|
||||
std::string GetLabel() const override;
|
||||
|
||||
[[nodiscard]] bool Encode(id<MTLBlitCommandEncoder> encoder) const override;
|
||||
};
|
||||
|
||||
struct BlitCopyBufferToTextureCommandMTL
|
||||
: public BlitCopyBufferToTextureCommand,
|
||||
public BlitEncodeMTL {
|
||||
~BlitCopyBufferToTextureCommandMTL() override;
|
||||
|
||||
std::string GetLabel() const override;
|
||||
|
||||
[[nodiscard]] bool Encode(id<MTLBlitCommandEncoder> encoder) const override;
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
#endif // FLUTTER_IMPELLER_RENDERER_BACKEND_METAL_BLIT_COMMAND_MTL_H_
|
||||
@ -1,152 +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/backend/metal/blit_command_mtl.h"
|
||||
|
||||
#include "impeller/renderer/backend/metal/device_buffer_mtl.h"
|
||||
#include "impeller/renderer/backend/metal/texture_mtl.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
BlitEncodeMTL::~BlitEncodeMTL() = default;
|
||||
|
||||
BlitCopyTextureToTextureCommandMTL::~BlitCopyTextureToTextureCommandMTL() =
|
||||
default;
|
||||
|
||||
std::string BlitCopyTextureToTextureCommandMTL::GetLabel() const {
|
||||
return label;
|
||||
}
|
||||
|
||||
bool BlitCopyTextureToTextureCommandMTL::Encode(
|
||||
id<MTLBlitCommandEncoder> encoder) const {
|
||||
auto source_mtl = TextureMTL::Cast(*source).GetMTLTexture();
|
||||
if (!source_mtl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto destination_mtl = TextureMTL::Cast(*destination).GetMTLTexture();
|
||||
if (!destination_mtl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto source_origin_mtl =
|
||||
MTLOriginMake(source_region.GetX(), source_region.GetY(), 0);
|
||||
auto source_size_mtl =
|
||||
MTLSizeMake(source_region.GetWidth(), source_region.GetHeight(), 1);
|
||||
auto destination_origin_mtl =
|
||||
MTLOriginMake(destination_origin.x, destination_origin.y, 0);
|
||||
|
||||
[encoder copyFromTexture:source_mtl
|
||||
sourceSlice:0
|
||||
sourceLevel:0
|
||||
sourceOrigin:source_origin_mtl
|
||||
sourceSize:source_size_mtl
|
||||
toTexture:destination_mtl
|
||||
destinationSlice:0
|
||||
destinationLevel:0
|
||||
destinationOrigin:destination_origin_mtl];
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
BlitCopyTextureToBufferCommandMTL::~BlitCopyTextureToBufferCommandMTL() =
|
||||
default;
|
||||
|
||||
std::string BlitCopyTextureToBufferCommandMTL::GetLabel() const {
|
||||
return label;
|
||||
}
|
||||
|
||||
bool BlitCopyTextureToBufferCommandMTL::Encode(
|
||||
id<MTLBlitCommandEncoder> encoder) const {
|
||||
auto source_mtl = TextureMTL::Cast(*source).GetMTLTexture();
|
||||
if (!source_mtl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto destination_mtl = DeviceBufferMTL::Cast(*destination).GetMTLBuffer();
|
||||
if (!destination_mtl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto source_origin_mtl =
|
||||
MTLOriginMake(source_region.GetX(), source_region.GetY(), 0);
|
||||
auto source_size_mtl =
|
||||
MTLSizeMake(source_region.GetWidth(), source_region.GetHeight(), 1);
|
||||
|
||||
auto destination_bytes_per_pixel =
|
||||
BytesPerPixelForPixelFormat(source->GetTextureDescriptor().format);
|
||||
auto destination_bytes_per_row =
|
||||
source_size_mtl.width * destination_bytes_per_pixel;
|
||||
auto destination_bytes_per_image =
|
||||
source_size_mtl.height * destination_bytes_per_row;
|
||||
|
||||
[encoder copyFromTexture:source_mtl
|
||||
sourceSlice:0
|
||||
sourceLevel:0
|
||||
sourceOrigin:source_origin_mtl
|
||||
sourceSize:source_size_mtl
|
||||
toBuffer:destination_mtl
|
||||
destinationOffset:destination_offset
|
||||
destinationBytesPerRow:destination_bytes_per_row
|
||||
destinationBytesPerImage:destination_bytes_per_image];
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
BlitCopyBufferToTextureCommandMTL::~BlitCopyBufferToTextureCommandMTL() =
|
||||
default;
|
||||
|
||||
std::string BlitCopyBufferToTextureCommandMTL::GetLabel() const {
|
||||
return label;
|
||||
}
|
||||
|
||||
bool BlitCopyBufferToTextureCommandMTL::Encode(
|
||||
id<MTLBlitCommandEncoder> encoder) const {
|
||||
auto source_mtl = DeviceBufferMTL::Cast(*source.buffer).GetMTLBuffer();
|
||||
if (!source_mtl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto destination_mtl = TextureMTL::Cast(*destination).GetMTLTexture();
|
||||
if (!destination_mtl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto destination_origin_mtl =
|
||||
MTLOriginMake(destination_region.GetX(), destination_region.GetY(), 0);
|
||||
auto source_size_mtl = MTLSizeMake(destination_region.GetWidth(),
|
||||
destination_region.GetHeight(), 1);
|
||||
|
||||
auto destination_bytes_per_pixel =
|
||||
BytesPerPixelForPixelFormat(destination->GetTextureDescriptor().format);
|
||||
auto source_bytes_per_row =
|
||||
destination_region.GetWidth() * destination_bytes_per_pixel;
|
||||
|
||||
[encoder copyFromBuffer:source_mtl
|
||||
sourceOffset:source.range.offset
|
||||
sourceBytesPerRow:source_bytes_per_row
|
||||
sourceBytesPerImage:
|
||||
0 // 0 for 2D textures according to
|
||||
// https://developer.apple.com/documentation/metal/mtlblitcommandencoder/1400752-copyfrombuffer
|
||||
sourceSize:source_size_mtl
|
||||
toTexture:destination_mtl
|
||||
destinationSlice:slice
|
||||
destinationLevel:0
|
||||
destinationOrigin:destination_origin_mtl];
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
BlitGenerateMipmapCommandMTL::~BlitGenerateMipmapCommandMTL() = default;
|
||||
|
||||
std::string BlitGenerateMipmapCommandMTL::GetLabel() const {
|
||||
return label;
|
||||
}
|
||||
|
||||
bool BlitGenerateMipmapCommandMTL::Encode(
|
||||
id<MTLBlitCommandEncoder> encoder) const {
|
||||
return TextureMTL::Cast(*texture).GenerateMipmap(encoder);
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
@ -7,7 +7,6 @@
|
||||
|
||||
#include <Metal/Metal.h>
|
||||
|
||||
#include "impeller/renderer/backend/metal/blit_command_mtl.h"
|
||||
#include "impeller/renderer/blit_pass.h"
|
||||
|
||||
namespace impeller {
|
||||
@ -20,10 +19,14 @@ class BlitPassMTL final : public BlitPass {
|
||||
private:
|
||||
friend class CommandBufferMTL;
|
||||
|
||||
std::vector<std::unique_ptr<BlitEncodeMTL>> commands_;
|
||||
id<MTLBlitCommandEncoder> encoder_ = nil;
|
||||
id<MTLCommandBuffer> buffer_ = nil;
|
||||
std::string label_;
|
||||
bool is_valid_ = false;
|
||||
bool is_metal_trace_active_ = false;
|
||||
// Many parts of the codebase will start writing to a render pass but
|
||||
// never submit them. This boolean is used to track if a submit happened
|
||||
// so that in the dtor we can always ensure the render pass is finished.
|
||||
mutable bool did_finish_encoding_ = false;
|
||||
|
||||
explicit BlitPassMTL(id<MTLCommandBuffer> buffer);
|
||||
|
||||
@ -37,8 +40,6 @@ class BlitPassMTL final : public BlitPass {
|
||||
bool EncodeCommands(
|
||||
const std::shared_ptr<Allocator>& transients_allocator) const override;
|
||||
|
||||
bool EncodeCommands(id<MTLBlitCommandEncoder> pass) const;
|
||||
|
||||
// |BlitPass|
|
||||
bool OnCopyTextureToTextureCommand(std::shared_ptr<Texture> source,
|
||||
std::shared_ptr<Texture> destination,
|
||||
|
||||
@ -15,12 +15,12 @@
|
||||
#include "impeller/core/formats.h"
|
||||
#include "impeller/core/host_buffer.h"
|
||||
#include "impeller/core/shader_types.h"
|
||||
#include "impeller/renderer/backend/metal/blit_command_mtl.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/blit_command.h"
|
||||
|
||||
namespace impeller {
|
||||
@ -29,10 +29,19 @@ BlitPassMTL::BlitPassMTL(id<MTLCommandBuffer> buffer) : buffer_(buffer) {
|
||||
if (!buffer_) {
|
||||
return;
|
||||
}
|
||||
encoder_ = [buffer_ blitCommandEncoder];
|
||||
#ifdef IMPELLER_DEBUG
|
||||
is_metal_trace_active_ =
|
||||
[[MTLCaptureManager sharedCaptureManager] isCapturing];
|
||||
#endif // IMPELLER_DEBUG
|
||||
is_valid_ = true;
|
||||
}
|
||||
|
||||
BlitPassMTL::~BlitPassMTL() = default;
|
||||
BlitPassMTL::~BlitPassMTL() {
|
||||
if (!did_finish_encoding_) {
|
||||
[encoder_ endEncoding];
|
||||
}
|
||||
}
|
||||
|
||||
bool BlitPassMTL::IsValid() const {
|
||||
return is_valid_;
|
||||
@ -42,49 +51,13 @@ void BlitPassMTL::OnSetLabel(std::string label) {
|
||||
if (label.empty()) {
|
||||
return;
|
||||
}
|
||||
label_ = std::move(label);
|
||||
[encoder_ setLabel:@(label.c_str())];
|
||||
}
|
||||
|
||||
bool BlitPassMTL::EncodeCommands(
|
||||
const std::shared_ptr<Allocator>& transients_allocator) const {
|
||||
TRACE_EVENT0("impeller", "BlitPassMTL::EncodeCommands");
|
||||
if (!IsValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto blit_command_encoder = [buffer_ blitCommandEncoder];
|
||||
|
||||
if (!blit_command_encoder) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!label_.empty()) {
|
||||
[blit_command_encoder 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(
|
||||
[blit_command_encoder]() { [blit_command_encoder endEncoding]; });
|
||||
|
||||
return EncodeCommands(blit_command_encoder);
|
||||
}
|
||||
|
||||
bool BlitPassMTL::EncodeCommands(id<MTLBlitCommandEncoder> encoder) const {
|
||||
fml::closure pop_debug_marker = [encoder]() { [encoder popDebugGroup]; };
|
||||
for (const auto& command : commands_) {
|
||||
fml::ScopedCleanupClosure auto_pop_debug_marker(pop_debug_marker);
|
||||
auto label = command->GetLabel();
|
||||
if (!label.empty()) {
|
||||
[encoder pushDebugGroup:@(label.c_str())];
|
||||
} else {
|
||||
auto_pop_debug_marker.Release();
|
||||
}
|
||||
|
||||
if (!command->Encode(encoder)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
[encoder_ endEncoding];
|
||||
did_finish_encoding_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -95,14 +68,44 @@ bool BlitPassMTL::OnCopyTextureToTextureCommand(
|
||||
IRect source_region,
|
||||
IPoint destination_origin,
|
||||
std::string label) {
|
||||
auto command = std::make_unique<BlitCopyTextureToTextureCommandMTL>();
|
||||
command->label = label;
|
||||
command->source = std::move(source);
|
||||
command->destination = std::move(destination);
|
||||
command->source_region = source_region;
|
||||
command->destination_origin = destination_origin;
|
||||
auto source_mtl = TextureMTL::Cast(*source).GetMTLTexture();
|
||||
if (!source_mtl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto destination_mtl = TextureMTL::Cast(*destination).GetMTLTexture();
|
||||
if (!destination_mtl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto source_origin_mtl =
|
||||
MTLOriginMake(source_region.GetX(), source_region.GetY(), 0);
|
||||
auto source_size_mtl =
|
||||
MTLSizeMake(source_region.GetWidth(), source_region.GetHeight(), 1);
|
||||
auto destination_origin_mtl =
|
||||
MTLOriginMake(destination_origin.x, destination_origin.y, 0);
|
||||
|
||||
#ifdef IMPELLER_DEBUG
|
||||
if (is_metal_trace_active_) {
|
||||
[encoder_ pushDebugGroup:@(label.c_str())];
|
||||
}
|
||||
#endif // IMPELLER_DEBUG
|
||||
[encoder_ copyFromTexture:source_mtl
|
||||
sourceSlice:0
|
||||
sourceLevel:0
|
||||
sourceOrigin:source_origin_mtl
|
||||
sourceSize:source_size_mtl
|
||||
toTexture:destination_mtl
|
||||
destinationSlice:0
|
||||
destinationLevel:0
|
||||
destinationOrigin:destination_origin_mtl];
|
||||
|
||||
#ifdef IMPELLER_DEBUG
|
||||
if (is_metal_trace_active_) {
|
||||
[encoder_ popDebugGroup];
|
||||
}
|
||||
#endif // IMPELLER_DEBUG
|
||||
|
||||
commands_.emplace_back(std::move(command));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -113,14 +116,48 @@ bool BlitPassMTL::OnCopyTextureToBufferCommand(
|
||||
IRect source_region,
|
||||
size_t destination_offset,
|
||||
std::string label) {
|
||||
auto command = std::make_unique<BlitCopyTextureToBufferCommandMTL>();
|
||||
command->label = label;
|
||||
command->source = std::move(source);
|
||||
command->destination = std::move(destination);
|
||||
command->source_region = source_region;
|
||||
command->destination_offset = destination_offset;
|
||||
auto source_mtl = TextureMTL::Cast(*source).GetMTLTexture();
|
||||
if (!source_mtl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
commands_.emplace_back(std::move(command));
|
||||
auto destination_mtl = DeviceBufferMTL::Cast(*destination).GetMTLBuffer();
|
||||
if (!destination_mtl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto source_origin_mtl =
|
||||
MTLOriginMake(source_region.GetX(), source_region.GetY(), 0);
|
||||
auto source_size_mtl =
|
||||
MTLSizeMake(source_region.GetWidth(), source_region.GetHeight(), 1);
|
||||
|
||||
auto destination_bytes_per_pixel =
|
||||
BytesPerPixelForPixelFormat(source->GetTextureDescriptor().format);
|
||||
auto destination_bytes_per_row =
|
||||
source_size_mtl.width * destination_bytes_per_pixel;
|
||||
auto destination_bytes_per_image =
|
||||
source_size_mtl.height * destination_bytes_per_row;
|
||||
|
||||
#ifdef IMPELLER_DEBUG
|
||||
if (is_metal_trace_active_) {
|
||||
[encoder_ pushDebugGroup:@(label.c_str())];
|
||||
}
|
||||
#endif // IMPELLER_DEBUG
|
||||
[encoder_ copyFromTexture:source_mtl
|
||||
sourceSlice:0
|
||||
sourceLevel:0
|
||||
sourceOrigin:source_origin_mtl
|
||||
sourceSize:source_size_mtl
|
||||
toBuffer:destination_mtl
|
||||
destinationOffset:destination_offset
|
||||
destinationBytesPerRow:destination_bytes_per_row
|
||||
destinationBytesPerImage:destination_bytes_per_image];
|
||||
|
||||
#ifdef IMPELLER_DEBUG
|
||||
if (is_metal_trace_active_) {
|
||||
[encoder_ popDebugGroup];
|
||||
}
|
||||
#endif // IMPELLER_DEBUG
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -130,26 +167,67 @@ bool BlitPassMTL::OnCopyBufferToTextureCommand(
|
||||
IRect destination_region,
|
||||
std::string label,
|
||||
uint32_t slice) {
|
||||
auto command = std::make_unique<BlitCopyBufferToTextureCommandMTL>();
|
||||
command->label = std::move(label);
|
||||
command->source = std::move(source);
|
||||
command->destination = std::move(destination);
|
||||
command->destination_region = destination_region;
|
||||
command->slice = slice;
|
||||
auto source_mtl = DeviceBufferMTL::Cast(*source.buffer).GetMTLBuffer();
|
||||
if (!source_mtl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
commands_.emplace_back(std::move(command));
|
||||
auto destination_mtl = TextureMTL::Cast(*destination).GetMTLTexture();
|
||||
if (!destination_mtl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto destination_origin_mtl =
|
||||
MTLOriginMake(destination_region.GetX(), destination_region.GetY(), 0);
|
||||
auto source_size_mtl = MTLSizeMake(destination_region.GetWidth(),
|
||||
destination_region.GetHeight(), 1);
|
||||
|
||||
auto destination_bytes_per_pixel =
|
||||
BytesPerPixelForPixelFormat(destination->GetTextureDescriptor().format);
|
||||
auto source_bytes_per_row =
|
||||
destination_region.GetWidth() * destination_bytes_per_pixel;
|
||||
|
||||
#ifdef IMPELLER_DEBUG
|
||||
if (is_metal_trace_active_) {
|
||||
[encoder_ pushDebugGroup:@(label.c_str())];
|
||||
}
|
||||
#endif // IMPELLER_DEBUG
|
||||
[encoder_
|
||||
copyFromBuffer:source_mtl
|
||||
sourceOffset:source.range.offset
|
||||
sourceBytesPerRow:source_bytes_per_row
|
||||
sourceBytesPerImage:
|
||||
0 // 0 for 2D textures according to
|
||||
// https://developer.apple.com/documentation/metal/mtlblitcommandencoder/1400752-copyfrombuffer
|
||||
sourceSize:source_size_mtl
|
||||
toTexture:destination_mtl
|
||||
destinationSlice:slice
|
||||
destinationLevel:0
|
||||
destinationOrigin:destination_origin_mtl];
|
||||
|
||||
#ifdef IMPELLER_DEBUG
|
||||
if (is_metal_trace_active_) {
|
||||
[encoder_ popDebugGroup];
|
||||
}
|
||||
#endif // IMPELLER_DEBUG
|
||||
return true;
|
||||
}
|
||||
|
||||
// |BlitPass|
|
||||
bool BlitPassMTL::OnGenerateMipmapCommand(std::shared_ptr<Texture> texture,
|
||||
std::string label) {
|
||||
auto command = std::make_unique<BlitGenerateMipmapCommandMTL>();
|
||||
command->label = label;
|
||||
command->texture = std::move(texture);
|
||||
|
||||
commands_.emplace_back(std::move(command));
|
||||
return true;
|
||||
#ifdef IMPELLER_DEBUG
|
||||
if (is_metal_trace_active_) {
|
||||
[encoder_ pushDebugGroup:@(label.c_str())];
|
||||
}
|
||||
#endif // IMPELLER_DEBUG
|
||||
auto result = TextureMTL::Cast(*texture).GenerateMipmap(encoder_);
|
||||
#ifdef IMPELLER_DEBUG
|
||||
if (is_metal_trace_active_) {
|
||||
[encoder_ popDebugGroup];
|
||||
}
|
||||
#endif // IMPELLER_DEBUG
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
@ -66,11 +66,13 @@ TEST_P(BlitPassTest, BlitPassesForMatchingFormats) {
|
||||
TextureDescriptor src_desc;
|
||||
src_desc.format = PixelFormat::kR8G8B8A8UNormInt;
|
||||
src_desc.size = {100, 100};
|
||||
src_desc.storage_mode = StorageMode::kHostVisible;
|
||||
auto src = context->GetResourceAllocator()->CreateTexture(src_desc);
|
||||
|
||||
TextureDescriptor dst_format;
|
||||
dst_format.format = PixelFormat::kR8G8B8A8UNormInt;
|
||||
dst_format.size = {100, 100};
|
||||
dst_format.storage_mode = StorageMode::kHostVisible;
|
||||
auto dst = context->GetResourceAllocator()->CreateTexture(dst_format);
|
||||
|
||||
EXPECT_TRUE(blit_pass->AddCopy(src, dst));
|
||||
|
||||
@ -306,43 +306,6 @@ static bool UpdateAtlasBitmap(const GlyphAtlas& atlas,
|
||||
return true;
|
||||
}
|
||||
|
||||
// The texture needs to be cleared to transparent black so that linearly
|
||||
// samplex rotated/skewed glyphs do not grab uninitialized data.
|
||||
bool ClearTextureToTransparentBlack(Context& context,
|
||||
HostBuffer& host_buffer,
|
||||
std::shared_ptr<CommandBuffer>& cmd_buffer,
|
||||
std::shared_ptr<BlitPass>& blit_pass,
|
||||
std::shared_ptr<Texture>& texture) {
|
||||
// The R8/A8 textures used for certain glyphs is not supported as color
|
||||
// attachments in most graphics drivers. To be safe, just do a CPU clear
|
||||
// for these.
|
||||
if (texture->GetTextureDescriptor().format ==
|
||||
context.GetCapabilities()->GetDefaultGlyphAtlasFormat()) {
|
||||
size_t byte_size =
|
||||
texture->GetTextureDescriptor().GetByteSizeOfBaseMipLevel();
|
||||
BufferView buffer_view =
|
||||
host_buffer.Emplace(nullptr, byte_size, DefaultUniformAlignment());
|
||||
|
||||
::memset(buffer_view.buffer->OnGetContents() + buffer_view.range.offset, 0,
|
||||
byte_size);
|
||||
buffer_view.buffer->Flush();
|
||||
return blit_pass->AddCopy(buffer_view, texture);
|
||||
}
|
||||
// In all other cases, we can use a render pass to clear to a transparent
|
||||
// color.
|
||||
ColorAttachment attachment;
|
||||
attachment.clear_color = Color::BlackTransparent();
|
||||
attachment.load_action = LoadAction::kClear;
|
||||
attachment.store_action = StoreAction::kStore;
|
||||
attachment.texture = texture;
|
||||
|
||||
RenderTarget render_target;
|
||||
render_target.SetColorAttachment(attachment, 0u);
|
||||
|
||||
auto render_pass = cmd_buffer->CreateRenderPass(render_target);
|
||||
return render_pass->EncodeCommands();
|
||||
}
|
||||
|
||||
std::shared_ptr<GlyphAtlas> TypographerContextSkia::CreateGlyphAtlas(
|
||||
Context& context,
|
||||
GlyphAtlas::Type type,
|
||||
@ -359,13 +322,6 @@ std::shared_ptr<GlyphAtlas> TypographerContextSkia::CreateGlyphAtlas(
|
||||
if (font_glyph_map.empty()) {
|
||||
return last_atlas;
|
||||
}
|
||||
std::shared_ptr<CommandBuffer> cmd_buffer = context.CreateCommandBuffer();
|
||||
std::shared_ptr<BlitPass> blit_pass = cmd_buffer->CreateBlitPass();
|
||||
|
||||
fml::ScopedCleanupClosure closure([&]() {
|
||||
blit_pass->EncodeCommands(context.GetResourceAllocator());
|
||||
context.GetCommandQueue()->Submit({std::move(cmd_buffer)});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Step 1: Determine if the atlas type and font glyph pairs are compatible
|
||||
@ -394,8 +350,7 @@ std::shared_ptr<GlyphAtlas> TypographerContextSkia::CreateGlyphAtlas(
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Step 2: Determine if the additional missing glyphs can be appended to the
|
||||
// existing bitmap without recreating the atlas. This requires that
|
||||
// the type is identical.
|
||||
// existing bitmap without recreating the atlas.
|
||||
// ---------------------------------------------------------------------------
|
||||
std::vector<Rect> glyph_positions;
|
||||
if (CanAppendToExistingAtlas(last_atlas, new_glyphs, glyph_positions,
|
||||
@ -412,6 +367,14 @@ std::shared_ptr<GlyphAtlas> TypographerContextSkia::CreateGlyphAtlas(
|
||||
last_atlas->AddTypefaceGlyphPosition(new_glyphs[i], glyph_positions[i]);
|
||||
}
|
||||
|
||||
std::shared_ptr<CommandBuffer> cmd_buffer = context.CreateCommandBuffer();
|
||||
std::shared_ptr<BlitPass> blit_pass = cmd_buffer->CreateBlitPass();
|
||||
|
||||
fml::ScopedCleanupClosure closure([&]() {
|
||||
blit_pass->EncodeCommands(context.GetResourceAllocator());
|
||||
context.GetCommandQueue()->Submit({std::move(cmd_buffer)});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Step 4a: Draw new font-glyph pairs into the a host buffer and encode
|
||||
// the uploads into the blit pass.
|
||||
@ -502,8 +465,46 @@ std::shared_ptr<GlyphAtlas> TypographerContextSkia::CreateGlyphAtlas(
|
||||
|
||||
new_texture->SetLabel("GlyphAtlas");
|
||||
|
||||
ClearTextureToTransparentBlack(context, host_buffer, cmd_buffer, blit_pass,
|
||||
new_texture);
|
||||
std::shared_ptr<CommandBuffer> cmd_buffer = context.CreateCommandBuffer();
|
||||
std::shared_ptr<BlitPass> blit_pass;
|
||||
|
||||
// The R8/A8 textures used for certain glyphs is not supported as color
|
||||
// attachments in most graphics drivers. To be safe, just do a CPU clear
|
||||
// for these.
|
||||
if (type == GlyphAtlas::Type::kAlphaBitmap) {
|
||||
size_t byte_size =
|
||||
new_texture->GetTextureDescriptor().GetByteSizeOfBaseMipLevel();
|
||||
BufferView buffer_view =
|
||||
host_buffer.Emplace(nullptr, byte_size, DefaultUniformAlignment());
|
||||
|
||||
::memset(buffer_view.buffer->OnGetContents() + buffer_view.range.offset, 0,
|
||||
byte_size);
|
||||
buffer_view.buffer->Flush();
|
||||
blit_pass = cmd_buffer->CreateBlitPass();
|
||||
blit_pass->AddCopy(buffer_view, new_texture);
|
||||
} else {
|
||||
// In all other cases, we can use a render pass to clear to a transparent
|
||||
// color.
|
||||
ColorAttachment attachment;
|
||||
attachment.clear_color = Color::BlackTransparent();
|
||||
attachment.load_action = LoadAction::kClear;
|
||||
attachment.store_action = StoreAction::kStore;
|
||||
attachment.texture = new_texture;
|
||||
|
||||
RenderTarget render_target;
|
||||
render_target.SetColorAttachment(attachment, 0u);
|
||||
|
||||
auto render_pass = cmd_buffer->CreateRenderPass(render_target);
|
||||
render_pass->EncodeCommands();
|
||||
blit_pass = cmd_buffer->CreateBlitPass();
|
||||
}
|
||||
FML_DCHECK(!!blit_pass);
|
||||
|
||||
fml::ScopedCleanupClosure closure([&]() {
|
||||
blit_pass->EncodeCommands(context.GetResourceAllocator());
|
||||
context.GetCommandQueue()->Submit({std::move(cmd_buffer)});
|
||||
});
|
||||
|
||||
if (!UpdateAtlasBitmap(*glyph_atlas, blit_pass, host_buffer, new_texture,
|
||||
font_glyph_pairs)) {
|
||||
return nullptr;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user