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:
parent
2021456be0
commit
e1c613666e
@ -85,6 +85,6 @@ If you really want to donate, you can donate via bitcoin or monero.
|
||||
|
||||
# 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.
|
||||
* 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.
|
||||
* 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
2
TODO
@ -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.
|
||||
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?
|
||||
|
||||
When using multiple monitors kms grab the target monitor instead of the whole screen.
|
3
build.sh
3
build.sh
@ -27,11 +27,12 @@ build_gsr() {
|
||||
gcc -c src/window_texture.c $opts $includes
|
||||
gcc -c src/shader.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/library_loader.c $opts $includes
|
||||
g++ -c src/sound.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
|
||||
|
@ -9,7 +9,6 @@
|
||||
typedef struct _XDisplay Display;
|
||||
|
||||
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 */
|
||||
gsr_gpu_info gpu_inf;
|
||||
const char *card_path; /* reference */
|
||||
|
@ -18,25 +18,15 @@ typedef struct {
|
||||
gsr_source_color source_color;
|
||||
gsr_destination_color destination_color;
|
||||
|
||||
unsigned int source_textures[2];
|
||||
int num_source_textures;
|
||||
|
||||
unsigned int destination_textures[2];
|
||||
int num_destination_textures;
|
||||
|
||||
float rotation;
|
||||
|
||||
vec2f position;
|
||||
vec2f size;
|
||||
} gsr_color_conversion_params;
|
||||
|
||||
typedef struct {
|
||||
gsr_egl *egl;
|
||||
gsr_color_conversion_params params;
|
||||
int rotation_uniforms[2];
|
||||
gsr_shader shaders[2];
|
||||
|
||||
unsigned int source_textures[2];
|
||||
unsigned int destination_textures[2];
|
||||
|
||||
unsigned int framebuffers[2];
|
||||
|
||||
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);
|
||||
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 */
|
||||
|
@ -15,6 +15,7 @@ typedef struct {
|
||||
unsigned int texture_id;
|
||||
vec2i size;
|
||||
vec2i hotspot;
|
||||
vec2i position;
|
||||
|
||||
bool cursor_image_set;
|
||||
} gsr_cursor;
|
||||
@ -24,5 +25,6 @@ void gsr_cursor_deinit(gsr_cursor *self);
|
||||
|
||||
int gsr_cursor_change_window_target(gsr_cursor *self, Window window);
|
||||
void gsr_cursor_update(gsr_cursor *self, XEvent *xev);
|
||||
void gsr_cursor_tick(gsr_cursor *self);
|
||||
|
||||
#endif /* GSR_CURSOR_H */
|
||||
|
@ -66,7 +66,6 @@ typedef void (*__eglMustCastToProperFunctionPointerType)(void);
|
||||
#define GL_TEXTURE_WRAP_T 0x2803
|
||||
#define GL_TEXTURE_MAG_FILTER 0x2800
|
||||
#define GL_TEXTURE_MIN_FILTER 0x2801
|
||||
#define GL_LINEAR_MIPMAP_LINEAR 0x2703
|
||||
#define GL_TEXTURE_WIDTH 0x1000
|
||||
#define GL_TEXTURE_HEIGHT 0x1001
|
||||
#define GL_NEAREST 0x2600
|
||||
@ -75,8 +74,11 @@ typedef void (*__eglMustCastToProperFunctionPointerType)(void);
|
||||
#define GL_FRAMEBUFFER 0x8D40
|
||||
#define GL_COLOR_ATTACHMENT0 0x8CE0
|
||||
#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
|
||||
#define GL_STATIC_DRAW 0x88E4
|
||||
#define GL_STREAM_DRAW 0x88E0
|
||||
#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_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 (*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 (*glGenerateMipmap)(unsigned int target);
|
||||
void (*glGenFramebuffers)(int n, unsigned int *framebuffers);
|
||||
void (*glBindFramebuffer)(unsigned int target, unsigned int framebuffer);
|
||||
void (*glDeleteFramebuffers)(int n, const unsigned int *framebuffers);
|
||||
@ -140,11 +141,11 @@ typedef struct {
|
||||
void (*glBindBuffer)(unsigned int target, unsigned int buffer);
|
||||
void (*glGenBuffers)(int n, unsigned int *buffers);
|
||||
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 (*glGenVertexArrays)(int n, unsigned int *arrays);
|
||||
void (*glBindVertexArray)(unsigned int array);
|
||||
void (*glDeleteVertexArrays)(int n, const unsigned int *arrays);
|
||||
|
||||
unsigned int (*glCreateProgram)(void);
|
||||
unsigned int (*glCreateShader)(unsigned int type);
|
||||
void (*glAttachShader)(unsigned int program, unsigned int shader);
|
||||
@ -162,6 +163,10 @@ typedef struct {
|
||||
void (*glVertexAttribPointer)(unsigned int index, int size, unsigned int type, unsigned char normalized, int stride, const void *pointer);
|
||||
void (*glEnableVertexAttribArray)(unsigned int index);
|
||||
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;
|
||||
|
||||
bool gsr_egl_load(gsr_egl *self, Display *dpy);
|
||||
|
@ -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) {
|
||||
drmModePlaneResPtr planes = NULL;
|
||||
drmModePlanePtr plane = NULL;
|
||||
drmModeFB2Ptr drmfb = NULL;
|
||||
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) {
|
||||
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) {
|
||||
plane = drmModeGetPlane(drm->drmfd, planes->planes[i]);
|
||||
drmModePlanePtr plane = drmModeGetPlane(drm->drmfd, planes->planes[i]);
|
||||
if(!plane) {
|
||||
fprintf(stderr, "kms server warning: failed to get drmModePlanePtr for plane %#x: %s (%d)\n", planes->planes[i], strerror(errno), errno);
|
||||
continue;
|
||||
@ -92,34 +92,28 @@ static int kms_get_plane_id(gsr_drm *drm) {
|
||||
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");
|
||||
goto error;
|
||||
}
|
||||
|
||||
// TODO: Fallback to getfb(1)?
|
||||
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;
|
||||
drm->plane_id = best_plane_match;
|
||||
result = 0;
|
||||
|
||||
error:
|
||||
if(drmfb)
|
||||
drmModeFreeFB2(drmfb);
|
||||
if(plane)
|
||||
drmModeFreePlane(plane);
|
||||
if(planes)
|
||||
drmModeFreePlaneResources(planes);
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "../../include/egl.h"
|
||||
#include "../../include/utils.h"
|
||||
#include "../../include/color_conversion.h"
|
||||
#include "../../include/cursor.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
@ -24,6 +25,9 @@ typedef enum {
|
||||
|
||||
typedef struct {
|
||||
gsr_capture_kms_vaapi_params params;
|
||||
Display *dpy;
|
||||
XEvent xev;
|
||||
|
||||
bool should_stop;
|
||||
bool stop_is_error;
|
||||
bool created_hw_frame;
|
||||
@ -54,7 +58,8 @@ typedef struct {
|
||||
unsigned int target_textures[2];
|
||||
|
||||
gsr_color_conversion color_conversion;
|
||||
unsigned int vao;
|
||||
|
||||
gsr_cursor cursor;
|
||||
} gsr_capture_kms_vaapi;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
MonitorCallbackUserdata monitor_callback_userdata = {0};
|
||||
for_each_active_monitor_output(cap_kms->params.dpy, monitor_callback, &monitor_callback_userdata);
|
||||
MonitorCallbackUserdata monitor_callback_userdata = {0, X11_ROT_0};
|
||||
for_each_active_monitor_output(cap_kms->dpy, monitor_callback, &monitor_callback_userdata);
|
||||
|
||||
gsr_monitor monitor;
|
||||
if(strcmp(cap_kms->params.display_to_capture, "screen") == 0) {
|
||||
monitor.pos.x = 0;
|
||||
monitor.pos.y = 0;
|
||||
monitor.size.x = XWidthOfScreen(DefaultScreenOfDisplay(cap_kms->params.dpy));
|
||||
monitor.size.y = XHeightOfScreen(DefaultScreenOfDisplay(cap_kms->params.dpy));
|
||||
monitor.size.x = WidthOfScreen(DefaultScreenOfDisplay(cap_kms->dpy));
|
||||
monitor.size.y = HeightOfScreen(DefaultScreenOfDisplay(cap_kms->dpy));
|
||||
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);
|
||||
gsr_capture_kms_vaapi_stop(cap, video_codec_context);
|
||||
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_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");
|
||||
gsr_capture_kms_vaapi_stop(cap, video_codec_context);
|
||||
return -1;
|
||||
@ -174,6 +179,14 @@ static int gsr_capture_kms_vaapi_start(gsr_capture *cap, AVCodecContext *video_c
|
||||
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;
|
||||
}
|
||||
|
||||
@ -189,6 +202,11 @@ static void gsr_capture_kms_vaapi_tick(gsr_capture *cap, AVCodecContext *video_c
|
||||
// TODO:
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
@ -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.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);
|
||||
|
||||
@ -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) {
|
||||
gsr_capture_kms_vaapi *cap_kms = cap->priv;
|
||||
|
||||
gsr_cursor_deinit(&cap_kms->cursor);
|
||||
gsr_color_conversion_deinit(&cap_kms->color_conversion);
|
||||
|
||||
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_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) {
|
||||
@ -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);
|
||||
if(!display_to_capture) {
|
||||
/* TODO XCloseDisplay */
|
||||
free(cap);
|
||||
free(cap_kms);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cap_kms->dpy = display;
|
||||
cap_kms->params = *params;
|
||||
cap_kms->params.display_to_capture = display_to_capture;
|
||||
|
||||
|
@ -12,6 +12,7 @@ typedef struct {
|
||||
gsr_capture_xcomposite_cuda_params params;
|
||||
Display *dpy;
|
||||
XEvent xev;
|
||||
|
||||
bool should_stop;
|
||||
bool stop_is_error;
|
||||
bool window_resized;
|
||||
@ -482,11 +483,6 @@ static void gsr_capture_xcomposite_cuda_destroy(gsr_capture *cap, AVCodecContext
|
||||
free(cap->priv);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@ typedef struct {
|
||||
gsr_capture_xcomposite_vaapi_params params;
|
||||
Display *dpy;
|
||||
XEvent xev;
|
||||
|
||||
bool should_stop;
|
||||
bool stop_is_error;
|
||||
bool window_resized;
|
||||
@ -611,11 +612,6 @@ static void gsr_capture_xcomposite_vaapi_destroy(gsr_capture *cap, AVCodecContex
|
||||
free(cap->priv);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,16 @@
|
||||
#include "../include/color_conversion.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define MAX_SHADERS 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" \
|
||||
" return mat4(cos(angle), -sin(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.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];
|
||||
snprintf(vertex_shader, sizeof(vertex_shader),
|
||||
"#version 300 es \n"
|
||||
"in vec2 pos; \n"
|
||||
"in vec2 texcoords; \n"
|
||||
"out vec2 texcoords_out; \n"
|
||||
"uniform float rotation; \n"
|
||||
ROTATE_Z
|
||||
"void main() \n"
|
||||
"{ \n"
|
||||
" texcoords_out = texcoords; \n"
|
||||
" gl_Position = vec4(pos.x, pos.y, 0.0, 1.0) * rotate_z(%f); \n"
|
||||
"} \n", rotation);
|
||||
" gl_Position = vec4(pos.x, pos.y, 0.0, 1.0) * rotate_z(rotation); \n"
|
||||
"} \n");
|
||||
|
||||
char fragment_shader[] =
|
||||
"#version 300 es \n"
|
||||
@ -41,7 +47,9 @@ static int load_shader_y(gsr_shader *shader, gsr_egl *egl, float rotation) {
|
||||
RGB_TO_YUV
|
||||
"void main() \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";
|
||||
|
||||
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, "texcoords", 1);
|
||||
*rotation_uniform = egl->glGetUniformLocation(shader->program_id, "rotation");
|
||||
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];
|
||||
snprintf(vertex_shader, sizeof(vertex_shader),
|
||||
"#version 300 es \n"
|
||||
"in vec2 pos; \n"
|
||||
"in vec2 texcoords; \n"
|
||||
"out vec2 texcoords_out; \n"
|
||||
"uniform float rotation; \n"
|
||||
ROTATE_Z
|
||||
"void main() \n"
|
||||
"{ \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"
|
||||
"} \n", rotation);
|
||||
" 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");
|
||||
|
||||
char fragment_shader[] =
|
||||
"#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
|
||||
"void main() \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";
|
||||
|
||||
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, "texcoords", 1);
|
||||
*rotation_uniform = egl->glGetUniformLocation(shader->program_id, "rotation");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int loader_framebuffers(gsr_color_conversion *self) {
|
||||
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->egl->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self->destination_textures[0], 0);
|
||||
self->egl->glDrawBuffers(1, &draw_buffer);
|
||||
if(self->egl->glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
||||
self->params.egl->glBindFramebuffer(GL_FRAMEBUFFER, self->framebuffers[0]);
|
||||
self->params.egl->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self->params.destination_textures[0], 0);
|
||||
self->params.egl->glDrawBuffers(1, &draw_buffer);
|
||||
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");
|
||||
goto err;
|
||||
}
|
||||
|
||||
self->egl->glBindFramebuffer(GL_FRAMEBUFFER, self->framebuffers[1]);
|
||||
self->egl->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self->destination_textures[1], 0);
|
||||
self->egl->glDrawBuffers(1, &draw_buffer);
|
||||
if(self->egl->glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
||||
self->params.egl->glBindFramebuffer(GL_FRAMEBUFFER, self->framebuffers[1]);
|
||||
self->params.egl->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self->params.destination_textures[1], 0);
|
||||
self->params.egl->glDrawBuffers(1, &draw_buffer);
|
||||
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");
|
||||
goto err;
|
||||
}
|
||||
|
||||
self->egl->glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
self->params.egl->glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
self->egl->glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
self->params.egl->glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int create_vertices(gsr_color_conversion *self, vec2f position, vec2f size) {
|
||||
const float vertices[] = {
|
||||
-1.0f, 1.0f, position.x, position.y + size.y,
|
||||
-1.0f, -1.0f, position.x, position.y,
|
||||
1.0f, -1.0f, position.x + size.x, position.y,
|
||||
static int create_vertices(gsr_color_conversion *self) {
|
||||
self->params.egl->glGenVertexArrays(1, &self->vertex_array_object_id);
|
||||
self->params.egl->glBindVertexArray(self->vertex_array_object_id);
|
||||
|
||||
-1.0f, 1.0f, position.x, position.y + size.y,
|
||||
1.0f, -1.0f, position.x + size.x, position.y,
|
||||
1.0f, 1.0f, position.x + size.x, position.y + size.y
|
||||
};
|
||||
self->params.egl->glGenBuffers(1, &self->vertex_buffer_object_id);
|
||||
self->params.egl->glBindBuffer(GL_ARRAY_BUFFER, self->vertex_buffer_object_id);
|
||||
self->params.egl->glBufferData(GL_ARRAY_BUFFER, 24 * sizeof(float), NULL, GL_STREAM_DRAW);
|
||||
|
||||
self->egl->glGenVertexArrays(1, &self->vertex_array_object_id);
|
||||
self->egl->glGenBuffers(1, &self->vertex_buffer_object_id);
|
||||
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->params.egl->glEnableVertexAttribArray(0);
|
||||
self->params.egl->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
|
||||
|
||||
self->egl->glEnableVertexAttribArray(0);
|
||||
self->egl->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
|
||||
self->params.egl->glEnableVertexAttribArray(1);
|
||||
self->params.egl->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
|
||||
|
||||
self->egl->glEnableVertexAttribArray(1);
|
||||
self->egl->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
|
||||
|
||||
self->egl->glBindVertexArray(0);
|
||||
self->params.egl->glBindVertexArray(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -145,61 +149,53 @@ int gsr_color_conversion_init(gsr_color_conversion *self, const gsr_color_conver
|
||||
assert(params);
|
||||
assert(params->egl);
|
||||
memset(self, 0, sizeof(*self));
|
||||
self->egl = params->egl;
|
||||
self->params.egl = params->egl;
|
||||
self->params = *params;
|
||||
|
||||
if(params->num_source_textures != 1) {
|
||||
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);
|
||||
if(self->params.num_destination_textures != 2) {
|
||||
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;
|
||||
}
|
||||
|
||||
if(params->num_destination_textures != 2) {
|
||||
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);
|
||||
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");
|
||||
if(load_shader_y(&self->shaders[0], self->params.egl, &self->rotation_uniforms[0]) != 0) {
|
||||
fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load Y shader\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if(load_shader_uv(&self->shaders[1], self->egl, params->rotation) != 0) {
|
||||
fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to loader UV shader\n");
|
||||
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 load UV shader\n");
|
||||
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)
|
||||
goto err;
|
||||
|
||||
if(create_vertices(self, params->position, params->size) != 0)
|
||||
if(create_vertices(self) != 0)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
self->egl->glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
self->params.egl->glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
gsr_color_conversion_deinit(self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void gsr_color_conversion_deinit(gsr_color_conversion *self) {
|
||||
if(!self->egl)
|
||||
if(!self->params.egl)
|
||||
return;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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->egl->glDeleteFramebuffers(MAX_FRAMEBUFFERS, self->framebuffers);
|
||||
self->params.egl->glDeleteFramebuffers(MAX_FRAMEBUFFERS, self->framebuffers);
|
||||
for(int i = 0; i < MAX_FRAMEBUFFERS; ++i) {
|
||||
self->framebuffers[i] = 0;
|
||||
}
|
||||
@ -208,33 +204,88 @@ void gsr_color_conversion_deinit(gsr_color_conversion *self) {
|
||||
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) {
|
||||
self->egl->glBindVertexArray(self->vertex_array_object_id);
|
||||
self->egl->glViewport(0, 0, width, height);
|
||||
self->egl->glBindTexture(GL_TEXTURE_2D, self->source_textures[0]);
|
||||
/* |source_pos| is in pixel coordinates and |source_size| */
|
||||
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) {
|
||||
/* TODO: Do not call this every frame? */
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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]);
|
||||
self->egl->glBindTexture(GL_TEXTURE_2D, 0);
|
||||
self->egl->glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
self->params.egl->glBindTexture(GL_TEXTURE_2D, 0);
|
||||
self->params.egl->glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
return 0;
|
||||
}
|
||||
|
20
src/cursor.c
20
src/cursor.c
@ -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);
|
||||
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_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_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);
|
||||
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 x_fixes_error_base = 0;
|
||||
|
||||
assert(egl);
|
||||
assert(display);
|
||||
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->x_fixes_event_base = 0;
|
||||
int x_fixes_error_base = 0;
|
||||
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. no cursor will be visible in the video\n");
|
||||
if(!XFixesQueryExtension(self->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");
|
||||
gsr_cursor_deinit(self);
|
||||
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) {
|
||||
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) {
|
||||
self->cursor_image_set = true;
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -138,7 +138,6 @@ static bool gsr_egl_load_gl(gsr_egl *self, void *library) {
|
||||
{ (void**)&self->glTexImage2D, "glTexImage2D" },
|
||||
{ (void**)&self->glCopyImageSubData, "glCopyImageSubData" },
|
||||
{ (void**)&self->glClearTexImage, "glClearTexImage" },
|
||||
{ (void**)&self->glGenerateMipmap, "glGenerateMipmap" },
|
||||
{ (void**)&self->glGenFramebuffers, "glGenFramebuffers" },
|
||||
{ (void**)&self->glBindFramebuffer, "glBindFramebuffer" },
|
||||
{ (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->glGenBuffers, "glGenBuffers" },
|
||||
{ (void**)&self->glBufferData, "glBufferData" },
|
||||
{ (void**)&self->glBufferSubData, "glBufferSubData" },
|
||||
{ (void**)&self->glDeleteBuffers, "glDeleteBuffers" },
|
||||
{ (void**)&self->glGenVertexArrays, "glGenVertexArrays" },
|
||||
{ (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->glEnableVertexAttribArray, "glEnableVertexAttribArray" },
|
||||
{ (void**)&self->glDrawArrays, "glDrawArrays" },
|
||||
{ (void**)&self->glEnable, "glEnable" },
|
||||
{ (void**)&self->glBlendFunc, "glBlendFunc" },
|
||||
{ (void**)&self->glGetUniformLocation, "glGetUniformLocation" },
|
||||
{ (void**)&self->glUniform1f, "glUniform1f" },
|
||||
|
||||
{ NULL, NULL }
|
||||
};
|
||||
@ -214,6 +218,9 @@ bool gsr_egl_load(gsr_egl *self, Display *dpy) {
|
||||
if(!gsr_egl_create_window(self))
|
||||
goto fail;
|
||||
|
||||
self->glEnable(GL_BLEND);
|
||||
self->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
self->egl_library = egl_lib;
|
||||
self->gl_library = gl_lib;
|
||||
return true;
|
||||
|
@ -1384,7 +1384,6 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
gsr_capture_kms_vaapi_params kms_params;
|
||||
kms_params.dpy = dpy;
|
||||
kms_params.display_to_capture = capture_target;
|
||||
kms_params.gpu_inf = gpu_inf;
|
||||
kms_params.card_path = card_path;
|
||||
|
Loading…
Reference in New Issue
Block a user