gpu_surface_gl.cc 9.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 8
#include "flutter/fml/arraysize.h"
#include "flutter/fml/logging.h"
9
#include "flutter/fml/trace_event.h"
10
#include "flutter/shell/common/persistent_cache.h"
11
#include "third_party/skia/include/core/SkColorFilter.h"
12
#include "third_party/skia/include/core/SkSurface.h"
13
#include "third_party/skia/include/gpu/GrBackendSurface.h"
14
#include "third_party/skia/include/gpu/GrContextOptions.h"
15
#include "third_party/skia/include/gpu/gl/GrGLAssembleInterface.h"
16
#include "third_party/skia/include/gpu/gl/GrGLInterface.h"
17 18 19 20 21 22 23 24

// 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
25

26 27 28 29
#ifdef ERROR
#undef ERROR
#endif

30 31
namespace shell {

32 33
// Default maximum number of budgeted resources in the cache.
static const int kGrCacheMaxCount = 8192;
34

35 36 37
// Default maximum number of bytes of GPU memory of budgeted resources in the
// cache.
static const size_t kGrCacheMaxByteSize = 512 * (1 << 20);
38

39
GPUSurfaceGL::GPUSurfaceGL(GPUSurfaceGLDelegate* delegate)
40
    : delegate_(delegate), weak_factory_(this) {
41
  if (!delegate_->GLContextMakeCurrent()) {
42
    FML_LOG(ERROR)
43 44
        << "Could not make the context current to setup the gr context.";
    return;
45 46
  }

47 48
  proc_resolver_ = delegate_->GetGLProcResolver();

49
  GrContextOptions options;
50 51 52

  options.fPersistentCache = PersistentCache::GetCacheForProcess();

53 54
  options.fAvoidStencilBuffers = true;

55 56 57 58
  // 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;

59 60 61 62 63 64 65 66 67 68 69 70
  auto interface =
      proc_resolver_
          ? GrGLMakeAssembledGLESInterface(
                this /* context */,
                [](void* context, const char gl_proc_name[]) -> GrGLFuncPtr {
                  return reinterpret_cast<GrGLFuncPtr>(
                      reinterpret_cast<GPUSurfaceGL*>(context)->proc_resolver_(
                          gl_proc_name));
                })
          : GrGLMakeNativeInterface();

  auto context = GrContext::MakeGL(interface, options);
71 72

  if (context == nullptr) {
73
    FML_LOG(ERROR) << "Failed to setup Skia Gr context.";
74
    return;
75 76
  }

77 78
  context_ = std::move(context);

79
  context_->setResourceCacheLimits(kGrCacheMaxCount, kGrCacheMaxByteSize);
80

81 82
  delegate_->GLContextClearCurrent();

83 84 85 86 87 88 89 90 91
  valid_ = true;
}

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

  if (!delegate_->GLContextMakeCurrent()) {
92
    FML_LOG(ERROR) << "Could not make the context current to destroy the "
93 94 95 96 97 98 99 100 101
                      "GrContext resources.";
    return;
  }

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

  delegate_->GLContextClearCurrent();
102 103
}

104
// |shell::Surface|
105
bool GPUSurfaceGL::IsValid() {
106 107 108
  return valid_;
}

109 110
static SkColorType FirstSupportedColorType(GrContext* context,
                                           GrGLenum* format) {
111 112 113 114
#define RETURN_IF_RENDERABLE(x, y)                 \
  if (context->colorTypeSupportedAsSurface((x))) { \
    *format = (y);                                 \
    return (x);                                    \
115
  }
116 117 118
  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);
119
  return kUnknown_SkColorType;
120 121
}

122 123
static sk_sp<SkSurface> WrapOnscreenSurface(GrContext* context,
                                            const SkISize& size,
124
                                            intptr_t fbo) {
125
  GrGLenum format;
126 127
  const SkColorType color_type = FirstSupportedColorType(context, &format);

128 129 130
  GrGLFramebufferInfo framebuffer_info = {};
  framebuffer_info.fFBOID = static_cast<GrGLuint>(fbo);
  framebuffer_info.fFormat = format;
131

132 133
  GrBackendRenderTarget render_target(size.width(),     // width
                                      size.height(),    // height
134 135 136
                                      0,                // sample count
                                      0,                // stencil bits (TODO)
                                      framebuffer_info  // framebuffer info
137
  );
138

139
  sk_sp<SkColorSpace> colorspace = nullptr;
140 141 142 143 144 145 146 147

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

  return SkSurface::MakeFromBackendRenderTarget(
      context,                                       // gr context
      render_target,                                 // render target
      GrSurfaceOrigin::kBottomLeft_GrSurfaceOrigin,  // origin
148
      color_type,                                    // color type
149 150
      colorspace,                                    // colorspace
      &surface_props                                 // surface properties
151
  );
152 153
}

154 155 156 157 158 159 160 161 162 163 164 165 166
static sk_sp<SkSurface> CreateOffscreenSurface(GrContext* context,
                                               const SkISize& size) {
  const SkImageInfo image_info =
      SkImageInfo::MakeN32(size.fWidth, size.fHeight, kOpaque_SkAlphaType);

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

  return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, image_info, 0,
                                     kBottomLeft_GrSurfaceOrigin,
                                     &surface_props);
}

