gl: Add out-fence to GLSurface swap completion callback

Add an out-fence parameter to the swap completion callback used by the
the GLSurface async methods. If present, the fence will be signaled when
the swap has completed.

This commit doesn't implement the actual mechanism for the callback in
any Ozone backend, it just updates the GLSurface API.

Bug: 867361
Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux_optional_gpu_tests_rel;luci.chromium.try:mac_optional_gpu_tests_rel;luci.chromium.try:win_optional_gpu_tests_rel
Change-Id: I1a853e8e21cd636802e978ca6cdcb429b39e8141
Reviewed-on: https://chromium-review.googlesource.com/1127953
Commit-Queue: Daniele Castagna <dcastagna@chromium.org>
Reviewed-by: Antoine Labour <piman@chromium.org>
Reviewed-by: Michael Spang <spang@chromium.org>
Reviewed-by: Daniele Castagna <dcastagna@chromium.org>
Cr-Commit-Position: refs/heads/master@{#578051}
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 5e597d7..1b98c564 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -1024,7 +1024,9 @@
                                        GLbitfield flags);
 
   // Callback for async SwapBuffers.
-  void FinishAsyncSwapBuffers(uint64_t swap_id, gfx::SwapResult result);
+  void FinishAsyncSwapBuffers(uint64_t swap_id,
+                              gfx::SwapResult result,
+                              std::unique_ptr<gfx::GpuFence>);
   void FinishSwapBuffers(gfx::SwapResult result);
 
   void DoCommitOverlayPlanes(uint64_t swap_id, GLbitfield flags);
@@ -16008,9 +16010,14 @@
   ExitCommandProcessingEarly();
 }
 
-void GLES2DecoderImpl::FinishAsyncSwapBuffers(uint64_t swap_id,
-                                              gfx::SwapResult result) {
+void GLES2DecoderImpl::FinishAsyncSwapBuffers(
+    uint64_t swap_id,
+    gfx::SwapResult result,
+    std::unique_ptr<gfx::GpuFence> gpu_fence) {
   TRACE_EVENT_ASYNC_END0("gpu", "AsyncSwapBuffers", swap_id);
+  // Handling of the out-fence should have already happened before reaching
+  // this function, so we don't expect to get a valid fence here.
+  DCHECK(!gpu_fence);
 
   FinishSwapBuffers(result);
 }
@@ -16044,8 +16051,8 @@
   if (supports_async_swap_) {
     client_->OnSwapBuffers(swap_id, flags);
     surface_->CommitOverlayPlanesAsync(
-        base::Bind(&GLES2DecoderImpl::FinishSwapBuffers,
-                   weak_ptr_factory_.GetWeakPtr()),
+        base::Bind(&GLES2DecoderImpl::FinishAsyncSwapBuffers,
+                   weak_ptr_factory_.GetWeakPtr(), swap_id),
         base::DoNothing());
   } else {
     client_->OnSwapBuffers(swap_id, flags);
diff --git a/gpu/ipc/service/pass_through_image_transport_surface.cc b/gpu/ipc/service/pass_through_image_transport_surface.cc
index 8cbe603..8827552 100644
--- a/gpu/ipc/service/pass_through_image_transport_surface.cc
+++ b/gpu/ipc/service/pass_through_image_transport_surface.cc
@@ -220,10 +220,17 @@
 void PassThroughImageTransportSurface::FinishSwapBuffersAsync(
     GLSurface::SwapCompletionCallback callback,
     gfx::SwapResponse response,
-    gfx::SwapResult result) {
+    gfx::SwapResult result,
+    std::unique_ptr<gfx::GpuFence> gpu_fence) {
+  // TODO(afrantzis): It's probably not ideal to introduce a wait here.
+  // However, since this is a temporary step to maintain existing behavior
+  // until we are ready to expose the gpu_fence further, and fences are only
+  // enabled with a flag, this should be fine for now.
+  if (gpu_fence)
+    gpu_fence->Wait();
   response.result = result;
   FinishSwapBuffers(std::move(response));
-  callback.Run(result);
+  callback.Run(result, nullptr);
 }
 
 void PassThroughImageTransportSurface::BufferPresented(
diff --git a/gpu/ipc/service/pass_through_image_transport_surface.h b/gpu/ipc/service/pass_through_image_transport_surface.h
index b177e41..279bfa3 100644
--- a/gpu/ipc/service/pass_through_image_transport_surface.h
+++ b/gpu/ipc/service/pass_through_image_transport_surface.h
@@ -64,7 +64,8 @@
   void FinishSwapBuffers(gfx::SwapResponse response);
   void FinishSwapBuffersAsync(GLSurface::SwapCompletionCallback callback,
                               gfx::SwapResponse response,
-                              gfx::SwapResult result);
+                              gfx::SwapResult result,
+                              std::unique_ptr<gfx::GpuFence> gpu_fence);
 
   void BufferPresented(const GLSurface::PresentationCallback& callback,
                        const gfx::PresentationFeedback& feedback);
diff --git a/ui/gl/gl_surface.h b/ui/gl/gl_surface.h
index 71dcc39..682070d1 100644
--- a/ui/gl/gl_surface.h
+++ b/ui/gl/gl_surface.h
@@ -130,7 +130,15 @@
   // FBO. Otherwise returns 0.
   virtual unsigned int GetBackingFramebufferObject();
 
-  using SwapCompletionCallback = base::Callback<void(gfx::SwapResult)>;
+  // The SwapCompletionCallback is used to receive notification about the
+  // completion of the swap operation from |SwapBuffersAsync|,
+  // |PostSubBufferAsync|, |CommitOverlayPlanesAsync|, etc. If a null gpu fence
+  // is returned, then the swap is guaranteed to have already completed. If a
+  // non-null gpu fence is returned, then the swap operation may still be in
+  // progress when this callback is invoked, and the signaling of the gpu fence
+  // will mark the completion of the swap operation.
+  using SwapCompletionCallback =
+      base::Callback<void(gfx::SwapResult, std::unique_ptr<gfx::GpuFence>)>;
   // Swaps front and back buffers. This has no effect for off-screen
   // contexts. On some platforms, we want to send SwapBufferAck only after the
   // surface is displayed on screen. The callback can be used to delay sending
diff --git a/ui/ozone/demo/gl_renderer.cc b/ui/ozone/demo/gl_renderer.cc
index 73e3d84..a9aca9f0 100644
--- a/ui/ozone/demo/gl_renderer.cc
+++ b/ui/ozone/demo/gl_renderer.cc
@@ -7,6 +7,7 @@
 #include "base/location.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/trace_event.h"
+#include "ui/gfx/gpu_fence.h"
 #include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_context.h"
 #include "ui/gl/gl_surface.h"
@@ -37,7 +38,7 @@
   }
 
   // Schedule the initial render.
-  PostRenderFrameTask(gfx::SwapResult::SWAP_ACK);
+  PostRenderFrameTask(gfx::SwapResult::SWAP_ACK, nullptr);
   return true;
 }
 
