From 47a1ce0e628cf5850210ac9d7f856f1e8d8ee923 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Tue, 28 Aug 2018 14:13:49 -0700 Subject: [PATCH] Allow embedders to set the root surface transformation. (#6085) --- flow/compositor_context.cc | 20 ++++++--- flow/compositor_context.h | 7 +++ flow/layers/layer.h | 1 + flow/layers/layer_tree.cc | 25 ++++++----- flow/layers/picture_layer.cc | 3 +- flow/raster_cache.cc | 8 +++- flow/raster_cache.h | 3 +- shell/common/rasterizer.cc | 21 ++++++--- shell/common/surface.h | 2 + shell/gpu/gpu_surface_gl.cc | 43 +++++++++++++++---- shell/gpu/gpu_surface_gl.h | 18 +++++++- shell/gpu/gpu_surface_software.cc | 12 ++++++ shell/gpu/gpu_surface_software.h | 7 +++ shell/gpu/gpu_surface_vulkan.cc | 12 ++++++ shell/gpu/gpu_surface_vulkan.h | 6 +++ .../darwin/ios/ios_surface_software.h | 6 +++ shell/platform/embedder/embedder.cc | 19 ++++++++ shell/platform/embedder/embedder.h | 25 +++++++++++ .../embedder/platform_view_embedder.cc | 11 +++++ .../embedder/platform_view_embedder.h | 5 +++ 20 files changed, 220 insertions(+), 34 deletions(-) diff --git a/flow/compositor_context.cc b/flow/compositor_context.cc index 53659103b..3863bde7a 100644 --- a/flow/compositor_context.cc +++ b/flow/compositor_context.cc @@ -32,18 +32,26 @@ void CompositorContext::EndFrame(ScopedFrame& frame, std::unique_ptr CompositorContext::AcquireFrame( GrContext* gr_context, SkCanvas* canvas, + const SkMatrix& root_surface_transformation, bool instrumentation_enabled) { - return std::make_unique(*this, gr_context, canvas, - instrumentation_enabled); + return std::make_unique(*this, // + gr_context, // + canvas, // + root_surface_transformation, // + instrumentation_enabled // + ); } -CompositorContext::ScopedFrame::ScopedFrame(CompositorContext& context, - GrContext* gr_context, - SkCanvas* canvas, - bool instrumentation_enabled) +CompositorContext::ScopedFrame::ScopedFrame( + CompositorContext& context, + GrContext* gr_context, + SkCanvas* canvas, + const SkMatrix& root_surface_transformation, + bool instrumentation_enabled) : context_(context), gr_context_(gr_context), canvas_(canvas), + root_surface_transformation_(root_surface_transformation), instrumentation_enabled_(instrumentation_enabled) { context_.BeginFrame(*this, instrumentation_enabled_); } diff --git a/flow/compositor_context.h b/flow/compositor_context.h index 5a6700ff3..522c53599 100644 --- a/flow/compositor_context.h +++ b/flow/compositor_context.h @@ -26,6 +26,7 @@ class CompositorContext { ScopedFrame(CompositorContext& context, GrContext* gr_context, SkCanvas* canvas, + const SkMatrix& root_surface_transformation, bool instrumentation_enabled); virtual ~ScopedFrame(); @@ -34,6 +35,10 @@ class CompositorContext { CompositorContext& context() const { return context_; } + const SkMatrix& root_surface_transformation() const { + return root_surface_transformation_; + } + GrContext* gr_context() const { return gr_context_; } virtual bool Raster(LayerTree& layer_tree, bool ignore_raster_cache); @@ -42,6 +47,7 @@ class CompositorContext { CompositorContext& context_; GrContext* gr_context_; SkCanvas* canvas_; + const SkMatrix& root_surface_transformation_; const bool instrumentation_enabled_; FML_DISALLOW_COPY_AND_ASSIGN(ScopedFrame); @@ -54,6 +60,7 @@ class CompositorContext { virtual std::unique_ptr AcquireFrame( GrContext* gr_context, SkCanvas* canvas, + const SkMatrix& root_surface_transformation, bool instrumentation_enabled); void OnGrContextCreated(); diff --git a/flow/layers/layer.h b/flow/layers/layer.h index 173c2890b..53e32941e 100644 --- a/flow/layers/layer.h +++ b/flow/layers/layer.h @@ -57,6 +57,7 @@ class Layer { struct PaintContext { SkCanvas& canvas; + const SkMatrix& root_surface_transformation; const Stopwatch& frame_time; const Stopwatch& engine_time; TextureRegistry& texture_registry; diff --git a/flow/layers/layer_tree.cc b/flow/layers/layer_tree.cc index 8f6f7494a..007bd0fbd 100644 --- a/flow/layers/layer_tree.cc +++ b/flow/layers/layer_tree.cc @@ -63,11 +63,12 @@ void LayerTree::UpdateScene(SceneUpdateContext& context, void LayerTree::Paint(CompositorContext::ScopedFrame& frame) const { TRACE_EVENT0("flutter", "LayerTree::Paint"); Layer::PaintContext context = { - *frame.canvas(), // - frame.context().frame_time(), // - frame.context().engine_time(), // - frame.context().texture_registry(), // - checkerboard_offscreen_layers_ // + *frame.canvas(), // + frame.root_surface_transformation(), // + frame.context().frame_time(), // + frame.context().engine_time(), // + frame.context().texture_registry(), // + checkerboard_offscreen_layers_ // }; if (root_layer_->needs_painting()) @@ -93,13 +94,17 @@ sk_sp LayerTree::Flatten(const SkRect& bounds) { const Stopwatch unused_stopwatch; TextureRegistry unused_texture_registry; + SkMatrix root_surface_transformation; + // No root surface transformation. So assume identity. + root_surface_transformation.reset(); Layer::PaintContext paint_context = { - *canvas, // canvas - unused_stopwatch, // frame time (dont care) - unused_stopwatch, // engine time (dont care) - unused_texture_registry, // texture registry (not supported) - false // checkerboard offscreen layers + *canvas, // canvas + root_surface_transformation, // root surface transformation + unused_stopwatch, // frame time (dont care) + unused_stopwatch, // engine time (dont care) + unused_texture_registry, // texture registry (not supported) + false // checkerboard offscreen layers }; // Even if we don't have a root layer, we still need to create an empty diff --git a/flow/layers/picture_layer.cc b/flow/layers/picture_layer.cc index 3cbf15a60..9389e0862 100644 --- a/flow/layers/picture_layer.cc +++ b/flow/layers/picture_layer.cc @@ -45,7 +45,8 @@ void PictureLayer::Paint(PaintContext& context) const { #endif if (raster_cache_result_.is_valid()) { - raster_cache_result_.draw(context.canvas); + raster_cache_result_.draw(context.canvas, + context.root_surface_transformation); } else { context.canvas.drawPicture(picture()); } diff --git a/flow/raster_cache.cc b/flow/raster_cache.cc index a3aef6e3d..aadebb72d 100644 --- a/flow/raster_cache.cc +++ b/flow/raster_cache.cc @@ -17,12 +17,16 @@ namespace flow { -void RasterCacheResult::draw(SkCanvas& canvas) const { +void RasterCacheResult::draw( + SkCanvas& canvas, + const SkMatrix& root_surface_transformation) const { SkAutoCanvasRestore auto_restore(&canvas, true); SkIRect bounds = RasterCache::GetDeviceBounds(logical_rect_, canvas.getTotalMatrix()); FML_DCHECK(bounds.size() == image_->dimensions()); - canvas.resetMatrix(); + // Clear all transformations on the canvas except the root surface + // transormation. + canvas.setMatrix(root_surface_transformation); canvas.drawImage(image_, bounds.fLeft, bounds.fTop); } diff --git a/flow/raster_cache.h b/flow/raster_cache.h index 348ab8000..b2084d3bf 100644 --- a/flow/raster_cache.h +++ b/flow/raster_cache.h @@ -28,7 +28,8 @@ class RasterCacheResult { bool is_valid() const { return static_cast(image_); }; - void draw(SkCanvas& canvas) const; + void draw(SkCanvas& canvas, + const SkMatrix& root_surface_transformation) const; private: sk_sp image_; diff --git a/shell/common/rasterizer.cc b/shell/common/rasterizer.cc index e2721a5d0..6f0ddd53a 100644 --- a/shell/common/rasterizer.cc +++ b/shell/common/rasterizer.cc @@ -110,8 +110,8 @@ bool Rasterizer::DrawToSurface(flow::LayerTree& layer_tree) { auto canvas = frame->SkiaCanvas(); - auto compositor_frame = - compositor_context_->AcquireFrame(surface_->GetContext(), canvas, true); + auto compositor_frame = compositor_context_->AcquireFrame( + surface_->GetContext(), canvas, surface_->GetRootTransformation(), true); if (canvas) { canvas->clear(SK_ColorBLACK); @@ -134,8 +134,12 @@ static sk_sp ScreenshotLayerTreeAsPicture( recorder.beginRecording( SkRect::MakeWH(tree->frame_size().width(), tree->frame_size().height())); - auto frame = compositor_context.AcquireFrame( - nullptr, recorder.getRecordingCanvas(), false); + SkMatrix root_surface_transformation; + root_surface_transformation.reset(); + + auto frame = + compositor_context.AcquireFrame(nullptr, recorder.getRecordingCanvas(), + root_surface_transformation, false); frame->Raster(*tree, true); @@ -174,7 +178,14 @@ static sk_sp ScreenshotLayerTreeAsImage( // Draw the current layer tree into the snapshot surface. auto canvas = snapshot_surface->getCanvas(); - auto frame = compositor_context.AcquireFrame(surface_context, canvas, false); + + // There is no root surface transformation for the screenshot layer. Reset the + // matrix to identity. + SkMatrix root_surface_transformation; + root_surface_transformation.reset(); + + auto frame = compositor_context.AcquireFrame( + surface_context, canvas, root_surface_transformation, false); canvas->clear(SK_ColorBLACK); frame->Raster(*tree, true); canvas->flush(); diff --git a/shell/common/surface.h b/shell/common/surface.h index f178dda44..beef9765d 100644 --- a/shell/common/surface.h +++ b/shell/common/surface.h @@ -51,6 +51,8 @@ class Surface { virtual std::unique_ptr AcquireFrame(const SkISize& size) = 0; + virtual SkMatrix GetRootTransformation() const = 0; + virtual GrContext* GetContext() = 0; private: diff --git a/shell/gpu/gpu_surface_gl.cc b/shell/gpu/gpu_surface_gl.cc index bb2350b8e..505f9e40e 100644 --- a/shell/gpu/gpu_surface_gl.cc +++ b/shell/gpu/gpu_surface_gl.cc @@ -83,6 +83,7 @@ GPUSurfaceGL::~GPUSurfaceGL() { delegate_->GLContextClearCurrent(); } +// |shell::Surface| bool GPUSurfaceGL::IsValid() { return valid_; } @@ -110,8 +111,8 @@ static sk_sp WrapOnscreenSurface(GrContext* context, framebuffer_info.fFBOID = static_cast(fbo); framebuffer_info.fFormat = format; - GrBackendRenderTarget render_target(size.fWidth, // width - size.fHeight, // height + GrBackendRenderTarget render_target(size.width(), // width + size.height(), // height 0, // sample count 0, // stencil bits (TODO) framebuffer_info // framebuffer info @@ -168,7 +169,10 @@ bool GPUSurfaceGL::CreateOrUpdateSurfaces(const SkISize& size) { sk_sp onscreen_surface, offscreen_surface; onscreen_surface = - WrapOnscreenSurface(context_.get(), size, delegate_->GLContextFBO()); + WrapOnscreenSurface(context_.get(), // GL context + size, // root surface size + delegate_->GLContextFBO() // window FBO ID + ); if (onscreen_surface == nullptr) { // If the onscreen surface could not be wrapped. There is absolutely no @@ -191,6 +195,12 @@ bool GPUSurfaceGL::CreateOrUpdateSurfaces(const SkISize& size) { return true; } +// |shell::Surface| +SkMatrix GPUSurfaceGL::GetRootTransformation() const { + return delegate_->GLContextSurfaceTransformation(); +} + +// |shell::Surface| std::unique_ptr GPUSurfaceGL::AcquireFrame(const SkISize& size) { if (delegate_ == nullptr) { return nullptr; @@ -202,12 +212,17 @@ std::unique_ptr GPUSurfaceGL::AcquireFrame(const SkISize& size) { return nullptr; } - sk_sp surface = AcquireRenderSurface(size); + const auto root_surface_transformation = GetRootTransformation(); + + sk_sp 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) { @@ -244,8 +259,11 @@ bool GPUSurfaceGL::PresentSurface(SkCanvas* canvas) { // The FBO has changed, ask the delegate for the new FBO and do a surface // re-wrap. - auto new_onscreen_surface = WrapOnscreenSurface( - context_.get(), current_size, delegate_->GLContextFBO()); + auto new_onscreen_surface = + WrapOnscreenSurface(context_.get(), // GL context + current_size, // root surface size + delegate_->GLContextFBO() // window FBO ID + ); if (!new_onscreen_surface) { return false; @@ -257,14 +275,23 @@ bool GPUSurfaceGL::PresentSurface(SkCanvas* canvas) { return true; } -sk_sp GPUSurfaceGL::AcquireRenderSurface(const SkISize& size) { - if (!CreateOrUpdateSurfaces(size)) { +sk_sp 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 offscreen_surface_ != nullptr ? offscreen_surface_ : onscreen_surface_; } +// |shell::Surface| GrContext* GPUSurfaceGL::GetContext() { return context_.get(); } diff --git a/shell/gpu/gpu_surface_gl.h b/shell/gpu/gpu_surface_gl.h index 0eb42dcae..971e4649d 100644 --- a/shell/gpu/gpu_surface_gl.h +++ b/shell/gpu/gpu_surface_gl.h @@ -5,6 +5,8 @@ #ifndef SHELL_GPU_GPU_SURFACE_GL_H_ #define SHELL_GPU_GPU_SURFACE_GL_H_ +#include + #include "flutter/fml/macros.h" #include "flutter/fml/memory/weak_ptr.h" #include "flutter/shell/common/surface.h" @@ -25,6 +27,12 @@ class GPUSurfaceGLDelegate { virtual bool GLContextFBOResetAfterPresent() const { return false; } virtual bool UseOffscreenSurface() const { return false; } + + virtual SkMatrix GLContextSurfaceTransformation() const { + SkMatrix matrix; + matrix.setIdentity(); + return matrix; + } }; class GPUSurfaceGL : public Surface { @@ -33,10 +41,16 @@ class GPUSurfaceGL : public Surface { ~GPUSurfaceGL() override; + // |shell::Surface| bool IsValid() override; + // |shell::Surface| std::unique_ptr AcquireFrame(const SkISize& size) override; + // |shell::Surface| + SkMatrix GetRootTransformation() const override; + + // |shell::Surface| GrContext* GetContext() override; private: @@ -49,7 +63,9 @@ class GPUSurfaceGL : public Surface { bool CreateOrUpdateSurfaces(const SkISize& size); - sk_sp AcquireRenderSurface(const SkISize& size); + sk_sp AcquireRenderSurface( + const SkISize& untransformed_size, + const SkMatrix& root_surface_transformation); bool PresentSurface(SkCanvas* canvas); diff --git a/shell/gpu/gpu_surface_software.cc b/shell/gpu/gpu_surface_software.cc index 1d5f851c5..7598aa243 100644 --- a/shell/gpu/gpu_surface_software.cc +++ b/shell/gpu/gpu_surface_software.cc @@ -14,10 +14,12 @@ GPUSurfaceSoftware::GPUSurfaceSoftware(GPUSurfaceSoftwareDelegate* delegate) GPUSurfaceSoftware::~GPUSurfaceSoftware() = default; +// |shell::Surface| bool GPUSurfaceSoftware::IsValid() { return delegate_ != nullptr; } +// |shell::Surface| std::unique_ptr GPUSurfaceSoftware::AcquireFrame( const SkISize& logical_size) { if (!IsValid()) { @@ -58,6 +60,16 @@ std::unique_ptr GPUSurfaceSoftware::AcquireFrame( return std::make_unique(backing_store, on_submit); } +// |shell::Surface| +SkMatrix GPUSurfaceSoftware::GetRootTransformation() const { + // This backend does not currently support root surface transformations. Just + // return identity. + SkMatrix matrix; + matrix.reset(); + return matrix; +} + +// |shell::Surface| GrContext* GPUSurfaceSoftware::GetContext() { // There is no GrContext associated with a software surface. return nullptr; diff --git a/shell/gpu/gpu_surface_software.h b/shell/gpu/gpu_surface_software.h index ca09537f9..95940c470 100644 --- a/shell/gpu/gpu_surface_software.h +++ b/shell/gpu/gpu_surface_software.h @@ -15,6 +15,7 @@ namespace shell { class GPUSurfaceSoftwareDelegate { public: virtual sk_sp AcquireBackingStore(const SkISize& size) = 0; + virtual bool PresentBackingStore(sk_sp backing_store) = 0; }; @@ -24,10 +25,16 @@ class GPUSurfaceSoftware : public Surface { ~GPUSurfaceSoftware() override; + // |shell::Surface| bool IsValid() override; + // |shell::Surface| std::unique_ptr AcquireFrame(const SkISize& size) override; + // |shell::Surface| + SkMatrix GetRootTransformation() const override; + + // |shell::Surface| GrContext* GetContext() override; private: diff --git a/shell/gpu/gpu_surface_vulkan.cc b/shell/gpu/gpu_surface_vulkan.cc index cf92b921b..728fca6a0 100644 --- a/shell/gpu/gpu_surface_vulkan.cc +++ b/shell/gpu/gpu_surface_vulkan.cc @@ -15,10 +15,12 @@ GPUSurfaceVulkan::GPUSurfaceVulkan( GPUSurfaceVulkan::~GPUSurfaceVulkan() = default; +// |shell::Surface| bool GPUSurfaceVulkan::IsValid() { return window_.IsValid(); } +// |shell::Surface| std::unique_ptr GPUSurfaceVulkan::AcquireFrame( const SkISize& size) { auto surface = window_.AcquireSurface(); @@ -42,6 +44,16 @@ std::unique_ptr GPUSurfaceVulkan::AcquireFrame( std::move(callback)); } +// |shell::Surface| +SkMatrix GPUSurfaceVulkan::GetRootTransformation() const { + // This backend does not support delegating to the underlying platform to + // query for root surface transformations. Just return identity. + SkMatrix matrix; + matrix.reset(); + return matrix; +} + +// |shell::Surface| GrContext* GPUSurfaceVulkan::GetContext() { return window_.GetSkiaGrContext(); } diff --git a/shell/gpu/gpu_surface_vulkan.h b/shell/gpu/gpu_surface_vulkan.h index 996dd1325..fe4a34b81 100644 --- a/shell/gpu/gpu_surface_vulkan.h +++ b/shell/gpu/gpu_surface_vulkan.h @@ -22,10 +22,16 @@ class GPUSurfaceVulkan : public Surface { ~GPUSurfaceVulkan() override; + // |shell::Surface| bool IsValid() override; + // |shell::Surface| std::unique_ptr AcquireFrame(const SkISize& size) override; + // |shell::Surface| + SkMatrix GetRootTransformation() const override; + + // |shell::Surface| GrContext* GetContext() override; private: diff --git a/shell/platform/darwin/ios/ios_surface_software.h b/shell/platform/darwin/ios/ios_surface_software.h index ab2b483d1..154f05748 100644 --- a/shell/platform/darwin/ios/ios_surface_software.h +++ b/shell/platform/darwin/ios/ios_surface_software.h @@ -21,16 +21,22 @@ class IOSSurfaceSoftware final : public IOSSurface, ~IOSSurfaceSoftware() override; + // |shell::IOSSurface| bool IsValid() const override; + // |shell::IOSSurface| bool ResourceContextMakeCurrent() override; + // |shell::IOSSurface| void UpdateStorageSizeIfNecessary() override; + // |shell::IOSSurface| std::unique_ptr CreateGPUSurface() override; + // |shell::GPUSurfaceSoftwareDelegate| sk_sp AcquireBackingStore(const SkISize& size) override; + // |shell::GPUSurfaceSoftwareDelegate| bool PresentBackingStore(sk_sp backing_store) override; private: diff --git a/shell/platform/embedder/embedder.cc b/shell/platform/embedder/embedder.cc index 553350931..37509d676 100644 --- a/shell/platform/embedder/embedder.cc +++ b/shell/platform/embedder/embedder.cc @@ -128,6 +128,24 @@ FlutterResult FlutterEngineRun(size_t version, user_data]() { return ptr(user_data); }; } + std::function gl_surface_transformation_callback = nullptr; + if (SAFE_ACCESS(open_gl_config, surface_transformation, nullptr) != nullptr) { + gl_surface_transformation_callback = + [ptr = config->open_gl.surface_transformation, user_data]() { + FlutterTransformation transformation = ptr(user_data); + return SkMatrix::MakeAll(transformation.scaleX, // + transformation.skewX, // + transformation.transX, // + transformation.skewY, // + transformation.scaleY, // + transformation.transY, // + transformation.pers0, // + transformation.pers1, // + transformation.pers2 // + ); + }; + } + bool fbo_reset_after_present = SAFE_ACCESS(open_gl_config, fbo_reset_after_present, false); @@ -194,6 +212,7 @@ FlutterResult FlutterEngineRun(size_t version, fbo_callback, // gl_fbo_callback platform_message_response_callback, // platform_message_response_callback make_resource_current_callback, // gl_make_resource_current_callback + gl_surface_transformation_callback // gl_surface_transformation_callback }; shell::Shell::CreateCallback on_create_platform_view = diff --git a/shell/platform/embedder/embedder.h b/shell/platform/embedder/embedder.h index fa5bb7ba3..68bed60ee 100644 --- a/shell/platform/embedder/embedder.h +++ b/shell/platform/embedder/embedder.h @@ -31,7 +31,29 @@ typedef enum { typedef struct _FlutterEngine* FlutterEngine; +typedef struct { + // horizontal scale factor + double scaleX; + // horizontal skew factor + double skewX; + // horizontal translation + double transX; + // vertical skew factor + double skewY; + // vertical scale factor + double scaleY; + // vertical translation + double transY; + // input x-axis perspective factor + double pers0; + // input y-axis perspective factor + double pers1; + // perspective scale factor + double pers2; +} FlutterTransformation; + typedef bool (*BoolCallback)(void* /* user data */); +typedef FlutterTransformation (*TransformationCallback)(void* /* user data */); typedef uint32_t (*UIntCallback)(void* /* user data */); typedef struct { @@ -47,6 +69,9 @@ typedef struct { // engine will ask the embedder for an updated FBO target (via an fbo_callback // invocation) after a present call. bool fbo_reset_after_present; + // The transformation to apply to the render target before any rendering + // operations. This callback is optional. + TransformationCallback surface_transformation; } FlutterOpenGLRendererConfig; typedef struct { diff --git a/shell/platform/embedder/platform_view_embedder.cc b/shell/platform/embedder/platform_view_embedder.cc index a4dea939d..31fcc7da3 100644 --- a/shell/platform/embedder/platform_view_embedder.cc +++ b/shell/platform/embedder/platform_view_embedder.cc @@ -43,6 +43,17 @@ bool PlatformViewEmbedder::GLContextFBOResetAfterPresent() const { return fbo_reset_after_present_; } +// |shell::GPUSurfaceGLDelegate| +SkMatrix PlatformViewEmbedder::GLContextSurfaceTransformation() const { + auto callback = dispatch_table_.gl_surface_transformation_callback; + if (!callback) { + SkMatrix matrix; + matrix.setIdentity(); + return matrix; + } + return callback(); +} + void PlatformViewEmbedder::HandlePlatformMessage( fml::RefPtr message) { if (!message) { diff --git a/shell/platform/embedder/platform_view_embedder.h b/shell/platform/embedder/platform_view_embedder.h index ae1b19787..0442003f9 100644 --- a/shell/platform/embedder/platform_view_embedder.h +++ b/shell/platform/embedder/platform_view_embedder.h @@ -25,6 +25,8 @@ class PlatformViewEmbedder final : public PlatformView, PlatformMessageResponseCallback platform_message_response_callback; // optional std::function gl_make_resource_current_callback; // optional + std::function + gl_surface_transformation_callback; // optional }; PlatformViewEmbedder(PlatformView::Delegate& delegate, @@ -49,6 +51,9 @@ class PlatformViewEmbedder final : public PlatformView, // |shell::GPUSurfaceGLDelegate| bool GLContextFBOResetAfterPresent() const override; + // |shell::GPUSurfaceGLDelegate| + SkMatrix GLContextSurfaceTransformation() const override; + // |shell::PlatformView| void HandlePlatformMessage( fml::RefPtr message) override; -- GitLab