Commit 6b82d425 authored by Alexandros Frantzis's avatar Alexandros Frantzis Committed by Commit Bot

ozone/drm: Implement support for plane overlay fences

Add support for using the plane overlay fences provided by the
GbmSurfaceless::ScheduleOverlayPlane() method to synchronize display of
overlays in Ozone-DRM. This also involves implementing the
GbmSurfaceless::SetUsePlaneGpuFences() method to control whether the
provided fences are used instead of the internally constructed
EGLSyncKHR object.

Since the PendingFrame in GbmSurfaceless owns (through GLSurfaceOverlay)
the fences used for that frame, some refactorings where required in the
frame submission code to keep the PendingFrame alive until the frame is
complete.

Bug: 828393
Test: ozone_demo --use-gpu-fences on Ozone-DRM
Change-Id: Id48485c55d7a31b01858ed5dbbf45815ac54c621
Reviewed-on: https://chromium-review.googlesource.com/1021514
Commit-Queue: Daniele Castagna <dcastagna@chromium.org>
Reviewed-by: default avatarDaniele Castagna <dcastagna@chromium.org>
Reviewed-by: default avatarAntoine Labour <piman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#559515}
parent 9b822f03
......@@ -84,7 +84,7 @@ std::vector<OverlayCheckReturn_Params> DrmOverlayValidator::TestPageFlip(
OverlayPlane plane(buffer, params[i].plane_z_order, params[i].transform,
params[i].display_rect, params[i].crop_rect,
/* enable_blend */ true, base::kInvalidPlatformFile);
/* enable_blend */ true, /* gpu_fence */ nullptr);
test_list.push_back(plane);
if (buffer && controller->TestPageFlip(test_list)) {
......
......@@ -138,7 +138,7 @@ void DrmOverlayValidatorTest::AddPlane(const ui::OverlayCheck_Params& params) {
params.buffer_size);
ui::OverlayPlane plane(std::move(scanout_buffer), params.plane_z_order,
params.transform, params.display_rect,
params.crop_rect, true, base::kInvalidPlatformFile);
params.crop_rect, true, nullptr);
plane_list_.push_back(plane);
}
......@@ -276,7 +276,7 @@ TEST_F(DrmOverlayValidatorTest,
new ui::CrtcController(drm_.get(), kSecondaryCrtc, kSecondaryConnector)));
ui::OverlayPlane plane1(scoped_refptr<ui::ScanoutBuffer>(
new ui::MockScanoutBuffer(primary_rect_.size())),
base::kInvalidPlatformFile);
nullptr);
EXPECT_TRUE(controller->Modeset(plane1, kDefaultMode));
gfx::RectF crop_rect = gfx::RectF(0, 0, 0.5, 0.5);
......@@ -338,7 +338,7 @@ TEST_F(DrmOverlayValidatorTest, OptimalFormatYUV_MirroredControllers) {
new ui::CrtcController(drm_.get(), kSecondaryCrtc, kSecondaryConnector)));
ui::OverlayPlane plane1(scoped_refptr<ui::ScanoutBuffer>(
new ui::MockScanoutBuffer(primary_rect_.size())),
base::kInvalidPlatformFile);
nullptr);
EXPECT_TRUE(controller->Modeset(plane1, kDefaultMode));
overlay_params_.back().buffer_size = overlay_rect_.size();
......
......@@ -176,7 +176,7 @@ TEST_F(DrmWindowTest, CheckCallbackOnFailedSwap) {
ui::DrmWindow* window = screen_manager_->GetWindow(kDefaultWidgetHandle);
ui::OverlayPlane plane(
buffer_generator.Create(drm_, DRM_FORMAT_XRGB8888, {}, window_size),
base::kInvalidPlatformFile);
nullptr);
drm_->set_page_flip_expectation(false);
......
......@@ -381,7 +381,7 @@ bool GbmPixmap::ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
if (buffer_->GetFramebufferId()) {
surface_manager_->GetSurface(widget)->QueueOverlayPlane(
OverlayPlane(buffer_, plane_z_order, plane_transform, display_bounds,
crop_rect, enable_blend, base::kInvalidPlatformFile));
crop_rect, enable_blend, gpu_fence));
}
return true;
......
......@@ -126,12 +126,9 @@ void GbmSurfaceless::SwapBuffersAsync(
glFlush();
unsubmitted_frames_.back()->Flush();
auto surface_swap_callback =
base::BindOnce(&GbmSurfaceless::SwapCompleted, weak_factory_.GetWeakPtr(),
completion_callback, presentation_callback);
PendingFrame* frame = unsubmitted_frames_.back().get();
frame->callback = std::move(surface_swap_callback);
frame->completion_callback = completion_callback;
frame->presentation_callback = presentation_callback;
unsubmitted_frames_.push_back(std::make_unique<PendingFrame>());
// TODO(dcastagna): Remove the following workaround once we get explicit sync
......@@ -143,7 +140,7 @@ void GbmSurfaceless::SwapBuffersAsync(
// GbmSurfaceless::SubmitFrame.
// This means |is_on_external_drm_device_| could be incorrectly set to true
// the first time we're testing it.
if (rely_on_implicit_sync_ && !is_on_external_drm_device_) {
if (!use_egl_fence_sync_ && !is_on_external_drm_device_) {
frame->ready = true;
SubmitFrame();
return;
......@@ -205,7 +202,11 @@ EGLConfig GbmSurfaceless::GetConfig() {
}
void GbmSurfaceless::SetRelyOnImplicitSync() {
rely_on_implicit_sync_ = true;
use_egl_fence_sync_ = false;
}
void GbmSurfaceless::SetUsePlaneGpuFences() {
use_egl_fence_sync_ = false;
}
GbmSurfaceless::~GbmSurfaceless() {
......@@ -238,15 +239,20 @@ void GbmSurfaceless::SubmitFrame() {
unsubmitted_frames_.erase(unsubmitted_frames_.begin());
swap_buffers_pending_ = true;
if (!frame->ScheduleOverlayPlanes(widget_)) {
bool schedule_planes_succeeded = frame->ScheduleOverlayPlanes(widget_);
auto callback = base::BindOnce(&GbmSurfaceless::SwapCompleted,
weak_factory_.GetWeakPtr(),
base::Passed(std::move(frame)));
if (!schedule_planes_succeeded) {
// |callback| is a wrapper for SwapCompleted(). Call it to properly
// propagate the failed state.
std::move(frame->callback)
.Run(gfx::SwapResult::SWAP_FAILED, gfx::PresentationFeedback());
std::move(callback).Run(gfx::SwapResult::SWAP_FAILED,
gfx::PresentationFeedback());
return;
}
window_->SchedulePageFlip(planes_, std::move(frame->callback));
window_->SchedulePageFlip(planes_, std::move(callback));
planes_.clear();
}
}
......@@ -264,13 +270,13 @@ void GbmSurfaceless::FenceRetired(PendingFrame* frame) {
SubmitFrame();
}
void GbmSurfaceless::SwapCompleted(
const SwapCompletionCallback& completion_callback,
const PresentationCallback& presentation_callback,
gfx::SwapResult result,
const gfx::PresentationFeedback& feedback) {
completion_callback.Run(result);
presentation_callback.Run(feedback);
void GbmSurfaceless::SwapCompleted(std::unique_ptr<PendingFrame> frame,
gfx::SwapResult result,
const gfx::PresentationFeedback& feedback) {
// Explicitly destroy overlays to free resources (e.g., fences) early.
frame->overlays.clear();
frame->completion_callback.Run(result);
frame->presentation_callback.Run(feedback);
swap_buffers_pending_ = false;
if (result == gfx::SwapResult::SWAP_FAILED) {
last_swap_buffers_result_ = false;
......
......@@ -66,6 +66,7 @@ class GbmSurfaceless : public gl::SurfacelessEGL {
const PresentationCallback& presentation_callback) override;
EGLConfig GetConfig() override;
void SetRelyOnImplicitSync() override;
void SetUsePlaneGpuFences() override;
protected:
~GbmSurfaceless() override;
......@@ -83,10 +84,8 @@ class GbmSurfaceless : public gl::SurfacelessEGL {
bool ready = false;
std::vector<gl::GLSurfaceOverlay> overlays;
using SwapCompletionAndPresentationCallback =
base::OnceCallback<void(gfx::SwapResult,
const gfx::PresentationFeedback&)>;
SwapCompletionAndPresentationCallback callback;
SwapCompletionCallback completion_callback;
PresentationCallback presentation_callback;
};
void SubmitFrame();
......@@ -94,8 +93,7 @@ class GbmSurfaceless : public gl::SurfacelessEGL {
EGLSyncKHR InsertFence(bool implicit);
void FenceRetired(PendingFrame* frame);
void SwapCompleted(const SwapCompletionCallback& completion_callback,
const PresentationCallback& presentation_callback,
void SwapCompleted(std::unique_ptr<PendingFrame> pending_frame,
gfx::SwapResult result,
const gfx::PresentationFeedback& feedback);
......@@ -110,7 +108,7 @@ class GbmSurfaceless : public gl::SurfacelessEGL {
bool has_implicit_external_sync_;
bool last_swap_buffers_result_ = true;
bool swap_buffers_pending_ = false;
bool rely_on_implicit_sync_ = false;
bool use_egl_fence_sync_ = true;
// Conservatively assume we begin on a device that requires
// explicit synchronization.
bool is_on_external_drm_device_ = true;
......
......@@ -11,6 +11,8 @@
#include "base/files/platform_file.h"
#include "base/stl_util.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "ui/gfx/gpu_fence.h"
#include "ui/gfx/gpu_fence_handle.h"
#include "ui/ozone/platform/drm/common/drm_util.h"
#include "ui/ozone/platform/drm/gpu/crtc_controller.h"
#include "ui/ozone/platform/drm/gpu/drm_device.h"
......@@ -193,10 +195,22 @@ bool HardwareDisplayPlaneManagerAtomic::SetPlaneData(
uint32_t framebuffer_id = overlay.enable_blend
? overlay.buffer->GetFramebufferId()
: overlay.buffer->GetOpaqueFramebufferId();
int fence_fd = base::kInvalidPlatformFile;
if (overlay.gpu_fence) {
const auto& gpu_fence_handle = overlay.gpu_fence->GetGpuFenceHandle();
if (gpu_fence_handle.type !=
gfx::GpuFenceHandleType::kAndroidNativeFenceSync) {
LOG(ERROR) << "Received invalid gpu fence";
return false;
}
fence_fd = gpu_fence_handle.native_fd.fd;
}
if (!atomic_plane->SetPlaneData(plane_list->atomic_property_set.get(),
crtc_id, framebuffer_id,
overlay.display_bounds, src_rect,
overlay.plane_transform, overlay.fence_fd)) {
overlay.plane_transform, fence_fd)) {
LOG(ERROR) << "Failed to set plane properties";
return false;
}
......
......@@ -10,6 +10,7 @@
#include "base/bind.h"
#include "base/posix/eintr_wrapper.h"
#include "base/task_scheduler/post_task.h"
#include "ui/gfx/gpu_fence.h"
#include "ui/gfx/presentation_feedback.h"
#include "ui/ozone/platform/drm/gpu/crtc_controller.h"
#include "ui/ozone/platform/drm/gpu/drm_device.h"
......@@ -19,15 +20,13 @@ namespace ui {
namespace {
const int kInfiniteSyncWaitTimeout = -1;
// We currently wait for the fences serially, but it's possible
// that merging the fences and waiting on the merged fence fd
// is more efficient. We should revisit once we have more info.
void WaitForPlaneFences(const ui::OverlayPlaneList& planes) {
for (const auto& plane : planes) {
if (plane.fence_fd >= 0)
sync_wait(plane.fence_fd, kInfiniteSyncWaitTimeout);
if (plane.gpu_fence)
plane.gpu_fence->Wait();
}
}
......
......@@ -11,13 +11,13 @@
namespace ui {
OverlayPlane::OverlayPlane(const scoped_refptr<ScanoutBuffer>& buffer,
int fence_fd)
gfx::GpuFence* gpu_fence)
: buffer(buffer),
plane_transform(gfx::OVERLAY_TRANSFORM_NONE),
display_bounds(gfx::Point(), buffer->GetSize()),
crop_rect(0, 0, 1, 1),
enable_blend(false),
fence_fd(fence_fd) {}
gpu_fence(gpu_fence) {}
OverlayPlane::OverlayPlane(const scoped_refptr<ScanoutBuffer>& buffer,
int z_order,
......@@ -25,14 +25,14 @@ OverlayPlane::OverlayPlane(const scoped_refptr<ScanoutBuffer>& buffer,
const gfx::Rect& display_bounds,
const gfx::RectF& crop_rect,
bool enable_blend,
int fence_fd)
gfx::GpuFence* gpu_fence)
: buffer(buffer),
z_order(z_order),
plane_transform(plane_transform),
display_bounds(display_bounds),
crop_rect(crop_rect),
enable_blend(enable_blend),
fence_fd(fence_fd) {}
gpu_fence(gpu_fence) {}
OverlayPlane::OverlayPlane(const OverlayPlane& other) = default;
......
......@@ -13,6 +13,10 @@
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/overlay_transform.h"
namespace gfx {
class GpuFence;
}
namespace ui {
class ScanoutBuffer;
......@@ -23,7 +27,7 @@ typedef std::vector<OverlayPlane> OverlayPlaneList;
struct OverlayPlane {
// Simpler constructor for the primary plane.
explicit OverlayPlane(const scoped_refptr<ScanoutBuffer>& buffer,
int fence_fd);
gfx::GpuFence* gpu_fence);
OverlayPlane(const scoped_refptr<ScanoutBuffer>& buffer,
int z_order,
......@@ -31,7 +35,7 @@ struct OverlayPlane {
const gfx::Rect& display_bounds,
const gfx::RectF& crop_rect,
bool enable_blend,
int fence_fd);
gfx::GpuFence* gpu_fence);
OverlayPlane(const OverlayPlane& other);
bool operator<(const OverlayPlane& plane) const;
......@@ -47,7 +51,7 @@ struct OverlayPlane {
gfx::Rect display_bounds;
gfx::RectF crop_rect;
bool enable_blend;
int fence_fd;
gfx::GpuFence* gpu_fence;
};
} // namespace ui
......
......@@ -377,11 +377,11 @@ OverlayPlane ScreenManager::GetModesetBuffer(
LOG(ERROR) << "Failed to create scanout buffer";
return OverlayPlane(nullptr, 0, gfx::OVERLAY_TRANSFORM_INVALID, gfx::Rect(),
gfx::RectF(), /* enable_blend */ true,
base::kInvalidPlatformFile);
/* gpu_fence */ nullptr);
}
FillModesetBuffer(drm, controller, buffer.get());
return OverlayPlane(buffer, base::kInvalidPlatformFile);
return OverlayPlane(buffer, nullptr);
}
bool ScreenManager::EnableController(HardwareDisplayController* controller) {
......
......@@ -502,8 +502,7 @@ TEST_F(ScreenManagerTest, EnableControllerWhenWindowHasBuffer) {
scoped_refptr<ui::ScanoutBuffer> buffer = buffer_generator_->Create(
drm_, DRM_FORMAT_XRGB8888, {}, GetPrimaryBounds().size());
window->SchedulePageFlip(
std::vector<ui::OverlayPlane>(
1, ui::OverlayPlane(buffer, base::kInvalidPlatformFile)),
std::vector<ui::OverlayPlane>(1, ui::OverlayPlane(buffer, nullptr)),
base::DoNothing());
screen_manager_->AddWindow(1, std::move(window));
......@@ -529,8 +528,7 @@ TEST_F(ScreenManagerTest, RejectBufferWithIncompatibleModifiers) {
GetPrimaryBounds().size());
window->SchedulePageFlip(
std::vector<ui::OverlayPlane>(
1, ui::OverlayPlane(buffer, base::kInvalidPlatformFile)),
std::vector<ui::OverlayPlane>(1, ui::OverlayPlane(buffer, nullptr)),
base::DoNothing());
screen_manager_->AddWindow(1, std::move(window));
......
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