osr: Implement shared texture support (fixes #1006, fixes #2575)

Adds support for the OnAcceleratedPaint callback. Verified to work
on macOS and Windows. Linux support is present but not implemented
for cefclient, so it is not verified to work.

To test:
Run `cefclient --off-screen-rendering-enabled --shared-texture-enabled`
This commit is contained in:
reito
2024-03-08 20:44:56 +08:00
committed by Marshall Greenblatt
parent dca0435d2f
commit 260dd0ca24
43 changed files with 768 additions and 108 deletions

View File

@@ -58,10 +58,10 @@ std::unique_ptr<CefBrowserPlatformDelegateOsr> CreateOSRDelegate(
std::move(native_delegate), use_shared_texture, use_external_begin_frame);
#elif BUILDFLAG(IS_MAC)
return std::make_unique<CefBrowserPlatformDelegateOsrMac>(
std::move(native_delegate));
std::move(native_delegate), use_shared_texture, use_external_begin_frame);
#elif BUILDFLAG(IS_LINUX)
return std::make_unique<CefBrowserPlatformDelegateOsrLinux>(
std::move(native_delegate), use_external_begin_frame);
std::move(native_delegate), use_shared_texture, use_external_begin_frame);
#endif
}

View File

@@ -8,9 +8,10 @@
CefBrowserPlatformDelegateOsrLinux::CefBrowserPlatformDelegateOsrLinux(
std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate,
bool use_shared_texture,
bool use_external_begin_frame)
: CefBrowserPlatformDelegateOsr(std::move(native_delegate),
/*use_shared_texture=*/false,
use_shared_texture,
use_external_begin_frame) {}
CefWindowHandle CefBrowserPlatformDelegateOsrLinux::GetHostWindowHandle()

View File

@@ -13,6 +13,7 @@ class CefBrowserPlatformDelegateOsrLinux
public:
CefBrowserPlatformDelegateOsrLinux(
std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate,
bool use_shared_texture,
bool use_external_begin_frame);
// CefBrowserPlatformDelegate methods:

View File

@@ -11,7 +11,9 @@
class CefBrowserPlatformDelegateOsrMac : public CefBrowserPlatformDelegateOsr {
public:
explicit CefBrowserPlatformDelegateOsrMac(
std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate);
std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate,
bool use_shared_texture,
bool use_external_begin_frame);
// CefBrowserPlatformDelegate methods:
CefWindowHandle GetHostWindowHandle() const override;

View File

