gpu_surface_gl.cc 7.9 KB
Newer Older
1 2 3 4
// 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.

5
#include "gpu_surface_gl.h"
6

7
#include "flutter/glue/trace_event.h"
8 9
#include "lib/ftl/arraysize.h"
#include "lib/ftl/logging.h"
10
#include "third_party/skia/include/core/SkColorFilter.h"
11
#include "third_party/skia/include/core/SkSurface.h"
12
#include "third_party/skia/include/gpu/GrBackendSurface.h"
13
#include "third_party/skia/include/gpu/GrContextOptions.h"
14 15
#include "third_party/skia/include/gpu/gl/GrGLInterface.h"

16 17
namespace shell {

18 19
// Default maximum number of budgeted resources in the cache.
static const int kGrCacheMaxCount = 8192;
20

21 22 23
// Default maximum number of bytes of GPU memory of budgeted resources in the
// cache.
static const size_t kGrCacheMaxByteSize = 512 * (1 << 20);
24

25
GPUSurfaceGL::GPUSurfaceGL(GPUSurfaceGLDelegate* delegate)
26
    : delegate_(delegate),
J
Jason Simmons 已提交
27
      onscreen_surface_supports_srgb_(delegate_->SurfaceSupportsSRGB()),
28
      weak_factory_(this) {
29
  if (!delegate_->GLContextMakeCurrent()) {
30 31 32
    FTL_LOG(ERROR)
        << "Could not make the context current to setup the gr context.";
    return;
33 34
  }

35 36 37
  auto backend_context =
      reinterpret_cast<GrBackendContext>(GrGLCreateNativeInterface());

38 39
  GrContextOptions options;
  options.fRequireDecodeDisableForSRGB = false;
40

41 42 43 44 45 46
  auto context = sk_sp<GrContext>(
      GrContext::Create(kOpenGL_GrBackend, backend_context, options));

  if (context == nullptr) {
    FTL_LOG(ERROR) << "Failed to setup Skia Gr context.";
    return;
47 48
  }

49 50
  context_ = std::move(context);

51
  context_->setResourceCacheLimits(kGrCacheMaxCount, kGrCacheMaxByteSize);
52

53 54
  delegate_->GLContextClearCurrent();

55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
  valid_ = true;
}

GPUSurfaceGL::~GPUSurfaceGL() {
  if (!valid_) {
    return;
  }

  if (!delegate_->GLContextMakeCurrent()) {
    FTL_LOG(ERROR) << "Could not make the context current to destroy the "
                      "GrContext resources.";
    return;
  }

  onscreen_surface_ = nullptr;
  offscreen_surface_ = nullptr;
  context_->releaseResourcesAndAbandonContext();
  context_ = nullptr;

  delegate_->GLContextClearCurrent();
75 76
}

77
bool GPUSurfaceGL::IsValid() {
78 79 80 81 82 83 84 85
  return valid_;
}

static sk_sp<SkSurface> WrapOnscreenSurface(GrContext* context,
                                            const SkISize& size,
                                            intptr_t fbo,
                                            bool supports_srgb) {
  const GrGLFramebufferInfo framebuffer_info = {
86
      .fFBOID = static_cast<GrGLuint>(fbo),
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
  };

  const GrPixelConfig pixel_config =
      supports_srgb ? kSRGBA_8888_GrPixelConfig : kRGBA_8888_GrPixelConfig;

  GrBackendRenderTarget render_target(size.fWidth,      // width
                                      size.fHeight,     // height
                                      0,                // sample count
                                      0,                // stencil bits (TODO)
                                      pixel_config,     // pixel config
                                      framebuffer_info  // framebuffer info
                                      );

  sk_sp<SkColorSpace> colorspace =
      supports_srgb ? SkColorSpace::MakeSRGB() : nullptr;

  SkSurfaceProps surface_props(
      SkSurfaceProps::InitType::kLegacyFontHost_InitType);

  return SkSurface::MakeFromBackendRenderTarget(
      context,                                       // gr context
      render_target,                                 // render target
      GrSurfaceOrigin::kBottomLeft_GrSurfaceOrigin,  // origin
      colorspace,                                    // colorspace
      &surface_props                                 // surface properties
      );
}

static sk_sp<SkSurface> CreateOffscreenSurface(GrContext* context,
                                               const SkISize& size) {
  const SkImageInfo image_info =
      SkImageInfo::MakeS32(size.fWidth, size.fHeight, kOpaque_SkAlphaType);

  const SkSurfaceProps surface_props(
      SkSurfaceProps::InitType::kLegacyFontHost_InitType);

  return SkSurface::MakeRenderTarget(
      context,                      // context
      SkBudgeted::kNo,              // budgeted
      image_info,                   // image info
      0,                            // sample count
      kBottomLeft_GrSurfaceOrigin,  // surface origin
      &surface_props                // surface props
      );
}

bool GPUSurfaceGL::CreateOrUpdateSurfaces(const SkISize& size) {
  if (onscreen_surface_ != nullptr &&
      size == SkISize::Make(onscreen_surface_->width(),
                            onscreen_surface_->height())) {
    // We know that if there is an offscreen surface, it will be sized to be
    // equal to the size of the onscreen surface. And the onscreen 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 surfaces.
  onscreen_surface_ = nullptr;
  offscreen_surface_ = nullptr;

  if (size.isEmpty()) {
    FTL_LOG(ERROR) << "Cannot create surfaces of empty size.";
    return false;
  }

  sk_sp<SkSurface> onscreen_surface, offscreen_surface;

  onscreen_surface =
      WrapOnscreenSurface(context_.get(), size, delegate_->GLContextFBO(),
J
Jason Simmons 已提交
159
                          onscreen_surface_supports_srgb_);
160 161 162 163 164
  if (onscreen_surface == nullptr) {
    FTL_LOG(ERROR) << "Could not wrap onscreen surface.";
    return false;
  }

J
Jason Simmons 已提交
165
  if (!onscreen_surface_supports_srgb_) {
166 167 168 169 170 171 172 173 174 175 176
    offscreen_surface = CreateOffscreenSurface(context_.get(), size);
    if (offscreen_surface == nullptr) {
      FTL_LOG(ERROR) << "Could not create offscreen surface.";
      return false;
    }
  }

  onscreen_surface_ = std::move(onscreen_surface);
  offscreen_surface_ = std::move(offscreen_surface);

  return true;
177 178
}

179 180 181 182 183
std::unique_ptr<SurfaceFrame> GPUSurfaceGL::AcquireFrame(const SkISize& size) {
  if (delegate_ == nullptr) {
    return nullptr;
  }

184
  if (!delegate_->GLContextMakeCurrent()) {
185 186
    FTL_LOG(ERROR)
        << "Could not make the context current to acquire the frame.";
187 188 189
    return nullptr;
  }

190
  sk_sp<SkSurface> surface = AcquireRenderSurface(size);
191 192 193 194 195

  if (surface == nullptr) {
    return nullptr;
  }

196 197
  auto weak_this = weak_factory_.GetWeakPtr();

198 199 200 201
  SurfaceFrame::SubmitCallback submit_callback =
      [weak_this](const SurfaceFrame& surface_frame, SkCanvas* canvas) {
        return weak_this ? weak_this->PresentSurface(canvas) : false;
      };
202

203
  return std::make_unique<SurfaceFrame>(surface, submit_callback);
204 205 206
}

bool GPUSurfaceGL::PresentSurface(SkCanvas* canvas) {
207
  if (delegate_ == nullptr || canvas == nullptr || context_ == nullptr) {
208 209 210
    return false;
  }

J
Jason Simmons 已提交
211
  if (!onscreen_surface_supports_srgb_) {
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
    // Because the surface did not support sRGB, we rendered to an offscreen
    // surface. Now we must ensure that the texture is copied onscreen.
    TRACE_EVENT0("flutter", "CopyTextureOnscreen");
    FTL_DCHECK(offscreen_surface_ != nullptr);
    SkPaint paint;
    const GrCaps* caps = context_->caps();
    if (caps->srgbSupport() && !caps->srgbDecodeDisableSupport()) {
      paint.setColorFilter(SkColorFilter::MakeLinearToSRGBGamma());
    }
    onscreen_surface_->getCanvas()->drawImage(
        offscreen_surface_->makeImageSnapshot(),  // image
        0,                                        // left
        0,                                        // top
        &paint                                    // paint
        );
  }

229 230
  {
    TRACE_EVENT0("flutter", "SkCanvas::Flush");
231
    onscreen_surface_->getCanvas()->flush();
232
  }
233 234 235 236

  delegate_->GLContextPresent();

  return true;
237 238
}

239 240
sk_sp<SkSurface> GPUSurfaceGL::AcquireRenderSurface(const SkISize& size) {
  if (!CreateOrUpdateSurfaces(size)) {
241 242 243
    return nullptr;
  }

J
Jason Simmons 已提交
244
  return onscreen_surface_supports_srgb_ ? onscreen_surface_
245
                                         : offscreen_surface_;
246 247
}

248
GrContext* GPUSurfaceGL::GetContext() {
249 250
  return context_.get();
}
251 252

}  // namespace shell