kms_vaapi: add cursor capture for amd/intel monitor capture

Always find largest drm buf, to fix some cases
when there are multiple planes and we accidentally
capture a drm buf that isn't the target buf.
We always want the full SCREEN drm buf.
This commit is contained in:
dec05eba 2023-04-22 00:46:48 +02:00 committed by dec05eba
parent 2021456be0
commit e1c613666e
15 changed files with 248 additions and 175 deletions

View File

@ -85,6 +85,6 @@ If you really want to donate, you can donate via bitcoin or monero.
# TODO # TODO
* Dynamically change bitrate/resolution to match desired fps. This would be helpful when streaming for example, where the encode output speed also depends on upload speed to the streaming service. * Dynamically change bitrate/resolution to match desired fps. This would be helpful when streaming for example, where the encode output speed also depends on upload speed to the streaming service.
* Show cursor when recording. Currently the cursor is not visible when recording a window or when using amd/intel. * Show cursor when recording a window. Currently the cursor is only visible when recording a monitor.
* Implement opengl injection to capture texture. This fixes VRR without having to use NvFBC direct capture. * Implement opengl injection to capture texture. This fixes VRR without having to use NvFBC direct capture.
* Always use direct capture with NvFBC once the capture issue in mpv fullscreen has been resolved (maybe detect if direct capture fails in nvfbc and switch to non-direct recording. NvFBC says if direct capture fails). * Always use direct capture with NvFBC once the capture issue in mpv fullscreen has been resolved (maybe detect if direct capture fails in nvfbc and switch to non-direct recording. NvFBC says if direct capture fails).

2
TODO
View File

@ -58,3 +58,5 @@ Test if vaapi copy version uses less memory than opengl version.
Intel is a bit weird with monitor capture and multiple monitors. If one of the monitors is rotated then all the kms will be rotated as well. Intel is a bit weird with monitor capture and multiple monitors. If one of the monitors is rotated then all the kms will be rotated as well.
Is that only the case when the primary monitor is rotated? Also the primary monitor becomes position 0, 0 so crtc (x11 randr) position doesn't match the drm pos. Maybe get monitor position and size from drm instead. Is that only the case when the primary monitor is rotated? Also the primary monitor becomes position 0, 0 so crtc (x11 randr) position doesn't match the drm pos. Maybe get monitor position and size from drm instead.
How about if multiple monitors are rotated? How about if multiple monitors are rotated?
When using multiple monitors kms grab the target monitor instead of the whole screen.

View File

@ -27,11 +27,12 @@ build_gsr() {
gcc -c src/window_texture.c $opts $includes gcc -c src/window_texture.c $opts $includes
gcc -c src/shader.c $opts $includes gcc -c src/shader.c $opts $includes
gcc -c src/color_conversion.c $opts $includes gcc -c src/color_conversion.c $opts $includes
gcc -c src/cursor.c $opts $includes
gcc -c src/utils.c $opts $includes gcc -c src/utils.c $opts $includes
gcc -c src/library_loader.c $opts $includes gcc -c src/library_loader.c $opts $includes
g++ -c src/sound.cpp $opts $includes g++ -c src/sound.cpp $opts $includes
g++ -c src/main.cpp $opts $includes g++ -c src/main.cpp $opts $includes
g++ -o gpu-screen-recorder -O2 capture.o nvfbc.o kms_client.o egl.o cuda.o xnvctrl.o overclock.o window_texture.o shader.o color_conversion.o utils.o library_loader.o xcomposite_cuda.o xcomposite_vaapi.o kms_vaapi.o sound.o main.o -s $libs g++ -o gpu-screen-recorder -O2 capture.o nvfbc.o kms_client.o egl.o cuda.o xnvctrl.o overclock.o window_texture.o shader.o color_conversion.o cursor.o utils.o library_loader.o xcomposite_cuda.o xcomposite_vaapi.o kms_vaapi.o sound.o main.o -s $libs
} }
build_gsr_kms_server build_gsr_kms_server

View File

