Commit a325be84 authored by Brian Ho's avatar Brian Ho Committed by Commit Bot

viz: Expose primary plane mailbox for SkiaOutputSurface

As part of the UseRealBuffersForPageFlipTest experiment,
OverlayProcessorOzone now uses the primary plane's buffer directly
for page flip tests [1]. This buffer is obtained via
OutputSurface::GetOverlayMailbox [2] which is unfortunately only
implemented for GL-based OutputSurfaces.

With SkiaRenderer enabled, OverlayProcessorOzone can't extract the
primary plane mailbox and skips promoting overlays at all [3]. This
CL implements GetOverlayMailbox for SkiaOutputSurface by threading
the corresponding mailbox from the GPU main thread back to the
compositor thread via the SwapBuffers callback.

Note that since GetOverlayMailbox corresponds to the *last* submitted
buffer, we need to skip the primary plane in the event of a reshape
because the page flip test result is meaningless.

[1] https://source.chromium.org/chromium/chromium/src/+/master:components/viz/service/display/overlay_processor_ozone.cc;l=139;drc=a44fcb321ea308b8f8d2227190a99c6cca2b79e6
[2] https://source.chromium.org/chromium/chromium/src/+/master:components/viz/service/display/direct_renderer.cc;l=356;drc=a44fcb321ea308b8f8d2227190a99c6cca2b79e6
[3] https://source.chromium.org/chromium/chromium/src/+/master:components/viz/service/display/overlay_processor_ozone.cc;l=210;drc=a44fcb321ea308b8f8d2227190a99c6cca2b79e6