@@ -58,12 +59,18 @@
                                base::Bind(&GlRenderer::OnPresentation,
                                           weak_ptr_factory_.GetWeakPtr()));
   } else {
-    PostRenderFrameTask(surface_->SwapBuffers(base::Bind(
-        &GlRenderer::OnPresentation, weak_ptr_factory_.GetWeakPtr())));
+    PostRenderFrameTask(
+        surface_->SwapBuffers(base::Bind(&GlRenderer::OnPresentation,
+                                         weak_ptr_factory_.GetWeakPtr())),
+        nullptr);
   }
 }
 
-void GlRenderer::PostRenderFrameTask(gfx::SwapResult result) {
+void GlRenderer::PostRenderFrameTask(gfx::SwapResult result,
+                                     std::unique_ptr<gfx::GpuFence> gpu_fence) {
+  if (gpu_fence)
+    gpu_fence->Wait();
+
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&GlRenderer::RenderFrame, weak_ptr_factory_.GetWeakPtr()));
diff --git a/ui/ozone/demo/gl_renderer.h b/ui/ozone/demo/gl_renderer.h
index 34bb9d0..9837b12 100644
--- a/ui/ozone/demo/gl_renderer.h
+++ b/ui/ozone/demo/gl_renderer.h
@@ -12,6 +12,7 @@
 #include "ui/ozone/demo/renderer_base.h"
 
 namespace gfx {
+class GpuFence;
 struct PresentationFeedback;
 }  // namespace gfx
 
@@ -34,7 +35,8 @@
 
  private:
   void RenderFrame();
-  void PostRenderFrameTask(gfx::SwapResult result);
+  void PostRenderFrameTask(gfx::SwapResult result,
+                           std::unique_ptr<gfx::GpuFence> gpu_fence);
   void OnPresentation(const gfx::PresentationFeedback& feedback);
 
   scoped_refptr<gl::GLSurface> surface_;
diff --git a/ui/ozone/demo/skia/skia_gl_renderer.cc b/ui/ozone/demo/skia/skia_gl_renderer.cc
index 681f673..9bbb135 100644
--- a/ui/ozone/demo/skia/skia_gl_renderer.cc
+++ b/ui/ozone/demo/skia/skia_gl_renderer.cc
@@ -13,6 +13,7 @@
 #include "third_party/skia/include/gpu/GrBackendSurface.h"
 #include "third_party/skia/include/gpu/gl/GrGLAssembleInterface.h"
 #include "third_party/skia/include/gpu/gl/GrGLInterface.h"
