Index: ui/gl/gl_surface_ozone.cc |
diff --git a/ui/gl/gl_surface_ozone.cc b/ui/gl/gl_surface_ozone.cc |
index 800be1759fe96331573944463123e00ce19968f2..ba7b02b036814056100705915fcd4bd4033603a5 100644 |
--- a/ui/gl/gl_surface_ozone.cc |
+++ b/ui/gl/gl_surface_ozone.cc |
@@ -9,6 +9,7 @@ |
#include "base/location.h" |
#include "base/logging.h" |
#include "base/memory/ref_counted.h" |
+#include "base/memory/scoped_vector.h" |
#include "base/memory/weak_ptr.h" |
#include "base/threading/worker_pool.h" |
#include "ui/gfx/native_widget_types.h" |
@@ -122,7 +123,9 @@ class GL_EXPORT GLSurfaceOzoneSurfaceless : public SurfacelessEGL { |
has_implicit_external_sync_( |
HasEGLExtension("EGL_ARM_implicit_external_sync")), |
last_swap_buffers_result_(true), |
- weak_factory_(this) {} |
+ weak_factory_(this) { |
+ unsubmitted_frames_.push_back(new PendingFrame()); |
+ } |
bool Initialize() override { |
if (!SurfacelessEGL::Initialize()) |
@@ -154,6 +157,9 @@ class GL_EXPORT GLSurfaceOzoneSurfaceless : public SurfacelessEGL { |
glFinish(); |
} |
+ unsubmitted_frames_.back()->ScheduleOverlayPlanes(widget_); |
+ unsubmitted_frames_.back()->overlays.clear(); |
+ |
return ozone_surface_->OnSwapBuffers(); |
} |
bool ScheduleOverlayPlane(int z_order, |
@@ -161,8 +167,9 @@ class GL_EXPORT GLSurfaceOzoneSurfaceless : public SurfacelessEGL { |
GLImage* image, |
const Rect& bounds_rect, |
const RectF& crop_rect) override { |
- return image->ScheduleOverlayPlane( |
- widget_, z_order, transform, bounds_rect, crop_rect); |
+ unsubmitted_frames_.back()->overlays.push_back(PendingFrame::Overlay( |
+ z_order, transform, image, bounds_rect, crop_rect)); |
+ return true; |
} |
bool IsOffscreen() override { return false; } |
VSyncProvider* GetVSyncProvider() override { return vsync_provider_.get(); } |
@@ -190,16 +197,21 @@ class GL_EXPORT GLSurfaceOzoneSurfaceless : public SurfacelessEGL { |
base::Closure fence_wait_task = |
base::Bind(&WaitForFence, GetDisplay(), fence); |
+ PendingFrame* frame = unsubmitted_frames_.back(); |
+ frame->callback = callback; |
base::Closure fence_retired_callback = |
base::Bind(&GLSurfaceOzoneSurfaceless::FenceRetired, |
- weak_factory_.GetWeakPtr(), fence, callback); |
+ weak_factory_.GetWeakPtr(), fence, frame); |
base::WorkerPool::PostTaskAndReply(FROM_HERE, fence_wait_task, |
fence_retired_callback, false); |
+ unsubmitted_frames_.push_back(new PendingFrame()); |
return true; |
} else if (ozone_surface_->IsUniversalDisplayLinkDevice()) { |
glFinish(); |
} |
+ unsubmitted_frames_.back()->ScheduleOverlayPlanes(widget_); |
+ unsubmitted_frames_.back()->overlays.clear(); |
return ozone_surface_->OnSwapBuffersAsync(callback); |
} |
bool PostSubBufferAsync(int x, |
@@ -211,10 +223,58 @@ class GL_EXPORT GLSurfaceOzoneSurfaceless : public SurfacelessEGL { |
} |
protected: |
+ struct PendingFrame { |
+ struct Overlay { |
+ Overlay(int z_order, |
+ OverlayTransform transform, |
+ GLImage* image, |
+ const Rect& bounds_rect, |
+ const RectF& crop_rect) |
+ : z_order(z_order), |
+ transform(transform), |
+ image(image), |
+ bounds_rect(bounds_rect), |
+ crop_rect(crop_rect) {} |
+ |
+ bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget) const { |
+ return image->ScheduleOverlayPlane(widget, z_order, transform, |
+ bounds_rect, crop_rect); |
+ } |
+ |
+ int z_order; |
+ OverlayTransform transform; |
+ scoped_refptr<GLImage> image; |
+ Rect bounds_rect; |
+ RectF crop_rect; |
+ }; |
+ |
+ PendingFrame() : ready(false) {} |
+ |
+ bool ScheduleOverlayPlanes(gfx::AcceleratedWidget widget) { |
+ for (const auto& overlay : overlays) |
+ if (!overlay.ScheduleOverlayPlane(widget)) |
+ return false; |
+ return true; |
+ } |
+ bool ready; |
+ std::vector<Overlay> overlays; |
+ SwapCompletionCallback callback; |
+ }; |
+ |
~GLSurfaceOzoneSurfaceless() override { |
Destroy(); // EGL surface must be destroyed before SurfaceOzone |
} |
+ void SubmitFrames() { |
+ while (!unsubmitted_frames_.empty() && unsubmitted_frames_.front()->ready) { |
+ PendingFrame* frame = unsubmitted_frames_.front(); |
+ last_swap_buffers_result_ = |
+ last_swap_buffers_result_ && frame->ScheduleOverlayPlanes(widget_) && |
+ ozone_surface_->OnSwapBuffersAsync(frame->callback); |
+ unsubmitted_frames_.erase(unsubmitted_frames_.begin()); |
+ } |
+ } |
+ |
EGLSyncKHR InsertFence() { |
const EGLint attrib_list[] = {EGL_SYNC_CONDITION_KHR, |
EGL_SYNC_PRIOR_COMMANDS_IMPLICIT_EXTERNAL_ARM, |
@@ -222,15 +282,17 @@ class GL_EXPORT GLSurfaceOzoneSurfaceless : public SurfacelessEGL { |
return eglCreateSyncKHR(GetDisplay(), EGL_SYNC_FENCE_KHR, attrib_list); |
} |
- void FenceRetired(EGLSyncKHR fence, const SwapCompletionCallback& callback) { |
+ void FenceRetired(EGLSyncKHR fence, PendingFrame* frame) { |
eglDestroySyncKHR(GetDisplay(), fence); |
- last_swap_buffers_result_ = ozone_surface_->OnSwapBuffersAsync(callback); |
+ frame->ready = true; |
+ SubmitFrames(); |
} |
// The native surface. Deleting this is allowed to free the EGLNativeWindow. |
scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface_; |
AcceleratedWidget widget_; |
scoped_ptr<VSyncProvider> vsync_provider_; |
+ ScopedVector<PendingFrame> unsubmitted_frames_; |
bool has_implicit_external_sync_; |
bool last_swap_buffers_result_; |