Change-Id: I88d10746ede9bdc8afa565e8a42aef27d5572e53
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2533416
Commit-Queue: Brian Ho <hob@chromium.org>
Reviewed-by: default avatarJonathan Backer <backer@chromium.org>
Reviewed-by: default avatarDaniele Castagna <dcastagna@chromium.org>
Reviewed-by: default avatarKramer Ge <fangzhoug@chromium.org>
Cr-Commit-Position: refs/heads/master@{#828865}
parent a5692288
...@@ -566,6 +566,7 @@ viz_source_set("unit_tests") { ...@@ -566,6 +566,7 @@ viz_source_set("unit_tests") {
if (use_ozone) { if (use_ozone) {
sources += [ sources += [
"display/overlay_processor_ozone_unittest.cc",
"display/overlay_unittest.cc", "display/overlay_unittest.cc",
"display_embedder/software_output_device_ozone_unittest.cc", "display_embedder/software_output_device_ozone_unittest.cc",
] ]
......
...@@ -209,9 +209,10 @@ bool OverlayProcessorOzone::SetNativePixmapForCandidate( ...@@ -209,9 +209,10 @@ bool OverlayProcessorOzone::SetNativePixmapForCandidate(
if (!mailbox.IsSharedImage()) if (!mailbox.IsSharedImage())
return false; return false;
candidate->native_pixmap = shared_image_interface_->GetNativePixmap(mailbox); scoped_refptr<gfx::NativePixmap> native_pixmap =
shared_image_interface_->GetNativePixmap(mailbox);
if (!candidate->native_pixmap) { if (!native_pixmap) {
// SharedImage creation and destruction happens on a different // SharedImage creation and destruction happens on a different
// thread so there is no guarantee that we can always look them up // thread so there is no guarantee that we can always look them up
// successfully. If a SharedImage doesn't exist, ignore the // successfully. If a SharedImage doesn't exist, ignore the
...@@ -221,9 +222,19 @@ bool OverlayProcessorOzone::SetNativePixmapForCandidate( ...@@ -221,9 +222,19 @@ bool OverlayProcessorOzone::SetNativePixmapForCandidate(
ReportSharedImageExists(false); ReportSharedImageExists(false);
return false; return false;
} }
ReportSharedImageExists(true);
if (candidate->buffer_size != native_pixmap->GetBufferSize() ||
candidate->format != native_pixmap->GetBufferFormat()) {
// If |mailbox| corresponds to the last submitted primary plane, its
// parameters may not match those of the current candidate due to a
// reshape. If the size and format don't match, skip this candidate for
// now, and try again next frame.
return false;
}
candidate->native_pixmap = std::move(native_pixmap);
candidate->native_pixmap_unique_id = MailboxToUInt32(mailbox); candidate->native_pixmap_unique_id = MailboxToUInt32(mailbox);
ReportSharedImageExists(true);
return true; return true;
} }
......
// Copyright 2020 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.
#include "components/viz/service/display/overlay_processor_ozone.h"
#include "components/viz/test/test_context_provider.h"
#include "gpu/command_buffer/client/shared_image_interface.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/linux/native_pixmap_dmabuf.h"
#include "ui/gfx/native_pixmap.h"
#include "ui/gfx/native_pixmap_handle.h"
using ::testing::_;
using ::testing::Return;
namespace viz {
namespace {
class FakeOverlayCandidatesOzone : public ui::OverlayCandidatesOzone {
public:
~FakeOverlayCandidatesOzone() override = default;
// Mark every overlay candidate as handled since we don't really care about
// OverlayCandidatesOzone internals in this test suite.
void CheckOverlaySupport(
std::vector<ui::OverlaySurfaceCandidate>* candidates) override {
for (auto& candidate : *candidates) {
candidate.overlay_handled = true;
}
}
};
class FakeNativePixmap : public gfx::NativePixmap {
public:
FakeNativePixmap(gfx::Size size, gfx::BufferFormat format)
: size_(size), format_(format) {}
bool AreDmaBufFdsValid() const override { return false; }
int GetDmaBufFd(size_t plane) const override { return -1; }
uint32_t GetDmaBufPitch(size_t plane) const override { return 0; }
size_t GetDmaBufOffset(size_t plane) const override { return 0; }
size_t GetDmaBufPlaneSize(size_t plane) const override { return 0; }
uint64_t GetBufferFormatModifier() const override { return 0; }
gfx::BufferFormat GetBufferFormat() const override { return format_; }
size_t GetNumberOfPlanes() const override { return 0; }
gfx::Size GetBufferSize() const override { return size_; }
uint32_t GetUniqueId() const override { return 0; }
bool ScheduleOverlayPlane(
gfx::AcceleratedWidget widget,
int plane_z_order,
gfx::OverlayTransform plane_transform,
const gfx::Rect& display_bounds,
const gfx::RectF& crop_rect,
bool enable_blend,
std::vector<gfx::GpuFence> acquire_fences,
std::vector<gfx::GpuFence> release_fences) override {
return false;
}
gfx::NativePixmapHandle ExportHandle() override {
return gfx::NativePixmapHandle();
}
private:
~FakeNativePixmap() override = default;
gfx::Size size_;
gfx::BufferFormat format_;
};
class MockSharedImageInterface : public TestSharedImageInterface {
public:
MOCK_METHOD1(GetNativePixmap,
scoped_refptr<gfx::NativePixmap>(const gpu::Mailbox& mailbox));
};
} // namespace
// TODO(crbug.com/1138568): Fuchsia claims support for presenting primary
// plane as overlay, but does not provide a mailbox. Handle this case.
#if !defined(OS_FUCHSIA)
TEST(OverlayProcessorOzoneTest, PrimaryPlaneSizeAndFormatMatches) {
// Set up the primary plane.
gfx::Size size(128, 128);
OverlayProcessorInterface::OutputSurfaceOverlayPlane primary_plane;
primary_plane.resource_size = size;
primary_plane.format = gfx::BufferFormat::BGRA_8888;
primary_plane.mailbox = gpu::Mailbox::GenerateForSharedImage();
// Set up a dummy OverlayCandidate.
OverlayCandidate candidate;
candidate.resource_size_in_pixels = size;
candidate.format = gfx::BufferFormat::BGRA_8888;
candidate.mailbox = gpu::Mailbox::GenerateForSharedImage();
candidate.overlay_handled = false;
OverlayCandidateList candidates;
candidates.push_back(candidate);
// Initialize a MockSharedImageInterface that returns a NativePixmap with
// matching params to the primary plane.
std::unique_ptr<MockSharedImageInterface> sii =
std::make_unique<MockSharedImageInterface>();
scoped_refptr<gfx::NativePixmap> primary_plane_pixmap =
base::MakeRefCounted<FakeNativePixmap>(size,
gfx::BufferFormat::BGRA_8888);
scoped_refptr<gfx::NativePixmap> candidate_pixmap =
base::MakeRefCounted<FakeNativePixmap>(size,
gfx::BufferFormat::BGRA_8888);
EXPECT_CALL(*sii, GetNativePixmap(_))
.WillOnce(Return(primary_plane_pixmap))
.WillOnce(Return(candidate_pixmap));
OverlayProcessorOzone processor(
std::make_unique<FakeOverlayCandidatesOzone>(), {}, sii.get());
processor.CheckOverlaySupport(&primary_plane, &candidates);
// Since the |OutputSurfaceOverlayPlane|'s size and format match those of
// primary plane's NativePixmap, the overlay candidate is promoted.
EXPECT_TRUE(candidates.at(0).overlay_handled);
}
TEST(OverlayProcessorOzoneTest, PrimaryPlaneFormatMismatch) {
// Set up the primary plane.
gfx::Size size(128, 128);
OverlayProcessorInterface::OutputSurfaceOverlayPlane primary_plane;
primary_plane.resource_size = size;
primary_plane.format = gfx::BufferFormat::BGRA_8888;
primary_plane.mailbox = gpu::Mailbox::GenerateForSharedImage();
// Set up a dummy OverlayCandidate.
OverlayCandidate candidate;
candidate.resource_size_in_pixels = size;
candidate.format = gfx::BufferFormat::BGRA_8888;
candidate.mailbox = gpu::Mailbox::GenerateForSharedImage();
candidate.overlay_handled = false;
OverlayCandidateList candidates;
candidates.push_back(candidate);
// Initialize a MockSharedImageInterface that returns a NativePixmap with
// a different buffer format than that of the primary plane.
std::unique_ptr<MockSharedImageInterface> sii =
std::make_unique<MockSharedImageInterface>();
scoped_refptr<gfx::NativePixmap> primary_plane_pixmap =
base::MakeRefCounted<FakeNativePixmap>(size, gfx::BufferFormat::R_8);
EXPECT_CALL(*sii, GetNativePixmap(_)).WillOnce(Return(primary_plane_pixmap));
OverlayProcessorOzone processor(
std::make_unique<FakeOverlayCandidatesOzone>(), {}, sii.get());
processor.CheckOverlaySupport(&primary_plane, &candidates);
// Since the |OutputSurfaceOverlayPlane|'s format doesn't match that of the
// primary plane's NativePixmap, the overlay candidate is NOT promoted.
EXPECT_FALSE(candidates.at(0).overlay_handled);
}
#endif
} // namespace viz
...@@ -170,12 +170,14 @@ void SkiaOutputDevice::FinishSwapBuffers( ...@@ -170,12 +170,14 @@ void SkiaOutputDevice::FinishSwapBuffers(
const gfx::Size& size, const gfx::Size& size,
std::vector<ui::LatencyInfo> latency_info, std::vector<ui::LatencyInfo> latency_info,
const base::Optional<gfx::Rect>& damage_area, const base::Optional<gfx::Rect>& damage_area,
std::vector<gpu::Mailbox> released_overlays) { std::vector<gpu::Mailbox> released_overlays,
const gpu::Mailbox& primary_plane_mailbox) {
DCHECK(!pending_swaps_.empty()); DCHECK(!pending_swaps_.empty());
const gpu::SwapBuffersCompleteParams& params = const gpu::SwapBuffersCompleteParams& params =
pending_swaps_.front().Complete(std::move(result), damage_area, pending_swaps_.front().Complete(std::move(result), damage_area,
std::move(released_overlays)); std::move(released_overlays),
primary_plane_mailbox);
did_swap_buffer_complete_callback_.Run(params, size); did_swap_buffer_complete_callback_.Run(params, size);
...@@ -214,13 +216,15 @@ SkiaOutputDevice::SwapInfo::~SwapInfo() = default; ...@@ -214,13 +216,15 @@ SkiaOutputDevice::SwapInfo::~SwapInfo() = default;
const gpu::SwapBuffersCompleteParams& SkiaOutputDevice::SwapInfo::Complete( const gpu::SwapBuffersCompleteParams& SkiaOutputDevice::SwapInfo::Complete(
gfx::SwapCompletionResult result, gfx::SwapCompletionResult result,
const base::Optional<gfx::Rect>& damage_rect, const base::Optional<gfx::Rect>& damage_rect,
std::vector<gpu::Mailbox> released_overlays) { std::vector<gpu::Mailbox> released_overlays,
const gpu::Mailbox& primary_plane_mailbox) {
params_.swap_response.result = result.swap_result; params_.swap_response.result = result.swap_result;
params_.swap_response.timings.swap_end = base::TimeTicks::Now(); params_.swap_response.timings.swap_end = base::TimeTicks::Now();
params_.frame_buffer_damage_area = damage_rect; params_.frame_buffer_damage_area = damage_rect;
if (result.ca_layer_params) if (result.ca_layer_params)
params_.ca_layer_params = *result.ca_layer_params; params_.ca_layer_params = *result.ca_layer_params;
params_.primary_plane_mailbox = primary_plane_mailbox;
params_.released_overlays = std::move(released_overlays); params_.released_overlays = std::move(released_overlays);
return params_; return params_;
} }
......
...@@ -164,7 +164,8 @@ class SkiaOutputDevice { ...@@ -164,7 +164,8 @@ class SkiaOutputDevice {
const gpu::SwapBuffersCompleteParams& Complete( const gpu::SwapBuffersCompleteParams& Complete(
gfx::SwapCompletionResult result, gfx::SwapCompletionResult result,
const base::Optional<gfx::Rect>& damage_area, const base::Optional<gfx::Rect>& damage_area,
std::vector<gpu::Mailbox> released_overlays); std::vector<gpu::Mailbox> released_overlays,
const gpu::Mailbox& primary_plane_mailbox);
void CallFeedback(); void CallFeedback();
private: private:
...@@ -204,7 +205,8 @@ class SkiaOutputDevice { ...@@ -204,7 +205,8 @@ class SkiaOutputDevice {
const gfx::Size& size, const gfx::Size& size,
std::vector<ui::LatencyInfo> latency_info, std::vector<ui::LatencyInfo> latency_info,
const base::Optional<gfx::Rect>& damage_area = base::nullopt, const base::Optional<gfx::Rect>& damage_area = base::nullopt,
std::vector<gpu::Mailbox> released_overlays = {}); std::vector<gpu::Mailbox> released_overlays = {},
const gpu::Mailbox& primary_plane_mailbox = gpu::Mailbox());
GrDirectContext* const gr_context_; GrDirectContext* const gr_context_;
......
...@@ -411,7 +411,8 @@ void SkiaOutputDeviceBufferQueue::DoFinishSwapBuffers( ...@@ -411,7 +411,8 @@ void SkiaOutputDeviceBufferQueue::DoFinishSwapBuffers(
DCHECK(!result.gpu_fence); DCHECK(!result.gpu_fence);
FinishSwapBuffers(std::move(result), size, latency_info, FinishSwapBuffers(std::move(result), size, latency_info,
/*damage_area=*/base::nullopt, /*damage_area=*/base::nullopt,
std::move(released_overlays)); std::move(released_overlays),
image ? image->skia_representation()->mailbox() : gpu::Mailbox());
PageFlipComplete(image.get()); PageFlipComplete(image.get());
} }
......
...@@ -891,6 +891,7 @@ void SkiaOutputSurfaceImpl::DidSwapBuffersComplete( ...@@ -891,6 +891,7 @@ void SkiaOutputSurfaceImpl::DidSwapBuffersComplete(
const gfx::Size& pixel_size) { const gfx::Size& pixel_size) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(client_); DCHECK(client_);
last_swapped_mailbox_ = params.primary_plane_mailbox;
// Reset |damage_of_buffers_|, if buffers are new created. // Reset |damage_of_buffers_|, if buffers are new created.
if (params.swap_response.result == if (params.swap_response.result ==
...@@ -1058,6 +1059,11 @@ unsigned SkiaOutputSurfaceImpl::GetOverlayTextureId() const { ...@@ -1058,6 +1059,11 @@ unsigned SkiaOutputSurfaceImpl::GetOverlayTextureId() const {
return 0; return 0;
} }
gpu::Mailbox SkiaOutputSurfaceImpl::GetOverlayMailbox() const {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
return last_swapped_mailbox_;
}
bool SkiaOutputSurfaceImpl::HasExternalStencilTest() const { bool SkiaOutputSurfaceImpl::HasExternalStencilTest() const {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
......
...@@ -79,6 +79,7 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurfaceImpl : public SkiaOutputSurface { ...@@ -79,6 +79,7 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurfaceImpl : public SkiaOutputSurface {
uint32_t GetFramebufferCopyTextureFormat() override; uint32_t GetFramebufferCopyTextureFormat() override;
bool IsDisplayedAsOverlayPlane() const override; bool IsDisplayedAsOverlayPlane() const override;
unsigned GetOverlayTextureId() const override; unsigned GetOverlayTextureId() const override;
gpu::Mailbox GetOverlayMailbox() const override;
bool HasExternalStencilTest() const override; bool HasExternalStencilTest() const override;
void ApplyExternalStencil() override; void ApplyExternalStencil() override;
unsigned UpdateGpuFence() override; unsigned UpdateGpuFence() override;
...@@ -204,6 +205,7 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurfaceImpl : public SkiaOutputSurface { ...@@ -204,6 +205,7 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurfaceImpl : public SkiaOutputSurface {
UpdateVSyncParametersCallback update_vsync_parameters_callback_; UpdateVSyncParametersCallback update_vsync_parameters_callback_;
GpuVSyncCallback gpu_vsync_callback_; GpuVSyncCallback gpu_vsync_callback_;
bool is_displayed_as_overlay_ = false; bool is_displayed_as_overlay_ = false;
gpu::Mailbox last_swapped_mailbox_;
gfx::Size size_; gfx::Size size_;
gfx::ColorSpace color_space_; gfx::ColorSpace color_space_;
......
...@@ -31,6 +31,11 @@ struct GPU_EXPORT SwapBuffersCompleteParams { ...@@ -31,6 +31,11 @@ struct GPU_EXPORT SwapBuffersCompleteParams {
// next frame. // next frame.
base::Optional<gfx::Rect> frame_buffer_damage_area; base::Optional<gfx::Rect> frame_buffer_damage_area;
// The mailbox corresponding to the primary plane that was just swapped to
// the front buffer. The overlay processor can use it to extract the buffer
// for page flip tests.
Mailbox primary_plane_mailbox;
// Used only on macOS, for coordinating IOSurface reuse with the system // Used only on macOS, for coordinating IOSurface reuse with the system
// WindowServer. // WindowServer.
gpu::TextureInUseResponses texture_in_use_responses; gpu::TextureInUseResponses texture_in_use_responses;
......
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