blob: 8380b6bd2ce6f05ed5cf721c1c2abd39d36e9757 [file] [log] [blame]
// Copyright 2016 The Chromium 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 "gpu_surface_gl.h"
#include "flutter/glue/trace_event.h"
#include "lib/ftl/arraysize.h"
#include "lib/ftl/logging.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/gpu/gl/GrGLInterface.h"
namespace shell {
// 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.
static const size_t kGrCacheMaxByteSize = 512 * (1 << 20);
GPUSurfaceGL::GPUSurfaceGL(GPUSurfaceGLDelegate* delegate)
: delegate_(delegate), weak_factory_(this) {}
GPUSurfaceGL::~GPUSurfaceGL() = default;
bool GPUSurfaceGL::Setup() {
if (delegate_ == nullptr) {
// Invalid delegate.
return false;
}
if (context_ != nullptr) {
// Already setup.
return false;
}
if (!delegate_->GLContextMakeCurrent()) {
// Could not make the context current to create the native interface.
return false;
}
// Create the native interface.
auto backend_context =
reinterpret_cast<GrBackendContext>(GrGLCreateNativeInterface());
context_ =
sk_sp<GrContext>(GrContext::Create(kOpenGL_GrBackend, backend_context));
if (context_ == nullptr) {
FTL_LOG(INFO) << "Failed to setup Skia Gr context.";
return false;
}
context_->setResourceCacheLimits(kGrCacheMaxCount, kGrCacheMaxByteSize);
delegate_->GLContextClearCurrent();
return true;
}
bool GPUSurfaceGL::IsValid() {
return context_ != nullptr;
}
std::unique_ptr<SurfaceFrame> GPUSurfaceGL::AcquireFrame(const SkISize& size) {
if (delegate_ == nullptr) {
return nullptr;
}
if (!delegate_->GLContextMakeCurrent()) {
return nullptr;
}
sk_sp<SkSurface> surface = AcquireSurface(size);
if (surface == nullptr) {
return nullptr;
}
auto weak_this = weak_factory_.GetWeakPtr();
SurfaceFrame::SubmitCallback submit_callback = [weak_this](
const SurfaceFrame& surface_frame, SkCanvas* canvas) {
return weak_this ? weak_this->PresentSurface(canvas) : false;
};
return std::make_unique<SurfaceFrame>(surface, submit_callback);
}
bool GPUSurfaceGL::PresentSurface(SkCanvas* canvas) {
if (delegate_ == nullptr || canvas == nullptr) {
return false;
}
{
TRACE_EVENT0("flutter", "SkCanvas::Flush");
canvas->flush();
}
delegate_->GLContextPresent();
return true;
}
bool GPUSurfaceGL::SelectPixelConfig(GrPixelConfig* config) {
static const GrPixelConfig kConfigOptions[] = {
kSkia8888_GrPixelConfig, kRGBA_4444_GrPixelConfig,
};
for (size_t i = 0; i < arraysize(kConfigOptions); i++) {
if (context_->caps()->isConfigRenderable(kConfigOptions[i], false)) {
*config = kConfigOptions[i];
return true;
}
}
return false;
}
sk_sp<SkSurface> GPUSurfaceGL::CreateSurface(const SkISize& size) {
if (delegate_ == nullptr || context_ == nullptr) {
return nullptr;
}
GrBackendRenderTargetDesc desc;
if (!SelectPixelConfig(&desc.fConfig)) {
return nullptr;
}
desc.fWidth = size.width();
desc.fHeight = size.height();
desc.fStencilBits = 8;
desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
desc.fRenderTargetHandle = delegate_->GLContextFBO();
return SkSurface::MakeFromBackendRenderTarget(context_.get(), desc, nullptr);
}
sk_sp<SkSurface> GPUSurfaceGL::AcquireSurface(const SkISize& size) {
// There is no cached surface.
if (cached_surface_ == nullptr) {
cached_surface_ = CreateSurface(size);
return cached_surface_;
}
// There is a surface previously created of the same size.
if (cached_surface_->width() == size.width() &&
cached_surface_->height() == size.height()) {
return cached_surface_;
}
cached_surface_ = CreateSurface(size);
return cached_surface_;
}
GrContext* GPUSurfaceGL::GetContext() {
return context_.get();
}
} // namespace shell