diff --git a/modules/desktop_capture/BUILD.gn b/modules/desktop_capture/BUILD.gn index 6248ccbfc2..d2b4eea652 100644 --- a/modules/desktop_capture/BUILD.gn +++ b/modules/desktop_capture/BUILD.gn @@ -225,19 +225,6 @@ if (is_linux || is_chromeos) { } } - 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,18 +542,12 @@ rtc_library("desktop_capture_generic") { 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) { diff --git a/modules/desktop_capture/DEPS b/modules/desktop_capture/DEPS index 033d318a9a..8c894c4430 100644 --- a/modules/desktop_capture/DEPS +++ b/modules/desktop_capture/DEPS @@ -13,9 +13,6 @@ specific_include_rules = { "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 263c8a647d..7212ad383e 100644 --- a/modules/desktop_capture/linux/base_capturer_pipewire.cc +++ b/modules/desktop_capture/linux/base_capturer_pipewire.cc @@ -14,13 +14,12 @@ #include #include #include + #include #include #include -#include #include -#include #include #include "absl/memory/memory.h" @@ -52,102 +51,65 @@ const int kBytesPerPixel = 4; 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& 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_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(MAP_FAILED); + unsigned char* map_ = nullptr; int map_size_; + bool is_dma_buf_; int fd_; }; @@ -272,26 +234,17 @@ void BaseCapturerPipeWire::OnStreamParamChanged(void* data, 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_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_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 @@ BaseCapturerPipeWire::~BaseCapturerPipeWire() { } } -#if PW_CHECK_VERSION(0, 3, 0) -void BaseCapturerPipeWire::InitEGL() { - egl_dmabuf_ = std::make_unique(); -} -#endif - void BaseCapturerPipeWire::InitPortal() { cancellable_ = g_cancellable_new(); g_dbus_proxy_new_for_bus( @@ -472,39 +419,34 @@ void BaseCapturerPipeWire::InitPipeWire() { } 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 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 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_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 @@ pw_stream* BaseCapturerPipeWire::CreateReceivingStream() { } void BaseCapturerPipeWire::HandleBuffer(pw_buffer* buffer) { - spa_buffer* spa_buffer = buffer->buffer; + spa_buffer* spaBuffer = buffer->buffer; ScopedBuf map; - std::unique_ptr 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 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( 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 @@ void BaseCapturerPipeWire::HandleBuffer(pw_buffer* buffer) { 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(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(spaBuffer->datas[0].data); } if (!src) { @@ -568,7 +497,7 @@ void BaseCapturerPipeWire::HandleBuffer(pw_buffer* buffer) { struct spa_meta_region* video_metadata = static_cast(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 @@ void BaseCapturerPipeWire::HandleBuffer(pw_buffer* buffer) { // 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 @@ void BaseCapturerPipeWire::HandleBuffer(pw_buffer* buffer) { } 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 @@ void BaseCapturerPipeWire::OnOpenPipeWireRemoteRequested( 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 8f9b61dc04..7ec5ea6950 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 @@ class BaseCapturerPipeWire : public DesktopCapturer { 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 @@ class BaseCapturerPipeWire : public DesktopCapturer { bool portal_init_failed_ = false; - std::unique_ptr 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 6bc148666c..0000000000 --- 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 -#include -#include -#include -#include -#include -#include - -#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 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 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 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 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 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(size.width()), - static_cast(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(size.width()); - import_info.height = static_cast(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(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 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 formats(count); - if (!EglQueryDmaBufFormatsEXT(egl_.display, count, - reinterpret_cast(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 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 bfa3a0a71c..0000000000 --- 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 -#include -#include - -#include -#include -#include - -#include "modules/desktop_capture/desktop_geometry.h" - -namespace webrtc { - -class EglDmaBuf { - public: - struct EGLStruct { - std::vector extensions; - EGLDisplay display = EGL_NO_DISPLAY; - EGLContext context = EGL_NO_CONTEXT; - }; - - EglDmaBuf(); - ~EglDmaBuf(); - - std::unique_ptr 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 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 debe04bbdc..78d241f40c 100644 --- a/modules/desktop_capture/linux/pipewire03.sigs +++ b/modules/desktop_capture/linux/pipewire03.sigs @@ -16,7 +16,6 @@ pw_loop * pw_loop_new(const spa_dict *props); // 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 d2d0d15bd2..a32e7bfc44 100644 --- a/webrtc.gni +++ b/webrtc.gni @@ -130,8 +130,7 @@ declare_args() { # 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