167 168 169 170
bool GPUSurfaceGL::CreateOrUpdateSurfaces(const SkISize& size) {
  if (onscreen_surface_ != nullptr &&
      size == SkISize::Make(onscreen_surface_->width(),
                            onscreen_surface_->height())) {
171
    // Surface size appears unchanged. So bail.
172 173 174 175 176 177
    return true;
  }

  // We need to do some updates.
  TRACE_EVENT0("flutter", "UpdateSurfacesSize");

178
  // Either way, we need to get rid of previous surface.
179
  onscreen_surface_ = nullptr;
180
  offscreen_surface_ = nullptr;
181 182

  if (size.isEmpty()) {
183
    FML_LOG(ERROR) << "Cannot create surfaces of empty size.";
184 185 186
    return false;
  }

187
  sk_sp<SkSurface> onscreen_surface, offscreen_surface;
188

189
  onscreen_surface =
190 191 192 193
      WrapOnscreenSurface(context_.get(),            // GL context
                          size,                      // root surface size
                          delegate_->GLContextFBO()  // window FBO ID
      );
194

195
  if (onscreen_surface == nullptr) {
196 197
    // If the onscreen surface could not be wrapped. There is absolutely no
    // point in moving forward.
198
    FML_LOG(ERROR) << "Could not wrap onscreen surface.";
199 200 201
    return false;
  }

202 203 204
  if (delegate_->UseOffscreenSurface()) {
    offscreen_surface = CreateOffscreenSurface(context_.get(), size);
    if (offscreen_surface == nullptr) {
205
      FML_LOG(ERROR) << "Could not create offscreen surface.";
206 207 208 209
      return false;
    }
  }

210
  onscreen_surface_ = std::move(onscreen_surface);
211
  offscreen_surface_ = std::move(offscreen_surface);
212 213

  return true;
214 215
}

216 217 218 219 220 221
// |shell::Surface|
SkMatrix GPUSurfaceGL::GetRootTransformation() const {
  return delegate_->GLContextSurfaceTransformation();
}

// |shell::Surface|
222 223 224 225 226
std::unique_ptr<SurfaceFrame> GPUSurfaceGL::AcquireFrame(const SkISize& size) {
  if (delegate_ == nullptr) {
    return nullptr;
  }

227
  if (!delegate_->GLContextMakeCurrent()) {
228
    FML_LOG(ERROR)
229
        << "Could not make the context current to acquire the frame.";
230 231 232
    return nullptr;
  }

233 234 235 236
  const auto root_surface_transformation = GetRootTransformation();

  sk_sp<SkSurface> surface =
      AcquireRenderSurface(size, root_surface_transformation);
237 238 239 240 241

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

242 243
  surface->getCanvas()->setMatrix(root_surface_transformation);

244 245 246 247 248
  SurfaceFrame::SubmitCallback submit_callback =
      [weak = weak_factory_.GetWeakPtr()](const SurfaceFrame& surface_frame,
                                          SkCanvas* canvas) {
        return weak ? weak->PresentSurface(canvas) : false;
      };
249

250
  return std::make_unique<SurfaceFrame>(surface, submit_callback);
251 252 253
}

bool GPUSurfaceGL::PresentSurface(SkCanvas* canvas) {
254
  if (delegate_ == nullptr || canvas == nullptr || context_ == nullptr) {
255 256 257
    return false;
  }

258 259 260 261 262 263 264
  if (offscreen_surface_ != nullptr) {
    TRACE_EVENT0("flutter", "CopyTextureOnscreen");
    SkPaint paint;
    onscreen_surface_->getCanvas()->drawImage(
        offscreen_surface_->makeImageSnapshot(), 0, 0, &paint);
  }

265 266
  {
    TRACE_EVENT0("flutter", "SkCanvas::Flush");
267
    onscreen_surface_->getCanvas()->flush();
268
  }
269

270 271 272 273 274 275 276 277 278 279
  if (!delegate_->GLContextPresent()) {
    return false;
  }

  if (delegate_->GLContextFBOResetAfterPresent()) {
    auto current_size =
        SkISize::Make(onscreen_surface_->width(), onscreen_surface_->height());

    // The FBO has changed, ask the delegate for the new FBO and do a surface
    // re-wrap.
280 281 282 283 284
    auto new_onscreen_surface =
        WrapOnscreenSurface(context_.get(),            // GL context
                            current_size,              // root surface size
                            delegate_->GLContextFBO()  // window FBO ID
        );
285 286 287 288 289 290 291

    if (!new_onscreen_surface) {
      return false;
    }

    onscreen_surface_ = std::move(new_onscreen_surface);
  }
292 293

  return true;
294 295
}

296 297 298 299 300 301 302 303 304 305
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)) {
306 307 308
    return nullptr;
  }

309
  return offscreen_surface_ != nullptr ? offscreen_surface_ : onscreen_surface_;
310 311
}

312
// |shell::Surface|
313
GrContext* GPUSurfaceGL::GetContext() {
314 315
  return context_.get();
}
316 317

}  // namespace shell