| Index: ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
|
| diff --git a/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc b/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
|
| index 9631d28229886a1d6394be62c512613af9027bfa..2fe3306e323c97594ca1fd7af49bbc1cdee3eba3 100644
|
| --- a/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
|
| +++ b/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
|
| @@ -1,4 +1,4 @@
|
| -// Copyright 2014 The Chromium Authors. All rights reserved.
|
| +// Copyright 2016 The Chromium Authors. All rights reserved.
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| @@ -6,11 +6,12 @@
|
|
|
| #include <utility>
|
|
|
| +#include "base/bind.h"
|
| +#include "base/logging.h"
|
| #include "base/memory/ptr_util.h"
|
| +#include "base/threading/worker_pool.h"
|
| #include "base/trace_event/trace_event.h"
|
| -#include "third_party/khronos/EGL/egl.h"
|
| #include "ui/ozone/common/egl_util.h"
|
| -#include "ui/ozone/platform/drm/gpu/drm_device.h"
|
| #include "ui/ozone/platform/drm/gpu/drm_vsync_provider.h"
|
| #include "ui/ozone/platform/drm/gpu/drm_window_proxy.h"
|
| #include "ui/ozone/platform/drm/gpu/gbm_surface_factory.h"
|
| @@ -18,67 +19,232 @@
|
|
|
| namespace ui {
|
|
|
| -GbmSurfaceless::GbmSurfaceless(std::unique_ptr<DrmWindowProxy> window,
|
| - GbmSurfaceFactory* surface_manager)
|
| - : window_(std::move(window)), surface_manager_(surface_manager) {
|
| - surface_manager_->RegisterSurface(window_->widget(), this);
|
| +namespace {
|
| +
|
| +void WaitForFence(EGLDisplay display, EGLSyncKHR fence) {
|
| + eglClientWaitSyncKHR(display, fence, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
|
| + EGL_FOREVER_KHR);
|
| }
|
|
|
| -GbmSurfaceless::~GbmSurfaceless() {
|
| - surface_manager_->UnregisterSurface(window_->widget());
|
| +} // namespace
|
| +
|
| +GbmSurfaceless::GbmSurfaceless(GbmSurfaceFactory* surface_factory,
|
| + std::unique_ptr<DrmWindowProxy> window,
|
| + gfx::AcceleratedWidget widget)
|
| + : SurfacelessEGL(gfx::Size()),
|
| + surface_factory_(surface_factory),
|
| + window_(std::move(window)),
|
| + widget_(widget),
|
| + has_implicit_external_sync_(
|
| + HasEGLExtension("EGL_ARM_implicit_external_sync")),
|
| + has_image_flush_external_(
|
| + HasEGLExtension("EGL_EXT_image_flush_external")),
|
| + weak_factory_(this) {
|
| + surface_factory_->RegisterSurface(window_->widget(), this);
|
| + unsubmitted_frames_.push_back(new PendingFrame());
|
| }
|
|
|
| void GbmSurfaceless::QueueOverlayPlane(const OverlayPlane& plane) {
|
| planes_.push_back(plane);
|
| }
|
|
|
| -intptr_t GbmSurfaceless::GetNativeWindow() {
|
| +bool GbmSurfaceless::Initialize(gl::GLSurface::Format format) {
|
| + if (!SurfacelessEGL::Initialize(format))
|
| + return false;
|
| + vsync_provider_ = base::MakeUnique<DrmVSyncProvider>(window_.get());
|
| + if (!vsync_provider_)
|
| + return false;
|
| + return true;
|
| +}
|
| +
|
| +gfx::SwapResult GbmSurfaceless::SwapBuffers() {
|
| NOTREACHED();
|
| - return 0;
|
| + return gfx::SwapResult::SWAP_FAILED;
|
| }
|
|
|
| -bool GbmSurfaceless::ResizeNativeWindow(const gfx::Size& viewport_size) {
|
| +bool GbmSurfaceless::ScheduleOverlayPlane(int z_order,
|
| + gfx::OverlayTransform transform,
|
| + gl::GLImage* image,
|
| + const gfx::Rect& bounds_rect,
|
| + const gfx::RectF& crop_rect) {
|
| + unsubmitted_frames_.back()->overlays.push_back(
|
| + gl::GLSurfaceOverlay(z_order, transform, image, bounds_rect, crop_rect));
|
| return true;
|
| }
|
|
|
| -bool GbmSurfaceless::OnSwapBuffers() {
|
| - NOTREACHED();
|
| +bool GbmSurfaceless::IsOffscreen() {
|
| return false;
|
| }
|
|
|
| -void GbmSurfaceless::OnSwapBuffersAsync(
|
| +gfx::VSyncProvider* GbmSurfaceless::GetVSyncProvider() {
|
| + return vsync_provider_.get();
|
| +}
|
| +
|
| +bool GbmSurfaceless::SupportsAsyncSwap() {
|
| + return true;
|
| +}
|
| +
|
| +bool GbmSurfaceless::SupportsPostSubBuffer() {
|
| + return true;
|
| +}
|
| +
|
| +gfx::SwapResult GbmSurfaceless::PostSubBuffer(int x,
|
| + int y,
|
| + int width,
|
| + int height) {
|
| + // The actual sub buffer handling is handled at higher layers.
|
| + NOTREACHED();
|
| + return gfx::SwapResult::SWAP_FAILED;
|
| +}
|
| +
|
| +void GbmSurfaceless::SwapBuffersAsync(const SwapCompletionCallback& callback) {
|
| + TRACE_EVENT0("drm", "GbmSurfaceless::SwapBuffersAsync");
|
| + // If last swap failed, don't try to schedule new ones.
|
| + if (!last_swap_buffers_result_) {
|
| + callback.Run(gfx::SwapResult::SWAP_FAILED);
|
| + return;
|
| + }
|
| +
|
| + glFlush();
|
| + unsubmitted_frames_.back()->Flush();
|
| +
|
| + SwapCompletionCallback surface_swap_callback = base::Bind(
|
| + &GbmSurfaceless::SwapCompleted, weak_factory_.GetWeakPtr(), callback);
|
| +
|
| + PendingFrame* frame = unsubmitted_frames_.back();
|
| + frame->callback = surface_swap_callback;
|
| + unsubmitted_frames_.push_back(new PendingFrame());
|
| +
|
| + // TODO: the following should be replaced by a per surface flush as it gets
|
| + // implemented in GL drivers.
|
| + if (has_implicit_external_sync_ || has_image_flush_external_) {
|
| + EGLSyncKHR fence = InsertFence(has_implicit_external_sync_);
|
| + if (!fence) {
|
| + callback.Run(gfx::SwapResult::SWAP_FAILED);
|
| + return;
|
| + }
|
| +
|
| + base::Closure fence_wait_task =
|
| + base::Bind(&WaitForFence, GetDisplay(), fence);
|
| +
|
| + base::Closure fence_retired_callback =
|
| + base::Bind(&GbmSurfaceless::FenceRetired, weak_factory_.GetWeakPtr(),
|
| + fence, frame);
|
| +
|
| + base::WorkerPool::PostTaskAndReply(FROM_HERE, fence_wait_task,
|
| + fence_retired_callback, false);
|
| + return; // Defer frame submission until fence signals.
|
| + }
|
| +
|
| + frame->ready = true;
|
| + SubmitFrame();
|
| +}
|
| +
|
| +void GbmSurfaceless::PostSubBufferAsync(
|
| + int x,
|
| + int y,
|
| + int width,
|
| + int height,
|
| const SwapCompletionCallback& callback) {
|
| - TRACE_EVENT0("drm", "GbmSurfaceless::OnSwapBuffersAsync");
|
| - window_->SchedulePageFlip(planes_, callback);
|
| - planes_.clear();
|
| + // The actual sub buffer handling is handled at higher layers.
|
| + SwapBuffersAsync(callback);
|
| }
|
|
|
| -std::unique_ptr<gfx::VSyncProvider> GbmSurfaceless::CreateVSyncProvider() {
|
| - return base::WrapUnique(new DrmVSyncProvider(window_.get()));
|
| +EGLConfig GbmSurfaceless::GetConfig() {
|
| + if (!config_) {
|
| + EGLint config_attribs[] = {EGL_BUFFER_SIZE,
|
| + 32,
|
| + EGL_ALPHA_SIZE,
|
| + 8,
|
| + EGL_BLUE_SIZE,
|
| + 8,
|
| + EGL_GREEN_SIZE,
|
| + 8,
|
| + EGL_RED_SIZE,
|
| + 8,
|
| + EGL_RENDERABLE_TYPE,
|
| + EGL_OPENGL_ES2_BIT,
|
| + EGL_SURFACE_TYPE,
|
| + EGL_DONT_CARE,
|
| + EGL_NONE};
|
| + config_ = ChooseEGLConfig(GetDisplay(), config_attribs);
|
| + }
|
| + return config_;
|
| }
|
|
|
| -bool GbmSurfaceless::IsUniversalDisplayLinkDevice() {
|
| - return planes_.empty() ? false : planes_[0].buffer->RequiresGlFinish();
|
| +GbmSurfaceless::~GbmSurfaceless() {
|
| + Destroy(); // The EGL surface must be destroyed before SurfaceOzone.
|
| + surface_factory_->UnregisterSurface(window_->widget());
|
| +}
|
| +
|
| +GbmSurfaceless::PendingFrame::PendingFrame() {}
|
| +
|
| +GbmSurfaceless::PendingFrame::~PendingFrame() {}
|
| +
|
| +bool GbmSurfaceless::PendingFrame::ScheduleOverlayPlanes(
|
| + gfx::AcceleratedWidget widget) {
|
| + for (const auto& overlay : overlays)
|
| + if (!overlay.ScheduleOverlayPlane(widget))
|
| + return false;
|
| + return true;
|
| +}
|
| +
|
| +void GbmSurfaceless::PendingFrame::Flush() {
|
| + for (const auto& overlay : overlays)
|
| + overlay.Flush();
|
| +}
|
| +
|
| +void GbmSurfaceless::SubmitFrame() {
|
| + DCHECK(!unsubmitted_frames_.empty());
|
| +
|
| + if (unsubmitted_frames_.front()->ready && !swap_buffers_pending_) {
|
| + std::unique_ptr<PendingFrame> frame(unsubmitted_frames_.front());
|
| + unsubmitted_frames_.weak_erase(unsubmitted_frames_.begin());
|
| + swap_buffers_pending_ = true;
|
| +
|
| + if (!frame->ScheduleOverlayPlanes(widget_)) {
|
| + // |callback| is a wrapper for SwapCompleted(). Call it to properly
|
| + // propagate the failed state.
|
| + frame->callback.Run(gfx::SwapResult::SWAP_FAILED);
|
| + return;
|
| + }
|
| +
|
| + if (IsUniversalDisplayLinkDevice())
|
| + glFinish();
|
| +
|
| + window_->SchedulePageFlip(planes_, frame->callback);
|
| + planes_.clear();
|
| + }
|
| }
|
|
|
| -void* /* EGLConfig */ GbmSurfaceless::GetEGLSurfaceConfig(
|
| - const EglConfigCallbacks& egl) {
|
| - EGLint config_attribs[] = {EGL_BUFFER_SIZE,
|
| - 32,
|
| - EGL_ALPHA_SIZE,
|
| - 8,
|
| - EGL_BLUE_SIZE,
|
| - 8,
|
| - EGL_GREEN_SIZE,
|
| - 8,
|
| - EGL_RED_SIZE,
|
| - 8,
|
| - EGL_RENDERABLE_TYPE,
|
| - EGL_OPENGL_ES2_BIT,
|
| - EGL_SURFACE_TYPE,
|
| - EGL_DONT_CARE,
|
| - EGL_NONE};
|
| - return ChooseEGLConfig(egl, config_attribs);
|
| +EGLSyncKHR GbmSurfaceless::InsertFence(bool implicit) {
|
| + const EGLint attrib_list[] = {EGL_SYNC_CONDITION_KHR,
|
| + EGL_SYNC_PRIOR_COMMANDS_IMPLICIT_EXTERNAL_ARM,
|
| + EGL_NONE};
|
| + return eglCreateSyncKHR(GetDisplay(), EGL_SYNC_FENCE_KHR,
|
| + implicit ? attrib_list : NULL);
|
| +}
|
| +
|
| +void GbmSurfaceless::FenceRetired(EGLSyncKHR fence, PendingFrame* frame) {
|
| + eglDestroySyncKHR(GetDisplay(), fence);
|
| + frame->ready = true;
|
| + SubmitFrame();
|
| +}
|
| +
|
| +void GbmSurfaceless::SwapCompleted(const SwapCompletionCallback& callback,
|
| + gfx::SwapResult result) {
|
| + callback.Run(result);
|
| + swap_buffers_pending_ = false;
|
| + if (result == gfx::SwapResult::SWAP_FAILED) {
|
| + last_swap_buffers_result_ = false;
|
| + return;
|
| + }
|
| +
|
| + SubmitFrame();
|
| +}
|
| +
|
| +bool GbmSurfaceless::IsUniversalDisplayLinkDevice() {
|
| + return planes_.empty() ? false : planes_[0].buffer->RequiresGlFinish();
|
| }
|
|
|
| } // namespace ui
|
|
|