+#include "ui/gfx/gpu_fence.h"
 #include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_context.h"
 #include "ui/gl/gl_implementation.h"
@@ -71,7 +72,7 @@
   gr_context_ = GrContext::MakeGL(std::move(native_interface), options);
   DCHECK(gr_context_);
 
-  PostRenderFrameTask(gfx::SwapResult::SWAP_ACK);
+  PostRenderFrameTask(gfx::SwapResult::SWAP_ACK, nullptr);
   return true;
 }
 
@@ -111,12 +112,19 @@
         base::BindRepeating(&SkiaGlRenderer::OnPresentation,
                             weak_ptr_factory_.GetWeakPtr()));
   } else {
-    PostRenderFrameTask(gl_surface_->SwapBuffers(base::BindRepeating(
-        &SkiaGlRenderer::OnPresentation, weak_ptr_factory_.GetWeakPtr())));
+    PostRenderFrameTask(
+        gl_surface_->SwapBuffers(base::BindRepeating(
+            &SkiaGlRenderer::OnPresentation, weak_ptr_factory_.GetWeakPtr())),
+        nullptr);
   }
 }
 
-void SkiaGlRenderer::PostRenderFrameTask(gfx::SwapResult result) {
+void SkiaGlRenderer::PostRenderFrameTask(
+    gfx::SwapResult result,
+    std::unique_ptr<gfx::GpuFence> gpu_fence) {
+  if (gpu_fence)
+    gpu_fence->Wait();
+
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::BindRepeating(&SkiaGlRenderer::RenderFrame,
                                      weak_ptr_factory_.GetWeakPtr()));
diff --git a/ui/ozone/demo/skia/skia_gl_renderer.h b/ui/ozone/demo/skia/skia_gl_renderer.h
index 8e9613a..7bb6772 100644
--- a/ui/ozone/demo/skia/skia_gl_renderer.h
+++ b/ui/ozone/demo/skia/skia_gl_renderer.h
@@ -19,6 +19,7 @@
 #include "ui/ozone/demo/renderer_base.h"
 
 namespace gfx {
+class GpuFence;
 struct PresentationFeedback;
 }  // namespace gfx
 
@@ -42,7 +43,8 @@
 
  protected:
   virtual void RenderFrame();
-  virtual void PostRenderFrameTask(gfx::SwapResult result);
+  virtual void PostRenderFrameTask(gfx::SwapResult result,
+                                   std::unique_ptr<gfx::GpuFence>);
 
   void Draw(SkCanvas* canvas, float fraction);
   void StartDDLRenderThreadIfNecessary(SkSurface* sk_surface);
diff --git a/ui/ozone/demo/skia/skia_surfaceless_gl_renderer.cc b/ui/ozone/demo/skia/skia_surfaceless_gl_renderer.cc
index c418c58d..b609232 100644
--- a/ui/ozone/demo/skia/skia_surfaceless_gl_renderer.cc
+++ b/ui/ozone/demo/skia/skia_surfaceless_gl_renderer.cc
@@ -264,7 +264,9 @@
       base::DoNothing());
 }
 
-void SurfacelessSkiaGlRenderer::PostRenderFrameTask(gfx::SwapResult result) {
+void SurfacelessSkiaGlRenderer::PostRenderFrameTask(
+    gfx::SwapResult result,
+    std::unique_ptr<gfx::GpuFence> gpu_fence) {
   switch (result) {
     case gfx::SwapResult::SWAP_NAK_RECREATE_BUFFERS:
       for (size_t i = 0; i < arraysize(buffers_); ++i) {
@@ -275,7 +277,7 @@
       }
       FALLTHROUGH;  // We want to render a new frame anyways.
     case gfx::SwapResult::SWAP_ACK:
-      SkiaGlRenderer::PostRenderFrameTask(result);
+      SkiaGlRenderer::PostRenderFrameTask(result, std::move(gpu_fence));
       break;
     case gfx::SwapResult::SWAP_FAILED:
       LOG(FATAL) << "Failed to swap buffers";
diff --git a/ui/ozone/demo/skia/skia_surfaceless_gl_renderer.h b/ui/ozone/demo/skia/skia_surfaceless_gl_renderer.h
index a34f4da2..a569273 100644
--- a/ui/ozone/demo/skia/skia_surfaceless_gl_renderer.h
+++ b/ui/ozone/demo/skia/skia_surfaceless_gl_renderer.h
@@ -27,7 +27,8 @@
  private:
   // SkiaGlRenderer:
   void RenderFrame() override;
-  void PostRenderFrameTask(gfx::SwapResult result) override;
+  void PostRenderFrameTask(gfx::SwapResult result,
+                           std::unique_ptr<gfx::GpuFence>) override;
 
   class BufferWrapper;
 
diff --git a/ui/ozone/demo/surfaceless_gl_renderer.cc b/ui/ozone/demo/surfaceless_gl_renderer.cc
index 53188cd4..94794ba 100644
--- a/ui/ozone/demo/surfaceless_gl_renderer.cc
+++ b/ui/ozone/demo/surfaceless_gl_renderer.cc
@@ -191,7 +191,7 @@
     surface_->SetUsePlaneGpuFences();
 
   // Schedule the initial render.
-  PostRenderFrameTask(gfx::SwapResult::SWAP_ACK);
+  PostRenderFrameTask(gfx::SwapResult::SWAP_ACK, nullptr);
   return true;
 }
 
@@ -271,7 +271,12 @@
       base::Bind([](const gfx::PresentationFeedback&) {}));
 }
 
