mirror of
https://repo.dec05eba.com/gpu-screen-recorder
synced 2026-04-24 18:42:57 +09:00
Fix deskto portal capture on nvidia (add missing modifiers)
This commit is contained in:
@@ -31,7 +31,6 @@ typedef void* EGLSurface;
|
|||||||
typedef void* EGLContext;
|
typedef void* EGLContext;
|
||||||
typedef void* EGLClientBuffer;
|
typedef void* EGLClientBuffer;
|
||||||
typedef void* EGLImage;
|
typedef void* EGLImage;
|
||||||
typedef void* EGLImageKHR;
|
|
||||||
typedef void *GLeglImageOES;
|
typedef void *GLeglImageOES;
|
||||||
typedef void (*__eglMustCastToProperFunctionPointerType)(void);
|
typedef void (*__eglMustCastToProperFunctionPointerType)(void);
|
||||||
typedef struct __GLXFBConfigRec *GLXFBConfig;
|
typedef struct __GLXFBConfigRec *GLXFBConfig;
|
||||||
@@ -122,8 +121,6 @@ typedef void(*__GLXextFuncPtr)(void);
|
|||||||
#define GL_COMPILE_STATUS 0x8B81
|
#define GL_COMPILE_STATUS 0x8B81
|
||||||
#define GL_LINK_STATUS 0x8B82
|
#define GL_LINK_STATUS 0x8B82
|
||||||
|
|
||||||
typedef unsigned int (*FUNC_eglExportDMABUFImageQueryMESA)(EGLDisplay dpy, EGLImageKHR image, int *fourcc, int *num_planes, uint64_t *modifiers);
|
|
||||||
typedef unsigned int (*FUNC_eglExportDMABUFImageMESA)(EGLDisplay dpy, EGLImageKHR image, int *fds, int32_t *strides, int32_t *offsets);
|
|
||||||
typedef void (*FUNC_glEGLImageTargetTexture2DOES)(unsigned int target, GLeglImageOES image);
|
typedef void (*FUNC_glEGLImageTargetTexture2DOES)(unsigned int target, GLeglImageOES image);
|
||||||
typedef GLXContext (*FUNC_glXCreateContextAttribsARB)(Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list);
|
typedef GLXContext (*FUNC_glXCreateContextAttribsARB)(Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list);
|
||||||
typedef void (*FUNC_glXSwapIntervalEXT)(Display * dpy, GLXDrawable drawable, int interval);
|
typedef void (*FUNC_glXSwapIntervalEXT)(Display * dpy, GLXDrawable drawable, int interval);
|
||||||
@@ -132,6 +129,7 @@ typedef int (*FUNC_glXSwapIntervalSGI)(int interval);
|
|||||||
typedef void (*GLDEBUGPROC)(unsigned int source, unsigned int type, unsigned int id, unsigned int severity, int length, const char *message, const void *userParam);
|
typedef void (*GLDEBUGPROC)(unsigned int source, unsigned int type, unsigned int id, unsigned int severity, int length, const char *message, const void *userParam);
|
||||||
typedef int (*FUNC_eglQueryDisplayAttribEXT)(EGLDisplay dpy, int32_t attribute, intptr_t *value);
|
typedef int (*FUNC_eglQueryDisplayAttribEXT)(EGLDisplay dpy, int32_t attribute, intptr_t *value);
|
||||||
typedef const char* (*FUNC_eglQueryDeviceStringEXT)(void *device, int32_t name);
|
typedef const char* (*FUNC_eglQueryDeviceStringEXT)(void *device, int32_t name);
|
||||||
|
typedef int (*FUNC_eglQueryDmaBufModifiersEXT)(EGLDisplay dpy, int32_t format, int32_t max_modifiers, uint64_t *modifiers, int *external_only, int32_t *num_modifiers);
|
||||||
|
|
||||||
#define GSR_MAX_OUTPUTS 32
|
#define GSR_MAX_OUTPUTS 32
|
||||||
|
|
||||||
@@ -203,11 +201,10 @@ struct gsr_egl {
|
|||||||
unsigned int (*eglBindAPI)(unsigned int api);
|
unsigned int (*eglBindAPI)(unsigned int api);
|
||||||
__eglMustCastToProperFunctionPointerType (*eglGetProcAddress)(const char *procname);
|
__eglMustCastToProperFunctionPointerType (*eglGetProcAddress)(const char *procname);
|
||||||
|
|
||||||
FUNC_eglExportDMABUFImageQueryMESA eglExportDMABUFImageQueryMESA;
|
|
||||||
FUNC_eglExportDMABUFImageMESA eglExportDMABUFImageMESA;
|
|
||||||
FUNC_glEGLImageTargetTexture2DOES glEGLImageTargetTexture2DOES;
|
FUNC_glEGLImageTargetTexture2DOES glEGLImageTargetTexture2DOES;
|
||||||
FUNC_eglQueryDisplayAttribEXT eglQueryDisplayAttribEXT;
|
FUNC_eglQueryDisplayAttribEXT eglQueryDisplayAttribEXT;
|
||||||
FUNC_eglQueryDeviceStringEXT eglQueryDeviceStringEXT;
|
FUNC_eglQueryDeviceStringEXT eglQueryDeviceStringEXT;
|
||||||
|
FUNC_eglQueryDmaBufModifiersEXT eglQueryDmaBufModifiersEXT;
|
||||||
|
|
||||||
__GLXextFuncPtr (*glXGetProcAddress)(const unsigned char *procName);
|
__GLXextFuncPtr (*glXGetProcAddress)(const unsigned char *procName);
|
||||||
GLXFBConfig* (*glXChooseFBConfig)(Display *dpy, int screen, const int *attribList, int *nitems);
|
GLXFBConfig* (*glXChooseFBConfig)(Display *dpy, int screen, const int *attribList, int *nitems);
|
||||||
|
|||||||
@@ -232,6 +232,7 @@ static bool hdr_metadata_is_supported_format(const struct hdr_output_metadata *h
|
|||||||
hdr_metadata->hdmi_metadata_type1.eotf == HDMI_EOTF_SMPTE_ST2084;
|
hdr_metadata->hdmi_metadata_type1.eotf == HDMI_EOTF_SMPTE_ST2084;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Check if this hdr data can be changed after the call to av_packet_side_data_add
|
||||||
static void gsr_kms_set_hdr_metadata(gsr_capture_kms *self, AVStream *video_stream, gsr_kms_response_fd *drm_fd) {
|
static void gsr_kms_set_hdr_metadata(gsr_capture_kms *self, AVStream *video_stream, gsr_kms_response_fd *drm_fd) {
|
||||||
if(self->hdr_metadata_set)
|
if(self->hdr_metadata_set)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -133,16 +133,6 @@ static int gsr_capture_xcomposite_start(gsr_capture *cap, AVCodecContext *video_
|
|||||||
// TODO: Get select and add these on top of it and then restore at the end. Also do the same in other xcomposite
|
// TODO: Get select and add these on top of it and then restore at the end. Also do the same in other xcomposite
|
||||||
XSelectInput(self->params.egl->x11.dpy, self->window, StructureNotifyMask | ExposureMask);
|
XSelectInput(self->params.egl->x11.dpy, self->window, StructureNotifyMask | ExposureMask);
|
||||||
|
|
||||||
if(!self->params.egl->eglExportDMABUFImageQueryMESA) {
|
|
||||||
fprintf(stderr, "gsr error: gsr_capture_xcomposite_start: could not find eglExportDMABUFImageQueryMESA\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!self->params.egl->eglExportDMABUFImageMESA) {
|
|
||||||
fprintf(stderr, "gsr error: gsr_capture_xcomposite_start: could not find eglExportDMABUFImageMESA\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Disable vsync */
|
/* Disable vsync */
|
||||||
self->params.egl->eglSwapInterval(self->params.egl->egl_display, 0);
|
self->params.egl->eglSwapInterval(self->params.egl->egl_display, 0);
|
||||||
if(window_texture_init(&self->window_texture, self->params.egl->x11.dpy, self->window, self->params.egl) != 0 && !self->params.follow_focused) {
|
if(window_texture_init(&self->window_texture, self->params.egl->x11.dpy, self->window, self->params.egl) != 0 && !self->params.follow_focused) {
|
||||||
|
|||||||
@@ -358,11 +358,10 @@ static bool gsr_egl_load_egl(gsr_egl *self, void *library) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool gsr_egl_proc_load_egl(gsr_egl *self) {
|
static bool gsr_egl_proc_load_egl(gsr_egl *self) {
|
||||||
self->eglExportDMABUFImageQueryMESA = (FUNC_eglExportDMABUFImageQueryMESA)self->eglGetProcAddress("eglExportDMABUFImageQueryMESA");
|
|
||||||
self->eglExportDMABUFImageMESA = (FUNC_eglExportDMABUFImageMESA)self->eglGetProcAddress("eglExportDMABUFImageMESA");
|
|
||||||
self->glEGLImageTargetTexture2DOES = (FUNC_glEGLImageTargetTexture2DOES)self->eglGetProcAddress("glEGLImageTargetTexture2DOES");
|
self->glEGLImageTargetTexture2DOES = (FUNC_glEGLImageTargetTexture2DOES)self->eglGetProcAddress("glEGLImageTargetTexture2DOES");
|
||||||
self->eglQueryDisplayAttribEXT = (FUNC_eglQueryDisplayAttribEXT)self->eglGetProcAddress("eglQueryDisplayAttribEXT");
|
self->eglQueryDisplayAttribEXT = (FUNC_eglQueryDisplayAttribEXT)self->eglGetProcAddress("eglQueryDisplayAttribEXT");
|
||||||
self->eglQueryDeviceStringEXT = (FUNC_eglQueryDeviceStringEXT)self->eglGetProcAddress("eglQueryDeviceStringEXT");
|
self->eglQueryDeviceStringEXT = (FUNC_eglQueryDeviceStringEXT)self->eglGetProcAddress("eglQueryDeviceStringEXT");
|
||||||
|
self->eglQueryDmaBufModifiersEXT = (FUNC_eglQueryDmaBufModifiersEXT)self->eglGetProcAddress("eglQueryDmaBufModifiersEXT");
|
||||||
|
|
||||||
if(!self->glEGLImageTargetTexture2DOES) {
|
if(!self->glEGLImageTargetTexture2DOES) {
|
||||||
fprintf(stderr, "gsr error: gsr_egl_load failed: could not find glEGLImageTargetTexture2DOES\n");
|
fprintf(stderr, "gsr error: gsr_egl_load failed: could not find glEGLImageTargetTexture2DOES\n");
|
||||||
|
|||||||
@@ -313,7 +313,7 @@ static inline struct spa_pod *build_format(struct spa_pod_builder *b,
|
|||||||
return spa_pod_builder_pop(b, &format_frame);
|
return spa_pod_builder_pop(b, &format_frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define NUM_FORMATS 10
|
#define NUM_VIDEO_FORMATS 10
|
||||||
|
|
||||||
/* https://gstreamer.freedesktop.org/documentation/additional/design/mediatype-video-raw.html?gi-language=c#formats */
|
/* https://gstreamer.freedesktop.org/documentation/additional/design/mediatype-video-raw.html?gi-language=c#formats */
|
||||||
/* For some reason gstreamer formats are in opposite order to drm formats */
|
/* For some reason gstreamer formats are in opposite order to drm formats */
|
||||||
@@ -334,28 +334,56 @@ static int64_t spa_video_format_to_drm_format(const enum spa_video_format format
|
|||||||
return DRM_FORMAT_INVALID;
|
return DRM_FORMAT_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const enum spa_video_format supported_video_formats[] = {
|
||||||
|
SPA_VIDEO_FORMAT_BGRx,
|
||||||
|
SPA_VIDEO_FORMAT_BGRA,
|
||||||
|
SPA_VIDEO_FORMAT_ABGR,
|
||||||
|
SPA_VIDEO_FORMAT_xBGR,
|
||||||
|
SPA_VIDEO_FORMAT_BGR,
|
||||||
|
SPA_VIDEO_FORMAT_RGBx,
|
||||||
|
SPA_VIDEO_FORMAT_xRGB,
|
||||||
|
SPA_VIDEO_FORMAT_RGBA,
|
||||||
|
SPA_VIDEO_FORMAT_ARGB,
|
||||||
|
SPA_VIDEO_FORMAT_RGB,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void spa_video_format_get_modifiers(gsr_pipewire *self, const enum spa_video_format format, uint64_t *modifiers, int32_t max_modifiers, int32_t *num_modifiers) {
|
||||||
|
*num_modifiers = 0;
|
||||||
|
|
||||||
|
if(!self->egl->eglQueryDmaBufModifiersEXT) {
|
||||||
|
fprintf(stderr, "gsr error: spa_video_format_get_modifiers: failed to initialize modifiers because eglQueryDmaBufModifiersEXT is not available\n");
|
||||||
|
modifiers[0] = DRM_FORMAT_MOD_LINEAR;
|
||||||
|
modifiers[1] = DRM_FORMAT_MOD_INVALID;
|
||||||
|
*num_modifiers = 2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int64_t drm_format = spa_video_format_to_drm_format(format);
|
||||||
|
if(!self->egl->eglQueryDmaBufModifiersEXT(self->egl->egl_display, drm_format, max_modifiers, modifiers, NULL, num_modifiers)) {
|
||||||
|
fprintf(stderr, "gsr error: spa_video_format_get_modifiers: eglQueryDmaBufModifiersEXT failed with drm format %" PRIi64 "\n", drm_format);
|
||||||
|
modifiers[0] = DRM_FORMAT_MOD_LINEAR;
|
||||||
|
modifiers[1] = DRM_FORMAT_MOD_INVALID;
|
||||||
|
*num_modifiers = 2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(*num_modifiers + 2 <= max_modifiers) {
|
||||||
|
modifiers[*num_modifiers + 0] = DRM_FORMAT_MOD_LINEAR;
|
||||||
|
modifiers[*num_modifiers + 1] = DRM_FORMAT_MOD_INVALID;
|
||||||
|
*num_modifiers += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static bool gsr_pipewire_build_format_params(gsr_pipewire *self, struct spa_pod_builder *pod_builder, struct spa_pod **params) {
|
static bool gsr_pipewire_build_format_params(gsr_pipewire *self, struct spa_pod_builder *pod_builder, struct spa_pod **params) {
|
||||||
if(!check_pw_version(&self->server_version, 0, 3, 33))
|
if(!check_pw_version(&self->server_version, 0, 3, 33))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const enum spa_video_format formats[] = {
|
uint64_t modifiers[1024];
|
||||||
SPA_VIDEO_FORMAT_RGBx,
|
int32_t num_modifiers = 0;
|
||||||
SPA_VIDEO_FORMAT_BGRx,
|
for(size_t i = 0; i < NUM_VIDEO_FORMATS; i++) {
|
||||||
SPA_VIDEO_FORMAT_xRGB,
|
const enum spa_video_format format = supported_video_formats[i];
|
||||||
SPA_VIDEO_FORMAT_xBGR,
|
spa_video_format_get_modifiers(self, format, modifiers, sizeof(modifiers), &num_modifiers);
|
||||||
SPA_VIDEO_FORMAT_RGBA,
|
params[i] = build_format(pod_builder, &self->video_info, format, modifiers, num_modifiers);
|
||||||
SPA_VIDEO_FORMAT_BGRA,
|
|
||||||
SPA_VIDEO_FORMAT_ARGB,
|
|
||||||
SPA_VIDEO_FORMAT_ABGR,
|
|
||||||
SPA_VIDEO_FORMAT_RGB,
|
|
||||||
SPA_VIDEO_FORMAT_BGR,
|
|
||||||
};
|
|
||||||
|
|
||||||
const uint64_t modifiers[] = { DRM_FORMAT_MOD_LINEAR, DRM_FORMAT_MOD_INVALID };
|
|
||||||
|
|
||||||
for (size_t i = 0; i < NUM_FORMATS; i++) {
|
|
||||||
enum spa_video_format format = formats[i];
|
|
||||||
params[i] = build_format(pod_builder, &self->video_info, format, modifiers, 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -367,7 +395,7 @@ static void renegotiate_format(void *data, uint64_t expirations) {
|
|||||||
|
|
||||||
pw_thread_loop_lock(self->thread_loop);
|
pw_thread_loop_lock(self->thread_loop);
|
||||||
|
|
||||||
struct spa_pod *params[NUM_FORMATS];
|
struct spa_pod *params[NUM_VIDEO_FORMATS];
|
||||||
uint8_t params_buffer[2048];
|
uint8_t params_buffer[2048];
|
||||||
struct spa_pod_builder pod_builder = SPA_POD_BUILDER_INIT(params_buffer, sizeof(params_buffer));
|
struct spa_pod_builder pod_builder = SPA_POD_BUILDER_INIT(params_buffer, sizeof(params_buffer));
|
||||||
if (!gsr_pipewire_build_format_params(self, &pod_builder, params)) {
|
if (!gsr_pipewire_build_format_params(self, &pod_builder, params)) {
|
||||||
@@ -375,12 +403,12 @@ static void renegotiate_format(void *data, uint64_t expirations) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pw_stream_update_params(self->stream, (const struct spa_pod**)params, NUM_FORMATS);
|
pw_stream_update_params(self->stream, (const struct spa_pod**)params, NUM_VIDEO_FORMATS);
|
||||||
pw_thread_loop_unlock(self->thread_loop);
|
pw_thread_loop_unlock(self->thread_loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool gsr_pipewire_setup_stream(gsr_pipewire *self) {
|
static bool gsr_pipewire_setup_stream(gsr_pipewire *self) {
|
||||||
struct spa_pod *params[NUM_FORMATS];
|
struct spa_pod *params[NUM_VIDEO_FORMATS];
|
||||||
uint8_t params_buffer[2048];
|
uint8_t params_buffer[2048];
|
||||||
struct spa_pod_builder pod_builder = SPA_POD_BUILDER_INIT(params_buffer, sizeof(params_buffer));
|
struct spa_pod_builder pod_builder = SPA_POD_BUILDER_INIT(params_buffer, sizeof(params_buffer));
|
||||||
|
|
||||||
@@ -445,7 +473,7 @@ static bool gsr_pipewire_setup_stream(gsr_pipewire *self) {
|
|||||||
if(pw_stream_connect(
|
if(pw_stream_connect(
|
||||||
self->stream, PW_DIRECTION_INPUT, self->node,
|
self->stream, PW_DIRECTION_INPUT, self->node,
|
||||||
PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_MAP_BUFFERS, (const struct spa_pod**)params,
|
PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_MAP_BUFFERS, (const struct spa_pod**)params,
|
||||||
NUM_FORMATS) < 0)
|
NUM_VIDEO_FORMATS) < 0)
|
||||||
{
|
{
|
||||||
pw_thread_loop_unlock(self->thread_loop);
|
pw_thread_loop_unlock(self->thread_loop);
|
||||||
fprintf(stderr, "gsr error: gsr_pipewire_setup_stream: failed to connect stream\n");
|
fprintf(stderr, "gsr error: gsr_pipewire_setup_stream: failed to connect stream\n");
|
||||||
|
|||||||
Reference in New Issue
Block a user