Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

[Impeller] use blit pass to resize decoded images. #54606

Merged
merged 28 commits into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 67 additions & 1 deletion impeller/renderer/backend/gles/blit_command_gles.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "impeller/base/validation.h"
#include "impeller/geometry/point.h"
#include "impeller/renderer/backend/gles/device_buffer_gles.h"
#include "impeller/renderer/backend/gles/reactor_gles.h"
#include "impeller/renderer/backend/gles/texture_gles.h"

namespace impeller {
Expand Down Expand Up @@ -73,7 +74,7 @@ bool BlitCopyTextureToTextureCommandGLES::Encode(
// emulate the blit when it's not available in the driver.
if (!gl.BlitFramebuffer.IsAvailable()) {
// TODO(135818): Emulate the blit using a raster draw call here.
FML_LOG(ERROR) << "Texture blit fallback not implemented yet for GLES2.";
VALIDATION_LOG << "Texture blit fallback not implemented yet for GLES2.";
return false;
}

Expand Down Expand Up @@ -353,4 +354,69 @@ bool BlitGenerateMipmapCommandGLES::Encode(const ReactorGLES& reactor) const {
return true;
};

////// BlitResizeTextureCommandGLES
//////////////////////////////////////////////////////

BlitResizeTextureCommandGLES::~BlitResizeTextureCommandGLES() = default;

std::string BlitResizeTextureCommandGLES::GetLabel() const {
return "Resize Texture";
}

bool BlitResizeTextureCommandGLES::Encode(const ReactorGLES& reactor) const {
const auto& gl = reactor.GetProcTable();

// glBlitFramebuffer is a GLES3 proc. Since we target GLES2, we need to
// emulate the blit when it's not available in the driver.
if (!gl.BlitFramebuffer.IsAvailable()) {
// TODO(135818): Emulate the blit using a raster draw call here.
VALIDATION_LOG << "Texture blit fallback not implemented yet for GLES2.";
return false;
}

GLuint read_fbo = GL_NONE;
GLuint draw_fbo = GL_NONE;
fml::ScopedCleanupClosure delete_fbos([&gl, &read_fbo, &draw_fbo]() {
DeleteFBO(gl, read_fbo, GL_READ_FRAMEBUFFER);
DeleteFBO(gl, draw_fbo, GL_DRAW_FRAMEBUFFER);
});

{
auto read = ConfigureFBO(gl, source, GL_READ_FRAMEBUFFER);
if (!read.has_value()) {
return false;
}
read_fbo = read.value();
}

{
auto draw = ConfigureFBO(gl, destination, GL_DRAW_FRAMEBUFFER);
if (!draw.has_value()) {
return false;
}
draw_fbo = draw.value();
}

gl.Disable(GL_SCISSOR_TEST);
gl.Disable(GL_DEPTH_TEST);
gl.Disable(GL_STENCIL_TEST);

const IRect source_region = IRect::MakeSize(source->GetSize());
const IRect destination_region = IRect::MakeSize(destination->GetSize());

gl.BlitFramebuffer(source_region.GetX(), // srcX0
source_region.GetY(), // srcY0
source_region.GetWidth(), // srcX1
source_region.GetHeight(), // srcY1
destination_region.GetX(), // dstX0
destination_region.GetY(), // dstY0
destination_region.GetWidth(), // dstX1
destination_region.GetHeight(), // dstY1
GL_COLOR_BUFFER_BIT, // mask
GL_LINEAR // filter
);

return true;
}

} // namespace impeller
9 changes: 9 additions & 0 deletions impeller/renderer/backend/gles/blit_command_gles.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,15 @@ struct BlitGenerateMipmapCommandGLES : public BlitEncodeGLES,
[[nodiscard]] bool Encode(const ReactorGLES& reactor) const override;
};

struct BlitResizeTextureCommandGLES : public BlitEncodeGLES,
public BlitResizeTextureCommand {
~BlitResizeTextureCommandGLES() override;

std::string GetLabel() const override;

[[nodiscard]] bool Encode(const ReactorGLES& reactor) const override;
};

} // namespace impeller

#endif // FLUTTER_IMPELLER_RENDERER_BACKEND_GLES_BLIT_COMMAND_GLES_H_
11 changes: 11 additions & 0 deletions impeller/renderer/backend/gles/blit_pass_gles.cc
Original file line number Diff line number Diff line change
Expand Up @@ -157,4 +157,15 @@ bool BlitPassGLES::OnGenerateMipmapCommand(std::shared_ptr<Texture> texture,
return true;
}

