From b221bfa3c9d2b48e7b2f9396720b67c7bdc6238e Mon Sep 17 00:00:00 2001 From: Dan Field Date: Tue, 9 Nov 2021 22:20:49 -0800 Subject: [PATCH 1/4] eglPresentationTimeANDROID --- flow/surface_frame.h | 7 ++ shell/common/rasterizer.cc | 90 +++++++++---------- shell/common/shell_test_platform_view_gl.cc | 3 +- shell/common/shell_test_platform_view_gl.h | 2 +- shell/gpu/gpu_surface_gl.cc | 9 +- shell/gpu/gpu_surface_gl.h | 2 +- shell/gpu/gpu_surface_gl_delegate.h | 3 +- shell/platform/android/android_context_gl.cc | 4 +- shell/platform/android/android_context_gl.h | 6 +- shell/platform/android/android_surface_gl.cc | 5 +- shell/platform/android/android_surface_gl.h | 2 +- .../android/surface/android_surface_mock.cc | 3 +- .../android/surface/android_surface_mock.h | 2 +- shell/platform/darwin/ios/ios_surface_gl.h | 2 +- shell/platform/darwin/ios/ios_surface_gl.mm | 2 +- .../platform/embedder/embedder_surface_gl.cc | 3 +- shell/platform/embedder/embedder_surface_gl.h | 2 +- 17 files changed, 84 insertions(+), 63 deletions(-) diff --git a/flow/surface_frame.h b/flow/surface_frame.h index 0e15cde4908e7..9ecac8b3d2fcc 100644 --- a/flow/surface_frame.h +++ b/flow/surface_frame.h @@ -10,6 +10,7 @@ #include "flutter/common/graphics/gl_context_switch.h" #include "flutter/fml/macros.h" +#include "flutter/fml/time/time_point.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkSurface.h" @@ -66,6 +67,12 @@ class SurfaceFrame { // // Corresponds to EGL_KHR_partial_update std::optional buffer_damage; + + // The vsync target time. + // + // Backends may use this information to avoid overloading the GPU with + // multiple frames per vsync. + fml::TimePoint target_time; }; bool Submit(); diff --git a/shell/common/rasterizer.cc b/shell/common/rasterizer.cc index 9a0dddfa1f365..026e45d293f62 100644 --- a/shell/common/rasterizer.cc +++ b/shell/common/rasterizer.cc @@ -536,60 +536,60 @@ RasterStatus Rasterizer::DrawToSurfaceUnsafe( .supports_readback, // surface supports pixel reads raster_thread_merger_ // thread merger ); - if (compositor_frame) { - compositor_context_->raster_cache().PrepareNewFrame(); - frame_timings_recorder.RecordRasterStart(fml::TimePoint::Now()); - - // Disable partial repaint if external_view_embedder_ SubmitFrame is - // involved - ExternalViewEmbedder unconditionally clears the entire - // surface and also partial repaint with platform view present is something - // that still need to be figured out. - bool disable_partial_repaint = - external_view_embedder_ && - (!raster_thread_merger_ || raster_thread_merger_->IsMerged()); - - FrameDamage damage; - if (!disable_partial_repaint && frame->framebuffer_info().existing_damage) { - damage.SetPreviousLayerTree(last_layer_tree_.get()); - damage.AddAdditonalDamage(*frame->framebuffer_info().existing_damage); - } + if (!compositor_frame) { + return RasterStatus::kFailed; + } - RasterStatus raster_status = - compositor_frame->Raster(layer_tree, false, &damage); - if (raster_status == RasterStatus::kFailed || - raster_status == RasterStatus::kSkipAndRetry) { - return raster_status; - } + compositor_context_->raster_cache().PrepareNewFrame(); + frame_timings_recorder.RecordRasterStart(fml::TimePoint::Now()); - SurfaceFrame::SubmitInfo submit_info; - submit_info.frame_damage = damage.GetFrameDamage(); - submit_info.buffer_damage = damage.GetBufferDamage(); + // Disable partial repaint if external_view_embedder_ SubmitFrame is + // involved - ExternalViewEmbedder unconditionally clears the entire + // surface and also partial repaint with platform view present is something + // that still need to be figured out. + bool disable_partial_repaint = + external_view_embedder_ && + (!raster_thread_merger_ || raster_thread_merger_->IsMerged()); - frame->set_submit_info(submit_info); + FrameDamage damage; + if (!disable_partial_repaint && frame->framebuffer_info().existing_damage) { + damage.SetPreviousLayerTree(last_layer_tree_.get()); + damage.AddAdditonalDamage(*frame->framebuffer_info().existing_damage); + } - if (external_view_embedder_ && - (!raster_thread_merger_ || raster_thread_merger_->IsMerged())) { - FML_DCHECK(!frame->IsSubmitted()); - external_view_embedder_->SubmitFrame(surface_->GetContext(), - std::move(frame)); - } else { - frame->Submit(); - } + RasterStatus raster_status = + compositor_frame->Raster(layer_tree, false, &damage); + if (raster_status == RasterStatus::kFailed || + raster_status == RasterStatus::kSkipAndRetry) { + return raster_status; + } - compositor_context_->raster_cache().CleanupAfterFrame(); - frame_timings_recorder.RecordRasterEnd( - &compositor_context_->raster_cache()); - FireNextFrameCallbackIfPresent(); + SurfaceFrame::SubmitInfo submit_info; + submit_info.frame_damage = damage.GetFrameDamage(); + submit_info.buffer_damage = damage.GetBufferDamage(); + submit_info.target_time = frame_timings_recorder.GetVsyncTargetTime(); - if (surface_->GetContext()) { - TRACE_EVENT0("flutter", "PerformDeferredSkiaCleanup"); - surface_->GetContext()->performDeferredCleanup(kSkiaCleanupExpiration); - } + frame->set_submit_info(submit_info); - return raster_status; + if (external_view_embedder_ && + (!raster_thread_merger_ || raster_thread_merger_->IsMerged())) { + FML_DCHECK(!frame->IsSubmitted()); + external_view_embedder_->SubmitFrame(surface_->GetContext(), + std::move(frame)); + } else { + frame->Submit(); } - return RasterStatus::kFailed; + compositor_context_->raster_cache().CleanupAfterFrame(); + frame_timings_recorder.RecordRasterEnd(&compositor_context_->raster_cache()); + FireNextFrameCallbackIfPresent(); + + if (surface_->GetContext()) { + TRACE_EVENT0("flutter", "PerformDeferredSkiaCleanup"); + surface_->GetContext()->performDeferredCleanup(kSkiaCleanupExpiration); + } + + return raster_status; } static sk_sp ScreenshotLayerTreeAsPicture( diff --git a/shell/common/shell_test_platform_view_gl.cc b/shell/common/shell_test_platform_view_gl.cc index 8717991c10a06..f43042c29a8c1 100644 --- a/shell/common/shell_test_platform_view_gl.cc +++ b/shell/common/shell_test_platform_view_gl.cc @@ -63,7 +63,8 @@ bool ShellTestPlatformViewGL::GLContextClearCurrent() { } // |GPUSurfaceGLDelegate| -bool ShellTestPlatformViewGL::GLContextPresent(uint32_t fbo_id) { +bool ShellTestPlatformViewGL::GLContextPresent(fml::TimePoint target_time, + uint32_t fbo_id) { return gl_surface_.Present(); } diff --git a/shell/common/shell_test_platform_view_gl.h b/shell/common/shell_test_platform_view_gl.h index d072dd9731b9c..51d52ab9a8246 100644 --- a/shell/common/shell_test_platform_view_gl.h +++ b/shell/common/shell_test_platform_view_gl.h @@ -58,7 +58,7 @@ class ShellTestPlatformViewGL : public ShellTestPlatformView, bool GLContextClearCurrent() override; // |GPUSurfaceGLDelegate| - bool GLContextPresent(uint32_t fbo_id) override; + bool GLContextPresent(fml::TimePoint target_time, uint32_t fbo_id) override; // |GPUSurfaceGLDelegate| intptr_t GLContextFBO(GLFrameInfo frame_info) const override; diff --git a/shell/gpu/gpu_surface_gl.cc b/shell/gpu/gpu_surface_gl.cc index 518764a15694e..30a5e7d4a993d 100644 --- a/shell/gpu/gpu_surface_gl.cc +++ b/shell/gpu/gpu_surface_gl.cc @@ -242,7 +242,9 @@ std::unique_ptr GPUSurfaceGL::AcquireFrame(const SkISize& size) { SurfaceFrame::SubmitCallback submit_callback = [weak = weak_factory_.GetWeakPtr()](const SurfaceFrame& surface_frame, SkCanvas* canvas) { - return weak ? weak->PresentSurface(canvas) : false; + return weak ? weak->PresentSurface( + surface_frame.submit_info().target_time, canvas) + : false; }; framebuffer_info = delegate_->GLContextFramebufferInfo(); @@ -251,7 +253,8 @@ std::unique_ptr GPUSurfaceGL::AcquireFrame(const SkISize& size) { std::move(context_switch)); } -bool GPUSurfaceGL::PresentSurface(SkCanvas* canvas) { +bool GPUSurfaceGL::PresentSurface(fml::TimePoint target_time, + SkCanvas* canvas) { if (delegate_ == nullptr || canvas == nullptr || context_ == nullptr) { return false; } @@ -261,7 +264,7 @@ bool GPUSurfaceGL::PresentSurface(SkCanvas* canvas) { onscreen_surface_->getCanvas()->flush(); } - if (!delegate_->GLContextPresent(fbo_id_)) { + if (!delegate_->GLContextPresent(target_time, fbo_id_)) { return false; } diff --git a/shell/gpu/gpu_surface_gl.h b/shell/gpu/gpu_surface_gl.h index e4b04d31f9ed5..d9a0f6c081084 100644 --- a/shell/gpu/gpu_surface_gl.h +++ b/shell/gpu/gpu_surface_gl.h @@ -74,7 +74,7 @@ class GPUSurfaceGL : public Surface { const SkISize& untransformed_size, const SkMatrix& root_surface_transformation); - bool PresentSurface(SkCanvas* canvas); + bool PresentSurface(fml::TimePoint target_time, SkCanvas* canvas); FML_DISALLOW_COPY_AND_ASSIGN(GPUSurfaceGL); }; diff --git a/shell/gpu/gpu_surface_gl_delegate.h b/shell/gpu/gpu_surface_gl_delegate.h index 58a600347feb6..864126dafc192 100644 --- a/shell/gpu/gpu_surface_gl_delegate.h +++ b/shell/gpu/gpu_surface_gl_delegate.h @@ -33,7 +33,8 @@ class GPUSurfaceGLDelegate { // Called to present the main GL surface. This is only called for the main GL // context and not any of the contexts dedicated for IO. - virtual bool GLContextPresent(uint32_t fbo_id) = 0; + virtual bool GLContextPresent(fml::TimePoint target_time, + uint32_t fbo_id) = 0; // The ID of the main window bound framebuffer. Typically FBO0. virtual intptr_t GLContextFBO(GLFrameInfo frame_info) const = 0; diff --git a/shell/platform/android/android_context_gl.cc b/shell/platform/android/android_context_gl.cc index 1d0f83cafa7e7..1535e1ca4c3a3 100644 --- a/shell/platform/android/android_context_gl.cc +++ b/shell/platform/android/android_context_gl.cc @@ -128,8 +128,10 @@ bool AndroidEGLSurface::MakeCurrent() const { return true; } -bool AndroidEGLSurface::SwapBuffers() { +bool AndroidEGLSurface::SwapBuffers(fml::TimePoint target_time) { TRACE_EVENT0("flutter", "AndroidContextGL::SwapBuffers"); + eglPresentationTimeANDROID(display_, surface_, + target_time.ToEpochDelta().ToNanoseconds()); return eglSwapBuffers(display_, surface_); } diff --git a/shell/platform/android/android_context_gl.h b/shell/platform/android/android_context_gl.h index b9e34ecf6f854..867cf0ad80393 100644 --- a/shell/platform/android/android_context_gl.h +++ b/shell/platform/android/android_context_gl.h @@ -5,6 +5,10 @@ #ifndef FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_CONTEXT_GL_H_ #define FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_CONTEXT_GL_H_ +#include +#define EGL_EGLEXT_PROTOTYPES +#include + #include "flutter/fml/macros.h" #include "flutter/fml/memory/ref_counted.h" #include "flutter/fml/memory/ref_ptr.h" @@ -49,7 +53,7 @@ class AndroidEGLSurface { /// /// @return Whether the EGL surface color buffer was swapped. /// - bool SwapBuffers(); + bool SwapBuffers(fml::TimePoint target_time); //---------------------------------------------------------------------------- /// @return The size of an `EGLSurface`. diff --git a/shell/platform/android/android_surface_gl.cc b/shell/platform/android/android_surface_gl.cc index ca3e24e8cdc0d..41a6b1d46ca56 100644 --- a/shell/platform/android/android_surface_gl.cc +++ b/shell/platform/android/android_surface_gl.cc @@ -120,10 +120,11 @@ bool AndroidSurfaceGL::GLContextClearCurrent() { return GLContextPtr()->ClearCurrent(); } -bool AndroidSurfaceGL::GLContextPresent(uint32_t fbo_id) { +bool AndroidSurfaceGL::GLContextPresent(fml::TimePoint target_time, + uint32_t fbo_id) { FML_DCHECK(IsValid()); FML_DCHECK(onscreen_surface_); - return onscreen_surface_->SwapBuffers(); + return onscreen_surface_->SwapBuffers(target_time); } intptr_t AndroidSurfaceGL::GLContextFBO(GLFrameInfo frame_info) const { diff --git a/shell/platform/android/android_surface_gl.h b/shell/platform/android/android_surface_gl.h index 31ea82727bf52..3b569845bcf3b 100644 --- a/shell/platform/android/android_surface_gl.h +++ b/shell/platform/android/android_surface_gl.h @@ -58,7 +58,7 @@ class AndroidSurfaceGL final : public GPUSurfaceGLDelegate, bool GLContextClearCurrent() override; // |GPUSurfaceGLDelegate| - bool GLContextPresent(uint32_t fbo_id) override; + bool GLContextPresent(fml::TimePoint target_time, uint32_t fbo_id) override; // |GPUSurfaceGLDelegate| intptr_t GLContextFBO(GLFrameInfo frame_info) const override; diff --git a/shell/platform/android/surface/android_surface_mock.cc b/shell/platform/android/surface/android_surface_mock.cc index a0b08cb4892d6..f06e911e31ef6 100644 --- a/shell/platform/android/surface/android_surface_mock.cc +++ b/shell/platform/android/surface/android_surface_mock.cc @@ -18,7 +18,8 @@ bool AndroidSurfaceMock::GLContextClearCurrent() { return true; } -bool AndroidSurfaceMock::GLContextPresent(uint32_t fbo_id) { +bool AndroidSurfaceMock::GLContextPresent(fml::TimePoint target_time, + uint32_t fbo_id) { return true; } diff --git a/shell/platform/android/surface/android_surface_mock.h b/shell/platform/android/surface/android_surface_mock.h index f710133f64c5d..ba26067a7256b 100644 --- a/shell/platform/android/surface/android_surface_mock.h +++ b/shell/platform/android/surface/android_surface_mock.h @@ -48,7 +48,7 @@ class AndroidSurfaceMock final : public GPUSurfaceGLDelegate, bool GLContextClearCurrent() override; // |GPUSurfaceGLDelegate| - bool GLContextPresent(uint32_t fbo_id) override; + bool GLContextPresent(fml::TimePoint target_time, uint32_t fbo_id) override; // |GPUSurfaceGLDelegate| intptr_t GLContextFBO(GLFrameInfo frame_info) const override; diff --git a/shell/platform/darwin/ios/ios_surface_gl.h b/shell/platform/darwin/ios/ios_surface_gl.h index 54a0584a7e0af..8878d824fe3b8 100644 --- a/shell/platform/darwin/ios/ios_surface_gl.h +++ b/shell/platform/darwin/ios/ios_surface_gl.h @@ -38,7 +38,7 @@ class IOSSurfaceGL final : public IOSSurface, public GPUSurfaceGLDelegate { bool GLContextClearCurrent() override; // |GPUSurfaceGLDelegate| - bool GLContextPresent(uint32_t fbo_id) override; + bool GLContextPresent(fml::TimePoint target_time, uint32_t fbo_id) override; // |GPUSurfaceGLDelegate| intptr_t GLContextFBO(GLFrameInfo frame_info) const override; diff --git a/shell/platform/darwin/ios/ios_surface_gl.mm b/shell/platform/darwin/ios/ios_surface_gl.mm index 9b6bb6a99aa1e..93223e91af37e 100644 --- a/shell/platform/darwin/ios/ios_surface_gl.mm +++ b/shell/platform/darwin/ios/ios_surface_gl.mm @@ -86,7 +86,7 @@ } // |GPUSurfaceGLDelegate| -bool IOSSurfaceGL::GLContextPresent(uint32_t fbo_id) { +bool IOSSurfaceGL::GLContextPresent(fml::TimePoint target_time, uint32_t fbo_id) { TRACE_EVENT0("flutter", "IOSSurfaceGL::GLContextPresent"); return IsValid() && render_target_->PresentRenderBuffer(); } diff --git a/shell/platform/embedder/embedder_surface_gl.cc b/shell/platform/embedder/embedder_surface_gl.cc index 69c75cb2e7462..0d2c8d883e101 100644 --- a/shell/platform/embedder/embedder_surface_gl.cc +++ b/shell/platform/embedder/embedder_surface_gl.cc @@ -45,7 +45,8 @@ bool EmbedderSurfaceGL::GLContextClearCurrent() { } // |GPUSurfaceGLDelegate| -bool EmbedderSurfaceGL::GLContextPresent(uint32_t fbo_id) { +bool EmbedderSurfaceGL::GLContextPresent(fml::TimePoint target_time, + uint32_t fbo_id) { return gl_dispatch_table_.gl_present_callback(fbo_id); } diff --git a/shell/platform/embedder/embedder_surface_gl.h b/shell/platform/embedder/embedder_surface_gl.h index 6f07bcce9ef51..aa3dbdb8d8779 100644 --- a/shell/platform/embedder/embedder_surface_gl.h +++ b/shell/platform/embedder/embedder_surface_gl.h @@ -56,7 +56,7 @@ class EmbedderSurfaceGL final : public EmbedderSurface, bool GLContextClearCurrent() override; // |GPUSurfaceGLDelegate| - bool GLContextPresent(uint32_t fbo_id) override; + bool GLContextPresent(fml::TimePoint target_time, uint32_t fbo_id) override; // |GPUSurfaceGLDelegate| intptr_t GLContextFBO(GLFrameInfo frame_info) const override; From 81f6b926a7ecef9c87a8a802da34ac77f83258ca Mon Sep 17 00:00:00 2001 From: Dan Field Date: Fri, 12 Nov 2021 09:30:45 -0800 Subject: [PATCH 2/4] add doc --- shell/platform/android/android_context_gl.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shell/platform/android/android_context_gl.h b/shell/platform/android/android_context_gl.h index 554c588bb0e50..c3a58f4868749 100644 --- a/shell/platform/android/android_context_gl.h +++ b/shell/platform/android/android_context_gl.h @@ -51,6 +51,8 @@ class AndroidEGLSurface { /// @brief This only applies to on-screen surfaces such as those created /// by `AndroidContextGL::CreateOnscreenSurface`. /// + /// @param target_time The vsync target time for the buffer. + /// /// @return Whether the EGL surface color buffer was swapped. /// bool SwapBuffers(fml::TimePoint target_time); From 4d44b071c066a6470ead23b3baa869848a3b994c Mon Sep 17 00:00:00 2001 From: Dan Field Date: Fri, 12 Nov 2021 19:58:16 -0800 Subject: [PATCH 3/4] test --- shell/platform/android/BUILD.gn | 1 + shell/platform/android/android_context_gl.cc | 40 +++++++++---------- shell/platform/android/android_context_gl.h | 6 ++- .../android/android_context_gl_unittests.cc | 40 +++++++++++++++++++ .../android/android_environment_gl.cc | 15 +++++++ .../platform/android/android_environment_gl.h | 31 ++++++++++---- shell/platform/android/android_surface_gl.cc | 5 --- 7 files changed, 103 insertions(+), 35 deletions(-) diff --git a/shell/platform/android/BUILD.gn b/shell/platform/android/BUILD.gn index 46b6d148a12d9..6de718072c616 100644 --- a/shell/platform/android/BUILD.gn +++ b/shell/platform/android/BUILD.gn @@ -46,6 +46,7 @@ executable("flutter_shell_native_unittests") { public_configs = [ "//flutter:config" ] deps = [ ":flutter_shell_native_src", + "//flutter/fml", "//third_party/googletest:gmock", "//third_party/googletest:gtest", ] diff --git a/shell/platform/android/android_context_gl.cc b/shell/platform/android/android_context_gl.cc index 627ee4d039f46..3c1f204f27400 100644 --- a/shell/platform/android/android_context_gl.cc +++ b/shell/platform/android/android_context_gl.cc @@ -8,6 +8,7 @@ #include +#include "android_environment_gl.h" #include "flutter/fml/trace_event.h" namespace flutter { @@ -105,13 +106,14 @@ static bool TeardownContext(EGLDisplay display, EGLContext context) { return true; } -AndroidEGLSurface::AndroidEGLSurface(EGLSurface surface, - EGLDisplay display, - EGLContext context) - : surface_(surface), display_(display), context_(context) {} +AndroidEGLSurface::AndroidEGLSurface( + EGLSurface surface, + fml::RefPtr environment, + EGLContext context) + : surface_(surface), environment_(environment), context_(context) {} AndroidEGLSurface::~AndroidEGLSurface() { - auto result = eglDestroySurface(display_, surface_); + auto result = eglDestroySurface(environment_->Display(), surface_); FML_DCHECK(result == EGL_TRUE); } @@ -120,7 +122,8 @@ bool AndroidEGLSurface::IsValid() const { } bool AndroidEGLSurface::MakeCurrent() const { - if (eglMakeCurrent(display_, surface_, surface_, context_) != EGL_TRUE) { + if (eglMakeCurrent(environment_->Display(), surface_, surface_, context_) != + EGL_TRUE) { FML_LOG(ERROR) << "Could not make the context current"; LogLastEGLError(); return false; @@ -130,17 +133,17 @@ bool AndroidEGLSurface::MakeCurrent() const { bool AndroidEGLSurface::SwapBuffers(fml::TimePoint target_time) { TRACE_EVENT0("flutter", "AndroidContextGL::SwapBuffers"); - eglPresentationTimeANDROID(display_, surface_, - target_time.ToEpochDelta().ToNanoseconds()); - return eglSwapBuffers(display_, surface_); + environment_->SetPresentationTime(surface_, target_time); + return eglSwapBuffers(environment_->Display(), surface_); } SkISize AndroidEGLSurface::GetSize() const { EGLint width = 0; EGLint height = 0; - if (!eglQuerySurface(display_, surface_, EGL_WIDTH, &width) || - !eglQuerySurface(display_, surface_, EGL_HEIGHT, &height)) { + if (!eglQuerySurface(environment_->Display(), surface_, EGL_WIDTH, &width) || + !eglQuerySurface(environment_->Display(), surface_, EGL_HEIGHT, + &height)) { FML_LOG(ERROR) << "Unable to query EGL surface size"; LogLastEGLError(); return SkISize::Make(0, 0); @@ -231,14 +234,12 @@ std::unique_ptr AndroidContextGL::CreateOnscreenSurface( if (window->IsFakeWindow()) { return CreatePbufferSurface(); } else { - EGLDisplay display = environment_->Display(); - const EGLint attribs[] = {EGL_NONE}; EGLSurface surface = eglCreateWindowSurface( - display, config_, + environment_->Display(), config_, reinterpret_cast(window->handle()), attribs); - return std::make_unique(surface, display, context_); + return std::make_unique(surface, environment_, context_); } } @@ -246,12 +247,11 @@ std::unique_ptr AndroidContextGL::CreateOffscreenSurface() const { // We only ever create pbuffer surfaces for background resource loading // contexts. We never bind the pbuffer to anything. - EGLDisplay display = environment_->Display(); - const EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE}; - EGLSurface surface = eglCreatePbufferSurface(display, config_, attribs); - return std::make_unique(surface, display, + EGLSurface surface = + eglCreatePbufferSurface(environment_->Display(), config_, attribs); + return std::make_unique(surface, environment_, resource_context_); } @@ -262,7 +262,7 @@ std::unique_ptr AndroidContextGL::CreatePbufferSurface() const EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE}; EGLSurface surface = eglCreatePbufferSurface(display, config_, attribs); - return std::make_unique(surface, display, context_); + return std::make_unique(surface, environment_, context_); } fml::RefPtr AndroidContextGL::Environment() const { diff --git a/shell/platform/android/android_context_gl.h b/shell/platform/android/android_context_gl.h index c3a58f4868749..691548dd01f6e 100644 --- a/shell/platform/android/android_context_gl.h +++ b/shell/platform/android/android_context_gl.h @@ -29,7 +29,9 @@ namespace flutter { /// class AndroidEGLSurface { public: - AndroidEGLSurface(EGLSurface surface, EGLDisplay display, EGLContext context); + AndroidEGLSurface(EGLSurface surface, + fml::RefPtr environment, + EGLContext context); ~AndroidEGLSurface(); //---------------------------------------------------------------------------- @@ -64,7 +66,7 @@ class AndroidEGLSurface { private: const EGLSurface surface_; - const EGLDisplay display_; + const fml::RefPtr environment_; const EGLContext context_; }; diff --git a/shell/platform/android/android_context_gl_unittests.cc b/shell/platform/android/android_context_gl_unittests.cc index 2278acd6b37eb..f3c0696b8ad21 100644 --- a/shell/platform/android/android_context_gl_unittests.cc +++ b/shell/platform/android/android_context_gl_unittests.cc @@ -1,5 +1,7 @@ #define FML_USED_ON_EMBEDDER +#include "android_environment_gl.h" + #include #include "flutter/shell/common/thread_host.h" #include "flutter/shell/platform/android/android_context_gl.h" @@ -23,6 +25,22 @@ TaskRunners MakeTaskRunners(const std::string& thread_label, } } // namespace +class InterceptingAndroidEnvironmentGL : public AndroidEnvironmentGL { + public: + InterceptingAndroidEnvironmentGL() = default; + ~InterceptingAndroidEnvironmentGL() override = default; + + bool SetPresentationTime(EGLSurface surface, + fml::TimePoint time) const override { + presentation_time_called_ = true; + return AndroidEnvironmentGL::SetPresentationTime(surface, time); + } + + mutable bool presentation_time_called_ = false; + + FML_DISALLOW_COPY_AND_ASSIGN(InterceptingAndroidEnvironmentGL); +}; + TEST(AndroidContextGl, Create) { GrMockOptions main_context_options; sk_sp main_context = @@ -62,6 +80,28 @@ TEST(AndroidContextGl, CreateSingleThread) { context.reset(); EXPECT_TRUE(main_context->abandoned()); } + +TEST(AndroidEGLSurface, SwapBuffersNotifiesAboutPresentationTime) { + GrMockOptions main_context_options; + sk_sp main_context = + GrDirectContext::MakeMock(&main_context_options); + auto environment = fml::MakeRefCounted(); + std::string thread_label = + ::testing::UnitTest::GetInstance()->current_test_info()->name(); + fml::MessageLoop::EnsureInitializedForCurrentThread(); + fml::RefPtr platform_runner = + fml::MessageLoop::GetCurrent().GetTaskRunner(); + TaskRunners task_runners = + TaskRunners(thread_label, platform_runner, platform_runner, + platform_runner, platform_runner); + auto context = std::make_unique( + AndroidRenderingAPI::kOpenGLES, environment, task_runners); + + auto surface = context->CreatePbufferSurface(); + surface->SwapBuffers(fml::TimePoint::Now()); + + EXPECT_TRUE(environment->presentation_time_called_); +} } // namespace android } // namespace testing } // namespace flutter diff --git a/shell/platform/android/android_environment_gl.cc b/shell/platform/android/android_environment_gl.cc index f384ee2d0835d..cd04e9afe1d00 100644 --- a/shell/platform/android/android_environment_gl.cc +++ b/shell/platform/android/android_environment_gl.cc @@ -20,6 +20,13 @@ AndroidEnvironmentGL::AndroidEnvironmentGL() return; } + auto* extensions = eglQueryString(display_, EGL_EXTENSIONS); + if (strstr(extensions, "EGL_ANDROID_presentation_time")) { + presentation_time_proc_ = + reinterpret_cast( + eglGetProcAddress("sEGL_ANDROID_presentation_time")); + } + valid_ = true; } @@ -38,4 +45,12 @@ EGLDisplay AndroidEnvironmentGL::Display() const { return display_; } +bool AndroidEnvironmentGL::SetPresentationTime(EGLSurface surface, + fml::TimePoint time) const { + if (!presentation_time_proc_) { + return false; + } + return presentation_time_proc_(display_, surface, + time.ToEpochDelta().ToNanoseconds()); +} } // namespace flutter diff --git a/shell/platform/android/android_environment_gl.h b/shell/platform/android/android_environment_gl.h index 23031a775d390..a8210c93a8d78 100644 --- a/shell/platform/android/android_environment_gl.h +++ b/shell/platform/android/android_environment_gl.h @@ -7,29 +7,44 @@ #include "flutter/fml/macros.h" #include "flutter/fml/memory/ref_counted.h" +#include "flutter/fml/time/time_delta.h" +#include "flutter/fml/time/time_point.h" #include +#include +#include namespace flutter { - +namespace testing::android { +class InterceptingAndroidEnvironmentGL; +} class AndroidEnvironmentGL : public fml::RefCountedThreadSafe { - private: - // MakeRefCounted - AndroidEnvironmentGL(); - - // MakeRefCounted - ~AndroidEnvironmentGL(); - public: bool IsValid() const; EGLDisplay Display() const; + // Sets the presentation time for the surface. + // + // Returns false if there was a GL error or if eglPresentationTimeANDROID is + // unavailable. + virtual bool SetPresentationTime(EGLSurface surface, + fml::TimePoint time) const; + + protected: + // MakeRefCounted + AndroidEnvironmentGL(); + // MakeRefCounted + virtual ~AndroidEnvironmentGL(); + private: + PFNEGLPRESENTATIONTIMEANDROIDPROC presentation_time_proc_; EGLDisplay display_; bool valid_; + friend class InterceptingAndroidEnvironmentGL; + FML_FRIEND_MAKE_REF_COUNTED(AndroidEnvironmentGL); FML_FRIEND_REF_COUNTED_THREAD_SAFE(AndroidEnvironmentGL); FML_DISALLOW_COPY_AND_ASSIGN(AndroidEnvironmentGL); diff --git a/shell/platform/android/android_surface_gl.cc b/shell/platform/android/android_surface_gl.cc index fea552d0a288e..1d97a0561e308 100644 --- a/shell/platform/android/android_surface_gl.cc +++ b/shell/platform/android/android_surface_gl.cc @@ -102,10 +102,6 @@ bool AndroidSurfaceGL::SetNativeWindow( FML_DCHECK(IsValid()); FML_DCHECK(window); native_window_ = window; - // Ensure the destructor is called since it destroys the `EGLSurface` before - // creating a new onscreen surface. - onscreen_surface_ = nullptr; - // Create the onscreen surface. onscreen_surface_ = GLContextPtr()->CreateOnscreenSurface(window); if (!onscreen_surface_->IsValid()) { return false; @@ -168,7 +164,6 @@ sk_sp AndroidSurfaceGL::GetGLInterface() const { FML_DCHECK(result == EGL_TRUE); } } - return GPUSurfaceGLDelegate::GetGLInterface(); } From 114cc6cf9804640ee0a08e1eb7dd68df58fe025c Mon Sep 17 00:00:00 2001 From: Dan Field Date: Fri, 12 Nov 2021 20:24:17 -0800 Subject: [PATCH 4/4] Fix test --- .../android/android_context_gl_unittests.cc | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/shell/platform/android/android_context_gl_unittests.cc b/shell/platform/android/android_context_gl_unittests.cc index f3c0696b8ad21..a8b32e5f2331c 100644 --- a/shell/platform/android/android_context_gl_unittests.cc +++ b/shell/platform/android/android_context_gl_unittests.cc @@ -32,11 +32,11 @@ class InterceptingAndroidEnvironmentGL : public AndroidEnvironmentGL { bool SetPresentationTime(EGLSurface surface, fml::TimePoint time) const override { - presentation_time_called_ = true; + presentation_time_ = time; return AndroidEnvironmentGL::SetPresentationTime(surface, time); } - mutable bool presentation_time_called_ = false; + mutable std::optional presentation_time_; FML_DISALLOW_COPY_AND_ASSIGN(InterceptingAndroidEnvironmentGL); }; @@ -82,9 +82,6 @@ TEST(AndroidContextGl, CreateSingleThread) { } TEST(AndroidEGLSurface, SwapBuffersNotifiesAboutPresentationTime) { - GrMockOptions main_context_options; - sk_sp main_context = - GrDirectContext::MakeMock(&main_context_options); auto environment = fml::MakeRefCounted(); std::string thread_label = ::testing::UnitTest::GetInstance()->current_test_info()->name(); @@ -98,9 +95,11 @@ TEST(AndroidEGLSurface, SwapBuffersNotifiesAboutPresentationTime) { AndroidRenderingAPI::kOpenGLES, environment, task_runners); auto surface = context->CreatePbufferSurface(); - surface->SwapBuffers(fml::TimePoint::Now()); - - EXPECT_TRUE(environment->presentation_time_called_); + EXPECT_TRUE(surface); + EXPECT_FALSE(environment->presentation_time_.has_value()); + auto now = fml::TimePoint::Now(); + surface->SwapBuffers(now); + EXPECT_EQ(environment->presentation_time_, now); } } // namespace android } // namespace testing