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

[ozone/wayland] Use CommitOverlays to send a frame from gpu to browser.

CommitOverlays is a more generic IPC that packages multiple overlay
configurations for a frame before sending it to browser process. This
replaces the CommitBuffer IPC.

This CL merely adds CommitOverlays. It does not send multiple buffers
using it.

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

Bug: 1063865
Change-Id: Id71d055bdb14b3d2e97cb2eef8811dca56323899
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2314665Reviewed-by: default avatarTom Sepez <tsepez@chromium.org>
Reviewed-by: default avatarMaksim Sisov (GMT+3) <msisov@igalia.com>
Reviewed-by: default avatarRobert Kroeger <rjkroege@chromium.org>
Commit-Queue: Kramer Ge <fangzhoug@chromium.org>
Cr-Commit-Position: refs/heads/master@{#796542}
parent cddf3e88
......@@ -13,6 +13,7 @@
#include "ui/gfx/gpu_fence.h"
#include "ui/ozone/common/egl_util.h"
#include "ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h"
#include "ui/ozone/public/mojom/wayland/wayland_overlay_config.mojom.h"
namespace ui {
......@@ -234,13 +235,19 @@ void GbmSurfacelessWayland::MaybeSubmitFrames() {
return;
}
DCHECK_EQ(submitted_frame->planes.size(), 1u);
submitted_frame->buffer_id = submitted_frame->planes.back().buffer_id;
buffer_manager_->CommitBuffer(widget_,
submitted_frame->planes.back().buffer_id,
submitted_frame->damage_region_);
submitted_frame->planes.clear();
std::vector<ui::ozone::mojom::WaylandOverlayConfigPtr> overlay_configs;
for (const auto& plane : submitted_frame->planes) {
overlay_configs.push_back(
ui::ozone::mojom::WaylandOverlayConfig::From(plane.plane));
overlay_configs.back()->buffer_id = plane.buffer_id;
if (plane.plane.z_order == 0) {
overlay_configs.back()->damage_region = submitted_frame->damage_region_;
submitted_frame->buffer_id = plane.buffer_id;
}
}
buffer_manager_->CommitOverlays(widget_, std::move(overlay_configs));
submitted_frame->planes.clear();
submitted_frames_.push_back(std::move(submitted_frame));
}
}
......@@ -250,7 +257,7 @@ EGLSyncKHR GbmSurfacelessWayland::InsertFence(bool implicit) {
EGL_SYNC_PRIOR_COMMANDS_IMPLICIT_EXTERNAL_ARM,
EGL_NONE};
return eglCreateSyncKHR(GetDisplay(), EGL_SYNC_FENCE_KHR,
implicit ? attrib_list : NULL);
implicit ? attrib_list : nullptr);
}
void GbmSurfacelessWayland::FenceRetired(PendingFrame* frame) {
......
......@@ -11,6 +11,30 @@
#include "base/task/current_thread.h"
#include "ui/gfx/linux/drm_util_linux.h"
#include "ui/ozone/platform/wayland/gpu/wayland_surface_gpu.h"
#include "ui/ozone/public/mojom/wayland/wayland_overlay_config.mojom.h"
#include "ui/ozone/public/overlay_plane.h"
namespace mojo {
// static
ui::ozone::mojom::WaylandOverlayConfigPtr
TypeConverter<ui::ozone::mojom::WaylandOverlayConfigPtr,
ui::OverlayPlane>::Convert(const ui::OverlayPlane& input) {
ui::ozone::mojom::WaylandOverlayConfigPtr wayland_overlay_config{
ui::ozone::mojom::WaylandOverlayConfig::New()};
wayland_overlay_config->z_order = input.z_order;
wayland_overlay_config->transform = input.plane_transform;
wayland_overlay_config->bounds_rect = input.display_bounds;
wayland_overlay_config->crop_rect = input.crop_rect;
wayland_overlay_config->enable_blend = input.enable_blend;
wayland_overlay_config->access_fence_handle =
!input.gpu_fence || input.gpu_fence->GetGpuFenceHandle().is_null()
? base::Optional<gfx::GpuFenceHandle>()
: base::Optional<gfx::GpuFenceHandle>(
gfx::CloneHandleForIPC(input.gpu_fence->GetGpuFenceHandle()));
return wayland_overlay_config;
}
} // namespace mojo
namespace ui {
......@@ -167,6 +191,22 @@ void WaylandBufferManagerGpu::CommitBuffer(gfx::AcceleratedWidget widget,
base::Unretained(this), widget, buffer_id, damage_region));
}
void WaylandBufferManagerGpu::CommitOverlays(
gfx::AcceleratedWidget widget,
std::vector<ozone::mojom::WaylandOverlayConfigPtr> overlays) {
if (!remote_host_) {
LOG(ERROR) << "Interface is not bound. Can't request "
"WaylandBufferManagerHost to create/commit/destroy buffers.";
return;
}
// Do the mojo call on the IO child thread.
io_thread_runner_->PostTask(
FROM_HERE,
base::BindOnce(&WaylandBufferManagerGpu::CommitOverlaysInternal,
base::Unretained(this), widget, std::move(overlays)));
}
void WaylandBufferManagerGpu::DestroyBuffer(gfx::AcceleratedWidget widget,
uint32_t buffer_id) {
if (!remote_host_) {
......@@ -234,6 +274,13 @@ void WaylandBufferManagerGpu::CommitBufferInternal(
remote_host_->CommitBuffer(widget, buffer_id, damage_region);
}
void WaylandBufferManagerGpu::CommitOverlaysInternal(
gfx::AcceleratedWidget widget,
std::vector<ozone::mojom::WaylandOverlayConfigPtr> overlays) {
DCHECK(io_thread_runner_->BelongsToCurrentThread());
remote_host_->CommitOverlays(widget, std::move(overlays));
}
void WaylandBufferManagerGpu::DestroyBufferInternal(
gfx::AcceleratedWidget widget,
uint32_t buffer_id) {
......
......@@ -15,6 +15,7 @@
#include "mojo/public/cpp/bindings/associated_receiver.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/bindings/type_converter.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/ozone/platform/wayland/common/wayland_util.h"
#include "ui/ozone/public/mojom/wayland/wayland_buffer_manager.mojom.h"
......@@ -33,6 +34,7 @@ namespace ui {
class WaylandConnection;
class WaylandSurfaceGpu;
class WaylandWindow;
struct OverlayPlane;
// Forwards calls through an associated mojo connection to WaylandBufferManager
// on the browser process side.
......@@ -105,6 +107,12 @@ class WaylandBufferManagerGpu : public ozone::mojom::WaylandBufferManagerGpu {
uint32_t buffer_id,
const gfx::Rect& damage_region);
// Send overlay configurations for a frame to a WaylandWindow identified by
// |widget|.
void CommitOverlays(
gfx::AcceleratedWidget widget,
std::vector<ozone::mojom::WaylandOverlayConfigPtr> overlays);
// Asks Wayland to destroy a wl_buffer.
void DestroyBuffer(gfx::AcceleratedWidget widget, uint32_t buffer_id);
......@@ -143,6 +151,9 @@ class WaylandBufferManagerGpu : public ozone::mojom::WaylandBufferManagerGpu {
void CommitBufferInternal(gfx::AcceleratedWidget widget,
uint32_t buffer_id,
const gfx::Rect& damage_region);
void CommitOverlaysInternal(
gfx::AcceleratedWidget widget,
std::vector<ozone::mojom::WaylandOverlayConfigPtr> overlays);
void DestroyBufferInternal(gfx::AcceleratedWidget widget, uint32_t buffer_id);
void BindHostInterface(
......@@ -214,4 +225,15 @@ class WaylandBufferManagerGpu : public ozone::mojom::WaylandBufferManagerGpu {
} // namespace ui
// This is a specialization of mojo::TypeConverter and has to be in the mojo
// namespace.
namespace mojo {
template <>
struct TypeConverter<ui::ozone::mojom::WaylandOverlayConfigPtr,
ui::OverlayPlane> {
static ui::ozone::mojom::WaylandOverlayConfigPtr Convert(
const ui::OverlayPlane& input);
};
} // namespace mojo
#endif // UI_OZONE_PLATFORM_WAYLAND_GPU_WAYLAND_BUFFER_MANAGER_GPU_H_
......@@ -757,6 +757,27 @@ void WaylandBufferManagerHost::CreateShmBasedBuffer(mojo::PlatformHandle shm_fd,
connection_->ScheduleFlush();
}
bool WaylandBufferManagerHost::CommitBufferInternal(
WaylandSurface* wayland_surface,
uint32_t buffer_id,
const gfx::Rect& damage_region) {
DCHECK(base::CurrentUIThread::IsSet());
Surface* surface = GetSurface(wayland_surface);
if (!surface || !ValidateBufferIdFromGpu(buffer_id))
return false;
if (!surface->CommitBuffer(buffer_id, damage_region)) {
error_message_ =
base::StrCat({"Buffer with ", NumberToString(buffer_id),
" id does not exist or failed to be created."});
}
if (!error_message_.empty())
TerminateGpuProcess();
return true;
}
void WaylandBufferManagerHost::CommitBuffer(gfx::AcceleratedWidget widget,
uint32_t buffer_id,
const gfx::Rect& damage_region) {
......@@ -769,23 +790,28 @@ void WaylandBufferManagerHost::CommitBuffer(gfx::AcceleratedWidget widget,
if (widget == gfx::kNullAcceleratedWidget) {
error_message_ = "Invalid widget.";
} else if (ValidateBufferIdFromGpu(buffer_id)) {
TerminateGpuProcess();
} else {
auto* window = connection_->wayland_window_manager()->GetWindow(widget);
if (!window)
return;
Surface* surface = GetSurface(window->root_surface());
if (!surface)
return;
if (!surface->CommitBuffer(buffer_id, damage_region)) {
error_message_ =
base::StrCat({"Buffer with ", NumberToString(buffer_id),
" id does not exist or failed to be created."});
}
CommitBufferInternal(window->root_surface(), buffer_id, damage_region);
}
}
if (!error_message_.empty())
TerminateGpuProcess();
void WaylandBufferManagerHost::CommitOverlays(
gfx::AcceleratedWidget widget,
std::vector<ui::ozone::mojom::WaylandOverlayConfigPtr> overlays) {
DCHECK(base::CurrentUIThread::IsSet());
TRACE_EVENT0("wayland", "WaylandBufferManagerHost::CommitOverlays");
DCHECK(error_message_.empty());
WaylandWindow* window =
connection_->wayland_window_manager()->GetWindow(widget);
DCHECK(window);
window->CommitOverlays(overlays);
}
void WaylandBufferManagerHost::DestroyBuffer(gfx::AcceleratedWidget widget,
......
......@@ -143,6 +143,20 @@ class WaylandBufferManagerHost : public ozone::mojom::WaylandBufferManagerHost,
void CommitBuffer(gfx::AcceleratedWidget widget,
uint32_t buffer_id,
const gfx::Rect& damage_region) override;
// Called by the GPU and asks to configure the surface/subsurfaces and attach
// wl_buffers to WaylandWindow with the specified |widget|. Calls OnSubmission
// and OnPresentation on successful swap and pixels presented.
void CommitOverlays(
gfx::AcceleratedWidget widget,
std::vector<ui::ozone::mojom::WaylandOverlayConfigPtr> overlays) override;
// Called by the WaylandWindow and asks to attach a wl_buffer with a
// |buffer_id| to a WaylandSurface.
// Calls OnSubmission and OnPresentation on successful swap and pixels
// presented.
bool CommitBufferInternal(WaylandSurface* wayland_surface,
uint32_t buffer_id,
const gfx::Rect& damage_region);
// When a surface is hidden, the client may want to detach the buffer attached
// to the surface to ensure Wayland does not present those contents and do not
......
......@@ -6,6 +6,7 @@
#include <wayland-client.h>
#include <algorithm>
#include <memory>
#include "base/bind.h"
......@@ -22,6 +23,17 @@
#include "ui/ozone/platform/wayland/host/wayland_output_manager.h"
#include "ui/ozone/platform/wayland/host/wayland_pointer.h"
#include "ui/ozone/platform/wayland/host/wayland_subsurface.h"
#include "ui/ozone/public/mojom/wayland/wayland_overlay_config.mojom.h"
namespace {
bool OverlayStackOrderCompare(
const ui::ozone::mojom::WaylandOverlayConfigPtr& i,
const ui::ozone::mojom::WaylandOverlayConfigPtr& j) {
return i->z_order < j->z_order;
}
} // namespace
namespace ui {
......@@ -481,9 +493,133 @@ bool WaylandWindow::RequestSubsurface() {
return false;
connection_->wayland_window_manager()->AddSubsurface(GetWidget(),
subsurface.get());
subsurface_stack_above_.push_back(subsurface.get());
auto result = wayland_subsurfaces_.emplace(std::move(subsurface));
DCHECK(result.second);
return true;
}
bool WaylandWindow::ArrangeSubsurfaceStack(size_t above, size_t below) {
while (wayland_subsurfaces_.size() < above + below) {
if (!RequestSubsurface())
return false;
}
DCHECK(subsurface_stack_below_.size() + subsurface_stack_above_.size() >=
above + below);
if (subsurface_stack_above_.size() < above) {
auto splice_start = subsurface_stack_below_.begin();
for (size_t i = 0; i < below; ++i)
++splice_start;
subsurface_stack_above_.splice(subsurface_stack_above_.end(),
subsurface_stack_below_, splice_start,
subsurface_stack_below_.end());
} else if (subsurface_stack_below_.size() < below) {
auto splice_start = subsurface_stack_above_.end();
for (size_t i = 0; i < below - subsurface_stack_below_.size(); ++i)
--splice_start;
subsurface_stack_below_.splice(subsurface_stack_below_.end(),
subsurface_stack_above_, splice_start,
subsurface_stack_above_.end());
}
DCHECK(subsurface_stack_below_.size() >= below);
DCHECK(subsurface_stack_above_.size() >= above);
return true;
}
bool WaylandWindow::CommitOverlays(
std::vector<ui::ozone::mojom::WaylandOverlayConfigPtr>& overlays) {
// |overlays| is sorted from bottom to top.
std::sort(overlays.begin(), overlays.end(), OverlayStackOrderCompare);
// Find the location where z_oder becomes non-negative.
ozone::mojom::WaylandOverlayConfigPtr value =
ozone::mojom::WaylandOverlayConfig::New();
auto split = std::lower_bound(overlays.begin(), overlays.end(), value,
OverlayStackOrderCompare);
CHECK((*split)->z_order >= 0);
size_t num_primary_planes = (*split)->z_order == 0 ? 1 : 0;
size_t above = (overlays.end() - split) - num_primary_planes;
size_t below = split - overlays.begin();
// Re-arrange the list of subsurfaces to fit the |overlays|. Request extra
// subsurfaces if needed.
if (!ArrangeSubsurfaceStack(above, below))
return false;
{
// Iterate through |subsurface_stack_below_|, setup subsurfaces and place
// them in corresponding order. Commit wl_buffers once a subsurface is
// configured.
auto overlay_iter = split - 1;
for (auto iter = subsurface_stack_below_.begin();
iter != subsurface_stack_below_.end(); ++iter, --overlay_iter) {
if (overlay_iter >= overlays.begin()) {
WaylandSurface* reference_above = nullptr;
if (overlay_iter == split - 1) {
// It's possible that |overlays| does not contain primary plane, we
// still want to place relative to the surface with z_order=0.
reference_above = root_surface();
} else {
reference_above = (*std::next(iter))->wayland_surface();
}
(*iter)->ConfigureAndShowSurface(
(*overlay_iter)->transform, (*overlay_iter)->bounds_rect,
(*overlay_iter)->enable_blend, nullptr, reference_above);
connection_->buffer_manager_host()->CommitBufferInternal(
(*iter)->wayland_surface(), (*overlay_iter)->buffer_id,
gfx::Rect());
} else {
// If there're more subsurfaces requested that we don't need at the
// moment, hide them.
(*iter)->Hide();
}
}
// Iterate through |subsurface_stack_above_|, setup subsurfaces and place
// them in corresponding order. Commit wl_buffers once a subsurface is
// configured.
overlay_iter = split + num_primary_planes;
for (auto iter = subsurface_stack_above_.begin();
iter != subsurface_stack_above_.end(); ++iter, ++overlay_iter) {
if (overlay_iter < overlays.end()) {
WaylandSurface* reference_below = nullptr;
if (overlay_iter == split + num_primary_planes) {
// It's possible that |overlays| does not contain primary plane, we
// still want to place relative to the surface with z_order=0.
reference_below = root_surface();
} else {
reference_below = (*std::prev(iter))->wayland_surface();
}
(*iter)->ConfigureAndShowSurface(
(*overlay_iter)->transform, (*overlay_iter)->bounds_rect,
(*overlay_iter)->enable_blend, reference_below, nullptr);
connection_->buffer_manager_host()->CommitBufferInternal(
(*iter)->wayland_surface(), (*overlay_iter)->buffer_id,
gfx::Rect());
} else {
// If there're more subsurfaces requested that we don't need at the
// moment, hide them.
(*iter)->Hide();
}
}
}
if (num_primary_planes) {
// TODO: forward fence.
connection_->buffer_manager_host()->CommitBufferInternal(
root_surface(), (*split)->buffer_id, (*split)->damage_region);
} else {
// Subsurfaces are set to desync, above operations will only take effects
// when root_surface is committed.
root_surface()->Commit();
}
// commit all;
return true;
}
} // namespace ui
......@@ -5,6 +5,7 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_WINDOW_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_WINDOW_H_
#include <list>
#include <memory>
#include <set>
#include <vector>
......@@ -18,6 +19,7 @@
#include "ui/gfx/native_widget_types.h"
#include "ui/ozone/platform/wayland/common/wayland_object.h"
#include "ui/ozone/platform/wayland/host/wayland_surface.h"
#include "ui/ozone/public/mojom/wayland/wayland_overlay_config.mojom-forward.h"
#include "ui/platform_window/platform_window.h"
#include "ui/platform_window/platform_window_delegate.h"
#include "ui/platform_window/platform_window_init_properties.h"
......@@ -71,6 +73,12 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
// Creates a WaylandSubsurface to put into |wayland_subsurfaces_|. Called if
// more subsurfaces are needed when a frame arrives.
bool RequestSubsurface();
// Re-arrange the |subsurface_stack_above_| and |subsurface_stack_below_| s.t.
// subsurface_stack_above_.size() >= above and
// subsurface_stack_below_.size() >= below.
bool ArrangeSubsurfaceStack(size_t above, size_t below);
bool CommitOverlays(
std::vector<ui::ozone::mojom::WaylandOverlayConfigPtr>& overlays);
// Set whether this window has pointer focus and should dispatch mouse events.
void SetPointerFocus(bool focus);
......@@ -222,6 +230,13 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
std::unique_ptr<WaylandSurface> root_surface_;
WidgetSubsurfaceSet wayland_subsurfaces_;
// The stack of sub-surfaces to take effect when Commit() is called.
// |subsurface_stack_above_| refers to subsurfaces that are stacked above the
// parent.
// Subsurface at the front of the list is the closest to the parent.
std::list<WaylandSubsurface*> subsurface_stack_above_;
std::list<WaylandSubsurface*> subsurface_stack_below_;
// The current cursor bitmap (immutable).
scoped_refptr<BitmapCursorOzone> bitmap_;
......
......@@ -5,7 +5,10 @@
import("//mojo/public/tools/bindings/mojom.gni")
mojom("wayland_mojom") {
sources = [ "wayland_buffer_manager.mojom" ]
sources = [
"wayland_buffer_manager.mojom",
"wayland_overlay_config.mojom",
]
public_deps = [
"//mojo/public/mojom/base",
......
......@@ -7,9 +7,10 @@ module ui.ozone.mojom;
import "mojo/public/mojom/base/file_path.mojom";
import "ui/gfx/geometry/mojom/geometry.mojom";
import "ui/gfx/mojom/accelerated_widget.mojom";
import "ui/gfx/mojom/buffer_types.mojom";
import "ui/gfx/mojom/presentation_feedback.mojom";
import "ui/gfx/mojom/swap_result.mojom";
import "ui/gfx/mojom/buffer_types.mojom";
import "ui/ozone/public/mojom/wayland/wayland_overlay_config.mojom";
// Used by the GPU for communication with the WaylandBufferManagerHost in
// the browser process.
......@@ -75,6 +76,11 @@ interface WaylandBufferManagerHost {
// the ones on the gpu process.
CommitBuffer(gfx.mojom.AcceleratedWidget widget, uint32 buffer_id,
gfx.mojom.Rect damage_region);
// Send overlay configurations for a frame to a WaylandWindow with the
// following |widget|.
CommitOverlays(gfx.mojom.AcceleratedWidget widget,
array<WaylandOverlayConfig> overlays);
};
......@@ -92,7 +98,7 @@ interface WaylandBufferManagerGpu {
Initialize(pending_remote<WaylandBufferManagerHost> remote_host,
map<gfx.mojom.BufferFormat,
array<uint64>> buffer_formats_with_modifiers,
bool supports_dma_buf);
bool supports_dma_buf);
// Signals about swap completion.
OnSubmission(gfx.mojom.AcceleratedWidget widget,
......
// 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.
module ui.ozone.mojom;
import "ui/gfx/geometry/mojom/geometry.mojom";
import "ui/gfx/mojom/gpu_fence_handle.mojom";
import "ui/gfx/mojom/overlay_transform.mojom";
// This is not a mirror of ui::OverlayPlane, it only contains things that are
// useful to ozone/wayland.
struct WaylandOverlayConfig {
// Specifies the stacking order of this overlay plane, relative to primary
// plane.
int32 z_order;
// Specifies how the buffer is to be transformed during composition.
gfx.mojom.OverlayTransform transform;
// A unique id for the buffer, which is used to identify imported wl_buffers
// on the browser process.
uint32 buffer_id;
// Specifies where it is supposed to be on the display in physical pixels.
// This, after scaled by buffer_scale sets the destination rectangle of
// Wayland Viewport.
gfx.mojom.Rect bounds_rect;
// Specifies the region within the buffer to be placed inside |bounds_rect|.
// This sets the source rectangle of Wayland Viewport.
gfx.mojom.RectF crop_rect;
// Describes the changed region of the buffer. Optional to hint a partial
// swap.
gfx.mojom.Rect damage_region;
// Specifies if alpha blending, with premultiplied alpha should be applied at
// scanout.
bool enable_blend;
// Specifies a GpuFenceHandle to be waited on before content of the buffer can
// be accessed by the display controller for overlay, or by the gpu for
// compositing.
gfx.mojom.GpuFenceHandle? access_fence_handle;
};
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