@@ -7,10 +7,12 @@
#include <utility>
CefBrowserPlatformDelegateOsrMac::CefBrowserPlatformDelegateOsrMac(
std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate)
std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate,
bool use_shared_texture,
bool use_external_begin_frame)
: CefBrowserPlatformDelegateOsr(std::move(native_delegate),
/*use_shared_texture=*/false,
/*use_external_begin_frame=*/false) {}
use_shared_texture,
use_external_begin_frame) {}
CefWindowHandle CefBrowserPlatformDelegateOsrMac::GetHostWindowHandle() const {
return native_delegate_->window_info().parent_view;

View File

@@ -202,6 +202,7 @@ CefRenderWidgetHostViewOSR::CefRenderWidgetHostViewOSR(
CefRenderWidgetHostViewOSR* parent_host_view)
: content::RenderWidgetHostViewBase(widget),
background_color_(background_color),
use_shared_texture_(use_shared_texture),
render_widget_host_(content::RenderWidgetHostImpl::From(widget)),
has_parent_(parent_host_view != nullptr),
parent_host_view_(parent_host_view),
@@ -400,7 +401,8 @@ void CefRenderWidgetHostViewOSR::ShowWithVisibility(
if (!content::GpuDataManagerImpl::GetInstance()->IsGpuCompositingDisabled()) {
// Start generating frames when we're visible and at the correct size.
if (!video_consumer_) {
video_consumer_ = std::make_unique<CefVideoConsumerOSR>(this);
video_consumer_ =
std::make_unique<CefVideoConsumerOSR>(this, use_shared_texture_);
UpdateFrameRate();
} else {
video_consumer_->SetActive(true);
@@ -1565,7 +1567,7 @@ void CefRenderWidgetHostViewOSR::OnPaint(const gfx::Rect& damage_rect,
const void* pixels) {
TRACE_EVENT0("cef", "CefRenderWidgetHostViewOSR::OnPaint");
// Workaround for https://github.com/chromiumembedded/cef/issues/2817
// Workaround for issue #2817.
if (!is_showing_) {
return;
}
@@ -1599,6 +1601,43 @@ void CefRenderWidgetHostViewOSR::OnPaint(const gfx::Rect& damage_rect,
}
}
void CefRenderWidgetHostViewOSR::OnAcceleratedPaint(
const gfx::Rect& damage_rect,
const gfx::Size& pixel_size,
const CefAcceleratedPaintInfo& info) {
TRACE_EVENT0("cef", "CefRenderWidgetHostViewOSR::OnAcceleratedPaint");
// Workaround for https://github.com/chromiumembedded/cef/issues/2817
if (!is_showing_) {
return;
}
CefRefPtr<CefRenderHandler> handler =
browser_impl_->client()->GetRenderHandler();
CHECK(handler);
gfx::Rect rect_in_pixels(0, 0, pixel_size.width(), pixel_size.height());
rect_in_pixels.Intersect(damage_rect);
CefRenderHandler::RectList rcList;
rcList.emplace_back(rect_in_pixels.x(), rect_in_pixels.y(),
rect_in_pixels.width(), rect_in_pixels.height());
handler->OnAcceleratedPaint(browser_impl_.get(),
IsPopupWidget() ? PET_POPUP : PET_VIEW, rcList,
info);
// Release the resize hold when we reach the desired size.
if (hold_resize_) {
DCHECK_GT(cached_scale_factor_, 0);
gfx::Size expected_size =
gfx::ScaleToCeiledSize(GetViewBounds().size(), cached_scale_factor_);
if (pixel_size == expected_size) {
ReleaseResizeHold();
}
}
}
ui::Layer* CefRenderWidgetHostViewOSR::GetRootLayer() const {
return root_layer_.get();
}

View File

@@ -254,6 +254,9 @@ class CefRenderWidgetHostViewOSR
void OnPaint(const gfx::Rect& damage_rect,
const gfx::Size& pixel_size,
const void* pixels);
void OnAcceleratedPaint(const gfx::Rect& damage_rect,
const gfx::Size& pixel_size,
const CefAcceleratedPaintInfo& info);
void OnBeginFame(base::TimeTicks frame_time);
@@ -401,6 +404,7 @@ class CefRenderWidgetHostViewOSR
uint64_t begin_frame_number_ = viz::BeginFrameArgs::kStartingFrameNumber;
bool begin_frame_pending_ = false;
bool use_shared_texture_ = false;
bool sync_frame_rate_ = false;
bool external_begin_frame_enabled_ = false;
bool needs_external_begin_frames_ = false;

View File

@@ -11,6 +11,12 @@
#include "media/capture/mojom/video_capture_types.mojom.h"
#include "ui/gfx/skbitmap_operations.h"
#if BUILDFLAG(IS_WIN)
#include "ipc/service/gpu_memory_buffer_factory_dxgi.h"
#elif BUILDFLAG(IS_APPLE)
#include "ipc/service/gpu_memory_buffer_factory_io_surface.h"
#endif
namespace {
// Helper to always call Done() at the end of OnFrameCaptured().
@@ -28,8 +34,11 @@ class ScopedVideoFrameDone {
} // namespace
CefVideoConsumerOSR::CefVideoConsumerOSR(CefRenderWidgetHostViewOSR* view)
: view_(view), video_capturer_(view->CreateVideoCapturer()) {
CefVideoConsumerOSR::CefVideoConsumerOSR(CefRenderWidgetHostViewOSR* view,
bool use_shared_texture)
: use_shared_texture_(use_shared_texture),
view_(view),
video_capturer_(view->CreateVideoCapturer()) {
video_capturer_->SetFormat(media::PIXEL_FORMAT_ARGB);
// Always use the highest resolution within constraints that doesn't exceed
@@ -45,7 +54,10 @@ CefVideoConsumerOSR::~CefVideoConsumerOSR() = default;
void CefVideoConsumerOSR::SetActive(bool active) {
if (active) {
video_capturer_->Start(this, viz::mojom::BufferFormatPreference::kDefault);
video_capturer_->Start(
this, use_shared_texture_
? viz::mojom::BufferFormatPreference::kPreferGpuMemoryBuffer
: viz::mojom::BufferFormatPreference::kDefault);
} else {
video_capturer_->Stop();
}
@@ -88,6 +100,55 @@ void CefVideoConsumerOSR::OnFrameCaptured(
callbacks) {
ScopedVideoFrameDone scoped_done(std::move(callbacks));
// If it is GPU Texture OSR.
if (use_shared_texture_) {
CHECK(data->is_gpu_memory_buffer_handle() &&
(info->pixel_format == media::PIXEL_FORMAT_ARGB ||
info->pixel_format == media::PIXEL_FORMAT_ABGR));
// The info->pixel_format will tell if the texture is RGBA or BGRA
// On Linux, X11 lacks support for RGBA_8888 so it might be BGRA.
// On Windows and macOS, it should always be RGBA.
auto pixel_format = info->pixel_format == media::PIXEL_FORMAT_ABGR
? CEF_COLOR_TYPE_RGBA_8888
: CEF_COLOR_TYPE_BGRA_8888;
#if BUILDFLAG(IS_WIN)
auto& gmb_handle = data->get_gpu_memory_buffer_handle();
cef_accelerated_paint_info_t paint_info;
paint_info.shared_texture_handle = gmb_handle.dxgi_handle.Get();
paint_info.format = pixel_format;
view_->OnAcceleratedPaint(content_rect, info->coded_size, paint_info);
#elif BUILDFLAG(IS_APPLE)
auto& gmb_handle = data->get_gpu_memory_buffer_handle();
cef_accelerated_paint_info_t paint_info;
paint_info.shared_texture_io_surface = gmb_handle.io_surface.get();
paint_info.format = pixel_format;
view_->OnAcceleratedPaint(content_rect, info->coded_size, paint_info);
#elif BUILDFLAG(IS_LINUX)
auto& gmb_handle = data->get_gpu_memory_buffer_handle();
auto& native_pixmap = gmb_handle.native_pixmap_handle;
CHECK(native_pixmap.planes.size() <= kAcceleratedPaintMaxPlanes);
cef_accelerated_paint_info_t paint_info;
paint_info.plane_count = native_pixmap.planes.size();
paint_info.modifier = native_pixmap.modifier;
paint_info.format = pixel_format;
auto cef_plain_index = 0;
for (const auto& plane : native_pixmap.planes) {
cef_accelerated_paint_native_pixmap_plane_t cef_plane;
cef_plane.stride = plane.stride;
cef_plane.offset = plane.offset;
cef_plane.size = plane.size;
cef_plane.fd = plane.fd.get();
paint_info.planes[cef_plain_index++] = cef_plane;
}
view_->OnAcceleratedPaint(content_rect, info->coded_size, paint_info);
#endif
return;
}
if (info->pixel_format != media::PIXEL_FORMAT_ARGB) {
DLOG(ERROR) << "Unsupported pixel format " << info->pixel_format;
return;

View File

@@ -11,7 +11,8 @@ class CefRenderWidgetHostViewOSR;
class CefVideoConsumerOSR : public viz::mojom::FrameSinkVideoConsumer {
public:
explicit CefVideoConsumerOSR(CefRenderWidgetHostViewOSR* view);
CefVideoConsumerOSR(CefRenderWidgetHostViewOSR* view,
bool use_shared_texture);
CefVideoConsumerOSR(const CefVideoConsumerOSR&) = delete;
CefVideoConsumerOSR& operator=(const CefVideoConsumerOSR&) = delete;
@@ -37,6 +38,8 @@ class CefVideoConsumerOSR : public viz::mojom::FrameSinkVideoConsumer {
void OnNewSubCaptureTargetVersion(
uint32_t sub_capture_target_version) override {}
const bool use_shared_texture_;
CefRenderWidgetHostViewOSR* const view_;
std::unique_ptr<viz::ClientFrameSinkVideoCapturer> video_capturer_;