aboutsummaryrefslogtreecommitdiff
path: root/src/capture
diff options
context:
space:
mode:
authordec05eba <dec05eba®protonmail.com>2023-04-14 09:36:24 +0200
committerdec05eba <dec05eba@protonmail.com>2023-04-15 19:06:08 +0200
commitf6107a0c5d41aa9fbaa41d64e2f6a5681f9237cc (patch)
tree8fae2bf69dd325d1da0ab1e475a58f32435768cf /src/capture
parent5c714ea7142272b7b95b95019501df1d49691db1 (diff)
Fix AMD single monitor rotated display being rotated in recording
If there is only one monitor connected and it's rotated then the drm buf will also be rotated. This only the case with AMD and only when using one monitor! To fix this, we perform color conversion with an opengl shader which allows us to also rotate the texture. VAAPI supports rotation but it's not implemented by AMD at least. Performance seems to be the same as when using VAAPI, even when GPU usage is 100%.
Diffstat (limited to 'src/capture')
-rw-r--r--src/capture/kms_vaapi.c389
-rw-r--r--src/capture/xcomposite_vaapi.c13
2 files changed, 233 insertions, 169 deletions
diff --git a/src/capture/kms_vaapi.c b/src/capture/kms_vaapi.c
index 2f7232f..8d650ed 100644
--- a/src/capture/kms_vaapi.c
+++ b/src/capture/kms_vaapi.c
@@ -2,6 +2,7 @@
#include "../../kms/client/kms_client.h"
#include "../../include/egl.h"
#include "../../include/utils.h"
+#include "../../include/color_conversion.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
@@ -14,6 +15,13 @@
#include <va/va.h>
#include <va/va_drmcommon.h>
+typedef enum {
+ X11_ROT_0 = 1 << 0,
+ X11_ROT_90 = 1 << 1,
+ X11_ROT_180 = 1 << 2,
+ X11_ROT_270 = 1 << 3
+} X11Rotation;
+
typedef struct {
gsr_capture_kms_vaapi_params params;
bool should_stop;
@@ -36,12 +44,17 @@ typedef struct {
bool screen_capture;
VADisplay va_dpy;
- VAConfigID config_id;
- VAContextID context_id;
- VASurfaceID input_surface;
- VABufferID buffer_id;
- VARectangle input_region;
- bool context_created;
+
+ bool requires_rotation;
+ X11Rotation x11_rot;
+
+ VADRMPRIMESurfaceDescriptor prime;
+
+ unsigned int input_texture;
+ unsigned int target_textures[2];
+
+ gsr_color_conversion color_conversion;
+ unsigned int vao;
} gsr_capture_kms_vaapi;
static int max_int(int a, int b) {
@@ -95,6 +108,17 @@ static bool drm_create_codec_context(gsr_capture_kms_vaapi *cap_kms, AVCodecCont
// TODO: On monitor reconfiguration, find monitor x, y, width and height again. Do the same for nvfbc.
+typedef struct {
+ int num_monitors;
+ int rotation;
+} MonitorCallbackUserdata;
+
+static void monitor_callback(const XRROutputInfo *output_info, const XRRCrtcInfo *crt_info, const XRRModeInfo *mode_info, void *userdata) {
+ MonitorCallbackUserdata *monitor_callback_userdata = userdata;
+ monitor_callback_userdata->rotation = crt_info->rotation;
+ ++monitor_callback_userdata->num_monitors;
+}
+
static int gsr_capture_kms_vaapi_start(gsr_capture *cap, AVCodecContext *video_codec_context) {
gsr_capture_kms_vaapi *cap_kms = cap->priv;
@@ -103,7 +127,9 @@ static int gsr_capture_kms_vaapi_start(gsr_capture *cap, AVCodecContext *video_c
return -1;
}
- // TODO: Update on monitor reconfiguration, make sure to update on window focus change (maybe for kms update each second?), needs to work on focus change to the witcher 3 on full window, fullscreen firefox, etc
+ MonitorCallbackUserdata monitor_callback_userdata = {0};
+ for_each_active_monitor_output(cap_kms->params.dpy, monitor_callback, &monitor_callback_userdata);
+
gsr_monitor monitor;
if(strcmp(cap_kms->params.display_to_capture, "screen") == 0) {
monitor.pos.x = 0;
@@ -117,12 +143,24 @@ static int gsr_capture_kms_vaapi_start(gsr_capture *cap, AVCodecContext *video_c
return -1;
}
+ // TODO: Find a better way to do this. Is this info available somewhere in drm? it should be!
+
+ // TODO: test on intel
+ // Note: workaround AMD issue. If there is one monitor enabled and it's rotated then
+ // the drm buf will also be rotated. This only happens when you only have one monitor enabled.
+ cap_kms->x11_rot = monitor_callback_userdata.rotation;
+ if(monitor_callback_userdata.num_monitors == 1 && cap_kms->x11_rot != X11_ROT_0 && cap_kms->params.gpu_inf.vendor == GSR_GPU_VENDOR_AMD) {
+ cap_kms->requires_rotation = true;
+ } else {
+ cap_kms->requires_rotation = false;
+ }
+
cap_kms->capture_pos = monitor.pos;
cap_kms->capture_size = monitor.size;
-
if(!gsr_egl_load(&cap_kms->egl, cap_kms->params.dpy)) {
fprintf(stderr, "gsr error: gsr_capture_kms_vaapi_start: failed to load opengl\n");
+ gsr_capture_kms_vaapi_stop(cap, video_codec_context);
return -1;
}
@@ -137,17 +175,21 @@ static int gsr_capture_kms_vaapi_start(gsr_capture *cap, AVCodecContext *video_c
return -1;
}
- //cap_kms->window_resize_timer = clock_get_monotonic_seconds(); // TODO:
return 0;
}
+static uint32_t fourcc(uint32_t a, uint32_t b, uint32_t c, uint32_t d) {
+ return (d << 24) | (c << 16) | (b << 8) | a;
+}
+
+#define FOURCC_NV12 842094158
+
static void gsr_capture_kms_vaapi_tick(gsr_capture *cap, AVCodecContext *video_codec_context, AVFrame **frame) {
gsr_capture_kms_vaapi *cap_kms = cap->priv;
// TODO:
- //cap_kms->egl.glClear(GL_COLOR_BUFFER_BIT);
+ cap_kms->egl.glClear(GL_COLOR_BUFFER_BIT);
- //const double window_resize_timeout = 1.0; // 1 second
if(!cap_kms->created_hw_frame) {
cap_kms->created_hw_frame = true;
@@ -175,6 +217,128 @@ static void gsr_capture_kms_vaapi_tick(gsr_capture *cap, AVCodecContext *video_c
cap_kms->stop_is_error = true;
return;
}
+
+ VASurfaceID target_surface_id = (uintptr_t)(*frame)->data[3];
+
+ VAStatus va_status = vaExportSurfaceHandle(cap_kms->va_dpy, target_surface_id, VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2, VA_EXPORT_SURFACE_READ_WRITE | VA_EXPORT_SURFACE_SEPARATE_LAYERS, &cap_kms->prime);
+ if(va_status != VA_STATUS_SUCCESS) {
+ fprintf(stderr, "gsr error: gsr_capture_kms_vaapi_tick: vaExportSurfaceHandle failed, error: %d\n", va_status);
+ cap_kms->should_stop = true;
+ cap_kms->stop_is_error = true;
+ return;
+ }
+ vaSyncSurface(cap_kms->va_dpy, target_surface_id);
+
+ cap_kms->egl.glGenTextures(1, &cap_kms->input_texture);
+ cap_kms->egl.glBindTexture(GL_TEXTURE_2D, cap_kms->input_texture);
+ cap_kms->egl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ cap_kms->egl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ cap_kms->egl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ cap_kms->egl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ cap_kms->egl.glBindTexture(GL_TEXTURE_2D, 0);
+
+ if(cap_kms->prime.fourcc == FOURCC_NV12) {
+ cap_kms->egl.glGenTextures(2, cap_kms->target_textures);
+ for(int i = 0; i < 2; ++i) {
+ const uint32_t formats[2] = { fourcc('R', '8', ' ', ' '), fourcc('G', 'R', '8', '8') };
+ const int layer = i;
+ const int plane = 0;
+
+ const int div[2] = {1, 2}; // divide UV texture size by 2 because chroma is half size
+
+ const intptr_t img_attr[] = {
+ EGL_LINUX_DRM_FOURCC_EXT, formats[i],
+ EGL_WIDTH, cap_kms->prime.width / div[i],
+ EGL_HEIGHT, cap_kms->prime.height / div[i],
+ EGL_DMA_BUF_PLANE0_FD_EXT, cap_kms->prime.objects[cap_kms->prime.layers[layer].object_index[plane]].fd,
+ EGL_DMA_BUF_PLANE0_OFFSET_EXT, cap_kms->prime.layers[layer].offset[plane],
+ EGL_DMA_BUF_PLANE0_PITCH_EXT, cap_kms->prime.layers[layer].pitch[plane],
+ EGL_NONE
+ };
+
+ while(cap_kms->egl.eglGetError() != EGL_SUCCESS){}
+ EGLImage image = cap_kms->egl.eglCreateImage(cap_kms->egl.egl_display, 0, EGL_LINUX_DMA_BUF_EXT, NULL, img_attr);
+ if(!image) {
+ fprintf(stderr, "gsr error: gsr_capture_kms_vaapi_tick: failed to create egl image from drm fd for output drm fd, error: %d\n", cap_kms->egl.eglGetError());
+ cap_kms->should_stop = true;
+ cap_kms->stop_is_error = true;
+ return;
+ }
+
+ cap_kms->egl.glBindTexture(GL_TEXTURE_2D, cap_kms->target_textures[i]);
+ cap_kms->egl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ cap_kms->egl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ cap_kms->egl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ cap_kms->egl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ while(cap_kms->egl.glGetError()) {}
+ while(cap_kms->egl.eglGetError() != EGL_SUCCESS){}
+ cap_kms->egl.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
+ if(cap_kms->egl.glGetError() != 0 || cap_kms->egl.eglGetError() != EGL_SUCCESS) {
+ fprintf(stderr, "gsr error: gsr_capture_kms_vaapi_tick: failed to bind egl image to gl texture, error: %d\n", cap_kms->egl.eglGetError());
+ cap_kms->should_stop = true;
+ cap_kms->stop_is_error = true;
+ cap_kms->egl.eglDestroyImage(cap_kms->egl.egl_display, image);
+ cap_kms->egl.glBindTexture(GL_TEXTURE_2D, 0);
+ return;
+ }
+
+ cap_kms->egl.eglDestroyImage(cap_kms->egl.egl_display, image);
+ cap_kms->egl.glBindTexture(GL_TEXTURE_2D, 0);
+ }
+
+ float texture_rotation = 0.0f;
+ if(cap_kms->requires_rotation) {
+ switch(cap_kms->x11_rot) {
+ case X11_ROT_90:
+ texture_rotation = M_PI*0.5f;
+ break;
+ case X11_ROT_180:
+ texture_rotation = M_PI;
+ break;
+ case X11_ROT_270:
+ texture_rotation = M_PI*1.5f;
+ break;
+ default:
+ texture_rotation = 0.0f;
+ break;
+ }
+ }
+
+ const double combined_monitor_width = (double)XWidthOfScreen(DefaultScreenOfDisplay(cap_kms->params.dpy));
+ const double combined_monitor_height = (double)XHeightOfScreen(DefaultScreenOfDisplay(cap_kms->params.dpy));
+
+ gsr_color_conversion_params color_conversion_params = {0};
+ color_conversion_params.egl = &cap_kms->egl;
+ color_conversion_params.source_color = GSR_SOURCE_COLOR_RGB;
+ color_conversion_params.destination_color = GSR_DESTINATION_COLOR_NV12;
+
+ color_conversion_params.source_textures[0] = cap_kms->input_texture;
+ color_conversion_params.num_source_textures = 1;
+
+ color_conversion_params.destination_textures[0] = cap_kms->target_textures[0];
+ color_conversion_params.destination_textures[1] = cap_kms->target_textures[1];
+ color_conversion_params.num_destination_textures = 2;
+
+ color_conversion_params.rotation = texture_rotation;
+
+ color_conversion_params.position.x = (double)cap_kms->capture_pos.x / combined_monitor_width;
+ color_conversion_params.position.y = (double)cap_kms->capture_pos.y / combined_monitor_height;
+ color_conversion_params.size.x = (double)cap_kms->capture_size.x / combined_monitor_width;
+ color_conversion_params.size.y = (double)cap_kms->capture_size.y / combined_monitor_height;
+
+ if(gsr_color_conversion_init(&cap_kms->color_conversion, &color_conversion_params) != 0) {
+ fprintf(stderr, "gsr error: gsr_capture_kms_vaapi_tick: failed to create color conversion\n");
+ cap_kms->should_stop = true;
+ cap_kms->stop_is_error = true;
+ return;
+ }
+ } else {
+ fprintf(stderr, "gsr error: gsr_capture_kms_vaapi_tick: unexpected fourcc %u for output drm fd, expected nv12\n", cap_kms->prime.fourcc);
+ cap_kms->should_stop = true;
+ cap_kms->stop_is_error = true;
+ return;
+ }
}
}
@@ -194,8 +358,6 @@ static bool gsr_capture_kms_vaapi_should_stop(gsr_capture *cap, bool *err) {
static int gsr_capture_kms_vaapi_capture(gsr_capture *cap, AVFrame *frame) {
gsr_capture_kms_vaapi *cap_kms = cap->priv;
- VASurfaceID target_surface_id = (uintptr_t)frame->data[3];
-
if(cap_kms->dmabuf_fd > 0) {
close(cap_kms->dmabuf_fd);
cap_kms->dmabuf_fd = 0;
@@ -215,150 +377,43 @@ static int gsr_capture_kms_vaapi_capture(gsr_capture *cap, AVFrame *frame) {
cap_kms->kms_size.x = kms_response.data.fd.width;
cap_kms->kms_size.y = kms_response.data.fd.height;
- if(!cap_kms->context_created) {
- cap_kms->context_created = true;
-
- VAStatus va_status = vaCreateConfig(cap_kms->va_dpy, VAProfileNone, VAEntrypointVideoProc, NULL, 0, &cap_kms->config_id);
- if(va_status != VA_STATUS_SUCCESS) {
- fprintf(stderr, "gsr error: gsr_capture_kms_vaapi_capture: vaCreateConfig failed: %d\n", va_status);
- cap_kms->should_stop = true;
- cap_kms->stop_is_error = true;
- return -1;
- }
-
- va_status = vaCreateContext(cap_kms->va_dpy, cap_kms->config_id, cap_kms->kms_size.x, cap_kms->kms_size.y, VA_PROGRESSIVE, &target_surface_id, 1, &cap_kms->context_id);
- if(va_status != VA_STATUS_SUCCESS) {
- fprintf(stderr, "gsr error: gsr_capture_kms_vaapi_capture: vaCreateContext failed: %d\n", va_status);
- cap_kms->should_stop = true;
- cap_kms->stop_is_error = true;
- return -1;
- }
- }
-
- if(cap_kms->buffer_id) {
- vaDestroyBuffer(cap_kms->va_dpy, cap_kms->buffer_id);
- cap_kms->buffer_id = 0;
- }
-
- if(cap_kms->input_surface) {
- vaDestroySurfaces(cap_kms->va_dpy, &cap_kms->input_surface, 1);
- cap_kms->input_surface = 0;
- }
-
- uintptr_t dmabuf = cap_kms->dmabuf_fd;
-
- VASurfaceAttribExternalBuffers buf = {0};
- buf.pixel_format = VA_FOURCC_BGRX;
- buf.width = cap_kms->kms_size.x;
- buf.height = cap_kms->kms_size.y;
- buf.data_size = cap_kms->kms_size.y * cap_kms->pitch;
- buf.num_planes = 1;
- buf.pitches[0] = cap_kms->pitch;
- buf.offsets[0] = cap_kms->offset;
- buf.buffers = &dmabuf;
- buf.num_buffers = 1;
- buf.flags = 0;
- buf.private_data = 0;
-
- #define VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME 0x20000000
-
- VASurfaceAttrib attribs[3] = {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;
- attribs[1].type = VASurfaceAttribExternalBufferDescriptor;
- attribs[1].flags = VA_SURFACE_ATTRIB_SETTABLE;
- attribs[1].value.type = VAGenericValueTypePointer;
- attribs[1].value.value.p = &buf;
-
- // TODO: Do we really need to create a new surface every frame?
- VAStatus va_status = vaCreateSurfaces(cap_kms->va_dpy, VA_RT_FORMAT_RGB32, cap_kms->kms_size.x, cap_kms->kms_size.y, &cap_kms->input_surface, 1, attribs, 2);
- if(va_status != VA_STATUS_SUCCESS) {
- fprintf(stderr, "gsr error: gsr_capture_kms_vaapi_capture: vaCreateSurfaces failed: %d\n", va_status);
- cap_kms->should_stop = true;
- cap_kms->stop_is_error = true;
- return -1;
- }
-
- cap_kms->input_region = (VARectangle) {
- .x = cap_kms->capture_pos.x,
- .y = cap_kms->capture_pos.y,
- .width = cap_kms->capture_size.x,
- .height = cap_kms->capture_size.y
+ // TODO: This causes a crash sometimes on steam deck, why? is it a driver bug? a vaapi pure version doesn't cause a crash.
+ // Even ffmpeg kmsgrab causes this crash. The error is:
+ // amdgpu: Failed to allocate a buffer:
+ // amdgpu: size : 28508160 bytes
+ // amdgpu: alignment : 2097152 bytes
+ // amdgpu: domains : 4
+ // amdgpu: flags : 4
+ // amdgpu: Failed to allocate a buffer:
+ // amdgpu: size : 28508160 bytes
+ // amdgpu: alignment : 2097152 bytes
+ // amdgpu: domains : 4
+ // amdgpu: flags : 4
+ // EE ../jupiter-mesa/src/gallium/drivers/radeonsi/radeon_vcn_enc.c:516 radeon_create_encoder UVD - Can't create CPB buffer.
+ // [hevc_vaapi @ 0x55ea72b09840] Failed to upload encode parameters: 2 (resource allocation failed).
+ // [hevc_vaapi @ 0x55ea72b09840] Encode failed: -5.
+ // Error: avcodec_send_frame failed, error: Input/output error
+ // Assertion pic->display_order == pic->encode_order failed at libavcodec/vaapi_encode_h265.c:765
+ // kms server info: kms client shutdown, shutting down the server
+ const intptr_t img_attr[] = {
+ EGL_LINUX_DRM_FOURCC_EXT, cap_kms->fourcc,
+ EGL_WIDTH, cap_kms->kms_size.x,
+ EGL_HEIGHT, cap_kms->kms_size.y,
+ EGL_DMA_BUF_PLANE0_FD_EXT, cap_kms->dmabuf_fd,
+ EGL_DMA_BUF_PLANE0_OFFSET_EXT, cap_kms->offset,
+ EGL_DMA_BUF_PLANE0_PITCH_EXT, cap_kms->pitch,
+ EGL_NONE
};
- // Copying a surface to another surface will automatically perform the color conversion. Thanks vaapi!
- VAProcPipelineParameterBuffer params = {0};
- params.surface = cap_kms->input_surface;
- if(cap_kms->screen_capture)
- params.surface_region = NULL;
- else
- params.surface_region = &cap_kms->input_region;
- params.output_region = NULL;
- params.output_background_color = 0;
- params.filter_flags = VA_FRAME_PICTURE;
- // TODO: Colors
- params.input_color_properties.color_range = frame->color_range == AVCOL_RANGE_JPEG ? VA_SOURCE_RANGE_FULL : VA_SOURCE_RANGE_REDUCED;
- params.output_color_properties.color_range = frame->color_range == AVCOL_RANGE_JPEG ? VA_SOURCE_RANGE_FULL : VA_SOURCE_RANGE_REDUCED;
-
- // Clear texture with black background because the source texture (window_texture_get_opengl_texture_id(&cap_kms->window_texture))
- // might be smaller than cap_kms->target_texture_id
- // TODO:
- //cap_kms->egl.glClearTexImage(cap_kms->target_texture_id, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
-
- va_status = vaBeginPicture(cap_kms->va_dpy, cap_kms->context_id, target_surface_id);
- if(va_status != VA_STATUS_SUCCESS) {
- static bool error_printed = false;
- if(!error_printed) {
- error_printed = true;
- fprintf(stderr, "gsr error: gsr_capture_kms_vaapi_capture: vaBeginPicture failed: %d\n", va_status);
- }
- return -1;
- }
+ EGLImage image = cap_kms->egl.eglCreateImage(cap_kms->egl.egl_display, 0, EGL_LINUX_DMA_BUF_EXT, NULL, img_attr);
+ cap_kms->egl.glBindTexture(GL_TEXTURE_2D, cap_kms->input_texture);
+ cap_kms->egl.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
+ cap_kms->egl.eglDestroyImage(cap_kms->egl.egl_display, image);
+ cap_kms->egl.glBindTexture(GL_TEXTURE_2D, 0);
- va_status = vaCreateBuffer(cap_kms->va_dpy, cap_kms->context_id, VAProcPipelineParameterBufferType, sizeof(params), 1, &params, &cap_kms->buffer_id);
- if(va_status != VA_STATUS_SUCCESS) {
- fprintf(stderr, "gsr error: gsr_capture_kms_vaapi_capture: vaCreateBuffer failed: %d\n", va_status);
- cap_kms->should_stop = true;
- cap_kms->stop_is_error = true;
- return -1;
- }
+ gsr_color_conversion_update(&cap_kms->color_conversion, frame->width, frame->height);
- va_status = vaRenderPicture(cap_kms->va_dpy, cap_kms->context_id, &cap_kms->buffer_id, 1);
- if(va_status != VA_STATUS_SUCCESS) {
- vaEndPicture(cap_kms->va_dpy, cap_kms->context_id);
- static bool error_printed = false;
- if(!error_printed) {
- error_printed = true;
- fprintf(stderr, "gsr error: gsr_capture_kms_vaapi_capture: vaRenderPicture failed: %d\n", va_status);
- }
- return -1;
- }
-
- va_status = vaEndPicture(cap_kms->va_dpy, cap_kms->context_id);
- if(va_status != VA_STATUS_SUCCESS) {
- static bool error_printed = false;
- if(!error_printed) {
- error_printed = true;
- fprintf(stderr, "gsr error: gsr_capture_kms_vaapi_capture: vaEndPicture failed: %d\n", va_status);
- }
- return -1;
- }
-
- // TODO: Needed?
- vaSyncSurface(cap_kms->va_dpy, cap_kms->input_surface);
- vaSyncSurface(cap_kms->va_dpy, target_surface_id);
-
- if(cap_kms->buffer_id) {
- vaDestroyBuffer(cap_kms->va_dpy, cap_kms->buffer_id);
- cap_kms->buffer_id = 0;
- }
-
- if(cap_kms->input_surface) {
- vaDestroySurfaces(cap_kms->va_dpy, &cap_kms->input_surface, 1);
- cap_kms->input_surface = 0;
- }
+ cap_kms->egl.eglSwapBuffers(cap_kms->egl.egl_display, cap_kms->egl.egl_surface);
if(cap_kms->dmabuf_fd > 0) {
close(cap_kms->dmabuf_fd);
@@ -366,7 +421,7 @@ static int gsr_capture_kms_vaapi_capture(gsr_capture *cap, AVFrame *frame) {
}
// TODO: Remove
- //cap_kms->egl.eglSwapBuffers(cap_kms->egl.egl_display, cap_kms->egl.egl_surface);
+ cap_kms->egl.eglSwapBuffers(cap_kms->egl.egl_display, cap_kms->egl.egl_surface);
return 0;
}
@@ -374,25 +429,23 @@ static int gsr_capture_kms_vaapi_capture(gsr_capture *cap, AVFrame *frame) {
static void gsr_capture_kms_vaapi_stop(gsr_capture *cap, AVCodecContext *video_codec_context) {
gsr_capture_kms_vaapi *cap_kms = cap->priv;
- if(cap_kms->buffer_id) {
- vaDestroyBuffer(cap_kms->va_dpy, cap_kms->buffer_id);
- cap_kms->buffer_id = 0;
- }
+ gsr_color_conversion_deinit(&cap_kms->color_conversion);
- if(cap_kms->context_id) {
- vaDestroyContext(cap_kms->va_dpy, cap_kms->context_id);
- cap_kms->context_id = 0;
+ for(uint32_t i = 0; i < cap_kms->prime.num_objects; ++i) {
+ if(cap_kms->prime.objects[i].fd > 0) {
+ close(cap_kms->prime.objects[i].fd);
+ cap_kms->prime.objects[i].fd = 0;
+ }
}
- if(cap_kms->config_id) {
- vaDestroyConfig(cap_kms->va_dpy, cap_kms->config_id);
- cap_kms->config_id = 0;
+ if(cap_kms->input_texture) {
+ cap_kms->egl.glDeleteTextures(1, &cap_kms->input_texture);
+ cap_kms->input_texture = 0;
}
- if(cap_kms->input_surface) {
- vaDestroySurfaces(cap_kms->va_dpy, &cap_kms->input_surface, 1);
- cap_kms->input_surface = 0;
- }
+ cap_kms->egl.glDeleteTextures(2, cap_kms->target_textures);
+ cap_kms->target_textures[0] = 0;
+ cap_kms->target_textures[1] = 0;
if(cap_kms->dmabuf_fd > 0) {
close(cap_kms->dmabuf_fd);
diff --git a/src/capture/xcomposite_vaapi.c b/src/capture/xcomposite_vaapi.c
index 532c0b0..3423af0 100644
--- a/src/capture/xcomposite_vaapi.c
+++ b/src/capture/xcomposite_vaapi.c
@@ -452,10 +452,21 @@ static void gsr_capture_xcomposite_vaapi_tick(gsr_capture *cap, AVCodecContext *
params.output_region = NULL;
params.output_background_color = 0;
params.filter_flags = VA_FRAME_PICTURE;
- // TODO: Colors
+
+ 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;
params.input_color_properties.color_range = (*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;
params.output_color_properties.color_range = (*frame)->color_range == AVCOL_RANGE_JPEG ? VA_SOURCE_RANGE_FULL : VA_SOURCE_RANGE_REDUCED;
+ params.processing_mode = VAProcPerformanceMode;
+
va_status = vaCreateBuffer(cap_xcomp->va_dpy, cap_xcomp->context_id, VAProcPipelineParameterBufferType, sizeof(params), 1, &params, &cap_xcomp->buffer_id);
if(va_status != VA_STATUS_SUCCESS) {
fprintf(stderr, "gsr error: gsr_capture_xcomposite_vaapi_tick: vaCreateBuffer failed: %d\n", va_status);