diff options
Diffstat (limited to 'src/utils.c')
-rw-r--r-- | src/utils.c | 467 |
1 files changed, 431 insertions, 36 deletions
diff --git a/src/utils.c b/src/utils.c index e00f3c5..6fe5904 100644 --- a/src/utils.c +++ b/src/utils.c @@ -1,13 +1,23 @@ #include "../include/utils.h" + #include <time.h> #include <string.h> #include <stdio.h> #include <unistd.h> #include <fcntl.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <errno.h> +#include <assert.h> + #include <xf86drmMode.h> #include <xf86drm.h> -#include <stdlib.h> +#include <libdrm/drm_fourcc.h> #include <X11/Xatom.h> +#include <X11/extensions/Xrandr.h> +#include <va/va_drmcommon.h> +#include <libavcodec/avcodec.h> +#include <libavutil/hwcontext_vaapi.h> double clock_get_monotonic_seconds(void) { struct timespec ts; @@ -17,6 +27,16 @@ double clock_get_monotonic_seconds(void) { return (double)ts.tv_sec + (double)ts.tv_nsec * 0.000000001; } +static gsr_monitor_rotation wayland_transform_to_gsr_rotation(int32_t rot) { + switch(rot) { + case 0: return GSR_MONITOR_ROT_0; + case 1: return GSR_MONITOR_ROT_90; + case 2: return GSR_MONITOR_ROT_180; + case 3: return GSR_MONITOR_ROT_270; + } + return GSR_MONITOR_ROT_0; +} + static const XRRModeInfo* get_mode_info(const XRRScreenResources *sr, RRMode id) { for(int i = 0; i < sr->nmode; ++i) { if(sr->modes[i].id == id) @@ -35,16 +55,6 @@ static gsr_monitor_rotation x11_rotation_to_gsr_rotation(int rot) { return GSR_MONITOR_ROT_0; } -static gsr_monitor_rotation wayland_transform_to_gsr_rotation(int32_t rot) { - switch(rot) { - case 0: return GSR_MONITOR_ROT_0; - case 1: return GSR_MONITOR_ROT_90; - case 2: return GSR_MONITOR_ROT_180; - case 3: return GSR_MONITOR_ROT_270; - } - return GSR_MONITOR_ROT_0; -} - static uint32_t x11_output_get_connector_id(Display *dpy, RROutput output, Atom randr_connector_id_atom) { Atom type = 0; int format = 0; @@ -61,7 +71,7 @@ static uint32_t x11_output_get_connector_id(Display *dpy, RROutput output, Atom return result; } -void for_each_active_monitor_output_x11(Display *display, active_monitor_callback callback, void *userdata) { +void for_each_active_monitor_output_x11_not_cached(Display *display, active_monitor_callback callback, void *userdata) { XRRScreenResources *screen_res = XRRGetScreenResources(display, DefaultRootWindow(display)); if(!screen_res) return; @@ -76,18 +86,15 @@ void for_each_active_monitor_output_x11(Display *display, active_monitor_callbac if(crt_info && crt_info->mode) { const XRRModeInfo *mode_info = get_mode_info(screen_res, crt_info->mode); if(mode_info && out_info->nameLen < (int)sizeof(display_name)) { - memcpy(display_name, out_info->name, out_info->nameLen); - display_name[out_info->nameLen] = '\0'; - + snprintf(display_name, sizeof(display_name), "%.*s", (int)out_info->nameLen, out_info->name); const gsr_monitor monitor = { .name = display_name, .name_len = out_info->nameLen, .pos = { .x = crt_info->x, .y = crt_info->y }, .size = { .x = (int)crt_info->width, .y = (int)crt_info->height }, - .crt_info = crt_info, .connector_id = x11_output_get_connector_id(display, screen_res->outputs[i], randr_connector_id_atom), .rotation = x11_rotation_to_gsr_rotation(crt_info->rotation), - .monitor_identifier = 0 + .monitor_identifier = out_info->crtc }; callback(&monitor, userdata); } @@ -102,6 +109,22 @@ void for_each_active_monitor_output_x11(Display *display, active_monitor_callbac XRRFreeScreenResources(screen_res); } +void for_each_active_monitor_output_x11(const gsr_egl *egl, active_monitor_callback callback, void *userdata) { + for(int i = 0; i < egl->x11.num_outputs; ++i) { + const gsr_x11_output *output = &egl->x11.outputs[i]; + const gsr_monitor monitor = { + .name = output->name, + .name_len = strlen(output->name), + .pos = output->pos, + .size = output->size, + .connector_id = output->connector_id, + .rotation = output->rotation, + .monitor_identifier = output->monitor_identifier + }; + callback(&monitor, userdata); + } +} + typedef struct { int type; int count; @@ -142,7 +165,7 @@ static bool connector_get_property_by_name(int drmfd, drmModeConnectorPtr props, return false; } -/* TODO: Support more connector types*/ +/* TODO: Support more connector types */ static int get_connector_type_by_name(const char *name) { int len = strlen(name); if(len >= 5 && strncmp(name, "HDMI-", 5) == 0) @@ -185,7 +208,6 @@ static void for_each_active_monitor_output_wayland(const gsr_egl *egl, active_mo .name_len = strlen(output->name), .pos = { .x = output->pos.x, .y = output->pos.y }, .size = { .x = output->size.x, .y = output->size.y }, - .crt_info = NULL, .connector_id = 0, .rotation = wayland_transform_to_gsr_rotation(output->transform), .monitor_identifier = connector_type ? monitor_identifier_from_type_and_count(connector_type_index, connector_type->count_active) : 0 @@ -233,12 +255,11 @@ static void for_each_active_monitor_output_drm(const gsr_egl *egl, active_monito if(connector_type && crtc_id > 0 && crtc && connection_name_len + 5 < (int)sizeof(display_name)) { const int display_name_len = snprintf(display_name, sizeof(display_name), "%s-%d", connection_name, connector_type->count); const int connector_type_index_name = get_connector_type_by_name(display_name); - const gsr_monitor monitor = { + gsr_monitor monitor = { .name = display_name, .name_len = display_name_len, .pos = { .x = crtc->x, .y = crtc->y }, .size = { .x = (int)crtc->width, .y = (int)crtc->height }, - .crt_info = NULL, .connector_id = connector->connector_id, .rotation = GSR_MONITOR_ROT_0, .monitor_identifier = connector_type_index_name != -1 ? monitor_identifier_from_type_and_count(connector_type_index_name, connector_type->count_active) : 0 @@ -260,7 +281,7 @@ static void for_each_active_monitor_output_drm(const gsr_egl *egl, active_monito void for_each_active_monitor_output(const gsr_egl *egl, gsr_connection_type connection_type, active_monitor_callback callback, void *userdata) { switch(connection_type) { case GSR_CONNECTION_X11: - for_each_active_monitor_output_x11(egl->x11.dpy, callback, userdata); + for_each_active_monitor_output_x11(egl, callback, userdata); break; case GSR_CONNECTION_WAYLAND: for_each_active_monitor_output_wayland(egl, callback, userdata); @@ -322,7 +343,7 @@ static void get_monitor_by_connector_id_callback(const gsr_monitor *monitor, voi } gsr_monitor_rotation drm_monitor_get_display_server_rotation(const gsr_egl *egl, const gsr_monitor *monitor) { - if(egl->wayland.dpy) { + if(gsr_egl_get_display_server(egl) == GSR_DISPLAY_SERVER_WAYLAND) { { get_monitor_by_connector_id_userdata userdata; userdata.monitor = monitor; @@ -345,7 +366,7 @@ gsr_monitor_rotation drm_monitor_get_display_server_rotation(const gsr_egl *egl, userdata.monitor = monitor; userdata.rotation = GSR_MONITOR_ROT_0; userdata.match_found = false; - for_each_active_monitor_output_x11(egl->x11.dpy, get_monitor_by_connector_id_callback, &userdata); + for_each_active_monitor_output_x11(egl, get_monitor_by_connector_id_callback, &userdata); return userdata.rotation; } @@ -359,6 +380,7 @@ bool gl_get_gpu_info(gsr_egl *egl, gsr_gpu_info *info) { const unsigned char *gl_renderer = egl->glGetString(GL_RENDERER); info->gpu_version = 0; + info->is_steam_deck = false; if(!gl_vendor) { fprintf(stderr, "gsr error: failed to get gpu vendor\n"); @@ -391,6 +413,7 @@ bool gl_get_gpu_info(gsr_egl *egl, gsr_gpu_info *info) { if(gl_renderer) { if(info->vendor == GSR_GPU_VENDOR_NVIDIA) sscanf((const char*)gl_renderer, "%*s %*s %*s %d", &info->gpu_version); + info->is_steam_deck = strstr((const char*)gl_renderer, "vangogh") != NULL; } end: @@ -441,23 +464,14 @@ static bool try_card_has_valid_plane(const char *card_path) { return false; } -static void string_copy(char *dst, const char *src, int len) { - int src_len = strlen(src); - int min_len = src_len; - if(len - 1 < min_len) - min_len = len - 1; - memcpy(dst, src, min_len); - dst[min_len] = '\0'; -} - bool gsr_get_valid_card_path(gsr_egl *egl, char *output, bool is_monitor_capture) { if(egl->dri_card_path) { - string_copy(output, egl->dri_card_path, 127); + snprintf(output, 128, "%s", egl->dri_card_path); return is_monitor_capture ? try_card_has_valid_plane(output) : true; } for(int i = 0; i < 10; ++i) { - snprintf(output, 127, DRM_DEV_NAME, DRM_DIR_NAME, i); + snprintf(output, 128, DRM_DEV_NAME, DRM_DIR_NAME, i); if(try_card_has_valid_plane(output)) return true; } @@ -471,7 +485,7 @@ bool gsr_card_path_get_render_path(const char *card_path, char *render_path) { char *render_path_tmp = drmGetRenderDeviceNameFromFd(fd); if(render_path_tmp) { - string_copy(render_path, render_path_tmp, 127); + snprintf(render_path, 128, "%s", render_path_tmp); free(render_path_tmp); close(fd); return true; @@ -480,3 +494,384 @@ bool gsr_card_path_get_render_path(const char *card_path, char *render_path) { close(fd); return false; } + +int create_directory_recursive(char *path) { + int path_len = strlen(path); + char *p = path; + char *end = path + path_len; + for(;;) { + char *slash_p = strchr(p, '/'); + + // Skips first '/', we don't want to try and create the root directory + if(slash_p == path) { + ++p; + continue; + } + + if(!slash_p) + slash_p = end; + + char prev_char = *slash_p; + *slash_p = '\0'; + int err = mkdir(path, S_IRWXU); + *slash_p = prev_char; + + if(err == -1 && errno != EEXIST) + return err; + + if(slash_p == end) + break; + else + p = slash_p + 1; + } + return 0; +} + +void setup_dma_buf_attrs(intptr_t *img_attr, uint32_t format, uint32_t width, uint32_t height, const int *fds, const uint32_t *offsets, const uint32_t *pitches, const uint64_t *modifiers, int num_planes, bool use_modifier) { + size_t img_attr_index = 0; + + img_attr[img_attr_index++] = EGL_LINUX_DRM_FOURCC_EXT; + img_attr[img_attr_index++] = format; + + img_attr[img_attr_index++] = EGL_WIDTH; + img_attr[img_attr_index++] = width; + + img_attr[img_attr_index++] = EGL_HEIGHT; + img_attr[img_attr_index++] = height; + + if(num_planes >= 1) { + img_attr[img_attr_index++] = EGL_DMA_BUF_PLANE0_FD_EXT; + img_attr[img_attr_index++] = fds[0]; + + img_attr[img_attr_index++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT; + img_attr[img_attr_index++] = offsets[0]; + + img_attr[img_attr_index++] = EGL_DMA_BUF_PLANE0_PITCH_EXT; + img_attr[img_attr_index++] = pitches[0]; + + if(use_modifier) { + img_attr[img_attr_index++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT; + img_attr[img_attr_index++] = modifiers[0] & 0xFFFFFFFFULL; + + img_attr[img_attr_index++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT; + img_attr[img_attr_index++] = modifiers[0] >> 32ULL; + } + } + + if(num_planes >= 2) { + img_attr[img_attr_index++] = EGL_DMA_BUF_PLANE1_FD_EXT; + img_attr[img_attr_index++] = fds[1]; + + img_attr[img_attr_index++] = EGL_DMA_BUF_PLANE1_OFFSET_EXT; + img_attr[img_attr_index++] = offsets[1]; + + img_attr[img_attr_index++] = EGL_DMA_BUF_PLANE1_PITCH_EXT; + img_attr[img_attr_index++] = pitches[1]; + + if(use_modifier) { + img_attr[img_attr_index++] = EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT; + img_attr[img_attr_index++] = modifiers[1] & 0xFFFFFFFFULL; + + img_attr[img_attr_index++] = EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT; + img_attr[img_attr_index++] = modifiers[1] >> 32ULL; + } + } + + if(num_planes >= 3) { + img_attr[img_attr_index++] = EGL_DMA_BUF_PLANE2_FD_EXT; + img_attr[img_attr_index++] = fds[2]; + + img_attr[img_attr_index++] = EGL_DMA_BUF_PLANE2_OFFSET_EXT; + img_attr[img_attr_index++] = offsets[2]; + + img_attr[img_attr_index++] = EGL_DMA_BUF_PLANE2_PITCH_EXT; + img_attr[img_attr_index++] = pitches[2]; + + if(use_modifier) { + img_attr[img_attr_index++] = EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT; + img_attr[img_attr_index++] = modifiers[2] & 0xFFFFFFFFULL; + + img_attr[img_attr_index++] = EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT; + img_attr[img_attr_index++] = modifiers[2] >> 32ULL; + } + } + + if(num_planes >= 4) { + img_attr[img_attr_index++] = EGL_DMA_BUF_PLANE3_FD_EXT; + img_attr[img_attr_index++] = fds[3]; + + img_attr[img_attr_index++] = EGL_DMA_BUF_PLANE3_OFFSET_EXT; + img_attr[img_attr_index++] = offsets[3]; + + img_attr[img_attr_index++] = EGL_DMA_BUF_PLANE3_PITCH_EXT; + img_attr[img_attr_index++] = pitches[3]; + + if(use_modifier) { + img_attr[img_attr_index++] = EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT; + img_attr[img_attr_index++] = modifiers[3] & 0xFFFFFFFFULL; + + img_attr[img_attr_index++] = EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT; + img_attr[img_attr_index++] = modifiers[3] >> 32ULL; + } + } + + img_attr[img_attr_index++] = EGL_NONE; + assert(img_attr_index <= 44); +} + +static VADisplay video_codec_context_get_vaapi_display(AVCodecContext *video_codec_context) { + AVBufferRef *hw_frames_ctx = video_codec_context->hw_frames_ctx; + if(!hw_frames_ctx) + return NULL; + + AVHWFramesContext *hw_frame_context = (AVHWFramesContext*)hw_frames_ctx->data; + AVHWDeviceContext *device_context = (AVHWDeviceContext*)hw_frame_context->device_ctx; + if(device_context->type != AV_HWDEVICE_TYPE_VAAPI) + return NULL; + + AVVAAPIDeviceContext *vactx = device_context->hwctx; + return vactx->display; +} + +bool video_codec_context_is_vaapi(AVCodecContext *video_codec_context) { + AVBufferRef *hw_frames_ctx = video_codec_context->hw_frames_ctx; + if(!hw_frames_ctx) + return NULL; + + AVHWFramesContext *hw_frame_context = (AVHWFramesContext*)hw_frames_ctx->data; + AVHWDeviceContext *device_context = (AVHWDeviceContext*)hw_frame_context->device_ctx; + return device_context->type == AV_HWDEVICE_TYPE_VAAPI; +} + +static uint32_t drm_fourcc_to_va_fourcc(uint32_t drm_fourcc) { + switch(drm_fourcc) { + case DRM_FORMAT_XRGB8888: return VA_FOURCC_BGRX; + case DRM_FORMAT_XBGR8888: return VA_FOURCC_RGBX; + case DRM_FORMAT_RGBX8888: return VA_FOURCC_XBGR; + case DRM_FORMAT_BGRX8888: return VA_FOURCC_XRGB; + case DRM_FORMAT_ARGB8888: return VA_FOURCC_BGRA; + case DRM_FORMAT_ABGR8888: return VA_FOURCC_RGBA; + case DRM_FORMAT_RGBA8888: return VA_FOURCC_ABGR; + case DRM_FORMAT_BGRA8888: return VA_FOURCC_ARGB; + default: return drm_fourcc; + } +} + +bool vaapi_copy_drm_planes_to_video_surface(AVCodecContext *video_codec_context, AVFrame *video_frame, vec2i source_pos, vec2i source_size, vec2i dest_pos, vec2i dest_size, uint32_t format, vec2i size, const int *fds, const uint32_t *offsets, const uint32_t *pitches, const uint64_t *modifiers, int num_planes) { + VAConfigID config_id = 0; + VAContextID context_id = 0; + VASurfaceID input_surface_id = 0; + VABufferID buffer_id = 0; + bool success = true; + + VADisplay va_dpy = video_codec_context_get_vaapi_display(video_codec_context); + if(!va_dpy) { + success = false; + goto done; + } + + VAStatus va_status = vaCreateConfig(va_dpy, VAProfileNone, VAEntrypointVideoProc, NULL, 0, &config_id); + if(va_status != VA_STATUS_SUCCESS) { + fprintf(stderr, "gsr error: vaapi_copy_drm_planes_to_video_surface: vaCreateConfig failed, error: %s\n", vaErrorStr(va_status)); + success = false; + goto done; + } + + VASurfaceID output_surface_id = (uintptr_t)video_frame->data[3]; + va_status = vaCreateContext(va_dpy, config_id, size.x, size.y, VA_PROGRESSIVE, &output_surface_id, 1, &context_id); + if(va_status != VA_STATUS_SUCCESS) { + fprintf(stderr, "gsr error: vaapi_copy_drm_planes_to_video_surface: vaCreateContext failed, error: %s\n", vaErrorStr(va_status)); + success = false; + goto done; + } + + VADRMPRIMESurfaceDescriptor buf = {0}; + buf.fourcc = drm_fourcc_to_va_fourcc(format);//VA_FOURCC_BGRX; // TODO: VA_FOURCC_BGRA, VA_FOURCC_X2R10G10B10 + buf.width = size.x; + buf.height = size.y; + buf.num_objects = num_planes; + buf.num_layers = 1; + buf.layers[0].drm_format = format; + buf.layers[0].num_planes = buf.num_objects; + for(int i = 0; i < num_planes; ++i) { + buf.objects[i].fd = fds[i]; + buf.objects[i].size = size.y * pitches[i]; // TODO: + buf.objects[i].drm_format_modifier = modifiers[i]; + + buf.layers[0].object_index[i] = i; + buf.layers[0].offset[i] = offsets[i]; + buf.layers[0].pitch[i] = pitches[i]; + } + + VASurfaceAttrib attribs[2] = {0}; + attribs[0].type = VASurfaceAttribMemoryType; + attribs[0].flags = VA_SURFACE_ATTRIB_SETTABLE; + attribs[0].value.type = VAGenericValueTypeInteger; + attribs[0].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2; + attribs[1].type = VASurfaceAttribExternalBufferDescriptor; + attribs[1].flags = VA_SURFACE_ATTRIB_SETTABLE; + attribs[1].value.type = VAGenericValueTypePointer; + attribs[1].value.value.p = &buf; + + // TODO: RT_FORMAT with 10 bit/hdr, VA_RT_FORMAT_RGB32_10 + // TODO: Max size same as source_size + va_status = vaCreateSurfaces(va_dpy, VA_RT_FORMAT_RGB32, size.x, size.y, &input_surface_id, 1, attribs, 2); + if(va_status != VA_STATUS_SUCCESS) { + fprintf(stderr, "gsr error: vaapi_copy_drm_planes_to_video_surface: vaCreateSurfaces failed, error: %s\n", vaErrorStr(va_status)); + success = false; + goto done; + } + + const VARectangle source_region = { + .x = source_pos.x, + .y = source_pos.y, + .width = source_size.x, + .height = source_size.y + }; + + const VARectangle output_region = { + .x = dest_pos.x, + .y = dest_pos.y, + .width = dest_size.x, + .height = dest_size.y + }; + + // Copying a surface to another surface will automatically perform the color conversion. Thanks vaapi! + VAProcPipelineParameterBuffer params = {0}; + params.surface = input_surface_id; + params.surface_region = NULL; + params.surface_region = &source_region; + params.output_region = &output_region; + params.output_background_color = 0; + params.filter_flags = VA_FRAME_PICTURE; + params.pipeline_flags = VA_PROC_PIPELINE_FAST; + + params.input_color_properties.colour_primaries = 1; + params.input_color_properties.transfer_characteristics = 1; + params.input_color_properties.matrix_coefficients = 1; + params.surface_color_standard = VAProcColorStandardBT709; // TODO: + params.input_color_properties.color_range = video_frame->color_range == AVCOL_RANGE_JPEG ? VA_SOURCE_RANGE_FULL : VA_SOURCE_RANGE_REDUCED; + + params.output_color_properties.colour_primaries = 1; + params.output_color_properties.transfer_characteristics = 1; + params.output_color_properties.matrix_coefficients = 1; + params.output_color_standard = VAProcColorStandardBT709; // TODO: + params.output_color_properties.color_range = video_frame->color_range == AVCOL_RANGE_JPEG ? VA_SOURCE_RANGE_FULL : VA_SOURCE_RANGE_REDUCED; + + params.processing_mode = VAProcPerformanceMode; + + // VAProcPipelineCaps pipeline_caps = {0}; + // va_status = vaQueryVideoProcPipelineCaps(self->va_dpy, + // self->context_id, + // NULL, 0, + // &pipeline_caps); + // if(va_status == VA_STATUS_SUCCESS) { + // fprintf(stderr, "pipeline_caps: %u, %u\n", (unsigned int)pipeline_caps.rotation_flags, pipeline_caps.blend_flags); + // } + + // TODO: params.output_hdr_metadata + + // TODO: + // if (first surface to render) + // pipeline_param->output_background_color = 0xff000000; // black + + va_status = vaCreateBuffer(va_dpy, context_id, VAProcPipelineParameterBufferType, sizeof(params), 1, ¶ms, &buffer_id); + if(va_status != VA_STATUS_SUCCESS) { + fprintf(stderr, "gsr error: vaapi_copy_drm_planes_to_video_surface: vaCreateBuffer failed, error: %d\n", va_status); + success = false; + goto done; + } + + va_status = vaBeginPicture(va_dpy, context_id, output_surface_id); + if(va_status != VA_STATUS_SUCCESS) { + fprintf(stderr, "gsr error: vaapi_copy_drm_planes_to_video_surface: vaBeginPicture failed, error: %d\n", va_status); + success = false; + goto done; + } + + va_status = vaRenderPicture(va_dpy, context_id, &buffer_id, 1); + if(va_status != VA_STATUS_SUCCESS) { + vaEndPicture(va_dpy, context_id); + fprintf(stderr, "gsr error: vaapi_copy_drm_planes_to_video_surface: vaRenderPicture failed, error: %d\n", va_status); + success = false; + goto done; + } + + va_status = vaEndPicture(va_dpy, context_id); + if(va_status != VA_STATUS_SUCCESS) { + fprintf(stderr, "gsr error: vaapi_copy_drm_planes_to_video_surface: vaEndPicture failed, error: %d\n", va_status); + success = false; + goto done; + } + + // vaSyncBuffer(va_dpy, buffer_id, 1000 * 1000 * 1000); + // vaSyncSurface(va_dpy, input_surface_id); + // vaSyncSurface(va_dpy, output_surface_id); + + done: + if(buffer_id) + vaDestroyBuffer(va_dpy, buffer_id); + + if(input_surface_id) + vaDestroySurfaces(va_dpy, &input_surface_id, 1); + + if(context_id) + vaDestroyContext(va_dpy, context_id); + + if(config_id) + vaDestroyConfig(va_dpy, config_id); + + return success; +} + +bool vaapi_copy_egl_image_to_video_surface(gsr_egl *egl, EGLImage image, vec2i source_pos, vec2i source_size, vec2i dest_pos, vec2i dest_size, AVCodecContext *video_codec_context, AVFrame *video_frame) { + if(!image) + return false; + + int texture_fourcc = 0; + int texture_num_planes = 0; + uint64_t texture_modifiers = 0; + if(!egl->eglExportDMABUFImageQueryMESA(egl->egl_display, image, &texture_fourcc, &texture_num_planes, &texture_modifiers)) { + fprintf(stderr, "gsr error: gsr_capture_xcomposite_vaapi_tick: eglExportDMABUFImageQueryMESA failed\n"); + return false; + } + + if(texture_num_planes <= 0 || texture_num_planes > 8) { + fprintf(stderr, "gsr error: gsr_capture_xcomposite_vaapi_tick: expected planes size to be 0<planes<8 for drm buf, got %d planes\n", texture_num_planes); + return false; + } + + int texture_fds[8]; + int32_t texture_strides[8]; + int32_t texture_offsets[8]; + + while(egl->eglGetError() != EGL_SUCCESS){} + if(!egl->eglExportDMABUFImageMESA(egl->egl_display, image, texture_fds, texture_strides, texture_offsets)) { + fprintf(stderr, "gsr error: gsr_capture_xcomposite_vaapi_tick: eglExportDMABUFImageMESA failed, error: %d\n", egl->eglGetError()); + return false; + } + + int fds[8]; + uint32_t offsets[8]; + uint32_t pitches[8]; + uint64_t modifiers[8]; + for(int i = 0; i < texture_num_planes; ++i) { + fds[i] = texture_fds[i]; + offsets[i] = texture_offsets[i]; + pitches[i] = texture_strides[i]; + modifiers[i] = texture_modifiers; + + if(fds[i] == -1) + texture_num_planes = i; + } + const bool success = texture_num_planes > 0 && vaapi_copy_drm_planes_to_video_surface(video_codec_context, video_frame, source_pos, source_size, dest_pos, dest_size, texture_fourcc, source_size, fds, offsets, pitches, modifiers, texture_num_planes); + + for(int i = 0; i < texture_num_planes; ++i) { + if(texture_fds[i] > 0) { + close(texture_fds[i]); + texture_fds[i] = -1; + } + } + + return success; +} |