-void SurfacelessGlRenderer::PostRenderFrameTask(gfx::SwapResult result) {
+void SurfacelessGlRenderer::PostRenderFrameTask(
+    gfx::SwapResult result,
+    std::unique_ptr<gfx::GpuFence> gpu_fence) {
+  if (gpu_fence)
+    gpu_fence->Wait();
+
   switch (result) {
     case gfx::SwapResult::SWAP_NAK_RECREATE_BUFFERS:
       for (size_t i = 0; i < base::size(buffers_); ++i) {
diff --git a/ui/ozone/demo/surfaceless_gl_renderer.h b/ui/ozone/demo/surfaceless_gl_renderer.h
index 8fee49c..9029a92 100644
--- a/ui/ozone/demo/surfaceless_gl_renderer.h
+++ b/ui/ozone/demo/surfaceless_gl_renderer.h
@@ -30,7 +30,8 @@
 
  private:
   void RenderFrame();
-  void PostRenderFrameTask(gfx::SwapResult result);
+  void PostRenderFrameTask(gfx::SwapResult result,
+                           std::unique_ptr<gfx::GpuFence> gpu_fence);
   void OnPresentation(const gfx::PresentationFeedback& feedback);
 
   class BufferWrapper {
diff --git a/ui/ozone/platform/drm/gpu/gbm_surface.cc b/ui/ozone/platform/drm/gpu/gbm_surface.cc
index be4c02c..8588a55 100644
--- a/ui/ozone/platform/drm/gpu/gbm_surface.cc
+++ b/ui/ozone/platform/drm/gpu/gbm_surface.cc
@@ -69,7 +69,7 @@
           widget(), 0, gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE,
           gfx::Rect(GetSize()), gfx::RectF(1, 1), /* enable_blend */ false,
           /* gpu_fence */ nullptr)) {
-    completion_callback.Run(gfx::SwapResult::SWAP_FAILED);
+    completion_callback.Run(gfx::SwapResult::SWAP_FAILED, nullptr);
     // Notify the caller, the buffer is never presented on a screen.
     presentation_callback.Run(gfx::PresentationFeedback::Failure());
     return;
diff --git a/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc b/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
index 281c3736..4c0ff77 100644
--- a/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
+++ b/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
@@ -115,7 +115,7 @@
   TRACE_EVENT0("drm", "GbmSurfaceless::SwapBuffersAsync");
   // If last swap failed, don't try to schedule new ones.
   if (!last_swap_buffers_result_) {
-    completion_callback.Run(gfx::SwapResult::SWAP_FAILED);
+    completion_callback.Run(gfx::SwapResult::SWAP_FAILED, nullptr);
     // Notify the caller, the buffer is never presented on a screen.
     presentation_callback.Run(gfx::PresentationFeedback::Failure());
     return;
@@ -150,7 +150,7 @@
   // implemented in GL drivers.
   EGLSyncKHR fence = InsertFence(has_implicit_external_sync_);
   if (!fence) {
-    completion_callback.Run(gfx::SwapResult::SWAP_FAILED);
+    completion_callback.Run(gfx::SwapResult::SWAP_FAILED, nullptr);
     // Notify the caller, the buffer is never presented on a screen.
     presentation_callback.Run(gfx::PresentationFeedback::Failure());
     return;
@@ -279,7 +279,7 @@
   submitted_frame_->overlays.clear();
 
   gfx::SwapResult result = submitted_frame_->swap_result;
-  std::move(submitted_frame_->completion_callback).Run(result);
+  std::move(submitted_frame_->completion_callback).Run(result, nullptr);
   std::move(submitted_frame_->presentation_callback).Run(feedback);
   submitted_frame_.reset();