Commit 77f08ab3 authored by achaulk's avatar achaulk Committed by Commit bot

Change ozone async swap to fix overlay scheduling

We keep a list of all pending frames insize the GLSurface. Each frame contains
a list of overlays. In the future it can contain overlay sync point info too.
When ready, we set the ready state and submit all completed frames in order

BUG=470185
TEST=link and rockchip

Review URL: https://codereview.chromium.org/1054073002

Cr-Commit-Position: refs/heads/master@{#324053}
parent 65212281
......@@ -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_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment