Commit aa21781d authored by Kramer Ge's avatar Kramer Ge Committed by Commit Bot

[ozone/wayland] Use 4x4 opaque background and stack underlay correctly

Using a 4x4 sized opaque background will not regress performance in
underlay cases because the root surface is still opaque. The background
will be stretched out by wayland viewporter extension.

This is 6/? CL for overlay forwarding using wl_subsurface.

Change-Id: I59b0d4cdbfbb6727d578e286c9d19cf69a9bff32
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2352523
Commit-Queue: Kramer Ge <fangzhoug@chromium.org>
Reviewed-by: default avatarRobert Kroeger <rjkroege@chromium.org>
Reviewed-by: default avatarMaksim Sisov (GMT+3) <msisov@igalia.com>
Cr-Commit-Position: refs/heads/master@{#810527}
parent 3dfd4f24
...@@ -352,11 +352,12 @@ void DirectRenderer::DrawFrame( ...@@ -352,11 +352,12 @@ void DirectRenderer::DrawFrame(
// If we promote any quad to an underlay then the main plane must support // If we promote any quad to an underlay then the main plane must support
// alpha. // alpha.
// TODO(ccameron): We should update // TODO(ccameron): We should update |frame_color_space|, and
// |root_render_pass->has_transparent_background|, |frame_color_space|, and
// |frame_buffer_format| based on the change in |frame_has_alpha|. // |frame_buffer_format| based on the change in |frame_has_alpha|.
if (current_frame()->output_surface_plane) if (current_frame()->output_surface_plane) {
frame_has_alpha |= current_frame()->output_surface_plane->enable_blending; frame_has_alpha |= current_frame()->output_surface_plane->enable_blending;
root_render_pass->has_transparent_background = frame_has_alpha;
}
overlay_processor_->AdjustOutputSurfaceOverlay( overlay_processor_->AdjustOutputSurfaceOverlay(
&(current_frame()->output_surface_plane)); &(current_frame()->output_surface_plane));
......
...@@ -115,4 +115,14 @@ void OutputPresenter::Image::PreGrContextSubmit() { ...@@ -115,4 +115,14 @@ void OutputPresenter::Image::PreGrContextSubmit() {
} }
} }
std::unique_ptr<OutputPresenter::Image>
OutputPresenter::AllocateBackgroundImage(gfx::ColorSpace color_space,
gfx::Size image_size) {
return nullptr;
}
void OutputPresenter::ScheduleBackground(Image* image) {
NOTREACHED();
}
} // namespace viz } // namespace viz
...@@ -86,6 +86,9 @@ class VIZ_SERVICE_EXPORT OutputPresenter { ...@@ -86,6 +86,9 @@ class VIZ_SERVICE_EXPORT OutputPresenter {
gfx::ColorSpace color_space, gfx::ColorSpace color_space,
gfx::Size image_size, gfx::Size image_size,
size_t num_images) = 0; size_t num_images) = 0;
virtual std::unique_ptr<Image> AllocateBackgroundImage(
gfx::ColorSpace color_space,
gfx::Size image_size);
virtual void SwapBuffers(SwapCompletionCallback completion_callback, virtual void SwapBuffers(SwapCompletionCallback completion_callback,
BufferPresentedCallback presentation_callback) = 0; BufferPresentedCallback presentation_callback) = 0;
virtual void PostSubBuffer(const gfx::Rect& rect, virtual void PostSubBuffer(const gfx::Rect& rect,
...@@ -102,6 +105,7 @@ class VIZ_SERVICE_EXPORT OutputPresenter { ...@@ -102,6 +105,7 @@ class VIZ_SERVICE_EXPORT OutputPresenter {
gpu::SharedImageRepresentationOverlay::ScopedReadAccess; gpu::SharedImageRepresentationOverlay::ScopedReadAccess;
virtual void ScheduleOverlays(SkiaOutputSurface::OverlayList overlays, virtual void ScheduleOverlays(SkiaOutputSurface::OverlayList overlays,
std::vector<ScopedOverlayAccess*> accesses) = 0; std::vector<ScopedOverlayAccess*> accesses) = 0;
virtual void ScheduleBackground(Image* image);
}; };
} // namespace viz } // namespace viz
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "ui/display/types/display_snapshot.h" #include "ui/display/types/display_snapshot.h"
#include "ui/gfx/buffer_format_util.h" #include "ui/gfx/buffer_format_util.h"
#include "ui/gfx/geometry/rect_conversions.h" #include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/overlay_transform.h"
#include "ui/gl/gl_fence.h" #include "ui/gl/gl_fence.h"
#include "ui/gl/gl_surface.h" #include "ui/gl/gl_surface.h"
...@@ -282,6 +283,20 @@ OutputPresenterGL::AllocateImages(gfx::ColorSpace color_space, ...@@ -282,6 +283,20 @@ OutputPresenterGL::AllocateImages(gfx::ColorSpace color_space,
return images; return images;
} }
std::unique_ptr<OutputPresenter::Image>
OutputPresenterGL::AllocateBackgroundImage(gfx::ColorSpace color_space,
gfx::Size image_size) {
auto image = std::make_unique<PresenterImageGL>();
if (!image->Initialize(shared_image_factory_,
shared_image_representation_factory_, image_size,
color_space, image_format_, dependency_,
shared_image_usage_)) {
DLOG(ERROR) << "Failed to initialize image.";
return nullptr;
}
return image;
}
void OutputPresenterGL::SwapBuffers( void OutputPresenterGL::SwapBuffers(
SwapCompletionCallback completion_callback, SwapCompletionCallback completion_callback,
BufferPresentedCallback presentation_callback) { BufferPresentedCallback presentation_callback) {
...@@ -329,6 +344,22 @@ void OutputPresenterGL::SchedulePrimaryPlane( ...@@ -329,6 +344,22 @@ void OutputPresenterGL::SchedulePrimaryPlane(
plane.enable_blending, std::move(fence)); plane.enable_blending, std::move(fence));
} }
void OutputPresenterGL::ScheduleBackground(Image* image) {
// Background is not seen by user, and is created before buffer queue buffers.
// So fence is not needed.
auto* gl_image =
reinterpret_cast<PresenterImageGL*>(image)->GetGLImage(nullptr);
// Background is also z-order 0.
constexpr int kPlaneZOrder = INT32_MIN;
// Background always uses the full texture.
constexpr gfx::RectF kUVRect(0.f, 0.f, 1.0f, 1.0f);
gl_surface_->ScheduleOverlayPlane(
kPlaneZOrder, gfx::OVERLAY_TRANSFORM_NONE, gl_image, gfx::Rect(),
/*crop_rect=*/kUVRect,
/*enable_blend=*/false, /*gpu_fence=*/nullptr);
}
void OutputPresenterGL::CommitOverlayPlanes( void OutputPresenterGL::CommitOverlayPlanes(
SwapCompletionCallback completion_callback, SwapCompletionCallback completion_callback,
BufferPresentedCallback presentation_callback) { BufferPresentedCallback presentation_callback) {
......
...@@ -49,6 +49,8 @@ class VIZ_SERVICE_EXPORT OutputPresenterGL : public OutputPresenter { ...@@ -49,6 +49,8 @@ class VIZ_SERVICE_EXPORT OutputPresenterGL : public OutputPresenter {
gfx::ColorSpace color_space, gfx::ColorSpace color_space,
gfx::Size image_size, gfx::Size image_size,
size_t num_images) final; size_t num_images) final;
std::unique_ptr<Image> AllocateBackgroundImage(gfx::ColorSpace color_space,
gfx::Size image_size) final;
void SwapBuffers(SwapCompletionCallback completion_callback, void SwapBuffers(SwapCompletionCallback completion_callback,
BufferPresentedCallback presentation_callback) final; BufferPresentedCallback presentation_callback) final;
void PostSubBuffer(const gfx::Rect& rect, void PostSubBuffer(const gfx::Rect& rect,
...@@ -62,6 +64,7 @@ class VIZ_SERVICE_EXPORT OutputPresenterGL : public OutputPresenter { ...@@ -62,6 +64,7 @@ class VIZ_SERVICE_EXPORT OutputPresenterGL : public OutputPresenter {
bool is_submitted) final; bool is_submitted) final;
void ScheduleOverlays(SkiaOutputSurface::OverlayList overlays, void ScheduleOverlays(SkiaOutputSurface::OverlayList overlays,
std::vector<ScopedOverlayAccess*> accesses) final; std::vector<ScopedOverlayAccess*> accesses) final;
void ScheduleBackground(Image* image) final;
private: private:
scoped_refptr<gl::GLSurface> gl_surface_; scoped_refptr<gl::GLSurface> gl_surface_;
......
...@@ -102,13 +102,15 @@ SkiaOutputDeviceBufferQueue::SkiaOutputDeviceBufferQueue( ...@@ -102,13 +102,15 @@ SkiaOutputDeviceBufferQueue::SkiaOutputDeviceBufferQueue(
SkiaOutputSurfaceDependency* deps, SkiaOutputSurfaceDependency* deps,
gpu::SharedImageRepresentationFactory* representation_factory, gpu::SharedImageRepresentationFactory* representation_factory,
gpu::MemoryTracker* memory_tracker, gpu::MemoryTracker* memory_tracker,
const DidSwapBufferCompleteCallback& did_swap_buffer_complete_callback) const DidSwapBufferCompleteCallback& did_swap_buffer_complete_callback,
bool needs_background_image)
: SkiaOutputDevice(deps->GetSharedContextState()->gr_context(), : SkiaOutputDevice(deps->GetSharedContextState()->gr_context(),
memory_tracker, memory_tracker,
did_swap_buffer_complete_callback), did_swap_buffer_complete_callback),
presenter_(std::move(presenter)), presenter_(std::move(presenter)),
dependency_(deps), dependency_(deps),
representation_factory_(representation_factory) { representation_factory_(representation_factory),
needs_background_image_(needs_background_image) {
capabilities_.uses_default_gl_framebuffer = false; capabilities_.uses_default_gl_framebuffer = false;
capabilities_.preserve_buffer_content = true; capabilities_.preserve_buffer_content = true;
capabilities_.only_invalidates_damage_rect = false; capabilities_.only_invalidates_damage_rect = false;
...@@ -190,6 +192,21 @@ bool SkiaOutputDeviceBufferQueue::IsPrimaryPlaneOverlay() const { ...@@ -190,6 +192,21 @@ bool SkiaOutputDeviceBufferQueue::IsPrimaryPlaneOverlay() const {
void SkiaOutputDeviceBufferQueue::SchedulePrimaryPlane( void SkiaOutputDeviceBufferQueue::SchedulePrimaryPlane(
const base::Optional<OverlayProcessorInterface::OutputSurfaceOverlayPlane>& const base::Optional<OverlayProcessorInterface::OutputSurfaceOverlayPlane>&
plane) { plane) {
if (background_image_) {
if (!background_image_is_scheduled_)
background_image_->BeginPresent();
// WaylandWindow can attach a null wl_buffer to its surface to hide its
// content so needs to reschedule |background_image_| so that
// the wl_surface has a non-null wl_buffer when the window re-appears.
//
// TODO(fangzhoug): It should not be necessary to schedule
// |background_image_| every frame. Make this a responsibility of
// WaylandWindow instead.
presenter_->ScheduleBackground(background_image_.get());
background_image_is_scheduled_ = true;
}
if (plane) { if (plane) {
// If the current_image_ is nullptr, it means there is no change on the // If the current_image_ is nullptr, it means there is no change on the
// primary plane. So we just need to schedule the last submitted image. // primary plane. So we just need to schedule the last submitted image.
...@@ -420,6 +437,12 @@ bool SkiaOutputDeviceBufferQueue::Reshape(const gfx::Size& size, ...@@ -420,6 +437,12 @@ bool SkiaOutputDeviceBufferQueue::Reshape(const gfx::Size& size,
image_size_ = size; image_size_ = size;
FreeAllSurfaces(); FreeAllSurfaces();
if (needs_background_image_ && !background_image_) {
background_image_ =
presenter_->AllocateBackgroundImage(color_space_, gfx::Size(4, 4));
background_image_is_scheduled_ = false;
}
images_ = presenter_->AllocateImages(color_space_, image_size_, images_ = presenter_->AllocateImages(color_space_, image_size_,
capabilities_.number_of_buffers); capabilities_.number_of_buffers);
if (images_.empty()) if (images_.empty())
......
...@@ -30,7 +30,8 @@ class VIZ_SERVICE_EXPORT SkiaOutputDeviceBufferQueue : public SkiaOutputDevice { ...@@ -30,7 +30,8 @@ class VIZ_SERVICE_EXPORT SkiaOutputDeviceBufferQueue : public SkiaOutputDevice {
SkiaOutputSurfaceDependency* deps, SkiaOutputSurfaceDependency* deps,
gpu::SharedImageRepresentationFactory* representation_factory, gpu::SharedImageRepresentationFactory* representation_factory,
gpu::MemoryTracker* memory_tracker, gpu::MemoryTracker* memory_tracker,
const DidSwapBufferCompleteCallback& did_swap_buffer_complete_callback); const DidSwapBufferCompleteCallback& did_swap_buffer_complete_callback,
bool needs_background_image);
~SkiaOutputDeviceBufferQueue() override; ~SkiaOutputDeviceBufferQueue() override;
...@@ -123,6 +124,13 @@ class VIZ_SERVICE_EXPORT SkiaOutputDeviceBufferQueue : public SkiaOutputDevice { ...@@ -123,6 +124,13 @@ class VIZ_SERVICE_EXPORT SkiaOutputDeviceBufferQueue : public SkiaOutputDevice {
// Set to true if no image is to be used for the primary plane of this frame. // Set to true if no image is to be used for the primary plane of this frame.
bool current_frame_has_no_primary_plane_ = false; bool current_frame_has_no_primary_plane_ = false;
// Whether the platform needs an occluded background image. Wayland needs it
// for opaque accelerated widgets and event wiring.
bool needs_background_image_ = false;
// A 4x4 small image that will be scaled to cover an opaque region.
std::unique_ptr<OutputPresenter::Image> background_image_ = nullptr;
// Set to true if background has been scheduled in a frame.
bool background_image_is_scheduled_ = false;
}; };
} // namespace viz } // namespace viz
......
...@@ -237,7 +237,7 @@ class SkiaOutputDeviceBufferQueueTest : public TestOnGpu { ...@@ -237,7 +237,7 @@ class SkiaOutputDeviceBufferQueueTest : public TestOnGpu {
gl_surface_, dependency_.get(), shared_image_factory_.get(), gl_surface_, dependency_.get(), shared_image_factory_.get(),
shared_image_representation_factory_.get(), shared_image_usage), shared_image_representation_factory_.get(), shared_image_usage),
dependency_.get(), shared_image_representation_factory_.get(), dependency_.get(), shared_image_representation_factory_.get(),
memory_tracker_.get(), present_callback); memory_tracker_.get(), present_callback, false);
output_device_ = std::move(onscreen_device); output_device_ = std::move(onscreen_device);
} }
......
...@@ -1126,16 +1126,26 @@ bool SkiaOutputSurfaceImplOnGpu::InitializeForGL() { ...@@ -1126,16 +1126,26 @@ bool SkiaOutputSurfaceImplOnGpu::InitializeForGL() {
if (MakeCurrent(true /* need_fbo0 */)) { if (MakeCurrent(true /* need_fbo0 */)) {
if (gl_surface_->IsSurfaceless()) { if (gl_surface_->IsSurfaceless()) {
#if defined(USE_OZONE)
bool needs_background_image = ui::OzonePlatform::GetInstance()
->GetPlatformProperties()
.needs_background_image;
#else // defined(USE_OZONE)
bool needs_background_image = false;
#endif // !defined(USE_OZONE)
#if !defined(OS_WIN) #if !defined(OS_WIN)
output_device_ = std::make_unique<SkiaOutputDeviceBufferQueue>( output_device_ = std::make_unique<SkiaOutputDeviceBufferQueue>(
std::make_unique<OutputPresenterGL>( std::make_unique<OutputPresenterGL>(
gl_surface_, dependency_, shared_image_factory_.get(), gl_surface_, dependency_, shared_image_factory_.get(),
shared_image_representation_factory_.get()), shared_image_representation_factory_.get()),
dependency_, shared_image_representation_factory_.get(), dependency_, shared_image_representation_factory_.get(),
memory_tracker_, GetDidSwapBuffersCompleteCallback()); memory_tracker_, GetDidSwapBuffersCompleteCallback(),
#else needs_background_image);
#else // !defined(OS_WIN)
NOTIMPLEMENTED(); NOTIMPLEMENTED();
#endif (void)needs_background_image;
#endif // defined(OS_WIN)
} else { } else {
if (dependency_->NeedsSupportForExternalStencil()) { if (dependency_->NeedsSupportForExternalStencil()) {
output_device_ = std::make_unique<SkiaOutputDeviceWebView>( output_device_ = std::make_unique<SkiaOutputDeviceWebView>(
...@@ -1187,6 +1197,14 @@ bool SkiaOutputSurfaceImplOnGpu::InitializeForVulkan() { ...@@ -1187,6 +1197,14 @@ bool SkiaOutputSurfaceImplOnGpu::InitializeForVulkan() {
} }
#endif // defined(USE_X11) #endif // defined(USE_X11)
#if defined(USE_OZONE)
bool needs_background_image = ui::OzonePlatform::GetInstance()
->GetPlatformProperties()
.needs_background_image;
#else // defined(USE_OZONE)
bool needs_background_image = false;
#endif // !defined(USE_OZONE)
#if !defined(OS_WIN) #if !defined(OS_WIN)
#if defined(OS_FUCHSIA) #if defined(OS_FUCHSIA)
auto output_presenter = OutputPresenterFuchsia::Create( auto output_presenter = OutputPresenterFuchsia::Create(
...@@ -1205,10 +1223,11 @@ bool SkiaOutputSurfaceImplOnGpu::InitializeForVulkan() { ...@@ -1205,10 +1223,11 @@ bool SkiaOutputSurfaceImplOnGpu::InitializeForVulkan() {
output_device_ = std::make_unique<SkiaOutputDeviceBufferQueue>( output_device_ = std::make_unique<SkiaOutputDeviceBufferQueue>(
std::move(output_presenter), dependency_, std::move(output_presenter), dependency_,
shared_image_representation_factory_.get(), memory_tracker_, shared_image_representation_factory_.get(), memory_tracker_,
GetDidSwapBuffersCompleteCallback()); GetDidSwapBuffersCompleteCallback(), needs_background_image);
return true; return true;
} }
#endif // !defined(OS_WIN) #endif // !defined(OS_WIN)
(void)needs_background_image;
auto output_device = SkiaOutputDeviceVulkan::Create( auto output_device = SkiaOutputDeviceVulkan::Create(
vulkan_context_provider_, dependency_->GetSurfaceHandle(), vulkan_context_provider_, dependency_->GetSurfaceHandle(),
......
...@@ -255,7 +255,7 @@ TEST_P(WaylandSurfaceFactoryTest, ...@@ -255,7 +255,7 @@ TEST_P(WaylandSurfaceFactoryTest,
// Prepare overlay plane. // Prepare overlay plane.
gl_surface->ScheduleOverlayPlane( gl_surface->ScheduleOverlayPlane(
0, gfx::OverlayTransform::OVERLAY_TRANSFORM_FLIP_VERTICAL, INT32_MIN, gfx::OverlayTransform::OVERLAY_TRANSFORM_FLIP_VERTICAL,
gl_image.get(), window_->GetBounds(), {}, false, nullptr); gl_image.get(), window_->GetBounds(), {}, false, nullptr);
std::vector<scoped_refptr<FakeGLImageNativePixmap>> gl_images; std::vector<scoped_refptr<FakeGLImageNativePixmap>> gl_images;
...@@ -452,8 +452,10 @@ TEST_P(WaylandSurfaceFactoryTest, ...@@ -452,8 +452,10 @@ TEST_P(WaylandSurfaceFactoryTest,
Sync(); Sync();
} }
auto* mock_primary_surface = server_.GetObject<wl::MockSurface>( auto* root_surface = server_.GetObject<wl::MockSurface>(
window_->root_surface()->GetSurfaceId()); window_->root_surface()->GetSurfaceId());
auto* mock_primary_surface = server_.GetObject<wl::MockSurface>(
window_->primary_subsurface()->wayland_surface()->GetSurfaceId());
CallbacksHelper cbs_helper; CallbacksHelper cbs_helper;
// Submit a frame with only primary plane // Submit a frame with only primary plane
...@@ -488,9 +490,11 @@ TEST_P(WaylandSurfaceFactoryTest, ...@@ -488,9 +490,11 @@ TEST_P(WaylandSurfaceFactoryTest,
// Also, we expect only one buffer to be committed. // Also, we expect only one buffer to be committed.
EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(1); EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(1);
EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(1); EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(0);
EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(1); EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(1);
EXPECT_CALL(*mock_primary_surface, Commit()).Times(1); EXPECT_CALL(*mock_primary_surface, Commit()).Times(1);
EXPECT_CALL(*root_surface, Frame(_)).Times(1);
EXPECT_CALL(*root_surface, Commit()).Times(1);
Sync(); Sync();
...@@ -546,13 +550,15 @@ TEST_P(WaylandSurfaceFactoryTest, ...@@ -546,13 +550,15 @@ TEST_P(WaylandSurfaceFactoryTest,
// Expect one buffer to be committed. // Expect one buffer to be committed.
EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(1); EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(1);
EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(1); EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(0);
EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(1); EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(1);
EXPECT_CALL(*mock_primary_surface, Commit()).Times(1); EXPECT_CALL(*mock_primary_surface, Commit()).Times(1);
EXPECT_CALL(*root_surface, Frame(_)).Times(1);
EXPECT_CALL(*root_surface, Commit()).Times(1);
// Send the frame callback so that pending buffer for swap id=1u is processed // Send the frame callback so that pending buffer for swap id=1u is processed
// and swapped. // and swapped.
mock_primary_surface->SendFrameCallback(); root_surface->SendFrameCallback();
Sync(); Sync();
...@@ -604,15 +610,19 @@ TEST_P(WaylandSurfaceFactoryTest, ...@@ -604,15 +610,19 @@ TEST_P(WaylandSurfaceFactoryTest,
base::BindOnce(&CallbacksHelper::BufferPresented, base::BindOnce(&CallbacksHelper::BufferPresented,
base::Unretained(&cbs_helper), swap_id)); base::Unretained(&cbs_helper), swap_id));
} }
// Expect parent surface to be committed without a buffer.
// Do not expect parent surface to be committed.
EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(0); EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(0);
EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(1); EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(0);
EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(0); EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(0);
EXPECT_CALL(*mock_primary_surface, Commit()).Times(1); EXPECT_CALL(*mock_primary_surface, Commit()).Times(0);
// Expect root surface to be committed.
EXPECT_CALL(*root_surface, Frame(_)).Times(1);
EXPECT_CALL(*root_surface, Commit()).Times(1);
// Send the frame callback so that pending buffer for swap id=2u is processed // Send the frame callback so that pending buffer for swap id=2u is processed
// and swapped. // and swapped.
mock_primary_surface->SendFrameCallback(); root_surface->SendFrameCallback();
Sync(); Sync();
...@@ -691,8 +701,10 @@ TEST_P(WaylandSurfaceFactoryTest, ...@@ -691,8 +701,10 @@ TEST_P(WaylandSurfaceFactoryTest,
Sync(); Sync();
} }
auto* mock_primary_surface = server_.GetObject<wl::MockSurface>( auto* root_surface = server_.GetObject<wl::MockSurface>(
window_->root_surface()->GetSurfaceId()); window_->root_surface()->GetSurfaceId());
auto* mock_primary_surface = server_.GetObject<wl::MockSurface>(
window_->primary_subsurface()->wayland_surface()->GetSurfaceId());
CallbacksHelper cbs_helper; CallbacksHelper cbs_helper;
// Submit a frame with 1 primary plane and 1 overlay // Submit a frame with 1 primary plane and 1 overlay
...@@ -737,11 +749,13 @@ TEST_P(WaylandSurfaceFactoryTest, ...@@ -737,11 +749,13 @@ TEST_P(WaylandSurfaceFactoryTest,
// Let's sync so that 1) GbmSurfacelessWayland submits the buffer according to // Let's sync so that 1) GbmSurfacelessWayland submits the buffer according to
// internal queue and fake server processes the request. // internal queue and fake server processes the request.
// Also, we expect only one buffer to be committed. // Also, we expect primary buffer to be committed.
EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(1); EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(1);
EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(1); EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(0);
EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(1); EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(1);
EXPECT_CALL(*mock_primary_surface, Commit()).Times(1); EXPECT_CALL(*mock_primary_surface, Commit()).Times(1);
EXPECT_CALL(*root_surface, Frame(_)).Times(1);
EXPECT_CALL(*root_surface, Commit()).Times(1);
Sync(); Sync();
...@@ -810,21 +824,25 @@ TEST_P(WaylandSurfaceFactoryTest, ...@@ -810,21 +824,25 @@ TEST_P(WaylandSurfaceFactoryTest,
base::Unretained(&cbs_helper), swap_id)); base::Unretained(&cbs_helper), swap_id));
} }
// Expect one buffer to be committed. // Expect primary buffer to be committed.
EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(1); EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(1);
EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(1); EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(0);
EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(1); EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(1);
EXPECT_CALL(*mock_primary_surface, Commit()).Times(1); EXPECT_CALL(*mock_primary_surface, Commit()).Times(1);
// Expect one buffer to be committed. // Expect overlay buffer to be committed.
EXPECT_CALL(*mock_overlay_surface, Attach(_, _, _)).Times(1); EXPECT_CALL(*mock_overlay_surface, Attach(_, _, _)).Times(1);
EXPECT_CALL(*mock_overlay_surface, Frame(_)).Times(0); EXPECT_CALL(*mock_overlay_surface, Frame(_)).Times(0);
EXPECT_CALL(*mock_overlay_surface, DamageBuffer(_, _, _, _)).Times(1); EXPECT_CALL(*mock_overlay_surface, DamageBuffer(_, _, _, _)).Times(1);
EXPECT_CALL(*mock_overlay_surface, Commit()).Times(1); EXPECT_CALL(*mock_overlay_surface, Commit()).Times(1);
// Expect root surface to be committed without buffer.
EXPECT_CALL(*root_surface, Frame(_)).Times(1);
EXPECT_CALL(*root_surface, Commit()).Times(1);
// Send the frame callback so that pending buffer for swap id=1u is processed // Send the frame callback so that pending buffer for swap id=1u is processed
// and swapped. // and swapped.
mock_primary_surface->SendFrameCallback(); root_surface->SendFrameCallback();
Sync(); Sync();
......
...@@ -234,9 +234,11 @@ class WaylandBufferManagerHost::Surface { ...@@ -234,9 +234,11 @@ class WaylandBufferManagerHost::Surface {
// If the same buffer has been submitted again right after the client // If the same buffer has been submitted again right after the client
// received OnSubmission for that buffer, just damage the buffer and // received OnSubmission for that buffer, just damage the buffer and
// commit the surface again. // commit the surface again. However, if the buffer is released, it's safe
// to reattach the buffer.
if (submitted_buffers_.empty() || if (submitted_buffers_.empty() ||
submitted_buffers_.back().buffer_id != buffer->buffer_id) { submitted_buffers_.back().buffer_id != buffer->buffer_id ||
buffer->released) {
// Once the BufferRelease is called, the buffer will be released. // Once the BufferRelease is called, the buffer will be released.
DCHECK(buffer->released); DCHECK(buffer->released);
buffer->released = false; buffer->released = false;
...@@ -923,11 +925,21 @@ void WaylandBufferManagerHost::DestroyBuffer(gfx::AcceleratedWidget widget, ...@@ -923,11 +925,21 @@ void WaylandBufferManagerHost::DestroyBuffer(gfx::AcceleratedWidget widget,
if (!surface->HasBuffers() && !surface->HasSurface()) if (!surface->HasBuffers() && !surface->HasSurface())
surfaces_.erase(window->root_surface()); surfaces_.erase(window->root_surface());
} }
const auto& subsurfaces = window->wayland_subsurfaces(); if (!destroyed_count) {
for (const auto& it : subsurfaces) { surface = GetSurface(window->primary_subsurface()->wayland_surface());
Surface* subsurface = GetSurface((*it).wayland_surface()); if (surface) {
if (subsurface) destroyed_count = surface->DestroyBuffer(buffer_id);
destroyed_count += subsurface->DestroyBuffer(buffer_id); if (!surface->HasBuffers() && !surface->HasSurface())
surfaces_.erase(window->root_surface());
}
}
if (!destroyed_count) {
const auto& subsurfaces = window->wayland_subsurfaces();
for (const auto& it : subsurfaces) {
Surface* subsurface = GetSurface((*it).wayland_surface());
if (subsurface)
destroyed_count += subsurface->DestroyBuffer(buffer_id);
}
} }
} else { } else {
// Case 3) // Case 3)
......
...@@ -19,13 +19,11 @@ gfx::Rect AdjustSubsurfaceBounds(const gfx::Rect& bounds_px, ...@@ -19,13 +19,11 @@ gfx::Rect AdjustSubsurfaceBounds(const gfx::Rect& bounds_px,
int32_t parent_buffer_scale) { int32_t parent_buffer_scale) {
// TODO(fangzhoug): Verify the correctness of using ui_scale here, and in // TODO(fangzhoug): Verify the correctness of using ui_scale here, and in
// other ozone wayland files. // other ozone wayland files.
const auto parent_bounds_dip = // Currently, the subsurface tree is at most 1 depth, gpu already sees buffer
gfx::ScaleToRoundedRect(parent_bounds_px, 1.0 / ui_scale); // bounds in the root_surface-local coordinates. So translation is not
// needed for now.
const auto bounds_dip = gfx::ScaleToRoundedRect(bounds_px, 1.0 / ui_scale); const auto bounds_dip = gfx::ScaleToRoundedRect(bounds_px, 1.0 / ui_scale);
auto new_bounds_dip = return gfx::ScaleToRoundedRect(bounds_dip, ui_scale / parent_buffer_scale);
wl::TranslateBoundsToParentCoordinates(bounds_dip, parent_bounds_dip);
return gfx::ScaleToRoundedRect(new_bounds_dip,
ui_scale / parent_buffer_scale);
} }
} // namespace } // namespace
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <viewporter-client-protocol.h> #include <viewporter-client-protocol.h>
#include "ui/gfx/geometry/rect_conversions.h" #include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/native_widget_types.h" #include "ui/gfx/native_widget_types.h"
#include "ui/ozone/platform/wayland/common/wayland_util.h" #include "ui/ozone/platform/wayland/common/wayland_util.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h" #include "ui/ozone/platform/wayland/host/wayland_connection.h"
...@@ -96,8 +97,6 @@ void WaylandSurface::UpdateBufferDamageRegion( ...@@ -96,8 +97,6 @@ void WaylandSurface::UpdateBufferDamageRegion(
if (!display_size_px_.IsEmpty()) { if (!display_size_px_.IsEmpty()) {
viewport_dst = viewport_dst =
gfx::ScaleToCeiledSize(display_size_px_, 1.f / buffer_scale_); gfx::ScaleToCeiledSize(display_size_px_, 1.f / buffer_scale_);
wp_viewport_set_destination(viewport(), viewport_dst.width(),
viewport_dst.height());
} }
if (connection_->compositor_version() >= if (connection_->compositor_version() >=
...@@ -159,6 +158,14 @@ void WaylandSurface::SetBufferScale(int32_t new_scale, bool update_bounds) { ...@@ -159,6 +158,14 @@ void WaylandSurface::SetBufferScale(int32_t new_scale, bool update_bounds) {
buffer_scale_ = new_scale; buffer_scale_ = new_scale;
wl_surface_set_buffer_scale(surface_.get(), buffer_scale_); wl_surface_set_buffer_scale(surface_.get(), buffer_scale_);
if (!display_size_px_.IsEmpty()) {
gfx::Size viewport_dst =
gfx::ScaleToCeiledSize(display_size_px_, 1.f / buffer_scale_);
wp_viewport_set_destination(viewport(), viewport_dst.width(),
viewport_dst.height());
}
connection_->ScheduleFlush(); connection_->ScheduleFlush();
} }
...@@ -200,6 +207,10 @@ void WaylandSurface::SetViewportDestination(const gfx::Size& dest_size_px) { ...@@ -200,6 +207,10 @@ void WaylandSurface::SetViewportDestination(const gfx::Size& dest_size_px) {
wp_viewport_set_destination(viewport(), -1, -1); wp_viewport_set_destination(viewport(), -1, -1);
} }
display_size_px_ = dest_size_px; display_size_px_ = dest_size_px;
gfx::Size viewport_dst =
gfx::ScaleToCeiledSize(display_size_px_, 1.f / buffer_scale_);
wp_viewport_set_destination(viewport(), viewport_dst.width(),
viewport_dst.height());
} }
wl::Object<wl_subsurface> WaylandSurface::CreateSubsurface( wl::Object<wl_subsurface> WaylandSurface::CreateSubsurface(
......
...@@ -74,10 +74,14 @@ class WaylandSurface { ...@@ -74,10 +74,14 @@ class WaylandSurface {
// See: // See:
// https://cgit.freedesktop.org/wayland/wayland-protocols/tree/stable/viewporter/viewporter.xml // https://cgit.freedesktop.org/wayland/wayland-protocols/tree/stable/viewporter/viewporter.xml
// If |src_rect| is empty, the source rectangle is unset. // If |src_rect| is empty, the source rectangle is unset.
// Note this method does not send corresponding wayland requests until
// attaching the next buffer.
void SetViewportSource(const gfx::RectF& src_rect); void SetViewportSource(const gfx::RectF& src_rect);
// Set the destination size of the associated wl_surface according to // Set the destination size of the associated wl_surface according to
// |dest_size_px|, which should be in physical pixels. // |dest_size_px|, which should be in physical pixels.
// Note this method sends corresponding wayland requests immediately because
// it does not need a new buffer attach to take effect.
void SetViewportDestination(const gfx::Size& dest_size_px); void SetViewportDestination(const gfx::Size& dest_size_px);
// Creates a wl_subsurface relating this surface and a parent surface, // Creates a wl_subsurface relating this surface and a parent surface,
......
...@@ -47,6 +47,8 @@ WaylandWindow::~WaylandWindow() { ...@@ -47,6 +47,8 @@ WaylandWindow::~WaylandWindow() {
PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this); PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
connection_->wayland_window_manager()->RemoveSubsurface(
GetWidget(), primary_subsurface_.get());
for (const auto& widget_subsurface : wayland_subsurfaces()) { for (const auto& widget_subsurface : wayland_subsurfaces()) {
connection_->wayland_window_manager()->RemoveSubsurface( connection_->wayland_window_manager()->RemoveSubsurface(
GetWidget(), widget_subsurface.get()); GetWidget(), widget_subsurface.get());
...@@ -351,6 +353,12 @@ bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) { ...@@ -351,6 +353,12 @@ bool WaylandWindow::Initialize(PlatformWindowInitProperties properties) {
if (!OnInitialize(std::move(properties))) if (!OnInitialize(std::move(properties)))
return false; return false;
primary_subsurface_ = std::make_unique<WaylandSubsurface>(connection_, this);
if (!primary_subsurface_->surface())
return false;
connection_->wayland_window_manager()->AddSubsurface(
GetWidget(), primary_subsurface_.get());
connection_->ScheduleFlush(); connection_->ScheduleFlush();
PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this); PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
...@@ -547,6 +555,10 @@ bool WaylandWindow::CommitOverlays( ...@@ -547,6 +555,10 @@ bool WaylandWindow::CommitOverlays(
size_t above = (overlays.end() - split) - num_primary_planes; size_t above = (overlays.end() - split) - num_primary_planes;
size_t below = split - overlays.begin(); size_t below = split - overlays.begin();
if (overlays.front()->z_order == INT32_MIN)
--below;
// Re-arrange the list of subsurfaces to fit the |overlays|. Request extra // Re-arrange the list of subsurfaces to fit the |overlays|. Request extra
// subsurfaces if needed. // subsurfaces if needed.
if (!ArrangeSubsurfaceStack(above, below)) if (!ArrangeSubsurfaceStack(above, below))
...@@ -559,12 +571,14 @@ bool WaylandWindow::CommitOverlays( ...@@ -559,12 +571,14 @@ bool WaylandWindow::CommitOverlays(
auto overlay_iter = split - 1; auto overlay_iter = split - 1;
for (auto iter = subsurface_stack_below_.begin(); for (auto iter = subsurface_stack_below_.begin();
iter != subsurface_stack_below_.end(); ++iter, --overlay_iter) { iter != subsurface_stack_below_.end(); ++iter, --overlay_iter) {
if (overlay_iter >= overlays.begin()) { if (overlays.front()->z_order == INT32_MIN
? overlay_iter >= ++overlays.begin()
: overlay_iter >= overlays.begin()) {
WaylandSurface* reference_above = nullptr; WaylandSurface* reference_above = nullptr;
if (overlay_iter == split - 1) { if (overlay_iter == split - 1) {
// It's possible that |overlays| does not contain primary plane, we // It's possible that |overlays| does not contain primary plane, we
// still want to place relative to the surface with z_order=0. // still want to place relative to the surface with z_order=0.
reference_above = root_surface(); reference_above = primary_subsurface_->wayland_surface();
} else { } else {
reference_above = (*std::next(iter))->wayland_surface(); reference_above = (*std::next(iter))->wayland_surface();
} }
...@@ -593,7 +607,7 @@ bool WaylandWindow::CommitOverlays( ...@@ -593,7 +607,7 @@ bool WaylandWindow::CommitOverlays(
if (overlay_iter == split + num_primary_planes) { if (overlay_iter == split + num_primary_planes) {
// It's possible that |overlays| does not contain primary plane, we // It's possible that |overlays| does not contain primary plane, we
// still want to place relative to the surface with z_order=0. // still want to place relative to the surface with z_order=0.
reference_below = root_surface(); reference_below = primary_subsurface_->wayland_surface();
} else { } else {
reference_below = (*std::prev(iter))->wayland_surface(); reference_below = (*std::prev(iter))->wayland_surface();
} }
...@@ -613,11 +627,22 @@ bool WaylandWindow::CommitOverlays( ...@@ -613,11 +627,22 @@ bool WaylandWindow::CommitOverlays(
} }
if (num_primary_planes) { if (num_primary_planes) {
primary_subsurface_->ConfigureAndShowSurface(
(*split)->transform, (*split)->crop_rect, (*split)->bounds_rect,
(*split)->enable_blend, nullptr, nullptr);
connection_->buffer_manager_host()->CommitBufferInternal(
primary_subsurface_->wayland_surface(), (*split)->buffer_id,
(*split)->damage_region, /*wait_for_frame_callback=*/false);
}
root_surface_->SetViewportDestination(bounds_px_.size());
if (overlays.front()->z_order == INT32_MIN) {
connection_->buffer_manager_host()->CommitBufferInternal( connection_->buffer_manager_host()->CommitBufferInternal(
root_surface(), (*split)->buffer_id, (*split)->damage_region, root_surface(), overlays.front()->buffer_id,
/*damage_region=*/gfx::Rect(0, 0, 1, 1),
/*wait_for_frame_callback=*/true); /*wait_for_frame_callback=*/true);
} else { } else {
// Subsurfaces are set to sync, above operations will only take effects // Subsurfaces are set to sync, above surface configs will only take effect
// when root_surface is committed. // when root_surface is committed.
connection_->buffer_manager_host()->CommitWithoutBufferInternal( connection_->buffer_manager_host()->CommitWithoutBufferInternal(
root_surface(), /*wait_for_frame_callback=*/true); root_surface(), /*wait_for_frame_callback=*/true);
......
...@@ -59,6 +59,9 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher { ...@@ -59,6 +59,9 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
void UpdateBufferScale(bool update_bounds); void UpdateBufferScale(bool update_bounds);
WaylandSurface* root_surface() const { return root_surface_.get(); } WaylandSurface* root_surface() const { return root_surface_.get(); }
WaylandSubsurface* primary_subsurface() const {
return primary_subsurface_.get();
}
const WidgetSubsurfaceSet& wayland_subsurfaces() const { const WidgetSubsurfaceSet& wayland_subsurfaces() const {
return wayland_subsurfaces_; return wayland_subsurfaces_;
} }
...@@ -227,13 +230,18 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher { ...@@ -227,13 +230,18 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
WaylandWindow* parent_window_ = nullptr; WaylandWindow* parent_window_ = nullptr;
WaylandWindow* child_window_ = nullptr; WaylandWindow* child_window_ = nullptr;
// |root_surface_| is a surface for the opaque background. Its z-order is
// INT32_MIN.
std::unique_ptr<WaylandSurface> root_surface_; std::unique_ptr<WaylandSurface> root_surface_;
// |primary_subsurface| is the primary that shows the widget content.
std::unique_ptr<WaylandSubsurface> primary_subsurface_;
// Subsurfaces excluding the primary_subsurface
WidgetSubsurfaceSet wayland_subsurfaces_; WidgetSubsurfaceSet wayland_subsurfaces_;
// The stack of sub-surfaces to take effect when Commit() is called. // The stack of sub-surfaces to take effect when Commit() is called.
// |subsurface_stack_above_| refers to subsurfaces that are stacked above the // |subsurface_stack_above_| refers to subsurfaces that are stacked above the
// parent. // primary.
// Subsurface at the front of the list is the closest to the parent. // Subsurface at the front of the list is the closest to the primary.
std::list<WaylandSubsurface*> subsurface_stack_above_; std::list<WaylandSubsurface*> subsurface_stack_above_;
std::list<WaylandSubsurface*> subsurface_stack_below_; std::list<WaylandSubsurface*> subsurface_stack_below_;
......
...@@ -235,6 +235,12 @@ class OzonePlatformWayland : public OzonePlatform { ...@@ -235,6 +235,12 @@ class OzonePlatformWayland : public OzonePlatform {
properties->ignore_screen_bounds_for_menus = true; properties->ignore_screen_bounds_for_menus = true;
properties->app_modal_dialogs_use_event_blocker = true; properties->app_modal_dialogs_use_event_blocker = true;
// Primary planes can be transluscent due to underlay strategy. As a
// result Wayland server draws contents occluded by an accelerated widget.
// To prevent this, an opaque background image is stacked below the
// accelerated widget to occlude contents below.
properties->needs_background_image = true;
initialised = true; initialised = true;
} }
......
...@@ -104,6 +104,10 @@ class COMPONENT_EXPORT(OZONE) OzonePlatform { ...@@ -104,6 +104,10 @@ class COMPONENT_EXPORT(OZONE) OzonePlatform {
// calculating bounds of menu windows. // calculating bounds of menu windows.
bool ignore_screen_bounds_for_menus = false; bool ignore_screen_bounds_for_menus = false;
// Wayland only: determines whether BufferQueue needs a background image to
// be stacked below an AcceleratedWidget to make a widget opaque.
bool needs_background_image = false;
// If true, the platform shows and updates the drag image. // If true, the platform shows and updates the drag image.
bool platform_shows_drag_image = true; bool platform_shows_drag_image = true;
......
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