@ -9,7 +9,6 @@
typedef struct _XDisplay Display; typedef struct _XDisplay Display;
typedef struct { typedef struct {
Display *dpy;
const char *display_to_capture; /* if this is "screen", then the entire x11 screen is captured (all displays). A copy is made of this */ const char *display_to_capture; /* if this is "screen", then the entire x11 screen is captured (all displays). A copy is made of this */
gsr_gpu_info gpu_inf; gsr_gpu_info gpu_inf;
const char *card_path; /* reference */ const char *card_path; /* reference */

View File

@ -18,25 +18,15 @@ typedef struct {
gsr_source_color source_color; gsr_source_color source_color;
gsr_destination_color destination_color; gsr_destination_color destination_color;
unsigned int source_textures[2];
int num_source_textures;
unsigned int destination_textures[2]; unsigned int destination_textures[2];
int num_destination_textures; int num_destination_textures;
float rotation;
vec2f position;
vec2f size;
} gsr_color_conversion_params; } gsr_color_conversion_params;
typedef struct { typedef struct {
gsr_egl *egl; gsr_color_conversion_params params;
int rotation_uniforms[2];
gsr_shader shaders[2]; gsr_shader shaders[2];
unsigned int source_textures[2];
unsigned int destination_textures[2];
unsigned int framebuffers[2]; unsigned int framebuffers[2];
unsigned int vertex_array_object_id; unsigned int vertex_array_object_id;
@ -46,6 +36,6 @@ typedef struct {
int gsr_color_conversion_init(gsr_color_conversion *self, const gsr_color_conversion_params *params); int gsr_color_conversion_init(gsr_color_conversion *self, const gsr_color_conversion_params *params);
void gsr_color_conversion_deinit(gsr_color_conversion *self); void gsr_color_conversion_deinit(gsr_color_conversion *self);
int gsr_color_conversion_update(gsr_color_conversion *self, int width, int height); int gsr_color_conversion_draw(gsr_color_conversion *self, unsigned int texture_id, vec2i source_pos, vec2i source_size, vec2i texture_pos, vec2i texture_size, float rotation);
#endif /* GSR_COLOR_CONVERSION_H */ #endif /* GSR_COLOR_CONVERSION_H */

View File

@ -15,6 +15,7 @@ typedef struct {
unsigned int texture_id; unsigned int texture_id;
vec2i size; vec2i size;
vec2i hotspot; vec2i hotspot;
vec2i position;
bool cursor_image_set; bool cursor_image_set;
} gsr_cursor; } gsr_cursor;
@ -24,5 +25,6 @@ void gsr_cursor_deinit(gsr_cursor *self);
int gsr_cursor_change_window_target(gsr_cursor *self, Window window); int gsr_cursor_change_window_target(gsr_cursor *self, Window window);
void gsr_cursor_update(gsr_cursor *self, XEvent *xev); void gsr_cursor_update(gsr_cursor *self, XEvent *xev);
void gsr_cursor_tick(gsr_cursor *self);
#endif /* GSR_CURSOR_H */ #endif /* GSR_CURSOR_H */

View File

@ -66,7 +66,6 @@ typedef void (*__eglMustCastToProperFunctionPointerType)(void);
#define GL_TEXTURE_WRAP_T 0x2803 #define GL_TEXTURE_WRAP_T 0x2803
#define GL_TEXTURE_MAG_FILTER 0x2800 #define GL_TEXTURE_MAG_FILTER 0x2800
#define GL_TEXTURE_MIN_FILTER 0x2801 #define GL_TEXTURE_MIN_FILTER 0x2801
#define GL_LINEAR_MIPMAP_LINEAR 0x2703
#define GL_TEXTURE_WIDTH 0x1000 #define GL_TEXTURE_WIDTH 0x1000
#define GL_TEXTURE_HEIGHT 0x1001 #define GL_TEXTURE_HEIGHT 0x1001
#define GL_NEAREST 0x2600 #define GL_NEAREST 0x2600
@ -75,8 +74,11 @@ typedef void (*__eglMustCastToProperFunctionPointerType)(void);
#define GL_FRAMEBUFFER 0x8D40 #define GL_FRAMEBUFFER 0x8D40
#define GL_COLOR_ATTACHMENT0 0x8CE0 #define GL_COLOR_ATTACHMENT0 0x8CE0
#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 #define GL_FRAMEBUFFER_COMPLETE 0x8CD5
#define GL_STATIC_DRAW 0x88E4 #define GL_STREAM_DRAW 0x88E0
#define GL_ARRAY_BUFFER 0x8892 #define GL_ARRAY_BUFFER 0x8892
#define GL_BLEND 0x0BE2
#define GL_SRC_ALPHA 0x0302
#define GL_ONE_MINUS_SRC_ALPHA 0x0303
#define GL_VENDOR 0x1F00 #define GL_VENDOR 0x1F00
#define GL_RENDERER 0x1F01 #define GL_RENDERER 0x1F01
@ -129,7 +131,6 @@ typedef struct {
void (*glTexImage2D)(unsigned int target, int level, int internalFormat, int width, int height, int border, unsigned int format, unsigned int type, const void *pixels); void (*glTexImage2D)(unsigned int target, int level, int internalFormat, int width, int height, int border, unsigned int format, unsigned int type, const void *pixels);
void (*glCopyImageSubData)(unsigned int srcName, unsigned int srcTarget, int srcLevel, int srcX, int srcY, int srcZ, unsigned int dstName, unsigned int dstTarget, int dstLevel, int dstX, int dstY, int dstZ, int srcWidth, int srcHeight, int srcDepth); void (*glCopyImageSubData)(unsigned int srcName, unsigned int srcTarget, int srcLevel, int srcX, int srcY, int srcZ, unsigned int dstName, unsigned int dstTarget, int dstLevel, int dstX, int dstY, int dstZ, int srcWidth, int srcHeight, int srcDepth);
void (*glClearTexImage)(unsigned int texture, unsigned int level, unsigned int format, unsigned int type, const void *data); void (*glClearTexImage)(unsigned int texture, unsigned int level, unsigned int format, unsigned int type, const void *data);
void (*glGenerateMipmap)(unsigned int target);
void (*glGenFramebuffers)(int n, unsigned int *framebuffers); void (*glGenFramebuffers)(int n, unsigned int *framebuffers);
void (*glBindFramebuffer)(unsigned int target, unsigned int framebuffer); void (*glBindFramebuffer)(unsigned int target, unsigned int framebuffer);
void (*glDeleteFramebuffers)(int n, const unsigned int *framebuffers); void (*glDeleteFramebuffers)(int n, const unsigned int *framebuffers);
@ -140,11 +141,11 @@ typedef struct {
void (*glBindBuffer)(unsigned int target, unsigned int buffer); void (*glBindBuffer)(unsigned int target, unsigned int buffer);
void (*glGenBuffers)(int n, unsigned int *buffers); void (*glGenBuffers)(int n, unsigned int *buffers);
void (*glBufferData)(unsigned int target, khronos_ssize_t size, const void *data, unsigned int usage); void (*glBufferData)(unsigned int target, khronos_ssize_t size, const void *data, unsigned int usage);
void (*glBufferSubData)(unsigned int target, khronos_intptr_t offset, khronos_ssize_t size, const void *data);
void (*glDeleteBuffers)(int n, const unsigned int *buffers); void (*glDeleteBuffers)(int n, const unsigned int *buffers);
void (*glGenVertexArrays)(int n, unsigned int *arrays); void (*glGenVertexArrays)(int n, unsigned int *arrays);
void (*glBindVertexArray)(unsigned int array); void (*glBindVertexArray)(unsigned int array);
void (*glDeleteVertexArrays)(int n, const unsigned int *arrays); void (*glDeleteVertexArrays)(int n, const unsigned int *arrays);
unsigned int (*glCreateProgram)(void); unsigned int (*glCreateProgram)(void);
unsigned int (*glCreateShader)(unsigned int type); unsigned int (*glCreateShader)(unsigned int type);
void (*glAttachShader)(unsigned int program, unsigned int shader); void (*glAttachShader)(unsigned int program, unsigned int shader);
@ -161,7 +162,11 @@ typedef struct {
void (*glGetProgramiv)(unsigned int program, unsigned int pname, int *params); void (*glGetProgramiv)(unsigned int program, unsigned int pname, int *params);
void (*glVertexAttribPointer)(unsigned int index, int size, unsigned int type, unsigned char normalized, int stride, const void *pointer); void (*glVertexAttribPointer)(unsigned int index, int size, unsigned int type, unsigned char normalized, int stride, const void *pointer);
void (*glEnableVertexAttribArray)(unsigned int index); void (*glEnableVertexAttribArray)(unsigned int index);
void (*glDrawArrays)(unsigned int mode, int first, int count ); void (*glDrawArrays)(unsigned int mode, int first, int count);
void (*glEnable)(unsigned int cap);
void (*glBlendFunc)(unsigned int sfactor, unsigned int dfactor);
int (*glGetUniformLocation)(unsigned int program, const char *name);
void (*glUniform1f)(int location, float v0);
} gsr_egl; } gsr_egl;
bool gsr_egl_load(gsr_egl *self, Display *dpy); bool gsr_egl_load(gsr_egl *self, Display *dpy);

View File

@ -65,9 +65,9 @@ static int send_msg_to_client(int client_fd, gsr_kms_response *response, int *fd
static int kms_get_plane_id(gsr_drm *drm) { static int kms_get_plane_id(gsr_drm *drm) {
drmModePlaneResPtr planes = NULL; drmModePlaneResPtr planes = NULL;
drmModePlanePtr plane = NULL;
drmModeFB2Ptr drmfb = NULL;
int result = -1; int result = -1;
int64_t max_size = 0;
uint32_t best_plane_match = UINT32_MAX;
if(drmSetClientCap(drm->drmfd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1) != 0) { if(drmSetClientCap(drm->drmfd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1) != 0) {
fprintf(stderr, "kms server error: drmSetClientCap failed, error: %s\n", strerror(errno)); fprintf(stderr, "kms server error: drmSetClientCap failed, error: %s\n", strerror(errno));
@ -81,7 +81,7 @@ static int kms_get_plane_id(gsr_drm *drm) {
} }
for(uint32_t i = 0; i < planes->count_planes; ++i) { for(uint32_t i = 0; i < planes->count_planes; ++i) {
plane = drmModeGetPlane(drm->drmfd, planes->planes[i]); drmModePlanePtr plane = drmModeGetPlane(drm->drmfd, planes->planes[i]);
if(!plane) { if(!plane) {
fprintf(stderr, "kms server warning: failed to get drmModePlanePtr for plane %#x: %s (%d)\n", planes->planes[i], strerror(errno), errno); fprintf(stderr, "kms server warning: failed to get drmModePlanePtr for plane %#x: %s (%d)\n", planes->planes[i], strerror(errno), errno);
continue; continue;
@ -92,34 +92,28 @@ static int kms_get_plane_id(gsr_drm *drm) {
continue; continue;
} }
break; // TODO: Fallback to getfb(1)?
drmModeFB2Ptr drmfb = drmModeGetFB2(drm->drmfd, plane->fb_id);
if(drmfb) {
const int64_t plane_size = (int64_t)drmfb->width * (int64_t)drmfb->height;
if(drmfb->handles[0] && plane_size >= max_size) {
max_size = plane_size;
best_plane_match = plane->plane_id;
}
drmModeFreeFB2(drmfb);
}
drmModeFreePlane(plane);
} }
if(!plane) { if(best_plane_match == UINT32_MAX || max_size == 0) {
fprintf(stderr, "kms server error: failed to find a usable plane\n"); fprintf(stderr, "kms server error: failed to find a usable plane\n");
goto error; goto error;
} }
// TODO: Fallback to getfb(1)? drm->plane_id = best_plane_match;
drmfb = drmModeGetFB2(drm->drmfd, plane->fb_id);
if(!drmfb) {
fprintf(stderr, "kms server error: drmModeGetFB2 failed on plane fb id %d, error: %s\n", plane->fb_id, strerror(errno));
goto error;
}
if(!drmfb->handles[0]) {
fprintf(stderr, "kms server error: drmfb handle is NULL\n");
goto error;
}
drm->plane_id = plane->plane_id;
result = 0; result = 0;
error: error:
if(drmfb)
drmModeFreeFB2(drmfb);
if(plane)
drmModeFreePlane(plane);
if(planes) if(planes)
drmModeFreePlaneResources(planes); drmModeFreePlaneResources(planes);

View File

@ -3,6 +3,7 @@
#include "../../include/egl.h" #include "../../include/egl.h"
#include "../../include/utils.h" #include "../../include/utils.h"
#include "../../include/color_conversion.h" #include "../../include/color_conversion.h"
#include "../../include/cursor.h"
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
@ -24,6 +25,9 @@ typedef enum {
typedef struct { typedef struct {
gsr_capture_kms_vaapi_params params; gsr_capture_kms_vaapi_params params;
Display *dpy;
XEvent xev;
bool should_stop; bool should_stop;
bool stop_is_error; bool stop_is_error;
bool created_hw_frame; bool created_hw_frame;
@ -54,7 +58,8 @@ typedef struct {
unsigned int target_textures[2]; unsigned int target_textures[2];
gsr_color_conversion color_conversion; gsr_color_conversion color_conversion;
unsigned int vao;
gsr_cursor cursor;
} gsr_capture_kms_vaapi; } gsr_capture_kms_vaapi;
static int max_int(int a, int b) { static int max_int(int a, int b) {
@ -127,17 +132,17 @@ static int gsr_capture_kms_vaapi_start(gsr_capture *cap, AVCodecContext *video_c
return -1; return -1;
} }
MonitorCallbackUserdata monitor_callback_userdata = {0}; MonitorCallbackUserdata monitor_callback_userdata = {0, X11_ROT_0};
for_each_active_monitor_output(cap_kms->params.dpy, monitor_callback, &monitor_callback_userdata); for_each_active_monitor_output(cap_kms->dpy, monitor_callback, &monitor_callback_userdata);
gsr_monitor monitor; gsr_monitor monitor;
if(strcmp(cap_kms->params.display_to_capture, "screen") == 0) { if(strcmp(cap_kms->params.display_to_capture, "screen") == 0) {
monitor.pos.x = 0; monitor.pos.x = 0;
monitor.pos.y = 0; monitor.pos.y = 0;
monitor.size.x = XWidthOfScreen(DefaultScreenOfDisplay(cap_kms->params.dpy)); monitor.size.x = WidthOfScreen(DefaultScreenOfDisplay(cap_kms->dpy));
monitor.size.y = XHeightOfScreen(DefaultScreenOfDisplay(cap_kms->params.dpy)); monitor.size.y = HeightOfScreen(DefaultScreenOfDisplay(cap_kms->dpy));
cap_kms->screen_capture = true; cap_kms->screen_capture = true;
} else if(!get_monitor_by_name(cap_kms->params.dpy, cap_kms->params.display_to_capture, &monitor)) { } else if(!get_monitor_by_name(cap_kms->dpy, cap_kms->params.display_to_capture, &monitor)) {
fprintf(stderr, "gsr error: gsr_capture_kms_vaapi_start: failed to find monitor by name \"%s\"\n", cap_kms->params.display_to_capture); fprintf(stderr, "gsr error: gsr_capture_kms_vaapi_start: failed to find monitor by name \"%s\"\n", cap_kms->params.display_to_capture);
gsr_capture_kms_vaapi_stop(cap, video_codec_context); gsr_capture_kms_vaapi_stop(cap, video_codec_context);
return -1; return -1;
@ -157,7 +162,7 @@ static int gsr_capture_kms_vaapi_start(gsr_capture *cap, AVCodecContext *video_c
cap_kms->capture_pos = monitor.pos; cap_kms->capture_pos = monitor.pos;
cap_kms->capture_size = monitor.size; cap_kms->capture_size = monitor.size;
if(!gsr_egl_load(&cap_kms->egl, cap_kms->params.dpy)) { if(!gsr_egl_load(&cap_kms->egl, cap_kms->dpy)) {
fprintf(stderr, "gsr error: gsr_capture_kms_vaapi_start: failed to load opengl\n"); fprintf(stderr, "gsr error: gsr_capture_kms_vaapi_start: failed to load opengl\n");
gsr_capture_kms_vaapi_stop(cap, video_codec_context); gsr_capture_kms_vaapi_stop(cap, video_codec_context);
return -1; return -1;
@ -174,6 +179,14 @@ static int gsr_capture_kms_vaapi_start(gsr_capture *cap, AVCodecContext *video_c
return -1; return -1;
} }
if(gsr_cursor_init(&cap_kms->cursor, &cap_kms->egl, cap_kms->dpy) != 0) {
gsr_capture_kms_vaapi_stop(cap, video_codec_context);
return -1;
}
gsr_cursor_change_window_target(&cap_kms->cursor, DefaultRootWindow(cap_kms->dpy));
gsr_cursor_update(&cap_kms->cursor, &cap_kms->xev);
return 0; return 0;
} }
@ -189,6 +202,11 @@ static void gsr_capture_kms_vaapi_tick(gsr_capture *cap, AVCodecContext *video_c
// TODO: // TODO:
cap_kms->egl.glClear(GL_COLOR_BUFFER_BIT); cap_kms->egl.glClear(GL_COLOR_BUFFER_BIT);
while(XPending(cap_kms->dpy)) {
XNextEvent(cap_kms->dpy, &cap_kms->xev);
gsr_cursor_update(&cap_kms->cursor, &cap_kms->xev);
}
if(!cap_kms->created_hw_frame) { if(!cap_kms->created_hw_frame) {
cap_kms->created_hw_frame = true; cap_kms->created_hw_frame = true;
@ -286,46 +304,15 @@ static void gsr_capture_kms_vaapi_tick(gsr_capture *cap, AVCodecContext *video_c
cap_kms->egl.glBindTexture(GL_TEXTURE_2D, 0); 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}; gsr_color_conversion_params color_conversion_params = {0};
color_conversion_params.egl = &cap_kms->egl; color_conversion_params.egl = &cap_kms->egl;
color_conversion_params.source_color = GSR_SOURCE_COLOR_RGB; color_conversion_params.source_color = GSR_SOURCE_COLOR_RGB;
color_conversion_params.destination_color = GSR_DESTINATION_COLOR_NV12; 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[0] = cap_kms->target_textures[0];
color_conversion_params.destination_textures[1] = cap_kms->target_textures[1]; color_conversion_params.destination_textures[1] = cap_kms->target_textures[1];
color_conversion_params.num_destination_textures = 2; 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) { 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"); fprintf(stderr, "gsr error: gsr_capture_kms_vaapi_tick: failed to create color conversion\n");
cap_kms->should_stop = true; cap_kms->should_stop = true;
@ -410,7 +397,35 @@ static int gsr_capture_kms_vaapi_capture(gsr_capture *cap, AVFrame *frame) {
cap_kms->egl.eglDestroyImage(cap_kms->egl.egl_display, image); cap_kms->egl.eglDestroyImage(cap_kms->egl.egl_display, image);
cap_kms->egl.glBindTexture(GL_TEXTURE_2D, 0); cap_kms->egl.glBindTexture(GL_TEXTURE_2D, 0);
gsr_color_conversion_update(&cap_kms->color_conversion, frame->width, frame->height); 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;
}
}
gsr_cursor_tick(&cap_kms->cursor);
gsr_color_conversion_draw(&cap_kms->color_conversion, cap_kms->input_texture,
(vec2i){0, 0}, (vec2i){cap_kms->capture_size.x, cap_kms->capture_size.y},
(vec2i){cap_kms->capture_pos.x, cap_kms->capture_pos.y}, (vec2i){cap_kms->capture_size.x, cap_kms->capture_size.y},
texture_rotation);
gsr_color_conversion_draw(&cap_kms->color_conversion, cap_kms->cursor.texture_id,
(vec2i){cap_kms->cursor.position.x - cap_kms->cursor.hotspot.x - cap_kms->capture_pos.x, cap_kms->cursor.position.y - cap_kms->cursor.hotspot.y - cap_kms->capture_pos.y}, (vec2i){cap_kms->cursor.size.x, cap_kms->cursor.size.y},
(vec2i){0, 0}, (vec2i){cap_kms->cursor.size.x, cap_kms->cursor.size.y},
0.0f);
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);
@ -425,6 +440,7 @@ 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) { static void gsr_capture_kms_vaapi_stop(gsr_capture *cap, AVCodecContext *video_codec_context) {
gsr_capture_kms_vaapi *cap_kms = cap->priv; gsr_capture_kms_vaapi *cap_kms = cap->priv;
gsr_cursor_deinit(&cap_kms->cursor);
gsr_color_conversion_deinit(&cap_kms->color_conversion); gsr_color_conversion_deinit(&cap_kms->color_conversion);
for(uint32_t i = 0; i < cap_kms->prime.num_objects; ++i) { for(uint32_t i = 0; i < cap_kms->prime.num_objects; ++i) {
@ -455,6 +471,11 @@ static void gsr_capture_kms_vaapi_stop(gsr_capture *cap, AVCodecContext *video_c
gsr_egl_unload(&cap_kms->egl); gsr_egl_unload(&cap_kms->egl);
gsr_kms_client_deinit(&cap_kms->kms_client); gsr_kms_client_deinit(&cap_kms->kms_client);
if(cap_kms->dpy) {
// TODO: This causes a crash, why? maybe some other library dlclose xlib and that also happened to unload this???
//XCloseDisplay(cap_kms->dpy);
cap_kms->dpy = NULL;
}
} }
static void gsr_capture_kms_vaapi_destroy(gsr_capture *cap, AVCodecContext *video_codec_context) { static void gsr_capture_kms_vaapi_destroy(gsr_capture *cap, AVCodecContext *video_codec_context) {
@ -496,11 +517,13 @@ gsr_capture* gsr_capture_kms_vaapi_create(const gsr_capture_kms_vaapi_params *pa
const char *display_to_capture = strdup(params->display_to_capture); const char *display_to_capture = strdup(params->display_to_capture);
if(!display_to_capture) { if(!display_to_capture) {
/* TODO XCloseDisplay */
free(cap); free(cap);
free(cap_kms); free(cap_kms);
return NULL; return NULL;
} }
cap_kms->dpy = display;
cap_kms->params = *params; cap_kms->params = *params;
cap_kms->params.display_to_capture = display_to_capture; cap_kms->params.display_to_capture = display_to_capture;

View File

@ -12,6 +12,7 @@ typedef struct {
gsr_capture_xcomposite_cuda_params params; gsr_capture_xcomposite_cuda_params params;
Display *dpy; Display *dpy;
XEvent xev; XEvent xev;
bool should_stop; bool should_stop;
bool stop_is_error; bool stop_is_error;
bool window_resized; bool window_resized;
@ -482,11 +483,6 @@ static void gsr_capture_xcomposite_cuda_destroy(gsr_capture *cap, AVCodecContext
free(cap->priv); free(cap->priv);
cap->priv = NULL; cap->priv = NULL;
} }
if(cap_xcomp->dpy) {
// TODO: This causes a crash, why? maybe some other library dlclose xlib and that also happened to unload this???
//XCloseDisplay(cap_xcomp->dpy);
cap_xcomp->dpy = NULL;
}
free(cap); free(cap);
} }

View File

@ -16,6 +16,7 @@ typedef struct {
gsr_capture_xcomposite_vaapi_params params; gsr_capture_xcomposite_vaapi_params params;
Display *dpy; Display *dpy;
XEvent xev; XEvent xev;
bool should_stop; bool should_stop;
bool stop_is_error; bool stop_is_error;
bool window_resized; bool window_resized;
@ -611,11 +612,6 @@ static void gsr_capture_xcomposite_vaapi_destroy(gsr_capture *cap, AVCodecContex
free(cap->priv); free(cap->priv);
cap->priv = NULL; cap->priv = NULL;
} }
if(cap_xcomp->dpy) {
// TODO: This causes a crash, why? maybe some other library dlclose xlib and that also happened to unload this???
//XCloseDisplay(cap_xcomp->dpy);
cap_xcomp->dpy = NULL;
}
free(cap); free(cap);
} }

View File

@ -1,11 +1,16 @@
#include "../include/color_conversion.h" #include "../include/color_conversion.h"
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <math.h>
#include <assert.h> #include <assert.h>
#define MAX_SHADERS 2 #define MAX_SHADERS 2
#define MAX_FRAMEBUFFERS 2 #define MAX_FRAMEBUFFERS 2
static float abs_f(float v) {
return v >= 0.0f ? v : -v;
}
#define ROTATE_Z "mat4 rotate_z(in float angle) {\n" \ #define ROTATE_Z "mat4 rotate_z(in float angle) {\n" \
" return mat4(cos(angle), -sin(angle), 0.0, 0.0,\n" \ " return mat4(cos(angle), -sin(angle), 0.0, 0.0,\n" \
" sin(angle), cos(angle), 0.0, 0.0,\n" \ " sin(angle), cos(angle), 0.0, 0.0,\n" \
@ -18,19 +23,20 @@
" 0.098, -0.071, 0.439, 0.0,\n" \ " 0.098, -0.071, 0.439, 0.0,\n" \
" 0.0625, 0.500, 0.500, 1.0);" " 0.0625, 0.500, 0.500, 1.0);"
static int load_shader_y(gsr_shader *shader, gsr_egl *egl, float rotation) { static int load_shader_y(gsr_shader *shader, gsr_egl *egl, int *rotation_uniform) {
char vertex_shader[2048]; char vertex_shader[2048];
snprintf(vertex_shader, sizeof(vertex_shader), snprintf(vertex_shader, sizeof(vertex_shader),
"#version 300 es \n" "#version 300 es \n"
"in vec2 pos; \n" "in vec2 pos; \n"
"in vec2 texcoords; \n" "in vec2 texcoords; \n"
"out vec2 texcoords_out; \n" "out vec2 texcoords_out; \n"
"uniform float rotation; \n"
ROTATE_Z ROTATE_Z
"void main() \n" "void main() \n"
"{ \n" "{ \n"
" texcoords_out = texcoords; \n" " texcoords_out = texcoords; \n"
" gl_Position = vec4(pos.x, pos.y, 0.0, 1.0) * rotate_z(%f); \n" " gl_Position = vec4(pos.x, pos.y, 0.0, 1.0) * rotate_z(rotation); \n"
"} \n", rotation); "} \n");
char fragment_shader[] = char fragment_shader[] =
"#version 300 es \n" "#version 300 es \n"
@ -41,7 +47,9 @@ static int load_shader_y(gsr_shader *shader, gsr_egl *egl, float rotation) {
RGB_TO_YUV RGB_TO_YUV
"void main() \n" "void main() \n"
"{ \n" "{ \n"
" FragColor.x = (RGBtoYUV * vec4(texture(tex1, texcoords_out).rgb, 1.0)).x; \n" " vec4 pixel = texture(tex1, texcoords_out); \n"
" FragColor.x = (RGBtoYUV * vec4(pixel.rgb, 1.0)).x; \n"
" FragColor.w = pixel.a; \n"
"} \n"; "} \n";
if(gsr_shader_init(shader, egl, vertex_shader, fragment_shader) != 0) if(gsr_shader_init(shader, egl, vertex_shader, fragment_shader) != 0)
@ -49,22 +57,24 @@ static int load_shader_y(gsr_shader *shader, gsr_egl *egl, float rotation) {
gsr_shader_bind_attribute_location(shader, "pos", 0); gsr_shader_bind_attribute_location(shader, "pos", 0);
gsr_shader_bind_attribute_location(shader, "texcoords", 1); gsr_shader_bind_attribute_location(shader, "texcoords", 1);
*rotation_uniform = egl->glGetUniformLocation(shader->program_id, "rotation");
return 0; return 0;
} }
static unsigned int load_shader_uv(gsr_shader *shader, gsr_egl *egl, float rotation) { static unsigned int load_shader_uv(gsr_shader *shader, gsr_egl *egl, int *rotation_uniform) {
char vertex_shader[2048]; char vertex_shader[2048];
snprintf(vertex_shader, sizeof(vertex_shader), snprintf(vertex_shader, sizeof(vertex_shader),
"#version 300 es \n" "#version 300 es \n"
"in vec2 pos; \n" "in vec2 pos; \n"
"in vec2 texcoords; \n" "in vec2 texcoords; \n"
"out vec2 texcoords_out; \n" "out vec2 texcoords_out; \n"
"uniform float rotation; \n"
ROTATE_Z ROTATE_Z
"void main() \n" "void main() \n"
"{ \n" "{ \n"
" texcoords_out = texcoords; \n" " texcoords_out = texcoords; \n"
" gl_Position = vec4(pos.x, pos.y, 0.0, 1.0) * rotate_z(%f) * vec4(0.5, 0.5, 1.0, 1.0) - vec4(0.5, 0.5, 0.0, 0.0); \n" " gl_Position = vec4(pos.x, pos.y, 0.0, 1.0) * rotate_z(rotation) * vec4(0.5, 0.5, 1.0, 1.0) - vec4(0.5, 0.5, 0.0, 0.0); \n"
"} \n", rotation); "} \n");
char fragment_shader[] = char fragment_shader[] =
"#version 300 es \n" "#version 300 es \n"
@ -75,7 +85,9 @@ static unsigned int load_shader_uv(gsr_shader *shader, gsr_egl *egl, float rotat
RGB_TO_YUV RGB_TO_YUV
"void main() \n" "void main() \n"
"{ \n" "{ \n"
" FragColor.xy = (RGBtoYUV * vec4(texture(tex1, texcoords_out).rgb, 1.0)).zy; \n" " vec4 pixel = texture(tex1, texcoords_out); \n"
" FragColor.xy = (RGBtoYUV * vec4(pixel.rgb, 1.0)).zy; \n"
" FragColor.w = pixel.a; \n"
"} \n"; "} \n";
if(gsr_shader_init(shader, egl, vertex_shader, fragment_shader) != 0) if(gsr_shader_init(shader, egl, vertex_shader, fragment_shader) != 0)
@ -83,61 +95,53 @@ static unsigned int load_shader_uv(gsr_shader *shader, gsr_egl *egl, float rotat
gsr_shader_bind_attribute_location(shader, "pos", 0); gsr_shader_bind_attribute_location(shader, "pos", 0);
gsr_shader_bind_attribute_location(shader, "texcoords", 1); gsr_shader_bind_attribute_location(shader, "texcoords", 1);
*rotation_uniform = egl->glGetUniformLocation(shader->program_id, "rotation");
return 0; return 0;
} }
static int loader_framebuffers(gsr_color_conversion *self) { static int loader_framebuffers(gsr_color_conversion *self) {
const unsigned int draw_buffer = GL_COLOR_ATTACHMENT0; const unsigned int draw_buffer = GL_COLOR_ATTACHMENT0;
self->egl->glGenFramebuffers(MAX_FRAMEBUFFERS, self->framebuffers); self->params.egl->glGenFramebuffers(MAX_FRAMEBUFFERS, self->framebuffers);
self->egl->glBindFramebuffer(GL_FRAMEBUFFER, self->framebuffers[0]); self->params.egl->glBindFramebuffer(GL_FRAMEBUFFER, self->framebuffers[0]);
self->egl->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self->destination_textures[0], 0); self->params.egl->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self->params.destination_textures[0], 0);
self->egl->glDrawBuffers(1, &draw_buffer); self->params.egl->glDrawBuffers(1, &draw_buffer);
if(self->egl->glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { if(self->params.egl->glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to create framebuffer for Y\n"); fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to create framebuffer for Y\n");
goto err; goto err;
} }
self->egl->glBindFramebuffer(GL_FRAMEBUFFER, self->framebuffers[1]); self->params.egl->glBindFramebuffer(GL_FRAMEBUFFER, self->framebuffers[1]);
self->egl->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self->destination_textures[1], 0); self->params.egl->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self->params.destination_textures[1], 0);
self->egl->glDrawBuffers(1, &draw_buffer); self->params.egl->glDrawBuffers(1, &draw_buffer);
if(self->egl->glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { if(self->params.egl->glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to create framebuffer for UV\n"); fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to create framebuffer for UV\n");
goto err; goto err;
} }
self->egl->glBindFramebuffer(GL_FRAMEBUFFER, 0); self->params.egl->glBindFramebuffer(GL_FRAMEBUFFER, 0);
return 0; return 0;
err: err:
self->egl->glBindFramebuffer(GL_FRAMEBUFFER, 0); self->params.egl->glBindFramebuffer(GL_FRAMEBUFFER, 0);
return -1; return -1;
} }
static int create_vertices(gsr_color_conversion *self, vec2f position, vec2f size) { static int create_vertices(gsr_color_conversion *self) {
const float vertices[] = { self->params.egl->glGenVertexArrays(1, &self->vertex_array_object_id);
-1.0f, 1.0f, position.x, position.y + size.y, self->params.egl->glBindVertexArray(self->vertex_array_object_id);
-1.0f, -1.0f, position.x, position.y,
1.0f, -1.0f, position.x + size.x, position.y,
-1.0f, 1.0f, position.x, position.y + size.y, self->params.egl->glGenBuffers(1, &self->vertex_buffer_object_id);
1.0f, -1.0f, position.x + size.x, position.y, self->params.egl->glBindBuffer(GL_ARRAY_BUFFER, self->vertex_buffer_object_id);
1.0f, 1.0f, position.x + size.x, position.y + size.y self->params.egl->glBufferData(GL_ARRAY_BUFFER, 24 * sizeof(float), NULL, GL_STREAM_DRAW);
};
self->egl->glGenVertexArrays(1, &self->vertex_array_object_id); self->params.egl->glEnableVertexAttribArray(0);
self->egl->glGenBuffers(1, &self->vertex_buffer_object_id); self->params.egl->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
self->egl->glBindVertexArray(self->vertex_array_object_id);
self->egl->glBindBuffer(GL_ARRAY_BUFFER, self->vertex_buffer_object_id);
self->egl->glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), &vertices, GL_STATIC_DRAW);
self->egl->glEnableVertexAttribArray(0); self->params.egl->glEnableVertexAttribArray(1);
self->egl->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0); self->params.egl->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
self->egl->glEnableVertexAttribArray(1); self->params.egl->glBindVertexArray(0);
self->egl->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
self->egl->glBindVertexArray(0);
return 0; return 0;
} }
@ -145,61 +149,53 @@ int gsr_color_conversion_init(gsr_color_conversion *self, const gsr_color_conver
assert(params); assert(params);
assert(params->egl); assert(params->egl);
memset(self, 0, sizeof(*self)); memset(self, 0, sizeof(*self));
self->egl = params->egl; self->params.egl = params->egl;
self->params = *params;
if(params->num_source_textures != 1) { if(self->params.num_destination_textures != 2) {
fprintf(stderr, "gsr error: gsr_color_conversion_init: expected 1 source texture for source color RGB, got %d source texture(s)\n", params->num_source_textures); fprintf(stderr, "gsr error: gsr_color_conversion_init: expected 2 destination textures for destination color NV12, got %d destination texture(s)\n", self->params.num_destination_textures);
return -1; return -1;
} }
if(params->num_destination_textures != 2) { if(load_shader_y(&self->shaders[0], self->params.egl, &self->rotation_uniforms[0]) != 0) {
fprintf(stderr, "gsr error: gsr_color_conversion_init: expected 2 destination textures for destination color NV12, got %d destination texture(s)\n", params->num_destination_textures); fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load Y shader\n");
return -1;
}
if(load_shader_y(&self->shaders[0], self->egl, params->rotation) != 0) {
fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to loader Y shader\n");
goto err; goto err;
} }
if(load_shader_uv(&self->shaders[1], self->egl, params->rotation) != 0) { if(load_shader_uv(&self->shaders[1], self->params.egl, &self->rotation_uniforms[1]) != 0) {
fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to loader UV shader\n"); fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load UV shader\n");
goto err; goto err;
} }
self->source_textures[0] = params->source_textures[0];
self->destination_textures[0] = params->destination_textures[0];
self->destination_textures[1] = params->destination_textures[1];
if(loader_framebuffers(self) != 0) if(loader_framebuffers(self) != 0)
goto err; goto err;
if(create_vertices(self, params->position, params->size) != 0) if(create_vertices(self) != 0)
goto err; goto err;
return 0; return 0;
err: err:
self->egl->glBindFramebuffer(GL_FRAMEBUFFER, 0); self->params.egl->glBindFramebuffer(GL_FRAMEBUFFER, 0);
gsr_color_conversion_deinit(self); gsr_color_conversion_deinit(self);
return -1; return -1;
} }
void gsr_color_conversion_deinit(gsr_color_conversion *self) { void gsr_color_conversion_deinit(gsr_color_conversion *self) {
if(!self->egl) if(!self->params.egl)
return; return;
if(self->vertex_buffer_object_id) { if(self->vertex_buffer_object_id) {
self->egl->glDeleteBuffers(1, &self->vertex_buffer_object_id); self->params.egl->glDeleteBuffers(1, &self->vertex_buffer_object_id);
self->vertex_buffer_object_id = 0; self->vertex_buffer_object_id = 0;
} }
if(self->vertex_array_object_id) { if(self->vertex_array_object_id) {
self->egl->glDeleteVertexArrays(1, &self->vertex_array_object_id); self->params.egl->glDeleteVertexArrays(1, &self->vertex_array_object_id);
self->vertex_array_object_id = 0; self->vertex_array_object_id = 0;
} }
self->egl->glDeleteFramebuffers(MAX_FRAMEBUFFERS, self->framebuffers); self->params.egl->glDeleteFramebuffers(MAX_FRAMEBUFFERS, self->framebuffers);
for(int i = 0; i < MAX_FRAMEBUFFERS; ++i) { for(int i = 0; i < MAX_FRAMEBUFFERS; ++i) {
self->framebuffers[i] = 0; self->framebuffers[i] = 0;
} }
@ -208,33 +204,88 @@ void gsr_color_conversion_deinit(gsr_color_conversion *self) {
gsr_shader_deinit(&self->shaders[i]); gsr_shader_deinit(&self->shaders[i]);
} }
self->egl = NULL; self->params.egl = NULL;
} }
int gsr_color_conversion_update(gsr_color_conversion *self, int width, int height) { /* |source_pos| is in pixel coordinates and |source_size| */
self->egl->glBindVertexArray(self->vertex_array_object_id); int gsr_color_conversion_draw(gsr_color_conversion *self, unsigned int texture_id, vec2i source_pos, vec2i source_size, vec2i texture_pos, vec2i texture_size, float rotation) {
self->egl->glViewport(0, 0, width, height); /* TODO: Do not call this every frame? */
self->egl->glBindTexture(GL_TEXTURE_2D, self->source_textures[0]); vec2i dest_texture_size = {0, 0};
self->params.egl->glBindTexture(GL_TEXTURE_2D, self->params.destination_textures[0]);
self->params.egl->glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &dest_texture_size.x);
self->params.egl->glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &dest_texture_size.y);
/* TODO: Do not call this every frame? */
vec2i source_texture_size = {0, 0};
self->params.egl->glBindTexture(GL_TEXTURE_2D, texture_id);
self->params.egl->glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &source_texture_size.x);
self->params.egl->glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &source_texture_size.y);
if(abs_f(M_PI * 0.5f - rotation) <= 0.001f || abs_f(M_PI * 1.5f - rotation) <= 0.001f) {
float tmp = source_texture_size.x;
source_texture_size.x = source_texture_size.y;
source_texture_size.y = tmp;
}
const vec2f pos_norm = {
((float)source_pos.x / (dest_texture_size.x == 0 ? 1.0f : (float)dest_texture_size.x)) * 2.0f,
((float)source_pos.y / (dest_texture_size.y == 0 ? 1.0f : (float)dest_texture_size.y)) * 2.0f,
};
const vec2f size_norm = {
((float)source_size.x / (dest_texture_size.x == 0 ? 1.0f : (float)dest_texture_size.x)) * 2.0f,
((float)source_size.y / (dest_texture_size.y == 0 ? 1.0f : (float)dest_texture_size.y)) * 2.0f,
};
const vec2f texture_pos_norm = {
(float)texture_pos.x / (source_texture_size.x == 0 ? 1.0f : (float)source_texture_size.x),
(float)texture_pos.y / (source_texture_size.y == 0 ? 1.0f : (float)source_texture_size.y),
};
const vec2f texture_size_norm = {
(float)texture_size.x / (source_texture_size.x == 0 ? 1.0f : (float)source_texture_size.x),
(float)texture_size.y / (source_texture_size.y == 0 ? 1.0f : (float)source_texture_size.y),
};
const float vertices[] = {
-1.0f + pos_norm.x, -1.0f + pos_norm.y + size_norm.y, texture_pos_norm.x, texture_pos_norm.y + texture_size_norm.y,
-1.0f + pos_norm.x, -1.0f + pos_norm.y, texture_pos_norm.x, texture_pos_norm.y,
-1.0f + pos_norm.x + size_norm.x, -1.0f + pos_norm.y, texture_pos_norm.x + texture_size_norm.x, texture_pos_norm.y,
-1.0f + pos_norm.x, -1.0f + pos_norm.y + size_norm.y, texture_pos_norm.x, texture_pos_norm.y + texture_size_norm.y,
-1.0f + pos_norm.x + size_norm.x, -1.0f + pos_norm.y, texture_pos_norm.x + texture_size_norm.x, texture_pos_norm.y,
-1.0f + pos_norm.x + size_norm.x, -1.0f + pos_norm.y + size_norm.y, texture_pos_norm.x + texture_size_norm.x, texture_pos_norm.y + texture_size_norm.y
};
self->params.egl->glBindVertexArray(self->vertex_array_object_id);
self->params.egl->glViewport(0, 0, dest_texture_size.x, dest_texture_size.y);
self->params.egl->glBindTexture(GL_TEXTURE_2D, texture_id);
/* TODO: this, also cleanup */
//self->params.egl->glBindBuffer(GL_ARRAY_BUFFER, self->vertex_buffer_object_id);
self->params.egl->glBufferSubData(GL_ARRAY_BUFFER, 0, 24 * sizeof(float), vertices);
{ {
self->egl->glBindFramebuffer(GL_FRAMEBUFFER, self->framebuffers[0]); self->params.egl->glBindFramebuffer(GL_FRAMEBUFFER, self->framebuffers[0]);
//cap_xcomp->egl.glClear(GL_COLOR_BUFFER_BIT); //cap_xcomp->egl.glClear(GL_COLOR_BUFFER_BIT);
gsr_shader_use(&self->shaders[0]); gsr_shader_use(&self->shaders[0]);
self->egl->glDrawArrays(GL_TRIANGLES, 0, 6); self->params.egl->glUniform1f(self->rotation_uniforms[0], rotation);
self->params.egl->glDrawArrays(GL_TRIANGLES, 0, 6);
} }
{ {
self->egl->glBindFramebuffer(GL_FRAMEBUFFER, self->framebuffers[1]); self->params.egl->glBindFramebuffer(GL_FRAMEBUFFER, self->framebuffers[1]);
//cap_xcomp->egl.glClear(GL_COLOR_BUFFER_BIT); //cap_xcomp->egl.glClear(GL_COLOR_BUFFER_BIT);
gsr_shader_use(&self->shaders[1]); gsr_shader_use(&self->shaders[1]);
self->egl->glDrawArrays(GL_TRIANGLES, 0, 6); self->params.egl->glUniform1f(self->rotation_uniforms[1], rotation);
self->params.egl->glDrawArrays(GL_TRIANGLES, 0, 6);
} }
self->egl->glBindVertexArray(0); self->params.egl->glBindVertexArray(0);
gsr_shader_use_none(&self->shaders[0]); gsr_shader_use_none(&self->shaders[0]);
self->egl->glBindTexture(GL_TEXTURE_2D, 0); self->params.egl->glBindTexture(GL_TEXTURE_2D, 0);
self->egl->glBindFramebuffer(GL_FRAMEBUFFER, 0); self->params.egl->glBindFramebuffer(GL_FRAMEBUFFER, 0);
return 0; return 0;
} }

View File

@ -46,12 +46,11 @@ static bool gsr_cursor_set_from_x11_cursor_image(gsr_cursor *self, XFixesCursorI
self->egl->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, self->size.x, self->size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, cursor_data); self->egl->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, self->size.x, self->size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, cursor_data);
free(cursor_data); free(cursor_data);
self->egl->glGenerateMipmap(GL_TEXTURE_2D);
self->egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); self->egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
self->egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); self->egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
self->egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); self->egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
self->egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); self->egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
self->egl->glBindTexture(GL_TEXTURE_2D, 0); self->egl->glBindTexture(GL_TEXTURE_2D, 0);
XFree(x11_cursor_image); XFree(x11_cursor_image);
@ -65,6 +64,8 @@ static bool gsr_cursor_set_from_x11_cursor_image(gsr_cursor *self, XFixesCursorI
} }
int gsr_cursor_init(gsr_cursor *self, gsr_egl *egl, Display *display) { int gsr_cursor_init(gsr_cursor *self, gsr_egl *egl, Display *display) {
int x_fixes_error_base = 0;
assert(egl); assert(egl);
assert(display); assert(display);
memset(self, 0, sizeof(*self)); memset(self, 0, sizeof(*self));
@ -72,9 +73,8 @@ int gsr_cursor_init(gsr_cursor *self, gsr_egl *egl, Display *display) {
self->display = display; self->display = display;
self->x_fixes_event_base = 0; self->x_fixes_event_base = 0;
int x_fixes_error_base = 0; if(!XFixesQueryExtension(self->display, &self->x_fixes_event_base, &x_fixes_error_base)) {
if(!XFixesQueryExtension(display, &self->x_fixes_event_base, &x_fixes_error_base)) { fprintf(stderr, "gsr error: gsr_cursor_init: your X11 server is missing the XFixes extension\n");
fprintf(stderr, "gsr error: gsr_cursor_init: your x11 server is missing the xfixes extension. no cursor will be visible in the video\n");
gsr_cursor_deinit(self); gsr_cursor_deinit(self);
return -1; return -1;
} }
@ -113,7 +113,7 @@ int gsr_cursor_change_window_target(gsr_cursor *self, Window window) {
void gsr_cursor_update(gsr_cursor *self, XEvent *xev) { void gsr_cursor_update(gsr_cursor *self, XEvent *xev) {
if(xev->type == self->x_fixes_event_base + XFixesCursorNotify) { if(xev->type == self->x_fixes_event_base + XFixesCursorNotify) {
XFixesCursorNotifyEvent *cursor_notify_event = (XFixesCursorNotifyEvent*)&xev; XFixesCursorNotifyEvent *cursor_notify_event = (XFixesCursorNotifyEvent*)xev;
if(cursor_notify_event->subtype == XFixesDisplayCursorNotify && cursor_notify_event->window == self->window) { if(cursor_notify_event->subtype == XFixesDisplayCursorNotify && cursor_notify_event->window == self->window) {
self->cursor_image_set = true; self->cursor_image_set = true;
gsr_cursor_set_from_x11_cursor_image(self, XFixesGetCursorImage(self->display)); gsr_cursor_set_from_x11_cursor_image(self, XFixesGetCursorImage(self->display));
@ -125,3 +125,11 @@ void gsr_cursor_update(gsr_cursor *self, XEvent *xev) {
gsr_cursor_set_from_x11_cursor_image(self, XFixesGetCursorImage(self->display)); gsr_cursor_set_from_x11_cursor_image(self, XFixesGetCursorImage(self->display));
} }
} }
void gsr_cursor_tick(gsr_cursor *self) {
/* TODO: Use XInput2 instead. However that doesn't work when the pointer is grabbed. Maybe check for focused window change and XSelectInput PointerMask */
Window dummy_window;
int dummy_i;
unsigned int dummy_u;
XQueryPointer(self->display, DefaultRootWindow(self->display), &dummy_window, &dummy_window, &dummy_i, &dummy_i, &self->position.x, &self->position.y, &dummy_u);
}

View File

@ -138,7 +138,6 @@ static bool gsr_egl_load_gl(gsr_egl *self, void *library) {
{ (void**)&self->glTexImage2D, "glTexImage2D" }, { (void**)&self->glTexImage2D, "glTexImage2D" },
{ (void**)&self->glCopyImageSubData, "glCopyImageSubData" }, { (void**)&self->glCopyImageSubData, "glCopyImageSubData" },
{ (void**)&self->glClearTexImage, "glClearTexImage" }, { (void**)&self->glClearTexImage, "glClearTexImage" },
{ (void**)&self->glGenerateMipmap, "glGenerateMipmap" },
{ (void**)&self->glGenFramebuffers, "glGenFramebuffers" }, { (void**)&self->glGenFramebuffers, "glGenFramebuffers" },
{ (void**)&self->glBindFramebuffer, "glBindFramebuffer" }, { (void**)&self->glBindFramebuffer, "glBindFramebuffer" },
{ (void**)&self->glDeleteFramebuffers, "glDeleteFramebuffers" }, { (void**)&self->glDeleteFramebuffers, "glDeleteFramebuffers" },
@ -149,6 +148,7 @@ static bool gsr_egl_load_gl(gsr_egl *self, void *library) {
{ (void**)&self->glBindBuffer, "glBindBuffer" }, { (void**)&self->glBindBuffer, "glBindBuffer" },
{ (void**)&self->glGenBuffers, "glGenBuffers" }, { (void**)&self->glGenBuffers, "glGenBuffers" },
{ (void**)&self->glBufferData, "glBufferData" }, { (void**)&self->glBufferData, "glBufferData" },
{ (void**)&self->glBufferSubData, "glBufferSubData" },
{ (void**)&self->glDeleteBuffers, "glDeleteBuffers" }, { (void**)&self->glDeleteBuffers, "glDeleteBuffers" },
{ (void**)&self->glGenVertexArrays, "glGenVertexArrays" }, { (void**)&self->glGenVertexArrays, "glGenVertexArrays" },
{ (void**)&self->glBindVertexArray, "glBindVertexArray" }, { (void**)&self->glBindVertexArray, "glBindVertexArray" },
@ -170,6 +170,10 @@ static bool gsr_egl_load_gl(gsr_egl *self, void *library) {
{ (void**)&self->glVertexAttribPointer, "glVertexAttribPointer" }, { (void**)&self->glVertexAttribPointer, "glVertexAttribPointer" },
{ (void**)&self->glEnableVertexAttribArray, "glEnableVertexAttribArray" }, { (void**)&self->glEnableVertexAttribArray, "glEnableVertexAttribArray" },
{ (void**)&self->glDrawArrays, "glDrawArrays" }, { (void**)&self->glDrawArrays, "glDrawArrays" },
{ (void**)&self->glEnable, "glEnable" },
{ (void**)&self->glBlendFunc, "glBlendFunc" },
{ (void**)&self->glGetUniformLocation, "glGetUniformLocation" },
{ (void**)&self->glUniform1f, "glUniform1f" },
{ NULL, NULL } { NULL, NULL }
}; };
@ -214,6 +218,9 @@ bool gsr_egl_load(gsr_egl *self, Display *dpy) {
if(!gsr_egl_create_window(self)) if(!gsr_egl_create_window(self))
goto fail; goto fail;
self->glEnable(GL_BLEND);
self->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
self->egl_library = egl_lib; self->egl_library = egl_lib;
self->gl_library = gl_lib; self->gl_library = gl_lib;
return true; return true;

View File

@ -1384,7 +1384,6 @@ int main(int argc, char **argv) {
} }
gsr_capture_kms_vaapi_params kms_params; gsr_capture_kms_vaapi_params kms_params;
kms_params.dpy = dpy;
kms_params.display_to_capture = capture_target; kms_params.display_to_capture = capture_target;
kms_params.gpu_inf = gpu_inf; kms_params.gpu_inf = gpu_inf;
kms_params.card_path = card_path; kms_params.card_path = card_path;