Index: ui/gl/gl_surface_ozone.cc |
diff --git a/ui/gl/gl_surface_ozone.cc b/ui/gl/gl_surface_ozone.cc |
index 47ea8d6dd9b6c1e63b22febcfc364cd6b5d71039..800be1759fe96331573944463123e00ce19968f2 100644 |
--- a/ui/gl/gl_surface_ozone.cc |
+++ b/ui/gl/gl_surface_ozone.cc |
@@ -5,8 +5,12 @@ |
#include "ui/gl/gl_surface.h" |
#include "base/bind.h" |
+#include "base/callback.h" |
+#include "base/location.h" |
#include "base/logging.h" |
#include "base/memory/ref_counted.h" |
+#include "base/memory/weak_ptr.h" |
+#include "base/threading/worker_pool.h" |
#include "ui/gfx/native_widget_types.h" |
#include "ui/gl/gl_context.h" |
#include "ui/gl/gl_image.h" |
@@ -25,6 +29,11 @@ namespace gfx { |
namespace { |
+void WaitForFence(EGLDisplay display, EGLSyncKHR fence) { |
+ eglClientWaitSyncKHR(display, fence, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, |
+ EGL_FOREVER_KHR); |
+} |
+ |
// A thin wrapper around GLSurfaceEGL that owns the EGLNativeWindow |
class GL_EXPORT GLSurfaceOzoneEGL : public NativeViewGLSurfaceEGL { |
public: |
@@ -111,7 +120,9 @@ class GL_EXPORT GLSurfaceOzoneSurfaceless : public SurfacelessEGL { |
ozone_surface_(ozone_surface.Pass()), |
widget_(widget), |
has_implicit_external_sync_( |
- HasEGLExtension("EGL_ARM_implicit_external_sync")) {} |
+ HasEGLExtension("EGL_ARM_implicit_external_sync")), |
+ last_swap_buffers_result_(true), |
+ weak_factory_(this) {} |
bool Initialize() override { |
if (!SurfacelessEGL::Initialize()) |
@@ -128,8 +139,21 @@ class GL_EXPORT GLSurfaceOzoneSurfaceless : public SurfacelessEGL { |
return SurfacelessEGL::Resize(size); |
} |
bool SwapBuffers() override { |
- if (!Flush()) |
- return false; |
+ glFlush(); |
+ // TODO: the following should be replaced by a per surface flush as it gets |
+ // implemented in GL drivers. |
+ if (has_implicit_external_sync_) { |
+ EGLSyncKHR fence = InsertFence(); |
+ if (!fence) |
+ return false; |
+ |
+ EGLDisplay display = GetDisplay(); |
+ WaitForFence(display, fence); |
+ eglDestroySyncKHR(display, fence); |
+ } else if (ozone_surface_->IsUniversalDisplayLinkDevice()) { |
+ glFinish(); |
+ } |
+ |
return ozone_surface_->OnSwapBuffers(); |
} |
bool ScheduleOverlayPlane(int z_order, |
@@ -149,8 +173,33 @@ class GL_EXPORT GLSurfaceOzoneSurfaceless : public SurfacelessEGL { |
return true; |
} |
bool SwapBuffersAsync(const SwapCompletionCallback& callback) override { |
- if (!Flush()) |
- return false; |
+ glFlush(); |
+ // TODO: the following should be replaced by a per surface flush as it gets |
+ // implemented in GL drivers. |
+ if (has_implicit_external_sync_) { |
+ // If last swap failed, don't try to schedule new ones. |
+ if (!last_swap_buffers_result_) { |
+ last_swap_buffers_result_ = true; |
+ return false; |
+ } |
+ |
+ EGLSyncKHR fence = InsertFence(); |
+ if (!fence) |
+ return false; |
+ |
+ base::Closure fence_wait_task = |
+ base::Bind(&WaitForFence, GetDisplay(), fence); |
+ |
+ base::Closure fence_retired_callback = |
+ base::Bind(&GLSurfaceOzoneSurfaceless::FenceRetired, |
+ weak_factory_.GetWeakPtr(), fence, callback); |
+ |
+ base::WorkerPool::PostTaskAndReply(FROM_HERE, fence_wait_task, |
+ fence_retired_callback, false); |
+ return true; |
+ } else if (ozone_surface_->IsUniversalDisplayLinkDevice()) { |
+ glFinish(); |
+ } |
return ozone_surface_->OnSwapBuffersAsync(callback); |
} |
bool PostSubBufferAsync(int x, |
@@ -166,30 +215,16 @@ class GL_EXPORT GLSurfaceOzoneSurfaceless : public SurfacelessEGL { |
Destroy(); // EGL surface must be destroyed before SurfaceOzone |
} |
- bool Flush() { |
- glFlush(); |
- // TODO: crbug.com/462360 the following should be replaced by a per surface |
- // flush as it gets implemented in GL drivers. |
- if (has_implicit_external_sync_) { |
- const EGLint attrib_list[] = { |
- EGL_SYNC_CONDITION_KHR, |
- EGL_SYNC_PRIOR_COMMANDS_IMPLICIT_EXTERNAL_ARM, |
- EGL_NONE}; |
- EGLSyncKHR fence = |
- eglCreateSyncKHR(GetDisplay(), EGL_SYNC_FENCE_KHR, attrib_list); |
- if (fence) { |
- // TODO(dbehr): piman@ suggests we could improve here by moving |
- // following wait to right before drmModePageFlip crbug.com/456417. |
- eglClientWaitSyncKHR(GetDisplay(), fence, |
- EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, EGL_FOREVER_KHR); |
- eglDestroySyncKHR(GetDisplay(), fence); |
- } else { |
- return false; |
- } |
- } else if (ozone_surface_->IsUniversalDisplayLinkDevice()) { |
- glFinish(); |
- } |
- return true; |
+ EGLSyncKHR InsertFence() { |
+ const EGLint attrib_list[] = {EGL_SYNC_CONDITION_KHR, |
+ EGL_SYNC_PRIOR_COMMANDS_IMPLICIT_EXTERNAL_ARM, |
+ EGL_NONE}; |
+ return eglCreateSyncKHR(GetDisplay(), EGL_SYNC_FENCE_KHR, attrib_list); |
+ } |
+ |
+ void FenceRetired(EGLSyncKHR fence, const SwapCompletionCallback& callback) { |
+ eglDestroySyncKHR(GetDisplay(), fence); |
+ last_swap_buffers_result_ = ozone_surface_->OnSwapBuffersAsync(callback); |
} |
// The native surface. Deleting this is allowed to free the EGLNativeWindow. |
@@ -197,6 +232,10 @@ class GL_EXPORT GLSurfaceOzoneSurfaceless : public SurfacelessEGL { |
AcceleratedWidget widget_; |
scoped_ptr<VSyncProvider> vsync_provider_; |
bool has_implicit_external_sync_; |
+ bool last_swap_buffers_result_; |
+ |
+ base::WeakPtrFactory<GLSurfaceOzoneSurfaceless> weak_factory_; |
+ |
DISALLOW_COPY_AND_ASSIGN(GLSurfaceOzoneSurfaceless); |
}; |