// |BlitPass|
bool BlitPassGLES::ResizeTexture(const std::shared_ptr<Texture>& source,
const std::shared_ptr<Texture>& destination) {
auto command = std::make_unique<BlitResizeTextureCommandGLES>();
command->source = source;
command->destination = destination;

commands_.push_back(std::move(command));
return true;
}

} // namespace impeller
4 changes: 4 additions & 0 deletions impeller/renderer/backend/gles/blit_pass_gles.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ class BlitPassGLES final : public BlitPass,
bool EncodeCommands(
const std::shared_ptr<Allocator>& transients_allocator) const override;

// |BlitPass|
bool ResizeTexture(const std::shared_ptr<Texture>& source,
const std::shared_ptr<Texture>& destination) override;

// |BlitPass|
bool OnCopyTextureToTextureCommand(std::shared_ptr<Texture> source,
std::shared_ptr<Texture> destination,
Expand Down
5 changes: 4 additions & 1 deletion impeller/renderer/backend/metal/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,10 @@ impeller_component("metal") {
"//flutter/fml",
]

frameworks = [ "Metal.framework" ]
frameworks = [
"Metal.framework",
"MetalPerformanceShaders.framework",
]
}

impeller_component("metal_unittests") {
Expand Down
7 changes: 6 additions & 1 deletion impeller/renderer/backend/metal/blit_pass_mtl.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,15 @@ class BlitPassMTL final : public BlitPass {

id<MTLBlitCommandEncoder> encoder_ = nil;
id<MTLCommandBuffer> buffer_ = nil;
id<MTLDevice> device_ = nil;
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);
explicit BlitPassMTL(id<MTLCommandBuffer> buffer, id<MTLDevice> device);

// |BlitPass|
bool IsValid() const override;
Expand All @@ -40,6 +41,10 @@ class BlitPassMTL final : public BlitPass {
bool EncodeCommands(
const std::shared_ptr<Allocator>& transients_allocator) const override;

// |BlitPass|
bool ResizeTexture(const std::shared_ptr<Texture>& source,
const std::shared_ptr<Texture>& destination) override;

// |BlitPass|
bool OnCopyTextureToTextureCommand(std::shared_ptr<Texture> source,
std::shared_ptr<Texture> destination,
Expand Down
25 changes: 24 additions & 1 deletion impeller/renderer/backend/metal/blit_pass_mtl.mm
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "impeller/renderer/backend/metal/blit_pass_mtl.h"
#include <Metal/Metal.h>
#import <MetalPerformanceShaders/MetalPerformanceShaders.h>
#include <memory>
#include <utility>
#include <variant>
Expand All @@ -25,7 +26,8 @@

namespace impeller {

BlitPassMTL::BlitPassMTL(id<MTLCommandBuffer> buffer) : buffer_(buffer) {
BlitPassMTL::BlitPassMTL(id<MTLCommandBuffer> buffer, id<MTLDevice> device)
: buffer_(buffer), device_(device) {
if (!buffer_) {
return;
}
Expand Down Expand Up @@ -105,7 +107,28 @@
[encoder_ popDebugGroup];
}
#endif // IMPELLER_DEBUG
return true;
}

// |BlitPass|
bool BlitPassMTL::ResizeTexture(const std::shared_ptr<Texture>& source,
const std::shared_ptr<Texture>& destination) {
auto source_mtl = TextureMTL::Cast(*source).GetMTLTexture();
if (!source_mtl) {
return false;
}

auto destination_mtl = TextureMTL::Cast(*destination).GetMTLTexture();
if (!destination_mtl) {
return false;
}

[encoder_ endEncoding];
auto filter = [[MPSImageBilinearScale alloc] initWithDevice:device_];
[filter encodeToCommandBuffer:buffer_
sourceTexture:source_mtl
destinationTexture:destination_mtl];
encoder_ = [buffer_ blitCommandEncoder];
return true;
}

Expand Down
4 changes: 3 additions & 1 deletion impeller/renderer/backend/metal/command_buffer_mtl.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ class CommandBufferMTL final : public CommandBuffer {
private:
friend class ContextMTL;

id<MTLCommandBuffer> buffer_ = nullptr;
id<MTLCommandBuffer> buffer_ = nil;
id<MTLDevice> device_ = nil;

CommandBufferMTL(const std::weak_ptr<const Context>& context,
id<MTLDevice> device,
id<MTLCommandQueue> queue);

// |CommandBuffer|
Expand Down
7 changes: 5 additions & 2 deletions impeller/renderer/backend/metal/command_buffer_mtl.mm
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,11 @@ static bool LogMTLCommandBufferErrorIfPresent(id<MTLCommandBuffer> buffer) {
}

CommandBufferMTL::CommandBufferMTL(const std::weak_ptr<const Context>& context,
id<MTLDevice> device,
id<MTLCommandQueue> queue)
: CommandBuffer(context), buffer_(CreateCommandBuffer(queue)) {}
: CommandBuffer(context),
buffer_(CreateCommandBuffer(queue)),
device_(device) {}

CommandBufferMTL::~CommandBufferMTL() = default;

Expand Down Expand Up @@ -208,7 +211,7 @@ static bool LogMTLCommandBufferErrorIfPresent(id<MTLCommandBuffer> buffer) {
return nullptr;
}

auto pass = std::shared_ptr<BlitPassMTL>(new BlitPassMTL(buffer_));
auto pass = std::shared_ptr<BlitPassMTL>(new BlitPassMTL(buffer_, device_));
if (!pass->IsValid()) {
return nullptr;
}
Expand Down
11 changes: 9 additions & 2 deletions impeller/renderer/backend/metal/context_mtl.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#include "flutter/fml/concurrent_message_loop.h"
#include "flutter/fml/synchronization/sync_switch.h"
#include "fml/closure.h"
#include "impeller/base/backend_cast.h"
#include "impeller/core/sampler.h"
#include "impeller/renderer/backend/metal/allocator_mtl.h"
Expand Down Expand Up @@ -136,7 +137,8 @@ class ContextMTL final : public Context,
#endif // IMPELLER_DEBUG

// |Context|
void StoreTaskForGPU(const std::function<void()>& task) override;
void StoreTaskForGPU(const fml::closure& task,
const fml::closure& failure) override;

private:
class SyncSwitchObserver : public fml::SyncSwitch::Observer {
Expand All @@ -149,6 +151,11 @@ class ContextMTL final : public Context,
ContextMTL& parent_;
};

struct PendingTasks {
fml::closure task;
fml::closure failure;
};

id<MTLDevice> device_ = nullptr;
id<MTLCommandQueue> command_queue_ = nullptr;
std::shared_ptr<ShaderLibraryMTL> shader_library_;
Expand All @@ -157,7 +164,7 @@ class ContextMTL final : public Context,
std::shared_ptr<AllocatorMTL> resource_allocator_;
std::shared_ptr<const Capabilities> device_capabilities_;
std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch_;
std::deque<std::function<void()>> tasks_awaiting_gpu_;
std::deque<PendingTasks> tasks_awaiting_gpu_;
std::unique_ptr<SyncSwitchObserver> sync_switch_observer_;
std::shared_ptr<CommandQueue> command_queue_ip_;
#ifdef IMPELLER_DEBUG
Expand Down
14 changes: 9 additions & 5 deletions impeller/renderer/backend/metal/context_mtl.mm
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ new ContextMTL(device, command_queue,
}

auto buffer = std::shared_ptr<CommandBufferMTL>(
new CommandBufferMTL(weak_from_this(), queue));
new CommandBufferMTL(weak_from_this(), device_, queue));
if (!buffer->IsValid()) {
return nullptr;
}
Expand Down Expand Up @@ -377,17 +377,21 @@ new ContextMTL(device, command_queue,
return buffer;
}

void ContextMTL::StoreTaskForGPU(const std::function<void()>& task) {
tasks_awaiting_gpu_.emplace_back(task);
void ContextMTL::StoreTaskForGPU(const fml::closure& task,
const fml::closure& failure) {
tasks_awaiting_gpu_.push_back(PendingTasks{task, failure});
while (tasks_awaiting_gpu_.size() > kMaxTasksAwaitingGPU) {
tasks_awaiting_gpu_.front()();
PendingTasks front = std::move(tasks_awaiting_gpu_.front());
if (front.failure) {
front.failure();
}
tasks_awaiting_gpu_.pop_front();
}
}

void ContextMTL::FlushTasksAwaitingGPU() {
for (const auto& task : tasks_awaiting_gpu_) {
task();
task.task();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perform null checks here or wrap a null ptr in a do-nothing fml::closure in StoreTaskForCPU perhaps?

}
tasks_awaiting_gpu_.clear();
}
Expand Down
Loading