blob: 2c45762a512fd7e9c66b405546502ad150b21868 [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 "flutter/shell/gpu/gpu_surface_gl_impeller.h"
#include "flutter/fml/make_copyable.h"
#include "impeller/display_list/dl_dispatcher.h"
#include "impeller/renderer/backend/gles/surface_gles.h"
#include "impeller/renderer/renderer.h"
#include "impeller/typographer/backends/skia/typographer_context_skia.h"
namespace flutter {
GPUSurfaceGLImpeller::GPUSurfaceGLImpeller(
GPUSurfaceGLDelegate* delegate,
std::shared_ptr<impeller::Context> context,
bool render_to_surface)
: weak_factory_(this) {
if (delegate == nullptr) {
return;
}
if (!context || !context->IsValid()) {
return;
}
auto renderer = std::make_shared<impeller::Renderer>(context);
if (!renderer->IsValid()) {
return;
}
auto aiks_context = std::make_shared<impeller::AiksContext>(
context, impeller::TypographerContextSkia::Make());
if (!aiks_context->IsValid()) {
return;
}
delegate_ = delegate;
impeller_context_ = std::move(context);
render_to_surface_ = render_to_surface;
impeller_renderer_ = std::move(renderer);
aiks_context_ = std::move(aiks_context);
is_valid_ = true;
}
// |Surface|
GPUSurfaceGLImpeller::~GPUSurfaceGLImpeller() = default;
// |Surface|
bool GPUSurfaceGLImpeller::IsValid() {
return is_valid_;
}
// |Surface|
std::unique_ptr<SurfaceFrame> GPUSurfaceGLImpeller::AcquireFrame(
const SkISize& size) {
if (!IsValid()) {
FML_LOG(ERROR) << "OpenGL surface was invalid.";
return nullptr;
}
auto swap_callback = [weak = weak_factory_.GetWeakPtr(),
delegate = delegate_]() -> bool {
if (weak) {
GLPresentInfo present_info = {
.fbo_id = 0u,
.frame_damage = std::nullopt,
// TODO (https://github.com/flutter/flutter/issues/105597): wire-up
// presentation time to impeller backend.
.presentation_time = std::nullopt,
.buffer_damage = std::nullopt,
};
delegate->GLContextPresent(present_info);
}
return true;
};
auto context_switch = delegate_->GLContextMakeCurrent();
if (!context_switch->GetResult()) {
FML_LOG(ERROR)
<< "Could not make the context current to acquire the frame.";
return nullptr;
}
if (!render_to_surface_) {
return std::make_unique<SurfaceFrame>(
nullptr, SurfaceFrame::FramebufferInfo{.supports_readback = true},
[](const SurfaceFrame& surface_frame, DlCanvas* canvas) {
return true;
},
size);
}
GLFrameInfo frame_info = {static_cast<uint32_t>(size.width()),
static_cast<uint32_t>(size.height())};
const GLFBOInfo fbo_info = delegate_->GLContextFBO(frame_info);
auto surface = impeller::SurfaceGLES::WrapFBO(
impeller_context_, // context
swap_callback, // swap_callback
fbo_info.fbo_id, // fbo
impeller::PixelFormat::kR8G8B8A8UNormInt, // color_format
impeller::ISize{size.width(), size.height()} // fbo_size
);
SurfaceFrame::SubmitCallback submit_callback =
fml::MakeCopyable([renderer = impeller_renderer_, //
aiks_context = aiks_context_, //
surface = std::move(surface) //
](SurfaceFrame& surface_frame, DlCanvas* canvas) mutable -> bool {
if (!aiks_context) {
return false;
}
auto display_list = surface_frame.BuildDisplayList();
if (!display_list) {
FML_LOG(ERROR) << "Could not build display list for surface frame.";
return false;
}
auto cull_rect =
surface->GetTargetRenderPassDescriptor().GetRenderTargetSize();
impeller::Rect dl_cull_rect = impeller::Rect::MakeSize(cull_rect);
impeller::DlDispatcher impeller_dispatcher(dl_cull_rect);
display_list->Dispatch(
impeller_dispatcher,
SkIRect::MakeWH(cull_rect.width, cull_rect.height));
auto picture = impeller_dispatcher.EndRecordingAsPicture();
return renderer->Render(
std::move(surface),
fml::MakeCopyable(
[aiks_context, picture = std::move(picture)](
impeller::RenderTarget& render_target) -> bool {
return aiks_context->Render(picture, render_target,
/*reset_host_buffer=*/true);
}));
});
return std::make_unique<SurfaceFrame>(
nullptr, // surface
delegate_->GLContextFramebufferInfo(), // framebuffer info
submit_callback, // submit callback
size, // frame size
std::move(context_switch), // context result
true // display list fallback
);
}
// |Surface|
SkMatrix GPUSurfaceGLImpeller::GetRootTransformation() const {
// This backend does not currently support root surface transformations. Just
// return identity.
return {};
}
// |Surface|
GrDirectContext* GPUSurfaceGLImpeller::GetContext() {
// Impeller != Skia.
return nullptr;
}
// |Surface|
std::unique_ptr<GLContextResult>
GPUSurfaceGLImpeller::MakeRenderContextCurrent() {
return delegate_->GLContextMakeCurrent();
}
// |Surface|
bool GPUSurfaceGLImpeller::ClearRenderContext() {
return delegate_->GLContextClearCurrent();
}
bool GPUSurfaceGLImpeller::AllowsDrawingWhenGpuDisabled() const {
return delegate_->AllowsDrawingWhenGpuDisabled();
}
// |Surface|
bool GPUSurfaceGLImpeller::EnableRasterCache() const {
return false;
}
// |Surface|
std::shared_ptr<impeller::AiksContext> GPUSurfaceGLImpeller::GetAiksContext()
const {
return aiks_context_;
}
} // namespace flutter