aboutsummaryrefslogtreecommitdiff
path: root/src/capture
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2022-10-17 02:55:59 +0200
committerdec05eba <dec05eba@protonmail.com>2022-11-30 19:36:33 +0100
commit6a6bb703bce2d844175950ede4bda5d06dc5a8ae (patch)
tree0e48877816f4596e506867b6b4f89144a0374143 /src/capture
parenta7e0dbd83381377bd05a3fa988511d3713996370 (diff)
wip intel
Diffstat (limited to 'src/capture')
-rw-r--r--src/capture/nvfbc.c71
-rw-r--r--src/capture/xcomposite_cuda.c (renamed from src/capture/xcomposite.c)213
-rw-r--r--src/capture/xcomposite_drm.c855
3 files changed, 1002 insertions, 137 deletions
diff --git a/src/capture/nvfbc.c b/src/capture/nvfbc.c
index a470879..17aedf8 100644
--- a/src/capture/nvfbc.c
+++ b/src/capture/nvfbc.c
@@ -22,6 +22,7 @@ typedef struct {
bool fbc_handle_created;
gsr_cuda cuda;
+ bool frame_initialized;
} gsr_capture_nvfbc;
#if defined(_WIN64) || defined(__LP64__)
@@ -52,28 +53,45 @@ static uint32_t get_output_id_from_display_name(NVFBC_RANDR_OUTPUT_INFO *outputs
}
/* TODO: Test with optimus and open kernel modules */
-static bool driver_supports_direct_capture_cursor() {
+static bool get_driver_version(int *major, int *minor) {
+ *major = 0;
+ *minor = 0;
+
FILE *f = fopen("/proc/driver/nvidia/version", "rb");
- if(!f)
+ if(!f) {
+ fprintf(stderr, "gsr warning: failed to get nvidia driver version (failed to read /proc/driver/nvidia/version)\n");
return false;
+ }
char buffer[2048];
size_t bytes_read = fread(buffer, 1, sizeof(buffer) - 1, f);
buffer[bytes_read] = '\0';
- bool supports_cursor = false;
+ bool success = false;
const char *p = strstr(buffer, "Kernel Module");
if(p) {
p += 13;
int driver_major_version = 0, driver_minor_version = 0;
if(sscanf(p, "%d.%d", &driver_major_version, &driver_minor_version) == 2) {
- if(driver_major_version > 515 || (driver_major_version == 515 && driver_minor_version >= 57))
- supports_cursor = true;
+ *major = driver_major_version;
+ *minor = driver_minor_version;
+ success = true;
}
}
+ if(!success)
+ fprintf(stderr, "gsr warning: failed to get nvidia driver version\n");
+
fclose(f);
- return supports_cursor;
+ return success;
+}
+
+static bool version_at_least(int major, int minor, int expected_major, int expected_minor) {
+ return major > expected_major || (major == expected_major && minor >= expected_minor);
+}
+
+static bool version_less_than(int major, int minor, int expected_major, int expected_minor) {
+ return major < expected_major || (major == expected_major && minor < expected_minor);
}
static bool gsr_capture_nvfbc_load_library(gsr_capture *cap) {
@@ -180,6 +198,30 @@ static int gsr_capture_nvfbc_start(gsr_capture *cap, AVCodecContext *video_codec
const bool capture_region = (x > 0 || y > 0 || width > 0 || height > 0);
+ bool supports_direct_cursor = false;
+ bool direct_capture = cap_nvfbc->params.direct_capture;
+ int driver_major_version = 0;
+ int driver_minor_version = 0;
+ if(direct_capture && get_driver_version(&driver_major_version, &driver_minor_version)) {
+ fprintf(stderr, "Info: detected nvidia version: %d.%d\n", driver_major_version, driver_minor_version);
+
+ if(version_at_least(driver_major_version, driver_minor_version, 515, 57) && version_less_than(driver_major_version, driver_minor_version, 520, 56)) {
+ direct_capture = false;
+ fprintf(stderr, "Warning: \"screen-direct\" has temporary been disabled as it causes stuttering with driver versions >= 515.57 and < 520.56. Please update your driver if possible. Capturing \"screen\" instead.\n");
+ }
+
+ // TODO:
+ // Cursor capture disabled because moving the cursor doesn't update capture rate to monitor hz and instead captures at 10-30 hz
+ /*
+ if(direct_capture) {
+ if(version_at_least(driver_major_version, driver_minor_version, 515, 57))
+ supports_direct_cursor = true;
+ else
+ fprintf(stderr, "Info: capturing \"screen-direct\" but driver version appears to be less than 515.57. Disabling capture of cursor. Please update your driver if you want to capture your cursor or record \"screen\" instead.\n");
+ }
+ */
+ }
+
NVFBCSTATUS status;
NVFBC_TRACKING_TYPE tracking_type;
bool capture_session_created = false;
@@ -245,11 +287,11 @@ static int gsr_capture_nvfbc_start(gsr_capture *cap, AVCodecContext *video_codec
memset(&create_capture_params, 0, sizeof(create_capture_params));
create_capture_params.dwVersion = NVFBC_CREATE_CAPTURE_SESSION_PARAMS_VER;
create_capture_params.eCaptureType = NVFBC_CAPTURE_SHARED_CUDA;
- create_capture_params.bWithCursor = (!cap_nvfbc->params.direct_capture || driver_supports_direct_capture_cursor()) ? NVFBC_TRUE : NVFBC_FALSE;
+ create_capture_params.bWithCursor = (!direct_capture || supports_direct_cursor) ? NVFBC_TRUE : NVFBC_FALSE;
if(capture_region)
create_capture_params.captureBox = (NVFBC_BOX){ x, y, width, height };
create_capture_params.eTrackingType = tracking_type;
- create_capture_params.dwSamplingRateMs = 1000u / (uint32_t)cap_nvfbc->params.fps;
+ create_capture_params.dwSamplingRateMs = 1000u / ((uint32_t)cap_nvfbc->params.fps + 1);
create_capture_params.bAllowDirectCapture = cap_nvfbc->params.direct_capture ? NVFBC_TRUE : NVFBC_FALSE;
create_capture_params.bPushModel = cap_nvfbc->params.direct_capture ? NVFBC_TRUE : NVFBC_FALSE;
if(tracking_type == NVFBC_TRACKING_OUTPUT)
@@ -324,6 +366,16 @@ static void gsr_capture_nvfbc_destroy_session(gsr_capture *cap) {
cap_nvfbc->nv_fbc_handle = 0;
}
+static void gsr_capture_nvfbc_tick(gsr_capture *cap, AVCodecContext *video_codec_context, AVFrame **frame) {
+ gsr_capture_nvfbc *cap_nvfbc = cap->priv;
+ if(!cap_nvfbc->frame_initialized && video_codec_context->hw_frames_ctx) {
+ cap_nvfbc->frame_initialized = true;
+ (*frame)->hw_frames_ctx = video_codec_context->hw_frames_ctx;
+ (*frame)->buf[0] = av_buffer_pool_get(((AVHWFramesContext*)video_codec_context->hw_frames_ctx->data)->pool);
+ (*frame)->extended_data = (*frame)->data;
+ }
+}
+
static int gsr_capture_nvfbc_capture(gsr_capture *cap, AVFrame *frame) {
gsr_capture_nvfbc *cap_nvfbc = cap->priv;
@@ -338,6 +390,7 @@ static int gsr_capture_nvfbc_capture(gsr_capture *cap, AVFrame *frame) {
grab_params.dwFlags = NVFBC_TOCUDA_GRAB_FLAGS_NOWAIT;/* | NVFBC_TOCUDA_GRAB_FLAGS_FORCE_REFRESH;*/
grab_params.pFrameGrabInfo = &frame_info;
grab_params.pCUDADeviceBuffer = &cu_device_ptr;
+ grab_params.dwTimeoutMs = 0;
NVFBCSTATUS status = cap_nvfbc->nv_fbc_function_list.nvFBCToCudaGrabFrame(cap_nvfbc->nv_fbc_handle, &grab_params);
if(status != NVFBC_SUCCESS) {
@@ -406,7 +459,7 @@ gsr_capture* gsr_capture_nvfbc_create(const gsr_capture_nvfbc_params *params) {
*cap = (gsr_capture) {
.start = gsr_capture_nvfbc_start,
- .tick = NULL,
+ .tick = gsr_capture_nvfbc_tick,
.should_stop = NULL,
.capture = gsr_capture_nvfbc_capture,
.destroy = gsr_capture_nvfbc_destroy,
diff --git a/src/capture/xcomposite.c b/src/capture/xcomposite_cuda.c
index 755ac92..d6c147b 100644
--- a/src/capture/xcomposite.c
+++ b/src/capture/xcomposite_cuda.c
@@ -1,5 +1,5 @@
-#include "../../include/capture/xcomposite.h"
-#include "../../include/gl.h"
+#include "../../include/capture/xcomposite_cuda.h"
+#include "../../include/egl.h"
#include "../../include/cuda.h"
#include "../../include/window_texture.h"
#include "../../include/time.h"
@@ -9,10 +9,8 @@
#include <libavutil/frame.h>
#include <libavcodec/avcodec.h>
-/* TODO: Proper error checks and cleanups */
-
typedef struct {
- gsr_capture_xcomposite_params params;
+ gsr_capture_xcomposite_cuda_params params;
Display *dpy;
XEvent xev;
bool should_stop;
@@ -32,9 +30,9 @@ typedef struct {
CUgraphicsResource cuda_graphics_resource;
CUarray mapped_array;
- gsr_gl gl;
+ gsr_egl egl;
gsr_cuda cuda;
-} gsr_capture_xcomposite;
+} gsr_capture_xcomposite_cuda;
static int max_int(int a, int b) {
return a > b ? a : b;
@@ -44,58 +42,9 @@ static int min_int(int a, int b) {
return a < b ? a : b;
}
-static void gsr_capture_xcomposite_stop(gsr_capture *cap, AVCodecContext *video_codec_context);
-
-static Window get_compositor_window(Display *display) {
- Window overlay_window = XCompositeGetOverlayWindow(display, DefaultRootWindow(display));
- XCompositeReleaseOverlayWindow(display, DefaultRootWindow(display));
-
- Window root_window, parent_window;
- Window *children = NULL;
- unsigned int num_children = 0;
- if(XQueryTree(display, overlay_window, &root_window, &parent_window, &children, &num_children) == 0)
- return None;
-
- Window compositor_window = None;
- if(num_children == 1) {
- compositor_window = children[0];
- const int screen_width = XWidthOfScreen(DefaultScreenOfDisplay(display));
- const int screen_height = XHeightOfScreen(DefaultScreenOfDisplay(display));
-
- XWindowAttributes attr;
- if(!XGetWindowAttributes(display, compositor_window, &attr) || attr.width != screen_width || attr.height != screen_height)
- compositor_window = None;
- }
-
- if(children)
- XFree(children);
-
- return compositor_window;
-}
-
-/* TODO: check for glx swap control extension string (GLX_EXT_swap_control, etc) */
-static void set_vertical_sync_enabled(Display *display, Window window, gsr_gl *gl, bool enabled) {
- int result = 0;
-
- if(gl->glXSwapIntervalEXT) {
- gl->glXSwapIntervalEXT(display, window, enabled ? 1 : 0);
- } else if(gl->glXSwapIntervalMESA) {
- result = gl->glXSwapIntervalMESA(enabled ? 1 : 0);
- } else if(gl->glXSwapIntervalSGI) {
- result = gl->glXSwapIntervalSGI(enabled ? 1 : 0);
- } else {
- static int warned = 0;
- if (!warned) {
- warned = 1;
- fprintf(stderr, "Warning: setting vertical sync not supported\n");
- }
- }
-
- if(result != 0)
- fprintf(stderr, "Warning: setting vertical sync failed\n");
-}
+static void gsr_capture_xcomposite_cuda_stop(gsr_capture *cap, AVCodecContext *video_codec_context);
-static bool cuda_register_opengl_texture(gsr_capture_xcomposite *cap_xcomp) {
+static bool cuda_register_opengl_texture(gsr_capture_xcomposite_cuda *cap_xcomp) {
CUresult res;
CUcontext old_ctx;
res = cap_xcomp->cuda.cuCtxPushCurrent_v2(cap_xcomp->cuda.cu_ctx);
@@ -112,23 +61,22 @@ static bool cuda_register_opengl_texture(gsr_capture_xcomposite *cap_xcomp) {
return false;
}
- /* Get texture */
res = cap_xcomp->cuda.cuGraphicsResourceSetMapFlags(cap_xcomp->cuda_graphics_resource, CU_GRAPHICS_MAP_RESOURCE_FLAGS_READ_ONLY);
res = cap_xcomp->cuda.cuGraphicsMapResources(1, &cap_xcomp->cuda_graphics_resource, 0);
- /* Map texture to cuda array */
res = cap_xcomp->cuda.cuGraphicsSubResourceGetMappedArray(&cap_xcomp->mapped_array, cap_xcomp->cuda_graphics_resource, 0, 0);
res = cap_xcomp->cuda.cuCtxPopCurrent_v2(&old_ctx);
return true;
}
-static bool cuda_create_codec_context(gsr_capture_xcomposite *cap_xcomp, AVCodecContext *video_codec_context) {
+static bool cuda_create_codec_context(gsr_capture_xcomposite_cuda *cap_xcomp, AVCodecContext *video_codec_context) {
CUcontext old_ctx;
cap_xcomp->cuda.cuCtxPushCurrent_v2(cap_xcomp->cuda.cu_ctx);
AVBufferRef *device_ctx = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_CUDA);
if(!device_ctx) {
fprintf(stderr, "Error: Failed to create hardware device context\n");
+ cap_xcomp->cuda.cuCtxPopCurrent_v2(&old_ctx);
return false;
}
@@ -173,7 +121,7 @@ static bool cuda_create_codec_context(gsr_capture_xcomposite *cap_xcomp, AVCodec
return true;
}
-static unsigned int gl_create_texture(gsr_capture_xcomposite *cap_xcomp, int width, int height) {
+static unsigned int gl_create_texture(gsr_capture_xcomposite_cuda *cap_xcomp, int width, int height) {
// Generating this second texture is needed because
// cuGraphicsGLRegisterImage cant be used with the texture that is mapped
// directly to the pixmap.
@@ -182,25 +130,25 @@ static unsigned int gl_create_texture(gsr_capture_xcomposite *cap_xcomp, int wid
// then needed every frame.
// Ignoring failure for now.. TODO: Show proper error
unsigned int texture_id = 0;
- cap_xcomp->gl.glGenTextures(1, &texture_id);
- cap_xcomp->gl.glBindTexture(GL_TEXTURE_2D, texture_id);
- cap_xcomp->gl.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
+ cap_xcomp->egl.glGenTextures(1, &texture_id);
+ cap_xcomp->egl.glBindTexture(GL_TEXTURE_2D, texture_id);
+ cap_xcomp->egl.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
- cap_xcomp->gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- cap_xcomp->gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- cap_xcomp->gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- cap_xcomp->gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ cap_xcomp->egl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ cap_xcomp->egl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ cap_xcomp->egl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ cap_xcomp->egl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- cap_xcomp->gl.glBindTexture(GL_TEXTURE_2D, 0);
+ cap_xcomp->egl.glBindTexture(GL_TEXTURE_2D, 0);
return texture_id;
}
-static int gsr_capture_xcomposite_start(gsr_capture *cap, AVCodecContext *video_codec_context) {
- gsr_capture_xcomposite *cap_xcomp = cap->priv;
+static int gsr_capture_xcomposite_cuda_start(gsr_capture *cap, AVCodecContext *video_codec_context) {
+ gsr_capture_xcomposite_cuda *cap_xcomp = cap->priv;
XWindowAttributes attr;
if(!XGetWindowAttributes(cap_xcomp->dpy, cap_xcomp->params.window, &attr)) {
- fprintf(stderr, "gsr error: gsr_capture_xcomposite_start failed: invalid window id: %lu\n", cap_xcomp->params.window);
+ fprintf(stderr, "gsr error: gsr_capture_xcomposite_cuda_start failed: invalid window id: %lu\n", cap_xcomp->params.window);
return -1;
}
@@ -211,32 +159,33 @@ static int gsr_capture_xcomposite_start(gsr_capture *cap, AVCodecContext *video_
XSelectInput(cap_xcomp->dpy, cap_xcomp->params.window, StructureNotifyMask | ExposureMask);
- if(!gsr_gl_load(&cap_xcomp->gl, cap_xcomp->dpy)) {
- fprintf(stderr, "gsr error: gsr_capture_xcomposite_start: failed to load opengl\n");
+ if(!gsr_egl_load(&cap_xcomp->egl, cap_xcomp->dpy)) {
+ fprintf(stderr, "gsr error: gsr_capture_xcomposite_cuda_start: failed to load opengl\n");
return -1;
}
- set_vertical_sync_enabled(cap_xcomp->dpy, cap_xcomp->gl.window, &cap_xcomp->gl, false);
- if(window_texture_init(&cap_xcomp->window_texture, cap_xcomp->dpy, cap_xcomp->params.window, &cap_xcomp->gl) != 0) {
- fprintf(stderr, "gsr error: gsr_capture_xcomposite_start: failed get window texture for window %ld\n", cap_xcomp->params.window);
- gsr_gl_unload(&cap_xcomp->gl);
+ cap_xcomp->egl.eglSwapInterval(cap_xcomp->egl.egl_display, 0);
+ // TODO: Fallback to composite window
+ if(window_texture_init(&cap_xcomp->window_texture, cap_xcomp->dpy, cap_xcomp->params.window, &cap_xcomp->egl) != 0) {
+ fprintf(stderr, "gsr error: gsr_capture_xcomposite_cuda_start: failed get window texture for window %ld\n", cap_xcomp->params.window);
+ gsr_egl_unload(&cap_xcomp->egl);
return -1;
}
- cap_xcomp->gl.glBindTexture(GL_TEXTURE_2D, window_texture_get_opengl_texture_id(&cap_xcomp->window_texture));
+ cap_xcomp->egl.glBindTexture(GL_TEXTURE_2D, window_texture_get_opengl_texture_id(&cap_xcomp->window_texture));
cap_xcomp->texture_size.x = 0;
cap_xcomp->texture_size.y = 0;
- cap_xcomp->gl.glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &cap_xcomp->texture_size.x);
- cap_xcomp->gl.glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &cap_xcomp->texture_size.y);
- cap_xcomp->gl.glBindTexture(GL_TEXTURE_2D, 0);
+ cap_xcomp->egl.glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &cap_xcomp->texture_size.x);
+ cap_xcomp->egl.glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &cap_xcomp->texture_size.y);
+ cap_xcomp->egl.glBindTexture(GL_TEXTURE_2D, 0);
cap_xcomp->texture_size.x = max_int(2, cap_xcomp->texture_size.x & ~1);
cap_xcomp->texture_size.y = max_int(2, cap_xcomp->texture_size.y & ~1);
cap_xcomp->target_texture_id = gl_create_texture(cap_xcomp, cap_xcomp->texture_size.x, cap_xcomp->texture_size.y);
if(cap_xcomp->target_texture_id == 0) {
- fprintf(stderr, "gsr error: gsr_capture_xcomposite_start: failed to create opengl texture\n");
- gsr_capture_xcomposite_stop(cap, video_codec_context);
+ fprintf(stderr, "gsr error: gsr_capture_xcomposite_cuda_start: failed to create opengl texture\n");
+ gsr_capture_xcomposite_cuda_stop(cap, video_codec_context);
return -1;
}
@@ -244,17 +193,17 @@ static int gsr_capture_xcomposite_start(gsr_capture *cap, AVCodecContext *video_
video_codec_context->height = cap_xcomp->texture_size.y;
if(!gsr_cuda_load(&cap_xcomp->cuda)) {
- gsr_capture_xcomposite_stop(cap, video_codec_context);
+ gsr_capture_xcomposite_cuda_stop(cap, video_codec_context);
return -1;
}
if(!cuda_create_codec_context(cap_xcomp, video_codec_context)) {
- gsr_capture_xcomposite_stop(cap, video_codec_context);
+ gsr_capture_xcomposite_cuda_stop(cap, video_codec_context);
return -1;
}
if(!cuda_register_opengl_texture(cap_xcomp)) {
- gsr_capture_xcomposite_stop(cap, video_codec_context);
+ gsr_capture_xcomposite_cuda_stop(cap, video_codec_context);
return -1;
}
@@ -262,13 +211,13 @@ static int gsr_capture_xcomposite_start(gsr_capture *cap, AVCodecContext *video_
return 0;
}
-static void gsr_capture_xcomposite_stop(gsr_capture *cap, AVCodecContext *video_codec_context) {
- gsr_capture_xcomposite *cap_xcomp = cap->priv;
+static void gsr_capture_xcomposite_cuda_stop(gsr_capture *cap, AVCodecContext *video_codec_context) {
+ gsr_capture_xcomposite_cuda *cap_xcomp = cap->priv;
window_texture_deinit(&cap_xcomp->window_texture);
if(cap_xcomp->target_texture_id) {
- cap_xcomp->gl.glDeleteTextures(1, &cap_xcomp->target_texture_id);
+ cap_xcomp->egl.glDeleteTextures(1, &cap_xcomp->target_texture_id);
cap_xcomp->target_texture_id = 0;
}
@@ -280,35 +229,42 @@ static void gsr_capture_xcomposite_stop(gsr_capture *cap, AVCodecContext *video_
av_buffer_unref(&video_codec_context->hw_device_ctx);
av_buffer_unref(&video_codec_context->hw_frames_ctx);
- cap_xcomp->cuda.cuGraphicsUnmapResources(1, &cap_xcomp->cuda_graphics_resource, 0);
- cap_xcomp->cuda.cuGraphicsUnregisterResource(cap_xcomp->cuda_graphics_resource);
+ if(cap_xcomp->cuda.cu_ctx) {
+ CUcontext old_ctx;
+ cap_xcomp->cuda.cuCtxPushCurrent_v2(cap_xcomp->cuda.cu_ctx);
+
+ cap_xcomp->cuda.cuGraphicsUnmapResources(1, &cap_xcomp->cuda_graphics_resource, 0);
+ cap_xcomp->cuda.cuGraphicsUnregisterResource(cap_xcomp->cuda_graphics_resource);
+ cap_xcomp->cuda.cuCtxPopCurrent_v2(&old_ctx);
+ }
gsr_cuda_unload(&cap_xcomp->cuda);
- gsr_gl_unload(&cap_xcomp->gl);
+ gsr_egl_unload(&cap_xcomp->egl);
if(cap_xcomp->dpy) {
+ // TODO: Why is this crashing?
XCloseDisplay(cap_xcomp->dpy);
cap_xcomp->dpy = NULL;
}
}
-static void gsr_capture_xcomposite_tick(gsr_capture *cap, AVCodecContext *video_codec_context, AVFrame **frame) {
- gsr_capture_xcomposite *cap_xcomp = cap->priv;
+static void gsr_capture_xcomposite_cuda_tick(gsr_capture *cap, AVCodecContext *video_codec_context, AVFrame **frame) {
+ gsr_capture_xcomposite_cuda *cap_xcomp = cap->priv;
- cap_xcomp->gl.glClear(GL_COLOR_BUFFER_BIT);
+ cap_xcomp->egl.glClear(GL_COLOR_BUFFER_BIT);
if(!cap_xcomp->created_hw_frame) {
+ cap_xcomp->created_hw_frame = true;
CUcontext old_ctx;
cap_xcomp->cuda.cuCtxPushCurrent_v2(cap_xcomp->cuda.cu_ctx);
if(av_hwframe_get_buffer(video_codec_context->hw_frames_ctx, *frame, 0) < 0) {
- fprintf(stderr, "gsr error: gsr_capture_xcomposite_tick: av_hwframe_get_buffer failed\n");
+ fprintf(stderr, "gsr error: gsr_capture_xcomposite_cuda_tick: av_hwframe_get_buffer failed\n");
cap_xcomp->should_stop = true;
cap_xcomp->stop_is_error = true;
cap_xcomp->cuda.cuCtxPopCurrent_v2(&old_ctx);
return;
}
- cap_xcomp->created_hw_frame = true;
cap_xcomp->cuda.cuCtxPopCurrent_v2(&old_ctx);
}
@@ -343,25 +299,25 @@ static void gsr_capture_xcomposite_tick(gsr_capture *cap, AVCodecContext *video_
cap_xcomp->window_resized = false;
fprintf(stderr, "Resize window!\n");
if(window_texture_on_resize(&cap_xcomp->window_texture) != 0) {
- fprintf(stderr, "gsr error: gsr_capture_xcomposite_tick: window_texture_on_resize failed\n");
+ fprintf(stderr, "gsr error: gsr_capture_xcomposite_cuda_tick: window_texture_on_resize failed\n");
cap_xcomp->should_stop = true;
cap_xcomp->stop_is_error = true;
return;
}
- cap_xcomp->gl.glBindTexture(GL_TEXTURE_2D, window_texture_get_opengl_texture_id(&cap_xcomp->window_texture));
+ cap_xcomp->egl.glBindTexture(GL_TEXTURE_2D, window_texture_get_opengl_texture_id(&cap_xcomp->window_texture));
cap_xcomp->texture_size.x = 0;
cap_xcomp->texture_size.y = 0;
- cap_xcomp->gl.glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &cap_xcomp->texture_size.x);
- cap_xcomp->gl.glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &cap_xcomp->texture_size.y);
- cap_xcomp->gl.glBindTexture(GL_TEXTURE_2D, 0);
+ cap_xcomp->egl.glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &cap_xcomp->texture_size.x);
+ cap_xcomp->egl.glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &cap_xcomp->texture_size.y);
+ cap_xcomp->egl.glBindTexture(GL_TEXTURE_2D, 0);
cap_xcomp->texture_size.x = min_int(video_codec_context->width, max_int(2, cap_xcomp->texture_size.x & ~1));
cap_xcomp->texture_size.y = min_int(video_codec_context->height, max_int(2, cap_xcomp->texture_size.y & ~1));
- cap_xcomp->gl.glBindTexture(GL_TEXTURE_2D, cap_xcomp->target_texture_id);
- cap_xcomp->gl.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, cap_xcomp->texture_size.x, cap_xcomp->texture_size.y, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
- cap_xcomp->gl.glBindTexture(GL_TEXTURE_2D, 0);
+ cap_xcomp->egl.glBindTexture(GL_TEXTURE_2D, cap_xcomp->target_texture_id);
+ cap_xcomp->egl.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, cap_xcomp->texture_size.x, cap_xcomp->texture_size.y, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
+ cap_xcomp->egl.glBindTexture(GL_TEXTURE_2D, 0);
CUcontext old_ctx;
CUresult res = cap_xcomp->cuda.cuCtxPushCurrent_v2(cap_xcomp->cuda.cu_ctx);
@@ -372,7 +328,7 @@ static void gsr_capture_xcomposite_tick(gsr_capture *cap, AVCodecContext *video_
if (res != CUDA_SUCCESS) {
const char *err_str = "unknown";
cap_xcomp->cuda.cuGetErrorString(res, &err_str);
- fprintf(stderr, "gsr error: gsr_capture_xcomposite_tick: cuGraphicsGLRegisterImage failed, error %s, texture id: %u\n", err_str, cap_xcomp->target_texture_id);
+ fprintf(stderr, "gsr error: gsr_capture_xcomposite_cuda_tick: cuGraphicsGLRegisterImage failed, error %s, texture id: %u\n", err_str, cap_xcomp->target_texture_id);
cap_xcomp->should_stop = true;
cap_xcomp->stop_is_error = true;
res = cap_xcomp->cuda.cuCtxPopCurrent_v2(&old_ctx);
@@ -386,7 +342,7 @@ static void gsr_capture_xcomposite_tick(gsr_capture *cap, AVCodecContext *video_
av_frame_free(frame);
*frame = av_frame_alloc();
if(!frame) {
- fprintf(stderr, "gsr error: gsr_capture_xcomposite_tick: failed to allocate frame\n");
+ fprintf(stderr, "gsr error: gsr_capture_xcomposite_cuda_tick: failed to allocate frame\n");
cap_xcomp->should_stop = true;
cap_xcomp->stop_is_error = true;
res = cap_xcomp->cuda.cuCtxPopCurrent_v2(&old_ctx);
@@ -395,9 +351,10 @@ static void gsr_capture_xcomposite_tick(gsr_capture *cap, AVCodecContext *video_
(*frame)->format = video_codec_context->pix_fmt;
(*frame)->width = video_codec_context->width;
(*frame)->height = video_codec_context->height;
+ (*frame)->color_range = AVCOL_RANGE_JPEG;
if(av_hwframe_get_buffer(video_codec_context->hw_frames_ctx, *frame, 0) < 0) {
- fprintf(stderr, "gsr error: gsr_capture_xcomposite_tick: av_hwframe_get_buffer failed\n");
+ fprintf(stderr, "gsr error: gsr_capture_xcomposite_cuda_tick: av_hwframe_get_buffer failed\n");
cap_xcomp->should_stop = true;
cap_xcomp->stop_is_error = true;
res = cap_xcomp->cuda.cuCtxPopCurrent_v2(&old_ctx);
@@ -411,8 +368,8 @@ static void gsr_capture_xcomposite_tick(gsr_capture *cap, AVCodecContext *video_
}
}
-static bool gsr_capture_xcomposite_should_stop(gsr_capture *cap, bool *err) {
- gsr_capture_xcomposite *cap_xcomp = cap->priv;
+static bool gsr_capture_xcomposite_cuda_should_stop(gsr_capture *cap, bool *err) {
+ gsr_capture_xcomposite_cuda *cap_xcomp = cap->priv;
if(cap_xcomp->should_stop) {
if(err)
*err = cap_xcomp->stop_is_error;
@@ -424,19 +381,19 @@ static bool gsr_capture_xcomposite_should_stop(gsr_capture *cap, bool *err) {
return false;
}
-static int gsr_capture_xcomposite_capture(gsr_capture *cap, AVFrame *frame) {
- gsr_capture_xcomposite *cap_xcomp = cap->priv;
+static int gsr_capture_xcomposite_cuda_capture(gsr_capture *cap, AVFrame *frame) {
+ gsr_capture_xcomposite_cuda *cap_xcomp = cap->priv;
// TODO: Use a framebuffer instead. glCopyImageSubData requires opengl 4.2
vec2i source_pos = { 0, 0 };
vec2i source_size = cap_xcomp->texture_size;
// Requires opengl 4.2... TODO: Replace with earlier opengl if opengl < 4.2.
- cap_xcomp->gl.glCopyImageSubData(
+ cap_xcomp->egl.glCopyImageSubData(
window_texture_get_opengl_texture_id(&cap_xcomp->window_texture), GL_TEXTURE_2D, 0, source_pos.x, source_pos.y, 0,
cap_xcomp->target_texture_id, GL_TEXTURE_2D, 0, 0, 0, 0,
source_size.x, source_size.y, 1);
- unsigned int err = cap_xcomp->gl.glGetError();
+ unsigned int err = cap_xcomp->egl.glGetError();
if(err != 0) {
static bool error_shown = false;
if(!error_shown) {
@@ -444,7 +401,7 @@ static int gsr_capture_xcomposite_capture(gsr_capture *cap, AVFrame *frame) {
fprintf(stderr, "Error: glCopyImageSubData failed, gl error: %d\n", err);
}
}
- cap_xcomp->gl.glXSwapBuffers(cap_xcomp->dpy, cap_xcomp->gl.window);
+ cap_xcomp->egl.eglSwapBuffers(cap_xcomp->egl.egl_display, cap_xcomp->egl.egl_surface);
// TODO: Remove this copy, which is only possible by using nvenc directly and encoding window_pixmap.target_texture_id
frame->linesize[0] = frame->width * 4;
@@ -468,8 +425,8 @@ static int gsr_capture_xcomposite_capture(gsr_capture *cap, AVFrame *frame) {
return 0;
}
-static void gsr_capture_xcomposite_destroy(gsr_capture *cap, AVCodecContext *video_codec_context) {
- gsr_capture_xcomposite_stop(cap, video_codec_context);
+static void gsr_capture_xcomposite_cuda_destroy(gsr_capture *cap, AVCodecContext *video_codec_context) {
+ gsr_capture_xcomposite_cuda_stop(cap, video_codec_context);
if(cap->priv) {
free(cap->priv);
cap->priv = NULL;
@@ -477,9 +434,9 @@ static void gsr_capture_xcomposite_destroy(gsr_capture *cap, AVCodecContext *vid
free(cap);
}
-gsr_capture* gsr_capture_xcomposite_create(const gsr_capture_xcomposite_params *params) {
+gsr_capture* gsr_capture_xcomposite_cuda_create(const gsr_capture_xcomposite_cuda_params *params) {
if(!params) {
- fprintf(stderr, "gsr error: gsr_capture_xcomposite_create params is NULL\n");
+ fprintf(stderr, "gsr error: gsr_capture_xcomposite_cuda_create params is NULL\n");
return NULL;
}
@@ -487,7 +444,7 @@ gsr_capture* gsr_capture_xcomposite_create(const gsr_capture_xcomposite_params *
if(!cap)
return NULL;
- gsr_capture_xcomposite *cap_xcomp = calloc(1, sizeof(gsr_capture_xcomposite));
+ gsr_capture_xcomposite_cuda *cap_xcomp = calloc(1, sizeof(gsr_capture_xcomposite_cuda));
if(!cap_xcomp) {
free(cap);
return NULL;
@@ -495,7 +452,7 @@ gsr_capture* gsr_capture_xcomposite_create(const gsr_capture_xcomposite_params *
Display *display = XOpenDisplay(NULL);
if(!display) {
- fprintf(stderr, "gsr error: gsr_capture_xcomposite_create failed: XOpenDisplay failed\n");
+ fprintf(stderr, "gsr error: gsr_capture_xcomposite_cuda_create failed: XOpenDisplay failed\n");
free(cap);
free(cap_xcomp);
return NULL;
@@ -505,11 +462,11 @@ gsr_capture* gsr_capture_xcomposite_create(const gsr_capture_xcomposite_params *
cap_xcomp->params = *params;
*cap = (gsr_capture) {
- .start = gsr_capture_xcomposite_start,
- .tick = gsr_capture_xcomposite_tick,
- .should_stop = gsr_capture_xcomposite_should_stop,
- .capture = gsr_capture_xcomposite_capture,
- .destroy = gsr_capture_xcomposite_destroy,
+ .start = gsr_capture_xcomposite_cuda_start,
+ .tick = gsr_capture_xcomposite_cuda_tick,
+ .should_stop = gsr_capture_xcomposite_cuda_should_stop,
+ .capture = gsr_capture_xcomposite_cuda_capture,
+ .destroy = gsr_capture_xcomposite_cuda_destroy,
.priv = cap_xcomp
};
diff --git a/src/capture/xcomposite_drm.c b/src/capture/xcomposite_drm.c
new file mode 100644
index 0000000..65dec1e
--- /dev/null
+++ b/src/capture/xcomposite_drm.c
@@ -0,0 +1,855 @@
+#include "../../include/capture/xcomposite_drm.h"
+#include "../../include/egl.h"
+#include "../../include/window_texture.h"
+#include "../../include/time.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <X11/Xlib.h>
+#include <X11/extensions/Xcomposite.h>
+#include <libavutil/hwcontext.h>
+#include <libavutil/hwcontext_drm.h>
+#include <libavutil/frame.h>
+#include <libavcodec/avcodec.h>
+//#include <drm_fourcc.h>
+#include <assert.h>
+/* TODO: Proper error checks and cleanups */
+
+typedef struct {
+ gsr_capture_xcomposite_drm_params params;
+ Display *dpy;
+ XEvent xev;
+ bool created_hw_frame;
+
+ vec2i window_pos;
+ vec2i window_size;
+ vec2i texture_size;
+ double window_resize_timer;
+
+ WindowTexture window_texture;
+
+ gsr_egl egl;
+
+ int fourcc;
+ int num_planes;
+ uint64_t modifiers;
+ int dmabuf_fd;
+ int32_t stride;
+ int32_t offset;
+
+ unsigned int target_texture_id;
+
+ unsigned int FramebufferName;
+ unsigned int quad_VertexArrayID;
+ unsigned int quad_vertexbuffer;
+ unsigned int quadVAO;
+} gsr_capture_xcomposite_drm;
+
+static int max_int(int a, int b) {
+ return a > b ? a : b;
+}
+
+static int min_int(int a, int b) {
+ return a < b ? a : b;
+}
+
+static bool drm_create_codec_context(gsr_capture_xcomposite_drm *cap_xcomp, AVCodecContext *video_codec_context) {
+ // TODO: "/dev/dri/card0"
+ AVBufferRef *device_ctx;
+ if(av_hwdevice_ctx_create(&device_ctx, AV_HWDEVICE_TYPE_VAAPI, "/dev/dri/card0", NULL, 0) < 0) {
+ fprintf(stderr, "Error: Failed to create hardware device context\n");
+ return false;
+ }
+
+ AVBufferRef *frame_context = av_hwframe_ctx_alloc(device_ctx);
+ if(!frame_context) {
+ fprintf(stderr, "Error: Failed to create hwframe context\n");
+ av_buffer_unref(&device_ctx);
+ return false;
+ }
+
+ AVHWFramesContext *hw_frame_context =
+ (AVHWFramesContext *)frame_context->data;
+ hw_frame_context->width = video_codec_context->width;
+ hw_frame_context->height = video_codec_context->height;
+ hw_frame_context->sw_format = AV_PIX_FMT_YUV420P;//AV_PIX_FMT_0RGB32;//AV_PIX_FMT_YUV420P;//AV_PIX_FMT_0RGB32;//AV_PIX_FMT_NV12;
+ hw_frame_context->format = video_codec_context->pix_fmt;
+ hw_frame_context->device_ref = device_ctx;
+ hw_frame_context->device_ctx = (AVHWDeviceContext*)device_ctx->data;
+
+ if (av_hwframe_ctx_init(frame_context) < 0) {
+ fprintf(stderr, "Error: Failed to initialize hardware frame context "
+ "(note: ffmpeg version needs to be > 4.0)\n");
+ av_buffer_unref(&device_ctx);
+ av_buffer_unref(&frame_context);
+ return false;
+ }
+
+ video_codec_context->hw_device_ctx = device_ctx; // TODO: av_buffer_ref? and in more places
+ video_codec_context->hw_frames_ctx = frame_context;
+ return true;
+}
+
+#define EGL_SURFACE_TYPE 0x3033
+#define EGL_WINDOW_BIT 0x0004
+#define EGL_PIXMAP_BIT 0x0002
+#define EGL_BIND_TO_TEXTURE_RGB 0x3039
+#define EGL_TRUE 1
+#define EGL_RED_SIZE 0x3024
+#define EGL_GREEN_SIZE 0x3023
+#define EGL_BLUE_SIZE 0x3022
+#define EGL_ALPHA_SIZE 0x3021
+#define EGL_TEXTURE_FORMAT 0x3080
+#define EGL_TEXTURE_RGB 0x305D
+#define EGL_TEXTURE_TARGET 0x3081
+#define EGL_TEXTURE_2D 0x305F
+#define EGL_GL_TEXTURE_2D 0x30B1
+
+#define GL_RGBA 0x1908
+
+static unsigned int gl_create_texture(gsr_capture_xcomposite_drm *cap_xcomp, int width, int height) {
+ // Generating this second texture is needed because
+ // cuGraphicsGLRegisterImage cant be used with the texture that is mapped
+ // directly to the pixmap.
+ // TODO: Investigate if it's somehow possible to use the pixmap texture
+ // directly, this should improve performance since only less image copy is
+ // then needed every frame.
+ // Ignoring failure for now.. TODO: Show proper error
+ unsigned int texture_id = 0;
+ cap_xcomp->egl.glGenTextures(1, &texture_id);
+ cap_xcomp->egl.glBindTexture(GL_TEXTURE_2D, texture_id);
+ cap_xcomp->egl.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+
+ cap_xcomp->egl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ cap_xcomp->egl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ cap_xcomp->egl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ cap_xcomp->egl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+
+ cap_xcomp->egl.glBindTexture(GL_TEXTURE_2D, 0);
+ return texture_id;
+}
+
+#define GL_COMPILE_STATUS 0x8B81
+#define GL_INFO_LOG_LENGTH 0x8B84
+
+unsigned int esLoadShader ( gsr_capture_xcomposite_drm *cap_xcomp, unsigned int type, const char *shaderSrc ) {
+ unsigned int shader;
+ int compiled;
+
+ // Create the shader object
+ shader = cap_xcomp->egl.glCreateShader ( type );
+
+ if ( shader == 0 )
+ return 0;
+
+ // Load the shader source
+ cap_xcomp->egl.glShaderSource ( shader, 1, &shaderSrc, NULL );
+
+ // Compile the shader
+ cap_xcomp->egl.glCompileShader ( shader );
+
+ // Check the compile status
+ cap_xcomp->egl.glGetShaderiv ( shader, GL_COMPILE_STATUS, &compiled );
+
+ if ( !compiled )
+ {
+ int infoLen = 0;
+
+ cap_xcomp->egl.glGetShaderiv ( shader, GL_INFO_LOG_LENGTH, &infoLen );
+
+ if ( infoLen > 1 )
+ {
+ char* infoLog = malloc (sizeof(char) * infoLen );
+
+ cap_xcomp->egl.glGetShaderInfoLog ( shader, infoLen, NULL, infoLog );
+ fprintf (stderr, "Error compiling shader:\n%s\n", infoLog );
+
+ free ( infoLog );
+ }
+
+ cap_xcomp->egl.glDeleteShader ( shader );
+ return 0;
+ }
+
+ return shader;
+
+}
+
+#define GL_FRAGMENT_SHADER 0x8B30
+#define GL_VERTEX_SHADER 0x8B31
+#define GL_COMPILE_STATUS 0x8B81
+#define GL_LINK_STATUS 0x8B82
+
+
+//
+///
+/// \brief Load a vertex and fragment shader, create a program object, link program.
+// Errors output to log.
+/// \param vertShaderSrc Vertex shader source code
+/// \param fragShaderSrc Fragment shader source code
+/// \return A new program object linked with the vertex/fragment shader pair, 0 on failure
+//
+unsigned int esLoadProgram ( gsr_capture_xcomposite_drm *cap_xcomp, const char *vertShaderSrc, const char *fragShaderSrc )
+{
+ unsigned int vertexShader;
+ unsigned int fragmentShader;
+ unsigned int programObject;
+ int linked;
+
+ // Load the vertex/fragment shaders
+ vertexShader = esLoadShader ( cap_xcomp, GL_VERTEX_SHADER, vertShaderSrc );
+ if ( vertexShader == 0 )
+ return 0;
+
+ fragmentShader = esLoadShader ( cap_xcomp, GL_FRAGMENT_SHADER, fragShaderSrc );
+ if ( fragmentShader == 0 )
+ {
+ cap_xcomp->egl.glDeleteShader( vertexShader );
+ return 0;
+ }
+
+ // Create the program object
+ programObject = cap_xcomp->egl.glCreateProgram ( );
+
+ if ( programObject == 0 )
+ return 0;
+
+ cap_xcomp->egl.glAttachShader ( programObject, vertexShader );
+ cap_xcomp->egl.glAttachShader ( programObject, fragmentShader );
+
+ // Link the program
+ cap_xcomp->egl.glLinkProgram ( programObject );
+
+ // Check the link status
+ cap_xcomp->egl.glGetProgramiv ( programObject, GL_LINK_STATUS, &linked );
+
+ if ( !linked )
+ {
+ int infoLen = 0;
+
+ cap_xcomp->egl.glGetProgramiv ( programObject, GL_INFO_LOG_LENGTH, &infoLen );
+
+ if ( infoLen > 1 )
+ {
+ char* infoLog = malloc (sizeof(char) * infoLen );
+
+ cap_xcomp->egl.glGetProgramInfoLog ( programObject, infoLen, NULL, infoLog );
+ fprintf (stderr, "Error linking program:\n%s\n", infoLog );
+
+ free ( infoLog );
+ }
+
+ cap_xcomp->egl.glDeleteProgram ( programObject );
+ return 0;
+ }
+
+ // Free up no longer needed shader resources
+ cap_xcomp->egl.glDeleteShader ( vertexShader );
+ cap_xcomp->egl.glDeleteShader ( fragmentShader );
+
+ return programObject;
+}
+
+static unsigned int shader_program = 0;
+static unsigned int texID = 0;
+
+static void LoadShaders(gsr_capture_xcomposite_drm *cap_xcomp) {
+ char vShaderStr[] =
+ "#version 300 es \n"
+ "in vec2 pos; \n"
+ "in vec2 texcoords; \n"
+ "out vec2 texcoords_out; \n"
+ "void main() \n"
+ "{ \n"
+ " texcoords_out = texcoords; \n"
+ " gl_Position = vec4(pos.x, pos.y, 0.0, 1.0); \n"
+ "} \n";
+
+#if 0
+ char fShaderStr[] =
+ "#version 300 es \n"
+ "precision mediump float; \n"
+ "in vec2 texcoords_out; \n"
+ "uniform sampler2D tex; \n"
+ "out vec4 FragColor; \n"
+
+
+ "float imageWidth = 1920.0;\n"
+ "float imageHeight = 1080.0;\n"
+
+ "float getYPixel(vec2 position) {\n"
+ " position.y = (position.y * 2.0 / 3.0) + (1.0 / 3.0);\n"
+ " return texture2D(tex, position).x;\n"
+ "}\n"
+"\n"
+ "vec2 mapCommon(vec2 position, float planarOffset) {\n"
+ " planarOffset += (imageWidth * floor(position.y / 2.0)) / 2.0 +\n"
+ " floor((imageWidth - 1.0 - position.x) / 2.0);\n"
+ " float x = floor(imageWidth - 1.0 - floor(mod(planarOffset, imageWidth)));\n"
+ " float y = floor(floor(planarOffset / imageWidth));\n"
+ " return vec2((x + 0.5) / imageWidth, (y + 0.5) / (1.5 * imageHeight));\n"
+ "}\n"
+"\n"
+ "vec2 mapU(vec2 position) {\n"
+ " float planarOffset = (imageWidth * imageHeight) / 4.0;\n"
+ " return mapCommon(position, planarOffset);\n"
+ "}\n"
+"\n"
+ "vec2 mapV(vec2 position) {\n"
+ " return mapCommon(position, 0.0);\n"
+ "}\n"
+
+ "void main() \n"
+ "{ \n"
+
+ "vec2 pixelPosition = vec2(floor(imageWidth * texcoords_out.x),\n"
+ " floor(imageHeight * texcoords_out.y));\n"
+ "pixelPosition -= vec2(0.5, 0.5);\n"
+"\n"
+ "float yChannel = getYPixel(texcoords_out);\n"
+ "float uChannel = texture2D(tex, mapU(pixelPosition)).x;\n"
+ "float vChannel = texture2D(tex, mapV(pixelPosition)).x;\n"
+ "vec4 channels = vec4(yChannel, uChannel, vChannel, 1.0);\n"
+ "mat4 conversion = mat4(1.0, 0.0, 1.402, -0.701,\n"
+ " 1.0, -0.344, -0.714, 0.529,\n"
+ " 1.0, 1.772, 0.0, -0.886,\n"
+ " 0, 0, 0, 0);\n"
+ "vec3 rgb = (channels * conversion).xyz;\n"
+
+ " FragColor = vec4(rgb, 1.0); \n"
+ "} \n";
+#elif 1
+ char fShaderStr[] =
+ "#version 300 es \n"
+ "precision mediump float; \n"
+ "in vec2 texcoords_out; \n"
+ "uniform sampler2D tex; \n"
+ "out vec4 FragColor; \n"
+ "void main() \n"
+ "{ \n"
+ " vec3 rgb = texture(tex, texcoords_out).rgb; \n"
+ " FragColor = vec4(rgb, 1.0); \n"
+ "} \n";
+#else
+ char fShaderStr[] =
+ "#version 300 es \n"
+ "precision mediump float; \n"
+ "in vec2 texcoords_out; \n"
+ "uniform sampler2D tex; \n"
+ "out vec4 FragColor; \n"
+
+ "vec3 rgb2yuv(vec3 rgb){\n"
+ " float y = 0.299*rgb.r + 0.587*rgb.g + 0.114*rgb.b;\n"
+ " return vec3(y, 0.493*(rgb.b-y), 0.877*(rgb.r-y));\n"
+ "}\n"
+
+ "vec3 yuv2rgb(vec3 yuv){\n"
+ " float y = yuv.x;\n"
+ " float u = yuv.y;\n"
+ " float v = yuv.z;\n"
+ " \n"
+ " return vec3(\n"
+ " y + 1.0/0.877*v,\n"
+ " y - 0.39393*u - 0.58081*v,\n"
+ " y + 1.0/0.493*u\n"
+ " );\n"
+ "}\n"
+
+ "void main() \n"
+ "{ \n"
+ " float s = 0.5;\n"
+ " vec3 lum = texture(tex, texcoords_out).rgb;\n"
+ " vec3 chr = texture(tex, floor(texcoords_out*s-.5)/s).rgb;\n"
+ " vec3 rgb = vec3(rgb2yuv(lum).x, rgb2yuv(chr).yz);\n"
+ " FragColor = vec4(rgb, 1.0); \n"
+ "} \n";
+#endif
+
+ shader_program = esLoadProgram(cap_xcomp, vShaderStr, fShaderStr);
+ if (shader_program == 0) {
+ fprintf(stderr, "failed to create shader!\n");
+ return;
+ }
+
+ cap_xcomp->egl.glBindAttribLocation(shader_program, 0, "pos");
+ cap_xcomp->egl.glBindAttribLocation(shader_program, 1, "texcoords");
+ return;
+}
+
+#define GL_FLOAT 0x1406
+#define GL_FALSE 0
+#define GL_TRUE 1
+#define GL_TRIANGLES 0x0004
+#define DRM_FORMAT_MOD_INVALID 72057594037927935
+
+static int gsr_capture_xcomposite_drm_start(gsr_capture *cap, AVCodecContext *video_codec_context) {
+ gsr_capture_xcomposite_drm *cap_xcomp = cap->priv;
+
+ XWindowAttributes attr;
+ if(!XGetWindowAttributes(cap_xcomp->dpy, cap_xcomp->params.window, &attr)) {
+ fprintf(stderr, "gsr error: gsr_capture_xcomposite_start failed: invalid window id: %lu\n", cap_xcomp->params.window);
+ return -1;
+ }
+
+ cap_xcomp->window_size.x = max_int(attr.width, 0);
+ cap_xcomp->window_size.y = max_int(attr.height, 0);
+ Window c;
+ XTranslateCoordinates(cap_xcomp->dpy, cap_xcomp->params.window, DefaultRootWindow(cap_xcomp->dpy), 0, 0, &cap_xcomp->window_pos.x, &cap_xcomp->window_pos.y, &c);
+
+ // TODO: Get select and add these on top of it and then restore at the end. Also do the same in other xcomposite
+ XSelectInput(cap_xcomp->dpy, cap_xcomp->params.window, StructureNotifyMask | ExposureMask);
+
+ if(!gsr_egl_load(&cap_xcomp->egl, cap_xcomp->dpy)) {
+ fprintf(stderr, "gsr error: gsr_capture_xcomposite_start: failed to load opengl\n");
+ return -1;
+ }
+
+ /* Disable vsync */
+ cap_xcomp->egl.eglSwapInterval(cap_xcomp->egl.egl_display, 0);
+#if 0
+ // TODO: Fallback to composite window
+ if(window_texture_init(&cap_xcomp->window_texture, cap_xcomp->dpy, cap_xcomp->params.window, &cap_xcomp->gl) != 0) {
+ fprintf(stderr, "gsr error: gsr_capture_xcomposite_start: failed get window texture for window %ld\n", cap_xcomp->params.window);
+ gsr_egl_unload(&cap_xcomp->egl);
+ return -1;
+ }
+
+ cap_xcomp->egl.glBindTexture(GL_TEXTURE_2D, window_texture_get_opengl_texture_id(&cap_xcomp->window_texture));
+ cap_xcomp->texture_size.x = 0;
+ cap_xcomp->texture_size.y = 0;
+ cap_xcomp->egl.glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &cap_xcomp->texture_size.x);
+ cap_xcomp->egl.glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &cap_xcomp->texture_size.y);
+ cap_xcomp->egl.glBindTexture(GL_TEXTURE_2D, 0);
+
+ cap_xcomp->texture_size.x = max_int(2, cap_xcomp->texture_size.x & ~1);
+ cap_xcomp->texture_size.y = max_int(2, cap_xcomp->texture_size.y & ~1);
+
+ cap_xcomp->target_texture_id = gl_create_texture(cap_xcomp, cap_xcomp->texture_size.x, cap_xcomp->texture_size.y);
+ if(cap_xcomp->target_texture_id == 0) {
+ fprintf(stderr, "gsr error: gsr_capture_xcomposite_start: failed to create opengl texture\n");
+ gsr_capture_xcomposite_stop(cap, video_codec_context);
+ return -1;
+ }
+
+ video_codec_context->width = cap_xcomp->texture_size.x;
+ video_codec_context->height = cap_xcomp->texture_size.y;
+
+ cap_xcomp->window_resize_timer = clock_get_monotonic_seconds();
+ return 0;
+#else
+ // TODO: Fallback to composite window
+ if(window_texture_init(&cap_xcomp->window_texture, cap_xcomp->dpy, cap_xcomp->params.window, &cap_xcomp->egl) != 0) {
+ fprintf(stderr, "gsr error: gsr_capture_xcomposite_drm_start: failed get window texture for window %ld\n", cap_xcomp->params.window);
+ gsr_egl_unload(&cap_xcomp->egl);
+ return -1;
+ }
+
+ cap_xcomp->egl.glBindTexture(GL_TEXTURE_2D, window_texture_get_opengl_texture_id(&cap_xcomp->window_texture));
+ cap_xcomp->texture_size.x = 0;
+ cap_xcomp->texture_size.y = 0;
+ cap_xcomp->egl.glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &cap_xcomp->texture_size.x);
+ cap_xcomp->egl.glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &cap_xcomp->texture_size.y);
+ cap_xcomp->egl.glBindTexture(GL_TEXTURE_2D, 0);
+
+ #if 1
+ cap_xcomp->target_texture_id = gl_create_texture(cap_xcomp, cap_xcomp->texture_size.x, cap_xcomp->texture_size.y);
+ if(cap_xcomp->target_texture_id == 0) {
+ fprintf(stderr, "gsr error: gsr_capture_xcomposite_drm_start: failed to create opengl texture\n");
+ return -1;
+ }
+ #else
+ // TODO:
+ cap_xcomp->target_texture_id = window_texture_get_opengl_texture_id(&cap_xcomp->window_texture);
+ #endif
+
+ cap_xcomp->texture_size.x = max_int(2, cap_xcomp->texture_size.x & ~1);
+ cap_xcomp->texture_size.y = max_int(2, cap_xcomp->texture_size.y & ~1);
+
+ video_codec_context->width = cap_xcomp->texture_size.x;
+ video_codec_context->height = cap_xcomp->texture_size.y;
+
+ {
+ EGLImage img = cap_xcomp->egl.eglCreateImage(cap_xcomp->egl.egl_display, cap_xcomp->egl.egl_context, EGL_GL_TEXTURE_2D, (EGLClientBuffer)(uint64_t)cap_xcomp->target_texture_id, NULL);
+ if(!img) {
+ fprintf(stderr, "eglCreateImage failed\n");
+ return -1;
+ }
+
+ if(!cap_xcomp->egl.eglExportDMABUFImageQueryMESA(cap_xcomp->egl.egl_display, img, &cap_xcomp->fourcc, &cap_xcomp->num_planes, &cap_xcomp->modifiers) || cap_xcomp->modifiers == DRM_FORMAT_MOD_INVALID) {
+ fprintf(stderr, "eglExportDMABUFImageQueryMESA failed\n");
+ return -1;
+ }
+
+ if(cap_xcomp->num_planes != 1) {
+ // TODO: FAIL!
+ fprintf(stderr, "Blablalba\n");
+ return -1;
+ }
+
+ if(!cap_xcomp->egl.eglExportDMABUFImageMESA(cap_xcomp->egl.egl_display, img, &cap_xcomp->dmabuf_fd, &cap_xcomp->stride, &cap_xcomp->offset)) {
+ fprintf(stderr, "eglExportDMABUFImageMESA failed\n");
+ return -1;
+ }
+
+ fprintf(stderr, "texture: %u, dmabuf: %d, stride: %d, offset: %d\n", cap_xcomp->target_texture_id, cap_xcomp->dmabuf_fd, cap_xcomp->stride, cap_xcomp->offset);
+ fprintf(stderr, "fourcc: %d, num planes: %d, modifiers: %zu\n", cap_xcomp->fourcc, cap_xcomp->num_planes, cap_xcomp->modifiers);
+ }
+
+ cap_xcomp->egl.glGenFramebuffers(1, &cap_xcomp->FramebufferName);
+ cap_xcomp->egl.glBindFramebuffer(GL_FRAMEBUFFER, cap_xcomp->FramebufferName);
+
+ cap_xcomp->egl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, cap_xcomp->target_texture_id, 0);
+
+ // Set the list of draw buffers.
+ unsigned int DrawBuffers[1] = {GL_COLOR_ATTACHMENT0};
+ cap_xcomp->egl.glDrawBuffers(1, DrawBuffers); // "1" is the size of DrawBuffers
+
+ if(cap_xcomp->egl.glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
+ fprintf(stderr, "Failed to setup framebuffer\n");
+ return -1;
+ }
+
+ cap_xcomp->egl.glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ //cap_xcomp->egl.glGenVertexArrays(1, &cap_xcomp->quad_VertexArrayID);
+ //cap_xcomp->egl.glBindVertexArray(cap_xcomp->quad_VertexArrayID);
+
+ static const float g_quad_vertex_buffer_data[] = {
+ -1.0f, -1.0f, 0.0f,
+ 1.0f, -1.0f, 0.0f,
+ -1.0f, 1.0f, 0.0f,
+ -1.0f, 1.0f, 0.0f,
+ 1.0f, -1.0f, 0.0f,
+ 1.0f, 1.0f, 0.0f,
+ };
+
+ //cap_xcomp->egl.glGenBuffers(1, &cap_xcomp->quad_vertexbuffer);
+ //cap_xcomp->egl.glBindBuffer(GL_ARRAY_BUFFER, cap_xcomp->quad_vertexbuffer);
+ //cap_xcomp->egl.glBufferData(GL_ARRAY_BUFFER, sizeof(g_quad_vertex_buffer_data), g_quad_vertex_buffer_data, GL_STATIC_DRAW);
+
+ // Create and compile our GLSL program from the shaders
+ LoadShaders(cap_xcomp);
+ texID = cap_xcomp->egl.glGetUniformLocation(shader_program, "tex");
+ fprintf(stderr, "uniform id: %u\n", texID);
+
+ float vVertices[] = {
+ -1.0f, 1.0f, 0.0f, 1.0f,
+ -1.0f, -1.0f, 0.0f, 0.0f,
+ 1.0f, -1.0f, 1.0f, 0.0f,
+
+ -1.0f, 1.0f, 0.0f, 1.0f,
+ 1.0f, -1.0f, 1.0f, 0.0f,
+ 1.0f, 1.0f, 1.0f, 1.0f
+ };
+
+ unsigned int quadVBO;
+ cap_xcomp->egl.glGenVertexArrays(1, &cap_xcomp->quadVAO);
+ cap_xcomp->egl.glGenBuffers(1, &quadVBO);
+ cap_xcomp->egl.glBindVertexArray(cap_xcomp->quadVAO);
+ cap_xcomp->egl.glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
+ cap_xcomp->egl.glBufferData(GL_ARRAY_BUFFER, sizeof(vVertices), &vVertices, GL_STATIC_DRAW);
+
+ cap_xcomp->egl.glEnableVertexAttribArray(0);
+ cap_xcomp->egl.glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
+
+ cap_xcomp->egl.glEnableVertexAttribArray(1);
+ cap_xcomp->egl.glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
+
+ cap_xcomp->egl.glBindVertexArray(0);
+
+ //cap_xcomp->egl.glUniform1i(texID, window_texture_get_opengl_texture_id(&cap_xcomp->window_texture));
+
+ //cap_xcomp->egl.glViewport(0, 0, 1920, 1080);
+
+ //cap_xcomp->egl.glBindBuffer(GL_ARRAY_BUFFER, 0);
+ //cap_xcomp->egl.glBindVertexArray(0);
+
+ if(!drm_create_codec_context(cap_xcomp, video_codec_context)) {
+ fprintf(stderr, "failed to create hw codec context\n");
+ gsr_egl_unload(&cap_xcomp->egl);
+ return -1;
+ }
+
+ fprintf(stderr, "sneed: %u\n", cap_xcomp->FramebufferName);
+ return 0;
+#endif
+}
+
+// TODO:
+static void free_desc(void *opaque, uint8_t *data) {
+ AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor*)data;
+ int i;
+
+ //for (i = 0; i < desc->nb_objects; i++)
+ // close(desc->objects[i].fd);
+
+ av_free(desc);
+}
+
+
+static void gsr_capture_xcomposite_drm_tick(gsr_capture *cap, AVCodecContext *video_codec_context, AVFrame **frame) {
+ gsr_capture_xcomposite_drm *cap_xcomp = cap->priv;
+
+ if(!cap_xcomp->created_hw_frame) {
+ cap_xcomp->created_hw_frame = true;
+
+ /*if(av_hwframe_get_buffer(video_codec_context->hw_frames_ctx, *frame, 0) < 0) {
+ fprintf(stderr, "gsr error: gsr_capture_xcomposite_drm_tick: av_hwframe_get_buffer failed\n");
+ return;
+ }*/
+
+ AVDRMFrameDescriptor *desc = av_malloc(sizeof(AVDRMFrameDescriptor));
+ if(!desc) {
+ fprintf(stderr, "poop\n");
+ return;
+ }
+
+ fprintf(stderr, "tick fd: %d\n", cap_xcomp->dmabuf_fd);
+
+ cap_xcomp->egl.glBindTexture(GL_TEXTURE_2D, cap_xcomp->target_texture_id);
+ int xx = 0;
+ int yy = 0;
+ cap_xcomp->egl.glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &xx);
+ cap_xcomp->egl.glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &yy);
+ cap_xcomp->egl.glBindTexture(GL_TEXTURE_2D, 0);
+
+ *desc = (AVDRMFrameDescriptor) {
+ .nb_objects = 1,
+ .objects[0] = {
+ .fd = cap_xcomp->dmabuf_fd,
+ .size = yy * cap_xcomp->stride,
+ .format_modifier = cap_xcomp->modifiers,
+ },
+ .nb_layers = 1,
+ .layers[0] = {
+ .format = cap_xcomp->fourcc, // DRM_FORMAT_NV12
+ .nb_planes = 1, //cap_xcomp->num_planes, // TODO: Ensure this is 1, otherwise ffmpeg cant handle it in av_hwframe_map
+ .planes[0] = {
+ .object_index = 0,
+ .offset = cap_xcomp->offset,
+ .pitch = cap_xcomp->stride,
+ },
+ },
+ };
+
+ #if 0
+ AVBufferRef *device_ctx;
+ if(av_hwdevice_ctx_create(&device_ctx, AV_HWDEVICE_TYPE_DRM, "/dev/dri/card0", NULL, 0) < 0) {
+ fprintf(stderr, "Error: Failed to create hardware device context\n");
+ return;
+ }
+
+ AVBufferRef *frame_context = av_hwframe_ctx_alloc(device_ctx);
+ if(!frame_context) {
+ fprintf(stderr, "Error: Failed to create hwframe context\n");
+ av_buffer_unref(&device_ctx);
+ return;
+ }
+
+ AVHWFramesContext *hw_frame_context =
+ (AVHWFramesContext *)frame_context->data;
+ hw_frame_context->width = video_codec_context->width;
+ hw_frame_context->height = video_codec_context->height;
+ hw_frame_context->sw_format = AV_PIX_FMT_0RGB32;
+ hw_frame_context->format = AV_PIX_FMT_DRM_PRIME;
+ hw_frame_context->device_ref = device_ctx;
+ hw_frame_context->device_ctx = (AVHWDeviceContext*)device_ctx->data;
+
+ if (av_hwframe_ctx_init(frame_context) < 0) {
+ fprintf(stderr, "Error: Failed to initialize hardware frame context "
+ "(note: ffmpeg version needs to be > 4.0)\n");
+ av_buffer_unref(&device_ctx);
+ av_buffer_unref(&frame_context);
+ return;
+ }
+ #endif
+
+ av_frame_free(frame);
+ *frame = av_frame_alloc();
+ if(!frame) {
+ fprintf(stderr, "gsr error: gsr_capture_xcomposite_tick: failed to allocate frame\n");
+ return;
+ }
+ (*frame)->format = video_codec_context->pix_fmt;
+ (*frame)->width = video_codec_context->width;
+ (*frame)->height = video_codec_context->height;
+ (*frame)->color_range = AVCOL_RANGE_JPEG;
+
+ int res = av_hwframe_get_buffer(video_codec_context->hw_frames_ctx, *frame, 0);
+ if(res < 0) {
+ fprintf(stderr, "gsr error: gsr_capture_xcomposite_tick: av_hwframe_get_buffer failed 1: %d\n", res);
+ return;
+ }
+
+ AVFrame *src_frame = av_frame_alloc();
+ assert(src_frame);
+ src_frame->format = AV_PIX_FMT_DRM_PRIME;
+ src_frame->width = video_codec_context->width;
+ src_frame->height = video_codec_context->height;
+ src_frame->color_range = AVCOL_RANGE_JPEG;
+
+ src_frame->buf[0] = av_buffer_create((uint8_t*)desc, sizeof(*desc),
+ &free_desc, video_codec_context, 0);
+ if (!src_frame->buf[0]) {
+ fprintf(stderr, "failed to create buffer!\n");
+ return;
+ }
+
+ src_frame->data[0] = (uint8_t*)desc;
+ src_frame->extended_data = src_frame->data;
+ src_frame->format = AV_PIX_FMT_DRM_PRIME;
+
+ res = av_hwframe_map(*frame, src_frame, AV_HWFRAME_MAP_DIRECT);
+ if(res < 0) {
+ fprintf(stderr, "av_hwframe_map failed: %d\n", res);
+ }
+ }
+
+ cap_xcomp->egl.glClear(GL_COLOR_BUFFER_BIT);
+}
+
+static bool gsr_capture_xcomposite_drm_should_stop(gsr_capture *cap, bool *err) {
+ return false;
+}
+
+#define GL_FLOAT 0x1406
+#define GL_FALSE 0
+#define GL_TRUE 1
+#define GL_TRIANGLES 0x0004
+
+void FBO_2_PPM_file(gsr_capture_xcomposite_drm *cap_xcomp, int output_width, int output_height)
+{
+ FILE *output_image;
+
+ /// READ THE PIXELS VALUES from FBO AND SAVE TO A .PPM FILE
+ int i, j, k;
+ unsigned char *pixels = (unsigned char*)malloc(output_width*output_height*3);
+
+ unsigned int err = cap_xcomp->egl.glGetError();
+ fprintf(stderr, "opengl err 1: %u\n", err);
+
+ /// READ THE CONTENT FROM THE FBO
+ cap_xcomp->egl.glReadBuffer(GL_COLOR_ATTACHMENT0);
+
+ err = cap_xcomp->egl.glGetError();
+ fprintf(stderr, "opengl err 2: %u\n", err);
+
+ cap_xcomp->egl.glReadPixels(0, 0, output_width, output_height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+
+ err = cap_xcomp->egl.glGetError();
+ fprintf(stderr, "opengl err 3: %u\n", err);
+
+ output_image = fopen("output.ppm", "wb");
+ fprintf(output_image,"P3\n");
+ fprintf(output_image,"# Created by Ricao\n");
+ fprintf(output_image,"%d %d\n",output_width,output_height);
+ fprintf(output_image,"255\n");
+
+ k = 0;
+ for(i=0; i<output_width; i++)
+ {
+ for(j=0; j<output_height; j++)
+ {
+ fprintf(output_image,"%u %u %u ",(unsigned int)pixels[k],(unsigned int)pixels[k+1],
+ (unsigned int)pixels[k+2]);
+ k = k+4;
+ }
+ fprintf(output_image,"\n");
+ }
+ free(pixels);
+ fclose(output_image);
+}
+
+static int gsr_capture_xcomposite_drm_capture(gsr_capture *cap, AVFrame *frame) {
+ gsr_capture_xcomposite_drm *cap_xcomp = cap->priv;
+ vec2i source_size = cap_xcomp->texture_size;
+
+ #if 1
+ // Requires opengl 4.2... TODO: Replace with earlier opengl if opengl < 4.2.
+ cap_xcomp->egl.glCopyImageSubData(
+ window_texture_get_opengl_texture_id(&cap_xcomp->window_texture), GL_TEXTURE_2D, 0, 0, 0, 0,
+ cap_xcomp->target_texture_id, GL_TEXTURE_2D, 0, 0, 0, 0,
+ source_size.x, source_size.y, 1);
+ unsigned int err = cap_xcomp->egl.glGetError();
+ if(err != 0) {
+ static bool error_shown = false;
+ if(!error_shown) {
+ error_shown = true;
+ fprintf(stderr, "Error: glCopyImageSubData failed, gl error: %d\n", err);
+ }
+ }
+ #elif 0
+ cap_xcomp->egl.glBindFramebuffer(GL_FRAMEBUFFER, cap_xcomp->FramebufferName);
+ cap_xcomp->egl.glViewport(0, 0, 1920, 1080);
+ //cap_xcomp->egl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+ cap_xcomp->egl.glClear(GL_COLOR_BUFFER_BIT);
+
+ cap_xcomp->egl.glUseProgram(shader_program);
+ cap_xcomp->egl.glBindTexture(GL_TEXTURE_2D, window_texture_get_opengl_texture_id(&cap_xcomp->window_texture));
+ cap_xcomp->egl.glBindVertexArray(cap_xcomp->quadVAO);
+ cap_xcomp->egl.glDrawArrays(GL_TRIANGLES, 0, 6);
+ cap_xcomp->egl.glBindTexture(GL_TEXTURE_2D, 0);
+
+ static int counter = 0;
+ ++counter;
+ static bool image_saved = false;
+ if(!image_saved && counter == 5) {
+ image_saved = true;
+ FBO_2_PPM_file(cap_xcomp, 1920, 1080);
+ fprintf(stderr, "saved image!\n");
+ }
+
+ cap_xcomp->egl.glBindVertexArray(0);
+ cap_xcomp->egl.glUseProgram(0);
+ cap_xcomp->egl.glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ #endif
+ cap_xcomp->egl.eglSwapBuffers(cap_xcomp->egl.egl_display, cap_xcomp->egl.egl_surface);
+
+ return 0;
+}
+
+static void gsr_capture_xcomposite_drm_destroy(gsr_capture *cap, AVCodecContext *video_codec_context) {
+ if(cap->priv) {
+ free(cap->priv);
+ cap->priv = NULL;
+ }
+ free(cap);
+}
+
+gsr_capture* gsr_capture_xcomposite_drm_create(const gsr_capture_xcomposite_drm_params *params) {
+ if(!params) {
+ fprintf(stderr, "gsr error: gsr_capture_xcomposite_drm_create params is NULL\n");
+ return NULL;
+ }
+
+ gsr_capture *cap = calloc(1, sizeof(gsr_capture));
+ if(!cap)
+ return NULL;
+
+ gsr_capture_xcomposite_drm *cap_xcomp = calloc(1, sizeof(gsr_capture_xcomposite_drm));
+ if(!cap_xcomp) {
+ free(cap);
+ return NULL;
+ }
+
+ Display *display = XOpenDisplay(NULL);
+ if(!display) {
+ fprintf(stderr, "gsr error: gsr_capture_xcomposite_drm_create failed: XOpenDisplay failed\n");
+ free(cap);
+ free(cap_xcomp);
+ return NULL;
+ }
+
+ cap_xcomp->dpy = display;
+ cap_xcomp->params = *params;
+
+ *cap = (gsr_capture) {
+ .start = gsr_capture_xcomposite_drm_start,
+ .tick = gsr_capture_xcomposite_drm_tick,
+ .should_stop = gsr_capture_xcomposite_drm_should_stop,
+ .capture = gsr_capture_xcomposite_drm_capture,
+ .destroy = gsr_capture_xcomposite_drm_destroy,
+ .priv = cap_xcomp
+ };
+
+ return cap;
+}