Revert "Reland "PipeWire capturer: implement proper DMA-BUFs support"""
This reverts commit 677195d3eb6a5f0bc1d31d794a5190ba281c0335.
Reason for revert: Broke WebRTC to Chrome rolls:
https://crrev.com/c/3141000
example: https://ci.chromium.org/ui/p/chromium/builders/try/linux-rel/790256/overview
The error is similar to the failure on previous attempt to land this CL. See: https://crrev.com/c/3135220, and crash https://ci.chromium.org/ui/p/chromium/builders/try/linux-rel/787945/overview
Original change's description:
> Reland "PipeWire capturer: implement proper DMA-BUFs support""
>
> This is a reland of f2177f6612079ccce9c320ea7e77bc934c684f5c
>
> Original change's description:
> > PipeWire capturer: implement proper DMA-BUFs support
> >
> > Currently both KWin (KDE) and Mutter (GNOME) window managers don't
> > use DMA-BUFs by default, but only when client asks specifically for
> > them (KWin) or when experimental DMA-BUF support is enabled (Mutter).
> > While current implementation works just fine on integrated graphics
> > cards, it causes issues on dedicated GPUs (AMD and NVidia) where the
> > code either crashes or screensharing is slow and unusable.
> >
> > To fix this, DMA-BUFs has to be opened using OpenGL context and not
> > being directly mmaped(). This implementation requires to use DMA-BUF
> > modifiers, as they are now mandatory for DMA-BUFs usage.
> >
> > Documentation for this behavior can be found here:
> > https://gitlab.freedesktop.org/pipewire/pipewire/-/blob/master/doc/dma-buf.dox
> >
> > Bug: chromium:1233417, webrtc:13137
> > Change-Id: I0cecf16d6bb0f576954b9e8f071cab526f7baf2c
> > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/227022
> > Commit-Queue: Tommi <tommi@webrtc.org>
> > Reviewed-by: Tommi <tommi@webrtc.org>
> > Reviewed-by: Erik Språng <sprang@webrtc.org>
> > Cr-Commit-Position: refs/heads/main@{#34889}
>
> Bug: chromium:1233417, webrtc:13137
> Change-Id: I7d5763dd5db708cee20a31e559b26db0287f40d6
> Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/230946
> Reviewed-by: Tommi <tommi@webrtc.org>
> Commit-Queue: Tommi <tommi@webrtc.org>
> Cr-Commit-Position: refs/heads/main@{#34903}
# Not skipping CQ checks because original CL landed > 1 day ago.
Bug: chromium:1233417, webrtc:13137
Change-Id: I64e2ce864f69e6097aba65ade04af7166e407409
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/231135
Reviewed-by: Tommi <tommi@webrtc.org>
Reviewed-by: Björn Terelius <terelius@webrtc.org>
Commit-Queue: Artem Titov <titovartem@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#34915}
diff --git a/modules/desktop_capture/BUILD.gn b/modules/desktop_capture/BUILD.gn
index cc89f0f..d2b4eea 100644
--- a/modules/desktop_capture/BUILD.gn
+++ b/modules/desktop_capture/BUILD.gn
@@ -225,19 +225,6 @@
}
}
- pkg_config("gbm") {
- packages = [ "gbm" ]
- }
- pkg_config("egl") {
- packages = [ "egl" ]
- }
- pkg_config("epoxy") {
- packages = [ "epoxy" ]
- }
- pkg_config("libdrm") {
- packages = [ "libdrm" ]
- }
-
if (!rtc_link_pipewire) {
# When libpipewire is not directly linked, use stubs to allow for dlopening of
# the binary.
@@ -555,25 +542,17 @@
sources += [
"linux/base_capturer_pipewire.cc",
"linux/base_capturer_pipewire.h",
- "linux/egl_dmabuf.cc",
- "linux/egl_dmabuf.h",
]
configs += [
":pipewire_config",
":gio",
":pipewire",
- ":gbm",
- ":egl",
- ":epoxy",
- ":libdrm",
]
if (!rtc_link_pipewire) {
deps += [ ":pipewire_stubs" ]
}
-
- deps += [ "../../rtc_base:sanitizer" ]
}
if (rtc_enable_win_wgc) {
diff --git a/modules/desktop_capture/DEPS b/modules/desktop_capture/DEPS
index 033d318..8c894c4 100644
--- a/modules/desktop_capture/DEPS
+++ b/modules/desktop_capture/DEPS
@@ -13,9 +13,6 @@
"desktop_frame_provider\.h": [
"+sdk/objc",
],
- "egl_dmabuf\.cc": [
- "+absl/strings/str_split.h",
- ],
"screen_capturer_mac\.mm": [
"+sdk/objc",
],
diff --git a/modules/desktop_capture/linux/base_capturer_pipewire.cc b/modules/desktop_capture/linux/base_capturer_pipewire.cc
index 263c8a6..7212ad3 100644
--- a/modules/desktop_capture/linux/base_capturer_pipewire.cc
+++ b/modules/desktop_capture/linux/base_capturer_pipewire.cc
@@ -14,13 +14,12 @@
#include <glib-object.h>
#include <spa/param/format-utils.h>
#include <spa/param/props.h>
+
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/syscall.h>
-#include <unistd.h>
#include <memory>
-#include <string>
#include <utility>
#include "absl/memory/memory.h"
@@ -52,102 +51,65 @@
const char kPipeWireLib[] = "libpipewire-0.3.so.0";
#endif
-#if !PW_CHECK_VERSION(0, 3, 29)
-#define SPA_POD_PROP_FLAG_MANDATORY (1u << 3)
-#endif
-#if !PW_CHECK_VERSION(0, 3, 33)
-#define SPA_POD_PROP_FLAG_DONT_FIXATE (1u << 4)
-#endif
-
-struct pw_version {
- int major = 0;
- int minor = 0;
- int micro = 0;
+// static
+struct dma_buf_sync {
+ uint64_t flags;
};
+#define DMA_BUF_SYNC_READ (1 << 0)
+#define DMA_BUF_SYNC_START (0 << 2)
+#define DMA_BUF_SYNC_END (1 << 2)
+#define DMA_BUF_BASE 'b'
+#define DMA_BUF_IOCTL_SYNC _IOW(DMA_BUF_BASE, 0, struct dma_buf_sync)
-pw_version ParsePipeWireVersion(const char* version) {
- pw_version pw_version;
- sscanf(version, "%d.%d.%d", &pw_version.major, &pw_version.minor,
- &pw_version.micro);
- return pw_version;
-}
+static void SyncDmaBuf(int fd, uint64_t start_or_end) {
+ struct dma_buf_sync sync = {0};
-spa_pod* BuildFormat(spa_pod_builder* builder,
- uint32_t format,
- const std::vector<uint64_t>& modifiers) {
- bool first = true;
- spa_pod_frame frames[2];
- spa_rectangle pw_min_screen_bounds = spa_rectangle{1, 1};
- spa_rectangle pw_max_screen_bounds = spa_rectangle{UINT32_MAX, UINT32_MAX};
+ sync.flags = start_or_end | DMA_BUF_SYNC_READ;
- spa_pod_builder_push_object(builder, &frames[0], SPA_TYPE_OBJECT_Format,
- SPA_PARAM_EnumFormat);
- spa_pod_builder_add(builder, SPA_FORMAT_mediaType,
- SPA_POD_Id(SPA_MEDIA_TYPE_video), 0);
- spa_pod_builder_add(builder, SPA_FORMAT_mediaSubtype,
- SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), 0);
- spa_pod_builder_add(builder, SPA_FORMAT_VIDEO_format, SPA_POD_Id(format), 0);
-
- if (modifiers.size()) {
- pw_version pw_version = ParsePipeWireVersion(pw_get_library_version());
-
- // SPA_POD_PROP_FLAG_DONT_FIXATE can be used with PipeWire >= 0.3.33
- if (pw_version.major >= 0 && pw_version.minor >= 3 &&
- pw_version.micro >= 33) {
- spa_pod_builder_prop(
- builder, SPA_FORMAT_VIDEO_modifier,
- SPA_POD_PROP_FLAG_MANDATORY | SPA_POD_PROP_FLAG_DONT_FIXATE);
+ while (true) {
+ int ret;
+ ret = ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync);
+ if (ret == -1 && errno == EINTR) {
+ continue;
+ } else if (ret == -1) {
+ RTC_LOG(LS_ERROR) << "Failed to synchronize DMA buffer: "
+ << g_strerror(errno);
+ break;
} else {
- spa_pod_builder_prop(builder, SPA_FORMAT_VIDEO_modifier,
- SPA_POD_PROP_FLAG_MANDATORY);
+ break;
}
- spa_pod_builder_push_choice(builder, &frames[1], SPA_CHOICE_Enum, 0);
- // modifiers from the array
- for (int64_t val : modifiers) {
- spa_pod_builder_long(builder, val);
- // Add the first modifier twice as the very first value is the default
- // option
- if (first) {
- spa_pod_builder_long(builder, val);
- first = false;
- }
- }
- spa_pod_builder_pop(builder, &frames[1]);
}
-
- spa_pod_builder_add(
- builder, SPA_FORMAT_VIDEO_size,
- SPA_POD_CHOICE_RANGE_Rectangle(
- &pw_min_screen_bounds, &pw_min_screen_bounds, &pw_max_screen_bounds),
- 0);
-
- return static_cast<spa_pod*>(spa_pod_builder_pop(builder, &frames[0]));
}
class ScopedBuf {
public:
ScopedBuf() {}
- ScopedBuf(unsigned char* map, int map_size, int fd)
- : map_(map), map_size_(map_size), fd_(fd) {}
+ ScopedBuf(unsigned char* map, int map_size, bool is_dma_buf, int fd)
+ : map_(map), map_size_(map_size), is_dma_buf_(is_dma_buf), fd_(fd) {}
~ScopedBuf() {
if (map_ != MAP_FAILED) {
+ if (is_dma_buf_) {
+ SyncDmaBuf(fd_, DMA_BUF_SYNC_END);
+ }
munmap(map_, map_size_);
}
}
operator bool() { return map_ != MAP_FAILED; }
- void initialize(unsigned char* map, int map_size, int fd) {
+ void initialize(unsigned char* map, int map_size, bool is_dma_buf, int fd) {
map_ = map;
map_size_ = map_size;
+ is_dma_buf_ = is_dma_buf;
fd_ = fd;
}
unsigned char* get() { return map_; }
protected:
- unsigned char* map_ = static_cast<unsigned char*>(MAP_FAILED);
+ unsigned char* map_ = nullptr;
int map_size_;
+ bool is_dma_buf_;
int fd_;
};
@@ -272,26 +234,17 @@
auto size = height * stride;
that->desktop_size_ = DesktopSize(width, height);
-#if PW_CHECK_VERSION(0, 3, 0)
- that->modifier_ = that->spa_video_format_.modifier;
-#endif
uint8_t buffer[1024] = {};
auto builder = spa_pod_builder{buffer, sizeof(buffer)};
// Setup buffers and meta header for new format.
const struct spa_pod* params[3];
- const int buffer_types =
- spa_pod_find_prop(format, nullptr, SPA_FORMAT_VIDEO_modifier)
- ? (1 << SPA_DATA_DmaBuf) | (1 << SPA_DATA_MemFd) |
- (1 << SPA_DATA_MemPtr)
- : (1 << SPA_DATA_MemFd) | (1 << SPA_DATA_MemPtr);
params[0] = reinterpret_cast<spa_pod*>(spa_pod_builder_add_object(
&builder, SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers,
SPA_PARAM_BUFFERS_size, SPA_POD_Int(size), SPA_PARAM_BUFFERS_stride,
SPA_POD_Int(stride), SPA_PARAM_BUFFERS_buffers,
- SPA_POD_CHOICE_RANGE_Int(8, 1, 32), SPA_PARAM_BUFFERS_dataType,
- SPA_POD_CHOICE_FLAGS_Int(buffer_types)));
+ SPA_POD_CHOICE_RANGE_Int(8, 1, 32)));
params[1] = reinterpret_cast<spa_pod*>(spa_pod_builder_add_object(
&builder, SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta, SPA_PARAM_META_type,
SPA_POD_Id(SPA_META_Header), SPA_PARAM_META_size,
@@ -397,12 +350,6 @@
}
}
-#if PW_CHECK_VERSION(0, 3, 0)
-void BaseCapturerPipeWire::InitEGL() {
- egl_dmabuf_ = std::make_unique<EglDmaBuf>();
-}
-#endif
-
void BaseCapturerPipeWire::InitPortal() {
cancellable_ = g_cancellable_new();
g_dbus_proxy_new_for_bus(
@@ -472,39 +419,34 @@
}
pw_stream* BaseCapturerPipeWire::CreateReceivingStream() {
+ spa_rectangle pwMinScreenBounds = spa_rectangle{1, 1};
+ spa_rectangle pwMaxScreenBounds = spa_rectangle{UINT32_MAX, UINT32_MAX};
+
pw_properties* reuseProps =
pw_properties_new_string("pipewire.client.reuse=1");
auto stream = pw_stream_new(pw_core_, "webrtc-consume-stream", reuseProps);
- spa_pod_builder builder;
- uint8_t buffer[2048] = {};
- std::vector<uint64_t> modifiers;
+ uint8_t buffer[1024] = {};
+ const spa_pod* params[1];
+ spa_pod_builder builder = spa_pod_builder{buffer, sizeof(buffer)};
- builder = spa_pod_builder{buffer, sizeof(buffer)};
-
- std::vector<const spa_pod*> params;
- for (uint32_t format : {SPA_VIDEO_FORMAT_BGRA, SPA_VIDEO_FORMAT_RGBA,
- SPA_VIDEO_FORMAT_BGRx, SPA_VIDEO_FORMAT_RGBx}) {
- pw_version pw_version = ParsePipeWireVersion(pw_get_library_version());
-
- // Modifiers can be used with PipeWire >= 0.3.29
- if (pw_version.major >= 0 && pw_version.minor >= 3 &&
- pw_version.micro >= 29) {
- modifiers = egl_dmabuf_->QueryDmaBufModifiers(format);
-
- if (!modifiers.empty()) {
- params.push_back(BuildFormat(&builder, format, modifiers));
- }
- }
-
- params.push_back(BuildFormat(&builder, format, /*modifiers=*/{}));
- }
+ params[0] = reinterpret_cast<spa_pod*>(spa_pod_builder_add_object(
+ &builder, SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
+ SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video),
+ SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
+ SPA_FORMAT_VIDEO_format,
+ SPA_POD_CHOICE_ENUM_Id(5, SPA_VIDEO_FORMAT_BGRx, SPA_VIDEO_FORMAT_RGBx,
+ SPA_VIDEO_FORMAT_RGBA, SPA_VIDEO_FORMAT_BGRx,
+ SPA_VIDEO_FORMAT_BGRA),
+ SPA_FORMAT_VIDEO_size,
+ SPA_POD_CHOICE_RANGE_Rectangle(&pwMinScreenBounds, &pwMinScreenBounds,
+ &pwMaxScreenBounds),
+ 0));
pw_stream_add_listener(stream, &spa_stream_listener_, &pw_stream_events_,
this);
if (pw_stream_connect(stream, PW_DIRECTION_INPUT, pw_stream_node_id_,
- PW_STREAM_FLAG_AUTOCONNECT, params.data(),
- params.size()) != 0) {
+ PW_STREAM_FLAG_AUTOCONNECT, params, 1) != 0) {
RTC_LOG(LS_ERROR) << "Could not connect receiving stream.";
portal_init_failed_ = true;
return nullptr;
@@ -514,26 +456,25 @@
}
void BaseCapturerPipeWire::HandleBuffer(pw_buffer* buffer) {
- spa_buffer* spa_buffer = buffer->buffer;
+ spa_buffer* spaBuffer = buffer->buffer;
ScopedBuf map;
- std::unique_ptr<uint8_t[]> src_unique_ptr;
uint8_t* src = nullptr;
- if (spa_buffer->datas[0].chunk->size == 0) {
+ if (spaBuffer->datas[0].chunk->size == 0) {
RTC_LOG(LS_ERROR) << "Failed to get video stream: Zero size.";
return;
}
- std::function<void()> cleanup;
- const int32_t src_stride = spa_buffer->datas[0].chunk->stride;
- if (spa_buffer->datas[0].type == SPA_DATA_MemFd) {
+ if (spaBuffer->datas[0].type == SPA_DATA_MemFd ||
+ spaBuffer->datas[0].type == SPA_DATA_DmaBuf) {
map.initialize(
static_cast<uint8_t*>(
mmap(nullptr,
- spa_buffer->datas[0].maxsize + spa_buffer->datas[0].mapoffset,
- PROT_READ, MAP_PRIVATE, spa_buffer->datas[0].fd, 0)),
- spa_buffer->datas[0].maxsize + spa_buffer->datas[0].mapoffset,
- spa_buffer->datas[0].fd);
+ spaBuffer->datas[0].maxsize + spaBuffer->datas[0].mapoffset,
+ PROT_READ, MAP_PRIVATE, spaBuffer->datas[0].fd, 0)),
+ spaBuffer->datas[0].maxsize + spaBuffer->datas[0].mapoffset,
+ spaBuffer->datas[0].type == SPA_DATA_DmaBuf,
+ spaBuffer->datas[0].fd);
if (!map) {
RTC_LOG(LS_ERROR) << "Failed to mmap the memory: "
@@ -541,25 +482,13 @@
return;
}
- src = SPA_MEMBER(map.get(), spa_buffer->datas[0].mapoffset, uint8_t);
- } else if (spa_buffer->datas[0].type == SPA_DATA_DmaBuf) {
- const uint n_planes = spa_buffer->n_datas;
- int fds[n_planes];
- uint32_t offsets[n_planes];
- uint32_t strides[n_planes];
-
- for (uint i = 0; i < n_planes; i++) {
- fds[i] = spa_buffer->datas[i].fd;
- offsets[i] = spa_buffer->datas[i].chunk->offset;
- strides[i] = spa_buffer->datas[i].chunk->stride;
+ if (spaBuffer->datas[0].type == SPA_DATA_DmaBuf) {
+ SyncDmaBuf(spaBuffer->datas[0].fd, DMA_BUF_SYNC_START);
}
- src_unique_ptr = egl_dmabuf_->ImageFromDmaBuf(
- desktop_size_, spa_video_format_.format, n_planes, fds, strides,
- offsets, modifier_);
- src = src_unique_ptr.get();
- } else if (spa_buffer->datas[0].type == SPA_DATA_MemPtr) {
- src = static_cast<uint8_t*>(spa_buffer->datas[0].data);
+ src = SPA_MEMBER(map.get(), spaBuffer->datas[0].mapoffset, uint8_t);
+ } else if (spaBuffer->datas[0].type == SPA_DATA_MemPtr) {
+ src = static_cast<uint8_t*>(spaBuffer->datas[0].data);
}
if (!src) {
@@ -568,7 +497,7 @@
struct spa_meta_region* video_metadata =
static_cast<struct spa_meta_region*>(spa_buffer_find_meta_data(
- spa_buffer, SPA_META_VideoCrop, sizeof(*video_metadata)));
+ spaBuffer, SPA_META_VideoCrop, sizeof(*video_metadata)));
// Video size from metadata is bigger than an actual video stream size.
// The metadata are wrong or we should up-scale the video...in both cases
@@ -584,6 +513,7 @@
// Use video metadata when video size from metadata is set and smaller than
// video stream size, so we need to adjust it.
bool video_metadata_use = false;
+
const struct spa_rectangle* video_metadata_size =
video_metadata ? &video_metadata->region.size : nullptr;
@@ -610,6 +540,7 @@
}
const int32_t dst_stride = video_size_.width() * kBytesPerPixel;
+ const int32_t src_stride = spaBuffer->datas[0].chunk->stride;
if (src_stride != (desktop_size_.width() * kBytesPerPixel)) {
RTC_LOG(LS_ERROR) << "Got buffer with stride different from screen stride: "
@@ -1070,9 +1001,6 @@
return;
}
-#if PW_CHECK_VERSION(0, 3, 0)
- that->InitEGL();
-#endif
that->InitPipeWire();
}
diff --git a/modules/desktop_capture/linux/base_capturer_pipewire.h b/modules/desktop_capture/linux/base_capturer_pipewire.h
index 8f9b61d..7ec5ea6 100644
--- a/modules/desktop_capture/linux/base_capturer_pipewire.h
+++ b/modules/desktop_capture/linux/base_capturer_pipewire.h
@@ -19,7 +19,6 @@
#include "absl/types/optional.h"
#include "modules/desktop_capture/desktop_capture_options.h"
#include "modules/desktop_capture/desktop_capturer.h"
-#include "modules/desktop_capture/linux/egl_dmabuf.h"
#include "rtc_base/constructor_magic.h"
#include "rtc_base/synchronization/mutex.h"
@@ -89,7 +88,6 @@
guint sources_request_signal_id_ = 0;
guint start_request_signal_id_ = 0;
- int64_t modifier_;
DesktopSize video_size_;
DesktopSize desktop_size_ = {};
DesktopCaptureOptions options_ = {};
@@ -100,9 +98,6 @@
bool portal_init_failed_ = false;
- std::unique_ptr<EglDmaBuf> egl_dmabuf_;
-
- void InitEGL();
void InitPortal();
void InitPipeWire();
void InitPipeWireTypes();
diff --git a/modules/desktop_capture/linux/egl_dmabuf.cc b/modules/desktop_capture/linux/egl_dmabuf.cc
deleted file mode 100644
index 6bc1486..0000000
--- a/modules/desktop_capture/linux/egl_dmabuf.cc
+++ /dev/null
@@ -1,411 +0,0 @@
-/*
- * Copyright 2021 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "modules/desktop_capture/linux/egl_dmabuf.h"
-
-#include <asm/ioctl.h>
-#include <fcntl.h>
-#include <libdrm/drm_fourcc.h>
-#include <linux/types.h>
-#include <spa/param/video/format-utils.h>
-#include <unistd.h>
-#include <xf86drm.h>
-
-#include "absl/memory/memory.h"
-#include "absl/strings/str_split.h"
-#include "absl/types/optional.h"
-#include "rtc_base/checks.h"
-#include "rtc_base/logging.h"
-#include "rtc_base/sanitizer.h"
-
-namespace webrtc {
-
-typedef EGLBoolean (*eglQueryDmaBufFormatsEXT_func)(EGLDisplay dpy,
- EGLint max_formats,
- EGLint* formats,
- EGLint* num_formats);
-typedef EGLBoolean (*eglQueryDmaBufModifiersEXT_func)(EGLDisplay dpy,
- EGLint format,
- EGLint max_modifiers,
- EGLuint64KHR* modifiers,
- EGLBoolean* external_only,
- EGLint* num_modifiers);
-eglQueryDmaBufFormatsEXT_func EglQueryDmaBufFormatsEXT = nullptr;
-eglQueryDmaBufModifiersEXT_func EglQueryDmaBufModifiersEXT = nullptr;
-
-static const std::string FormatGLError(GLenum err) {
- switch (err) {
- case GL_NO_ERROR:
- return "GL_NO_ERROR";
- case GL_INVALID_ENUM:
- return "GL_INVALID_ENUM";
- case GL_INVALID_VALUE:
- return "GL_INVALID_VALUE";
- case GL_INVALID_OPERATION:
- return "GL_INVALID_OPERATION";
- case GL_STACK_OVERFLOW:
- return "GL_STACK_OVERFLOW";
- case GL_STACK_UNDERFLOW:
- return "GL_STACK_UNDERFLOW";
- case GL_OUT_OF_MEMORY:
- return "GL_OUT_OF_MEMORY";
- default:
- return std::string("0x") + std::to_string(err);
- }
-}
-
-static uint32_t SpaPixelFormatToDrmFormat(uint32_t spa_format) {
- switch (spa_format) {
- case SPA_VIDEO_FORMAT_RGBA:
- return DRM_FORMAT_ABGR8888;
- case SPA_VIDEO_FORMAT_RGBx:
- return DRM_FORMAT_XBGR8888;
- case SPA_VIDEO_FORMAT_BGRA:
- return DRM_FORMAT_ARGB8888;
- case SPA_VIDEO_FORMAT_BGRx:
- return DRM_FORMAT_XRGB8888;
- default:
- return DRM_FORMAT_INVALID;
- }
-}
-
-static absl::optional<std::string> GetRenderNode() {
- int ret, max_devices;
- std::string render_node;
-
- max_devices = drmGetDevices2(0, nullptr, 0);
- if (max_devices <= 0) {
- RTC_LOG(LS_ERROR) << "drmGetDevices2() has not found any devices (errno="
- << -max_devices << ")";
- return absl::nullopt;
- }
-
- std::vector<drmDevicePtr> devices(max_devices);
- ret = drmGetDevices2(0, devices.data(), max_devices);
- if (ret < 0) {
- RTC_LOG(LS_ERROR) << "drmGetDevices2() returned an error " << ret;
- return absl::nullopt;
- }
-
- for (const drmDevicePtr& device : devices) {
- if (device->available_nodes & (1 << DRM_NODE_RENDER)) {
- render_node = device->nodes[DRM_NODE_RENDER];
- break;
- }
- }
-
- drmFreeDevices(devices.data(), ret);
- return render_node;
-}
-
-RTC_NO_SANITIZE("cfi-icall")
-EglDmaBuf::EglDmaBuf() {
- absl::optional<std::string> render_node = GetRenderNode();
- if (!render_node) {
- return;
- }
-
- drm_fd_ = open(render_node->c_str(), O_RDWR);
-
- if (drm_fd_ < 0) {
- RTC_LOG(LS_ERROR) << "Failed to open drm render node: " << strerror(errno);
- return;
- }
-
- gbm_device_ = gbm_create_device(drm_fd_);
-
- if (!gbm_device_) {
- RTC_LOG(LS_ERROR) << "Cannot create GBM device: " << strerror(errno);
- return;
- }
-
- // Get the list of client extensions
- const char* client_extensions_cstring_no_display =
- eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
- std::string client_extensions_string = client_extensions_cstring_no_display;
- if (!client_extensions_cstring_no_display) {
- // If eglQueryString() returned NULL, the implementation doesn't support
- // EGL_EXT_client_extensions. Expect an EGL_BAD_DISPLAY error.
- RTC_LOG(LS_ERROR) << "No client extensions defined! "
- << FormatGLError(eglGetError());
- return;
- }
-
- for (const auto& extension :
- absl::StrSplit(client_extensions_cstring_no_display, " ")) {
- egl_.extensions.push_back(std::string(extension));
- }
-
- bool has_platform_base_ext = false;
- bool has_platform_gbm_ext = false;
-
- for (const auto& extension : egl_.extensions) {
- if (extension == "EGL_EXT_platform_base") {
- has_platform_base_ext = true;
- continue;
- } else if (extension == "EGL_MESA_platform_gbm") {
- has_platform_gbm_ext = true;
- continue;
- }
- }
-
- if (!has_platform_base_ext || !has_platform_gbm_ext) {
- RTC_LOG(LS_ERROR) << "One of required EGL extensions is missing";
- return;
- }
-
- // Use eglGetPlatformDisplayEXT() to get the display pointer
- // if the implementation supports it.
- egl_.display =
- eglGetPlatformDisplayEXT(EGL_PLATFORM_GBM_MESA, gbm_device_, nullptr);
-
- if (egl_.display == EGL_NO_DISPLAY) {
- RTC_LOG(LS_ERROR) << "Error during obtaining EGL display: "
- << FormatGLError(eglGetError());
- return;
- }
-
- EGLint major, minor;
- if (eglInitialize(egl_.display, &major, &minor) == EGL_FALSE) {
- RTC_LOG(LS_ERROR) << "Error during eglInitialize: "
- << FormatGLError(eglGetError());
- return;
- }
-
- if (eglBindAPI(EGL_OPENGL_API) == EGL_FALSE) {
- RTC_LOG(LS_ERROR) << "bind OpenGL API failed";
- return;
- }
-
- egl_.context =
- eglCreateContext(egl_.display, nullptr, EGL_NO_CONTEXT, nullptr);
-
- if (egl_.context == EGL_NO_CONTEXT) {
- RTC_LOG(LS_ERROR) << "Couldn't create EGL context: "
- << FormatGLError(eglGetError());
- return;
- }
-
- const char* client_extensions_cstring_display =
- eglQueryString(egl_.display, EGL_EXTENSIONS);
- client_extensions_string = client_extensions_cstring_display;
-
- for (const auto& extension : absl::StrSplit(client_extensions_string, " ")) {
- egl_.extensions.push_back(std::string(extension));
- }
-
- bool has_image_dma_buf_import_ext = false;
- bool has_image_dma_buf_import_modifiers_ext = false;
-
- for (const auto& extension : egl_.extensions) {
- if (extension == "EGL_EXT_image_dma_buf_import") {
- has_image_dma_buf_import_ext = true;
- continue;
- } else if (extension == "EGL_EXT_image_dma_buf_import_modifiers") {
- has_image_dma_buf_import_modifiers_ext = true;
- continue;
- }
- }
-
- if (has_image_dma_buf_import_ext && has_image_dma_buf_import_modifiers_ext) {
- EglQueryDmaBufFormatsEXT = (eglQueryDmaBufFormatsEXT_func)eglGetProcAddress(
- "eglQueryDmaBufFormatsEXT");
- EglQueryDmaBufModifiersEXT =
- (eglQueryDmaBufModifiersEXT_func)eglGetProcAddress(
- "eglQueryDmaBufModifiersEXT");
- }
-
- RTC_LOG(LS_INFO) << "Egl initialization succeeded";
- egl_initialized_ = true;
-}
-
-EglDmaBuf::~EglDmaBuf() {
- if (gbm_device_) {
- gbm_device_destroy(gbm_device_);
- }
-}
-
-RTC_NO_SANITIZE("cfi-icall")
-std::unique_ptr<uint8_t[]> EglDmaBuf::ImageFromDmaBuf(const DesktopSize& size,
- uint32_t format,
- uint32_t n_planes,
- const int32_t* fds,
- const uint32_t* strides,
- const uint32_t* offsets,
- uint64_t modifier) {
- std::unique_ptr<uint8_t[]> src;
-
- if (!egl_initialized_) {
- return src;
- }
-
- if (n_planes <= 0) {
- RTC_LOG(LS_ERROR) << "Failed to process buffer: invalid number of planes";
- return src;
- }
-
- gbm_bo* imported;
- if (modifier == DRM_FORMAT_MOD_INVALID) {
- gbm_import_fd_data import_info = {fds[0],
- static_cast<uint32_t>(size.width()),
- static_cast<uint32_t>(size.height()),
- strides[0], GBM_BO_FORMAT_ARGB8888};
-
- imported = gbm_bo_import(gbm_device_, GBM_BO_IMPORT_FD, &import_info, 0);
- } else {
- gbm_import_fd_modifier_data import_info = {};
- import_info.format = GBM_BO_FORMAT_ARGB8888;
- import_info.width = static_cast<uint32_t>(size.width());
- import_info.height = static_cast<uint32_t>(size.height());
- import_info.num_fds = n_planes;
- import_info.modifier = modifier;
- for (uint32_t i = 0; i < n_planes; i++) {
- import_info.fds[i] = fds[i];
- import_info.offsets[i] = offsets[i];
- import_info.strides[i] = strides[i];
- }
-
- imported =
- gbm_bo_import(gbm_device_, GBM_BO_IMPORT_FD_MODIFIER, &import_info, 0);
- }
-
- if (!imported) {
- RTC_LOG(LS_ERROR)
- << "Failed to process buffer: Cannot import passed GBM fd - "
- << strerror(errno);
- return src;
- }
-
- // bind context to render thread
- eglMakeCurrent(egl_.display, EGL_NO_SURFACE, EGL_NO_SURFACE, egl_.context);
-
- // create EGL image from imported BO
- EGLImageKHR image = eglCreateImageKHR(
- egl_.display, nullptr, EGL_NATIVE_PIXMAP_KHR, imported, nullptr);
-
- if (image == EGL_NO_IMAGE_KHR) {
- RTC_LOG(LS_ERROR) << "Failed to record frame: Error creating EGLImageKHR - "
- << FormatGLError(glGetError());
- gbm_bo_destroy(imported);
- return src;
- }
-
- // create GL 2D texture for framebuffer
- GLuint texture;
- glGenTextures(1, &texture);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glBindTexture(GL_TEXTURE_2D, texture);
- glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
-
- src = std::make_unique<uint8_t[]>(strides[0] * size.height());
-
- GLenum gl_format = GL_BGRA;
- switch (format) {
- case SPA_VIDEO_FORMAT_RGBx:
- gl_format = GL_RGBA;
- break;
- case SPA_VIDEO_FORMAT_RGBA:
- gl_format = GL_RGBA;
- break;
- case SPA_VIDEO_FORMAT_BGRx:
- gl_format = GL_BGRA;
- break;
- case SPA_VIDEO_FORMAT_RGB:
- gl_format = GL_RGB;
- break;
- case SPA_VIDEO_FORMAT_BGR:
- gl_format = GL_BGR;
- break;
- default:
- gl_format = GL_BGRA;
- break;
- }
- glGetTexImage(GL_TEXTURE_2D, 0, gl_format, GL_UNSIGNED_BYTE, src.get());
-
- if (glGetError()) {
- RTC_LOG(LS_ERROR) << "Failed to get image from DMA buffer.";
- gbm_bo_destroy(imported);
- return src;
- }
-
- glDeleteTextures(1, &texture);
- eglDestroyImageKHR(egl_.display, image);
-
- gbm_bo_destroy(imported);
-
- return src;
-}
-
-RTC_NO_SANITIZE("cfi-icall")
-std::vector<uint64_t> EglDmaBuf::QueryDmaBufModifiers(uint32_t format) {
- if (!egl_initialized_) {
- return {};
- }
-
- // Modifiers not supported, return just DRM_FORMAT_MOD_INVALID as we can still
- // use modifier-less DMA-BUFs
- if (EglQueryDmaBufFormatsEXT == nullptr ||
- EglQueryDmaBufModifiersEXT == nullptr) {
- return {DRM_FORMAT_MOD_INVALID};
- }
-
- uint32_t drm_format = SpaPixelFormatToDrmFormat(format);
- if (drm_format == DRM_FORMAT_INVALID) {
- RTC_LOG(LS_ERROR) << "Failed to find matching DRM format.";
- return {DRM_FORMAT_MOD_INVALID};
- }
-
- EGLint count = 0;
- EGLBoolean success =
- EglQueryDmaBufFormatsEXT(egl_.display, 0, nullptr, &count);
-
- if (!success || !count) {
- RTC_LOG(LS_ERROR) << "Failed to query DMA-BUF formats.";
- return {DRM_FORMAT_MOD_INVALID};
- }
-
- std::vector<uint32_t> formats(count);
- if (!EglQueryDmaBufFormatsEXT(egl_.display, count,
- reinterpret_cast<EGLint*>(formats.data()),
- &count)) {
- RTC_LOG(LS_ERROR) << "Failed to query DMA-BUF formats.";
- return {DRM_FORMAT_MOD_INVALID};
- }
-
- if (std::find(formats.begin(), formats.end(), drm_format) == formats.end()) {
- RTC_LOG(LS_ERROR) << "Format " << drm_format
- << " not supported for modifiers.";
- return {DRM_FORMAT_MOD_INVALID};
- }
-
- success = EglQueryDmaBufModifiersEXT(egl_.display, drm_format, 0, nullptr,
- nullptr, &count);
-
- if (!success || !count) {
- RTC_LOG(LS_ERROR) << "Failed to query DMA-BUF modifiers.";
- return {DRM_FORMAT_MOD_INVALID};
- }
-
- std::vector<uint64_t> modifiers(count);
- if (!EglQueryDmaBufModifiersEXT(egl_.display, drm_format, count,
- modifiers.data(), nullptr, &count)) {
- RTC_LOG(LS_ERROR) << "Failed to query DMA-BUF modifiers.";
- }
-
- // Support modifier-less buffers
- modifiers.push_back(DRM_FORMAT_MOD_INVALID);
-
- return modifiers;
-}
-
-} // namespace webrtc
diff --git a/modules/desktop_capture/linux/egl_dmabuf.h b/modules/desktop_capture/linux/egl_dmabuf.h
deleted file mode 100644
index bfa3a0a..0000000
--- a/modules/desktop_capture/linux/egl_dmabuf.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2021 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef MODULES_DESKTOP_CAPTURE_LINUX_EGL_DMABUF_H_
-#define MODULES_DESKTOP_CAPTURE_LINUX_EGL_DMABUF_H_
-
-#include <epoxy/egl.h>
-#include <epoxy/gl.h>
-#include <gbm.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "modules/desktop_capture/desktop_geometry.h"
-
-namespace webrtc {
-
-class EglDmaBuf {
- public:
- struct EGLStruct {
- std::vector<std::string> extensions;
- EGLDisplay display = EGL_NO_DISPLAY;
- EGLContext context = EGL_NO_CONTEXT;
- };
-
- EglDmaBuf();
- ~EglDmaBuf();
-
- std::unique_ptr<uint8_t[]> ImageFromDmaBuf(const DesktopSize& size,
- uint32_t format,
- uint32_t n_planes,
- const int32_t* fds,
- const uint32_t* strides,
- const uint32_t* offsets,
- uint64_t modifiers);
- std::vector<uint64_t> QueryDmaBufModifiers(uint32_t format);
-
- bool IsEglInitialized() const { return egl_initialized_; }
-
- private:
- bool egl_initialized_ = false;
- int32_t drm_fd_ = -1; // for GBM buffer mmap
- gbm_device* gbm_device_ = nullptr; // for passed GBM buffer retrieval
-
- EGLStruct egl_;
-};
-
-} // namespace webrtc
-
-#endif // MODULES_DESKTOP_CAPTURE_LINUX_EGL_DMABUF_H_
diff --git a/modules/desktop_capture/linux/pipewire03.sigs b/modules/desktop_capture/linux/pipewire03.sigs
index debe04b..78d241f 100644
--- a/modules/desktop_capture/linux/pipewire03.sigs
+++ b/modules/desktop_capture/linux/pipewire03.sigs
@@ -16,7 +16,6 @@
// pipewire.h
void pw_init(int *argc, char **argv[]);
-const char* pw_get_library_version();
// properties.h
pw_properties * pw_properties_new_string(const char *args);
diff --git a/webrtc.gni b/webrtc.gni
index d2d0d15..a32e7bf 100644
--- a/webrtc.gni
+++ b/webrtc.gni
@@ -130,8 +130,7 @@
# By default it's only enabled on desktop Linux (excludes ChromeOS) and
# only when using the sysroot as PipeWire is not available in older and
# supported Ubuntu and Debian distributions.
- # TODO: remove !is_msan (https://bugs.chromium.org/p/webrtc/issues/detail?id=13137)
- rtc_use_pipewire = is_linux && use_sysroot && !is_msan
+ rtc_use_pipewire = is_linux && use_sysroot
# Set this to link PipeWire directly instead of using the dlopen.
rtc_link_pipewire = false