blob: 430dfb64899038c7452c4dfeb1a52bb1fcceb04c [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_vulkan_impeller.h"
#include "flutter/fml/make_copyable.h"
#include "impeller/display_list/dl_dispatcher.h"
#include "impeller/renderer/backend/vulkan/surface_context_vk.h"
#include "impeller/renderer/renderer.h"
#include "impeller/renderer/surface.h"
#include "impeller/typographer/backends/skia/typographer_context_skia.h"
namespace flutter {
#define ENABLE_EXPERIMENTAL_CANVAS false
GPUSurfaceVulkanImpeller::GPUSurfaceVulkanImpeller(
std::shared_ptr<impeller::Context> context) {
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;
}
impeller_context_ = std::move(context);
impeller_renderer_ = std::move(renderer);
aiks_context_ = std::move(aiks_context);
is_valid_ = true;
}
// |Surface|
GPUSurfaceVulkanImpeller::~GPUSurfaceVulkanImpeller() = default;
// |Surface|
bool GPUSurfaceVulkanImpeller::IsValid() {
return is_valid_;
}
// |Surface|
std::unique_ptr<SurfaceFrame> GPUSurfaceVulkanImpeller::AcquireFrame(
const SkISize& size) {
if (!IsValid()) {
FML_LOG(ERROR) << "Vulkan surface was invalid.";
return nullptr;
}
if (size.isEmpty()) {
FML_LOG(ERROR) << "Vulkan surface was asked for an empty frame.";
return nullptr;
}
auto& context_vk = impeller::SurfaceContextVK::Cast(*impeller_context_);
std::unique_ptr<impeller::Surface> surface = context_vk.AcquireNextSurface();
if (!surface) {
FML_LOG(ERROR) << "No surface available.";
return nullptr;
}
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();
[[maybe_unused]] auto supports_readback =
surface_frame.framebuffer_info().supports_readback;
return renderer->Render(
std::move(surface),
fml::MakeCopyable([&](impeller::RenderTarget& render_target)
-> bool {
#if ENABLE_EXPERIMENTAL_CANVAS
impeller::TextFrameDispatcher collector(
aiks_context->GetContentContext(), impeller::Matrix());
display_list->Dispatch(
collector,
SkIRect::MakeWH(cull_rect.width, cull_rect.height));
impeller::ExperimentalDlDispatcher impeller_dispatcher(
aiks_context->GetContentContext(), render_target,
supports_readback,
impeller::IRect::RoundOut(
impeller::Rect::MakeSize(cull_rect)));
display_list->Dispatch(
impeller_dispatcher,
SkIRect::MakeWH(cull_rect.width, cull_rect.height));
impeller_dispatcher.FinishRecording();
aiks_context->GetContentContext().GetTransientsBuffer().Reset();
aiks_context->GetContentContext()
.GetLazyGlyphAtlas()
->ResetTextFrames();
return true;
#else
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 aiks_context->Render(picture, render_target,
/*reset_host_buffer=*/true);
#endif
}));
});
return std::make_unique<SurfaceFrame>(
nullptr, // surface
SurfaceFrame::FramebufferInfo{}, // framebuffer info
submit_callback, // submit callback
size, // frame size
nullptr, // context result
true // display list fallback
);
}
// |Surface|
SkMatrix GPUSurfaceVulkanImpeller::GetRootTransformation() const {
// This backend does not currently support root surface transformations. Just
// return identity.
return {};
}
// |Surface|
GrDirectContext* GPUSurfaceVulkanImpeller::GetContext() {
// Impeller != Skia.
return nullptr;
}
// |Surface|
std::unique_ptr<GLContextResult>
GPUSurfaceVulkanImpeller::MakeRenderContextCurrent() {
// This backend has no such concept.
return std::make_unique<GLContextDefaultResult>(true);
}
// |Surface|
bool GPUSurfaceVulkanImpeller::EnableRasterCache() const {
return false;
}
// |Surface|
std::shared_ptr<impeller::AiksContext>
GPUSurfaceVulkanImpeller::GetAiksContext() const {
return aiks_context_;
}
} // namespace flutter