Skip to content

Commit

Permalink
On iOS, render to an offscreen surface to avoid renderbuffer slowdown (
Browse files Browse the repository at this point in the history
…flutter#4680)

* On iOS, render to an offscreen surface to avoid renderbuffer slowdown

Fixes flutter/flutter#14565

* null out old offscreen surface
  • Loading branch information
brianosman authored Feb 14, 2018
1 parent 1e054c3 commit f8778fc
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 2 deletions.
34 changes: 32 additions & 2 deletions shell/gpu/gpu_surface_gl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,19 @@ static sk_sp<SkSurface> WrapOnscreenSurface(GrContext* context,
);
}

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);
}

bool GPUSurfaceGL::CreateOrUpdateSurfaces(const SkISize& size) {
if (onscreen_surface_ != nullptr &&
size == SkISize::Make(onscreen_surface_->width(),
Expand All @@ -126,13 +139,14 @@ bool GPUSurfaceGL::CreateOrUpdateSurfaces(const SkISize& size) {

// Either way, we need to get rid of previous surface.
onscreen_surface_ = nullptr;
offscreen_surface_ = nullptr;

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

sk_sp<SkSurface> onscreen_surface;
sk_sp<SkSurface> onscreen_surface, offscreen_surface;

onscreen_surface =
WrapOnscreenSurface(context_.get(), size, delegate_->GLContextFBO());
Expand All @@ -144,7 +158,16 @@ bool GPUSurfaceGL::CreateOrUpdateSurfaces(const SkISize& size) {
return false;
}

if (delegate_->UseOffscreenSurface()) {
offscreen_surface = CreateOffscreenSurface(context_.get(), size);
if (offscreen_surface == nullptr) {
FXL_LOG(ERROR) << "Could not create offscreen surface.";
return false;
}
}

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

return true;
}
Expand Down Expand Up @@ -181,6 +204,13 @@ bool GPUSurfaceGL::PresentSurface(SkCanvas* canvas) {
return false;
}

if (offscreen_surface_ != nullptr) {
TRACE_EVENT0("flutter", "CopyTextureOnscreen");
SkPaint paint;
onscreen_surface_->getCanvas()->drawImage(
offscreen_surface_->makeImageSnapshot(), 0, 0, &paint);
}

{
TRACE_EVENT0("flutter", "SkCanvas::Flush");
onscreen_surface_->getCanvas()->flush();
Expand All @@ -196,7 +226,7 @@ sk_sp<SkSurface> GPUSurfaceGL::AcquireRenderSurface(const SkISize& size) {
return nullptr;
}

return onscreen_surface_;
return offscreen_surface_ != nullptr ? offscreen_surface_ : onscreen_surface_;
}

GrContext* GPUSurfaceGL::GetContext() {
Expand Down
3 changes: 3 additions & 0 deletions shell/gpu/gpu_surface_gl.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ class GPUSurfaceGLDelegate {
virtual bool GLContextPresent() = 0;

virtual intptr_t GLContextFBO() const = 0;

virtual bool UseOffscreenSurface() const { return false; }
};

class GPUSurfaceGL : public Surface {
Expand All @@ -40,6 +42,7 @@ class GPUSurfaceGL : public Surface {
GPUSurfaceGLDelegate* delegate_;
sk_sp<GrContext> context_;
sk_sp<SkSurface> onscreen_surface_;
sk_sp<SkSurface> offscreen_surface_;
bool valid_ = false;
fml::WeakPtrFactory<GPUSurfaceGL> weak_factory_;

Expand Down
2 changes: 2 additions & 0 deletions shell/platform/darwin/ios/ios_surface_gl.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ class IOSSurfaceGL : public IOSSurface, public GPUSurfaceGLDelegate {

intptr_t GLContextFBO() const override;

bool UseOffscreenSurface() const override;

private:
IOSGLContext context_;

Expand Down
7 changes: 7 additions & 0 deletions shell/platform/darwin/ios/ios_surface_gl.mm
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@
return IsValid() ? context_.framebuffer() : GL_NONE;
}

bool IOSSurfaceGL::UseOffscreenSurface() const {
// The onscreen surface wraps a GL renderbuffer, which is extremely slow to read.
// Certain filter effects require making a copy of the current destination, so we
// always render to an offscreen surface, which will be much quicker to read/copy.
return true;
}

bool IOSSurfaceGL::GLContextMakeCurrent() {
return IsValid() ? context_.MakeCurrent() : false;
}
Expand Down

0 comments on commit f8778fc

Please sign in to comment.