blob: 329fe5197caf87ac8d09b3eb2c28bd45e3f16fd0 [file] [log] [blame]
// 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_pass_mtl.h"
#include <Metal/Metal.h>
#include <memory>
#include <utility>
#include <variant>
#include "flutter/fml/closure.h"
#include "flutter/fml/logging.h"
#include "flutter/fml/trace_event.h"
#include "impeller/base/backend_cast.h"
#include "impeller/core/formats.h"
#include "impeller/core/host_buffer.h"
#include "impeller/core/shader_types.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 {
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() {
if (!did_finish_encoding_) {
[encoder_ endEncoding];
}
}
bool BlitPassMTL::IsValid() const {
return is_valid_;
}
void BlitPassMTL::OnSetLabel(std::string label) {
if (label.empty()) {
return;
}
[encoder_ setLabel:@(label.c_str())];
}
bool BlitPassMTL::EncodeCommands(
const std::shared_ptr<Allocator>& transients_allocator) const {
[encoder_ endEncoding];
did_finish_encoding_ = true;
return true;
}
// |BlitPass|
bool BlitPassMTL::OnCopyTextureToTextureCommand(
std::shared_ptr<Texture> source,
std::shared_ptr<Texture> destination,
IRect source_region,
IPoint destination_origin,
std::string label) {
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
return true;
}
// |BlitPass|
bool BlitPassMTL::OnCopyTextureToBufferCommand(
std::shared_ptr<Texture> source,
std::shared_ptr<DeviceBuffer> destination,
IRect source_region,
size_t destination_offset,
std::string label) {
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;
#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;
}
bool BlitPassMTL::OnCopyBufferToTextureCommand(
BufferView source,
std::shared_ptr<Texture> destination,
IRect destination_region,
std::string label,
uint32_t slice,
bool convert_to_read) {
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;
#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) {
#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