blob: 54068f92ec59f20ab38104f5b9c248ca40d80036 [file] [log] [blame] [edit]
/*
* 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_WAYLAND_EGL_DMABUF_H_
#define MODULES_DESKTOP_CAPTURE_LINUX_WAYLAND_EGL_DMABUF_H_
#include <EGL/egl.h>
#include <EGL/eglplatform.h>
#include <GL/gl.h>
#include <gbm.h>
#include <cstdint>
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include "modules/desktop_capture/desktop_geometry.h"
#include "rtc_base/containers/flat_map.h"
#include "rtc_base/containers/flat_set.h"
#include "rtc_base/synchronization/mutex.h"
#include "rtc_base/thread_annotations.h"
namespace webrtc {
constexpr dev_t DEVICE_ID_INVALID = static_cast<dev_t>(0);
class EglDrmDevice {
public:
struct EGLStruct {
std::vector<std::string> extensions;
EGLDisplay display = EGL_NO_DISPLAY;
EGLContext context = EGL_NO_CONTEXT;
};
struct PlaneData {
int32_t fd;
uint32_t stride;
uint32_t offset;
};
EglDrmDevice(EGLDisplay display, dev_t device_id = DEVICE_ID_INVALID);
EglDrmDevice(std::string render_node, dev_t device_id = DEVICE_ID_INVALID);
virtual ~EglDrmDevice();
bool EnsureInitialized();
bool IsInitialized() const { return initialized_; }
dev_t GetDeviceId() const { return device_id_; }
virtual bool ImageFromDmaBuf(const DesktopSize& size,
uint32_t format,
const std::vector<PlaneData>& plane_datas,
uint64_t modifiers,
const DesktopVector& offset,
const DesktopSize& buffer_size,
uint8_t* data);
virtual std::vector<uint64_t> QueryDmaBufModifiers(uint32_t format);
void MarkModifierFailed(uint32_t format, uint64_t modifier);
void MarkModifierFailed(uint64_t modifier);
private:
friend class TestEglDrmDevice;
EGLStruct egl_;
bool initialized_ = false;
bool has_image_dma_buf_import_ext_ = false;
dev_t device_id_ = DEVICE_ID_INVALID;
struct GbmDeviceDeleter {
void operator()(gbm_device* device) const {
if (device) {
gbm_device_destroy(device);
}
}
};
std::unique_ptr<gbm_device, GbmDeviceDeleter> gbm_device_;
int32_t drm_fd_ = -1;
std::string render_node_;
GLuint fbo_ = 0;
GLuint texture_ = 0;
// Map of format -> failed modifiers that didn't work during import
// The lock is needed for concurrent read/write in case a frame import
// fails, we started to negotiate a new format, but meanwhile can still
// receive a new frame and fail again, leading to again marking modifier
// as failed.
Mutex failed_modifiers_lock_;
flat_map<uint32_t, flat_set<uint64_t>> failed_modifiers_
RTC_GUARDED_BY(failed_modifiers_lock_);
};
// Base class for EGL DMA-BUF implementations.
// Provides shared device management logic for both real and test
// implementations.
class EglDmaBuf {
public:
static std::unique_ptr<EglDmaBuf> CreateDefault();
virtual ~EglDmaBuf() = default;
// Returns the DRM device to use for querying DMA-BUF modifiers and importing
// frames. Device selection follows this priority order:
//
// 1. Platform device - created from Wayland platform EGL display during
// initialization if EGL platform extensions are available
// 2. First enumerated device - fallback if platform device creation fails,
// uses EGL device enumeration to discover available DRM devices
// 3. nullptr - if no devices are available
EglDrmDevice* GetRenderDevice();
// Returns the DRM device given the id or nullptr in case the device is not
// found
EglDrmDevice* GetRenderDevice(dev_t id);
std::vector<dev_t> GetDevices() const;
bool SetPreferredRenderDevice(dev_t device_id);
protected:
EglDmaBuf() = default;
// Initializes EGL/DRM devices.
// Returns true if at least one device is available, false otherwise.
virtual bool Initialize();
private:
friend class TestEglDmaBuf;
bool CreatePlatformDevice();
void EnumerateDrmDevices();
std::map<dev_t, std::unique_ptr<EglDrmDevice>> devices_;
std::unique_ptr<EglDrmDevice> default_platform_device_;
dev_t preferred_render_device_id_ = DEVICE_ID_INVALID;
};
} // namespace webrtc
#endif // MODULES_DESKTOP_CAPTURE_LINUX_WAYLAND_EGL_DMABUF_H_