flutter_flutter/shell/gpu/gpu_surface_gl.cc
bungeman a6a6fd163b
Replace kLegacyFontHost_InitType with kUnknown_SkPixelGeometry. (#21474)
Skia is removing the deprecated legacy display setting globals and
associated kLegacyFontHost_InitType. This change replaces all such uses
with default surface properties with no special flags and an unknown
pixel geometry. Flutter never set the associated globals, leaving them
with their initial default values, which were no special flags and
horizontal RGB pixel geometry. The values used here are different but
this change should make no difference as Flutter never mentions
SkFont::kSubpixelAntiAlias to take advantage of the pixel geometry.
2020-09-29 12:46:08 -04:00

353 lines
11 KiB
C++

// 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.
// FLUTTER_NOLINT
#include "flutter/shell/gpu/gpu_surface_gl.h"
#include "flutter/fml/base32.h"
#include "flutter/fml/logging.h"
#include "flutter/fml/size.h"
#include "flutter/fml/trace_event.h"
#include "flutter/shell/common/persistent_cache.h"
#include "third_party/skia/include/core/SkColorFilter.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/gpu/GrBackendSurface.h"
#include "third_party/skia/include/gpu/GrContextOptions.h"
// These are common defines present on all OpenGL headers. However, we don't
// want to perform GL header reasolution on each platform we support. So just
// define these upfront. It is unlikely we will need more. But, if we do, we can
// add the same here.
#define GPU_GL_RGBA8 0x8058
#define GPU_GL_RGBA4 0x8056
#define GPU_GL_RGB565 0x8D62
namespace flutter {
// Default maximum number of budgeted resources in the cache.
static const int kGrCacheMaxCount = 8192;
// Default maximum number of bytes of GPU memory of budgeted resources in the
// cache.
// The shell will dynamically increase or decrease this cache based on the
// viewport size, unless a user has specifically requested a size on the Skia
// system channel.
static const size_t kGrCacheMaxByteSize = 24 * (1 << 20);
GPUSurfaceGL::GPUSurfaceGL(GPUSurfaceGLDelegate* delegate,
bool render_to_surface)
: delegate_(delegate),
render_to_surface_(render_to_surface),
weak_factory_(this) {
auto context_switch = delegate_->GLContextMakeCurrent();
if (!context_switch->GetResult()) {
FML_LOG(ERROR)
<< "Could not make the context current to setup the gr context.";
return;
}
GrContextOptions options;
if (PersistentCache::cache_sksl()) {
FML_LOG(INFO) << "Cache SkSL";
options.fShaderCacheStrategy = GrContextOptions::ShaderCacheStrategy::kSkSL;
}
PersistentCache::MarkStrategySet();
options.fPersistentCache = PersistentCache::GetCacheForProcess();
options.fAvoidStencilBuffers = true;
// To get video playback on the widest range of devices, we limit Skia to
// ES2 shading language when the ES3 external image extension is missing.
options.fPreferExternalImagesOverES3 = true;
// TODO(goderbauer): remove option when skbug.com/7523 is fixed.
// A similar work-around is also used in shell/common/io_manager.cc.
options.fDisableGpuYUVConversion = true;
auto context = GrDirectContext::MakeGL(delegate_->GetGLInterface(), options);
if (context == nullptr) {
FML_LOG(ERROR) << "Failed to setup Skia Gr context.";
return;
}
context_ = std::move(context);
context_->setResourceCacheLimits(kGrCacheMaxCount, kGrCacheMaxByteSize);
context_owner_ = true;
valid_ = true;
std::vector<PersistentCache::SkSLCache> caches =
PersistentCache::GetCacheForProcess()->LoadSkSLs();
int compiled_count = 0;
for (const auto& cache : caches) {
compiled_count += context_->precompileShader(*cache.first, *cache.second);
}
FML_LOG(INFO) << "Found " << caches.size() << " SkSL shaders; precompiled "
<< compiled_count;
delegate_->GLContextClearCurrent();
}
GPUSurfaceGL::GPUSurfaceGL(sk_sp<GrDirectContext> gr_context,
GPUSurfaceGLDelegate* delegate,
bool render_to_surface)
: delegate_(delegate),
context_(gr_context),
render_to_surface_(render_to_surface),
weak_factory_(this) {
auto context_switch = delegate_->GLContextMakeCurrent();
if (!context_switch->GetResult()) {
FML_LOG(ERROR)
<< "Could not make the context current to setup the gr context.";
return;
}
delegate_->GLContextClearCurrent();
valid_ = true;
context_owner_ = false;
}
GPUSurfaceGL::~GPUSurfaceGL() {
if (!valid_) {
return;
}
auto context_switch = delegate_->GLContextMakeCurrent();
if (!context_switch->GetResult()) {
FML_LOG(ERROR) << "Could not make the context current to destroy the "
"GrDirectContext resources.";
return;
}
onscreen_surface_ = nullptr;
fbo_id_ = 0;
if (context_owner_) {
context_->releaseResourcesAndAbandonContext();
}
context_ = nullptr;
delegate_->GLContextClearCurrent();
}
// |Surface|
bool GPUSurfaceGL::IsValid() {
return valid_;
}
static SkColorType FirstSupportedColorType(GrDirectContext* context,
GrGLenum* format) {
#define RETURN_IF_RENDERABLE(x, y) \
if (context->colorTypeSupportedAsSurface((x))) { \
*format = (y); \
return (x); \
}
RETURN_IF_RENDERABLE(kRGBA_8888_SkColorType, GPU_GL_RGBA8);
RETURN_IF_RENDERABLE(kARGB_4444_SkColorType, GPU_GL_RGBA4);
RETURN_IF_RENDERABLE(kRGB_565_SkColorType, GPU_GL_RGB565);
return kUnknown_SkColorType;
}
static sk_sp<SkSurface> WrapOnscreenSurface(GrDirectContext* context,
const SkISize& size,
intptr_t fbo) {
GrGLenum format;
const SkColorType color_type = FirstSupportedColorType(context, &format);
GrGLFramebufferInfo framebuffer_info = {};
framebuffer_info.fFBOID = static_cast<GrGLuint>(fbo);
framebuffer_info.fFormat = format;
GrBackendRenderTarget render_target(size.width(), // width
size.height(), // height
0, // sample count
0, // stencil bits (TODO)
framebuffer_info // framebuffer info
);
sk_sp<SkColorSpace> colorspace = SkColorSpace::MakeSRGB();
SkSurfaceProps surface_props(0, kUnknown_SkPixelGeometry);
return SkSurface::MakeFromBackendRenderTarget(
context, // gr context
render_target, // render target
GrSurfaceOrigin::kBottomLeft_GrSurfaceOrigin, // origin
color_type, // color type
colorspace, // colorspace
&surface_props // surface properties
);
}
bool GPUSurfaceGL::CreateOrUpdateSurfaces(const SkISize& size) {
if (onscreen_surface_ != nullptr &&
size == SkISize::Make(onscreen_surface_->width(),
onscreen_surface_->height())) {
// Surface size appears unchanged. So bail.
return true;
}
// We need to do some updates.
TRACE_EVENT0("flutter", "UpdateSurfacesSize");
// Either way, we need to get rid of previous surface.
onscreen_surface_ = nullptr;
fbo_id_ = 0;
if (size.isEmpty()) {
FML_LOG(ERROR) << "Cannot create surfaces of empty size.";
return false;
}
sk_sp<SkSurface> onscreen_surface;
GLFrameInfo frame_info = {static_cast<uint32_t>(size.width()),
static_cast<uint32_t>(size.height())};
const uint32_t fbo_id = delegate_->GLContextFBO(frame_info);
onscreen_surface = WrapOnscreenSurface(context_.get(), // GL context
size, // root surface size
fbo_id // window FBO ID
);
if (onscreen_surface == nullptr) {
// If the onscreen surface could not be wrapped. There is absolutely no
// point in moving forward.
FML_LOG(ERROR) << "Could not wrap onscreen surface.";
return false;
}
onscreen_surface_ = std::move(onscreen_surface);
fbo_id_ = fbo_id;
return true;
}
// |Surface|
SkMatrix GPUSurfaceGL::GetRootTransformation() const {
return delegate_->GLContextSurfaceTransformation();
}
// |Surface|
std::unique_ptr<SurfaceFrame> GPUSurfaceGL::AcquireFrame(const SkISize& size) {
if (delegate_ == nullptr) {
return nullptr;
}
auto context_switch = delegate_->GLContextMakeCurrent();
if (!context_switch->GetResult()) {
FML_LOG(ERROR)
<< "Could not make the context current to acquire the frame.";
return nullptr;
}
// TODO(38466): Refactor GPU surface APIs take into account the fact that an
// external view embedder may want to render to the root surface.
if (!render_to_surface_) {
return std::make_unique<SurfaceFrame>(
nullptr, true, [](const SurfaceFrame& surface_frame, SkCanvas* canvas) {
return true;
});
}
const auto root_surface_transformation = GetRootTransformation();
sk_sp<SkSurface> surface =
AcquireRenderSurface(size, root_surface_transformation);
if (surface == nullptr) {
return nullptr;
}
surface->getCanvas()->setMatrix(root_surface_transformation);
SurfaceFrame::SubmitCallback submit_callback =
[weak = weak_factory_.GetWeakPtr()](const SurfaceFrame& surface_frame,
SkCanvas* canvas) {
return weak ? weak->PresentSurface(canvas) : false;
};
return std::make_unique<SurfaceFrame>(
surface, delegate_->SurfaceSupportsReadback(), submit_callback,
std::move(context_switch));
}
bool GPUSurfaceGL::PresentSurface(SkCanvas* canvas) {
if (delegate_ == nullptr || canvas == nullptr || context_ == nullptr) {
return false;
}
{
TRACE_EVENT0("flutter", "SkCanvas::Flush");
onscreen_surface_->getCanvas()->flush();
}
if (!delegate_->GLContextPresent(fbo_id_)) {
return false;
}
if (delegate_->GLContextFBOResetAfterPresent()) {
auto current_size =
SkISize::Make(onscreen_surface_->width(), onscreen_surface_->height());
GLFrameInfo frame_info = {static_cast<uint32_t>(current_size.width()),
static_cast<uint32_t>(current_size.height())};
// The FBO has changed, ask the delegate for the new FBO and do a surface
// re-wrap.
const uint32_t fbo_id = delegate_->GLContextFBO(frame_info);
auto new_onscreen_surface =
WrapOnscreenSurface(context_.get(), // GL context
current_size, // root surface size
fbo_id // window FBO ID
);
if (!new_onscreen_surface) {
return false;
}
onscreen_surface_ = std::move(new_onscreen_surface);
fbo_id_ = fbo_id;
}
return true;
}
sk_sp<SkSurface> GPUSurfaceGL::AcquireRenderSurface(
const SkISize& untransformed_size,
const SkMatrix& root_surface_transformation) {
const auto transformed_rect = root_surface_transformation.mapRect(
SkRect::MakeWH(untransformed_size.width(), untransformed_size.height()));
const auto transformed_size =
SkISize::Make(transformed_rect.width(), transformed_rect.height());
if (!CreateOrUpdateSurfaces(transformed_size)) {
return nullptr;
}
return onscreen_surface_;
}
// |Surface|
GrDirectContext* GPUSurfaceGL::GetContext() {
return context_.get();
}
// |Surface|
flutter::ExternalViewEmbedder* GPUSurfaceGL::GetExternalViewEmbedder() {
return delegate_->GetExternalViewEmbedder();
}
// |Surface|
std::unique_ptr<GLContextResult> GPUSurfaceGL::MakeRenderContextCurrent() {
return delegate_->GLContextMakeCurrent();
}
// |Surface|
bool GPUSurfaceGL::ClearRenderContext() {
return delegate_->GLContextClearCurrent();
}
} // namespace flutter