aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/GlLibrary.hpp156
-rw-r--r--include/LibraryLoader.hpp38
-rw-r--r--include/NvFBCLibrary.hpp321
-rw-r--r--include/capture/capture.h68
-rw-r--r--include/capture/kms.h50
-rw-r--r--include/capture/kms_cuda.h20
-rw-r--r--include/capture/kms_vaapi.h20
-rw-r--r--include/capture/nvfbc.h22
-rw-r--r--include/capture/xcomposite.h51
-rw-r--r--include/capture/xcomposite_cuda.h14
-rw-r--r--include/capture/xcomposite_vaapi.h13
-rw-r--r--include/color_conversion.h58
-rw-r--r--include/cuda.h (renamed from include/CudaLibrary.hpp)89
-rw-r--r--include/cursor.h26
-rw-r--r--include/defs.h28
-rw-r--r--include/egl.h285
-rw-r--r--include/library_loader.h17
-rw-r--r--include/overclock.h17
-rw-r--r--include/shader.h19
-rw-r--r--include/sound.hpp14
-rw-r--r--include/utils.h46
-rw-r--r--include/vec2.h12
-rw-r--r--include/window_texture.h27
-rw-r--r--include/xnvctrl.h45
24 files changed, 877 insertions, 579 deletions
diff --git a/include/GlLibrary.hpp b/include/GlLibrary.hpp
deleted file mode 100644
index 1337ef3..0000000
--- a/include/GlLibrary.hpp
+++ /dev/null
@@ -1,156 +0,0 @@
-#pragma once
-
-#include "LibraryLoader.hpp"
-
-#include <X11/X.h>
-#include <X11/Xutil.h>
-#include <dlfcn.h>
-#include <stdio.h>
-
-typedef XID GLXPixmap;
-typedef XID GLXDrawable;
-typedef XID GLXWindow;
-
-typedef struct __GLXcontextRec *GLXContext;
-typedef struct __GLXFBConfigRec *GLXFBConfig;
-
-#define GL_TEXTURE_2D 0x0DE1
-#define GL_RGB 0x1907
-#define GL_UNSIGNED_BYTE 0x1401
-#define GL_COLOR_BUFFER_BIT 0x00004000
-#define GL_TEXTURE_WRAP_S 0x2802
-#define GL_TEXTURE_WRAP_T 0x2803
-#define GL_TEXTURE_MAG_FILTER 0x2800
-#define GL_TEXTURE_MIN_FILTER 0x2801
-#define GL_TEXTURE_WIDTH 0x1000
-#define GL_TEXTURE_HEIGHT 0x1001
-#define GL_NEAREST 0x2600
-
-#define GL_RENDERER 0x1F01
-
-#define GLX_BUFFER_SIZE 2
-#define GLX_DOUBLEBUFFER 5
-#define GLX_RED_SIZE 8
-#define GLX_GREEN_SIZE 9
-#define GLX_BLUE_SIZE 10
-#define GLX_ALPHA_SIZE 11
-#define GLX_DEPTH_SIZE 12
-
-#define GLX_RGBA_BIT 0x00000001
-#define GLX_RENDER_TYPE 0x8011
-#define GLX_FRONT_EXT 0x20DE
-#define GLX_BIND_TO_TEXTURE_RGB_EXT 0x20D0
-#define GLX_DRAWABLE_TYPE 0x8010
-#define GLX_WINDOW_BIT 0x00000001
-#define GLX_PIXMAP_BIT 0x00000002
-#define GLX_BIND_TO_TEXTURE_TARGETS_EXT 0x20D3
-#define GLX_TEXTURE_2D_BIT_EXT 0x00000002
-#define GLX_TEXTURE_TARGET_EXT 0x20D6
-#define GLX_TEXTURE_2D_EXT 0x20DC
-#define GLX_TEXTURE_FORMAT_EXT 0x20D5
-#define GLX_TEXTURE_FORMAT_RGB_EXT 0x20D9
-#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
-#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
-#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
-#define GLX_CONTEXT_FLAGS_ARB 0x2094
-
-struct GlLibrary {
- GLXPixmap (*glXCreatePixmap)(Display *dpy, GLXFBConfig config, Pixmap pixmap, const int *attribList);
- void (*glXDestroyPixmap)(Display *dpy, GLXPixmap pixmap);
- void (*glXBindTexImageEXT)(Display *dpy, GLXDrawable drawable, int buffer, const int *attrib_list);
- void (*glXReleaseTexImageEXT)(Display *dpy, GLXDrawable drawable, int buffer);
- GLXFBConfig* (*glXChooseFBConfig)(Display *dpy, int screen, const int *attribList, int *nitems);
- XVisualInfo* (*glXGetVisualFromFBConfig)(Display *dpy, GLXFBConfig config);
- GLXContext (*glXCreateContextAttribsARB)(Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list);
- Bool (*glXMakeContextCurrent)(Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx);
- void (*glXDestroyContext)(Display *dpy, GLXContext ctx);
- void (*glXSwapBuffers)(Display *dpy, GLXDrawable drawable);
-
- void (*glXSwapIntervalEXT)(Display *dpy, GLXDrawable drawable, int interval);
- int (*glXSwapIntervalMESA)(unsigned int interval);
- int (*glXSwapIntervalSGI)(int interval);
-
- void (*glClearTexImage)(unsigned int texture, unsigned int level, unsigned int format, unsigned int type, const void *data);
-
- unsigned int (*glGetError)(void);
- const unsigned char* (*glGetString)(unsigned int name);
- void (*glClear)(unsigned int mask);
- void (*glGenTextures)(int n, unsigned int *textures);
- void (*glDeleteTextures)(int n, const unsigned int *texture);
- void (*glBindTexture)(unsigned int target, unsigned int texture);
- void (*glTexParameteri)(unsigned int target, unsigned int pname, int param);
- void (*glGetTexLevelParameteriv)(unsigned int target, int level, unsigned int pname, int *params);
- 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);
-
- ~GlLibrary() {
- unload();
- }
-
- bool load() {
- if(library)
- return true;
-
- dlerror(); // clear
- void *lib = dlopen("libGL.so.1", RTLD_LAZY);
- if(!lib) {
- fprintf(stderr, "Error: failed to load libGL.so.1, error: %s\n", dlerror());
- return false;
- }
-
- dlsym_assign optional_dlsym[] = {
- { (void**)&glClearTexImage, "glClearTexImage" },
- { (void**)&glXSwapIntervalEXT, "glXSwapIntervalEXT" },
- { (void**)&glXSwapIntervalMESA, "glXSwapIntervalMESA" },
- { (void**)&glXSwapIntervalSGI, "glXSwapIntervalSGI" },
-
- { NULL, NULL }
- };
-
- dlsym_load_list_optional(lib, optional_dlsym);
-
- dlsym_assign required_dlsym[] = {
- { (void**)&glXCreatePixmap, "glXCreatePixmap" },
- { (void**)&glXDestroyPixmap, "glXDestroyPixmap" },
- { (void**)&glXBindTexImageEXT, "glXBindTexImageEXT" },
- { (void**)&glXReleaseTexImageEXT, "glXReleaseTexImageEXT" },
- { (void**)&glXChooseFBConfig, "glXChooseFBConfig" },
- { (void**)&glXGetVisualFromFBConfig, "glXGetVisualFromFBConfig" },
- { (void**)&glXCreateContextAttribsARB, "glXCreateContextAttribsARB" },
- { (void**)&glXMakeContextCurrent, "glXMakeContextCurrent" },
- { (void**)&glXDestroyContext, "glXDestroyContext" },
- { (void**)&glXSwapBuffers, "glXSwapBuffers" },
-
- { (void**)&glGetError, "glGetError" },
- { (void**)&glGetString, "glGetString" },
- { (void**)&glClear, "glClear" },
- { (void**)&glGenTextures, "glGenTextures" },
- { (void**)&glDeleteTextures, "glDeleteTextures" },
- { (void**)&glBindTexture, "glBindTexture" },
- { (void**)&glTexParameteri, "glTexParameteri" },
- { (void**)&glGetTexLevelParameteriv, "glGetTexLevelParameteriv" },
- { (void**)&glTexImage2D, "glTexImage2D" },
- { (void**)&glCopyImageSubData, "glCopyImageSubData" },
-
- { NULL, NULL }
- };
-
- if(dlsym_load_list(lib, required_dlsym)) {
- library = lib;
- return true;
- } else {
- fprintf(stderr, "Error: missing required symbols in libGL.so.1\n");
- dlclose(lib);
- return false;
- }
- }
-
- void unload() {
- if(library) {
- dlclose(library);
- library = nullptr;
- }
- }
-private:
- void *library = nullptr;
-};
diff --git a/include/LibraryLoader.hpp b/include/LibraryLoader.hpp
deleted file mode 100644
index 16dc580..0000000
--- a/include/LibraryLoader.hpp
+++ /dev/null
@@ -1,38 +0,0 @@
-#pragma once
-
-#include <dlfcn.h>
-#include <stdio.h>
-
-typedef struct {
- void **func;
- const char *name;
-} dlsym_assign;
-
-static void* dlsym_print_fail(void *handle, const char *name, bool required) {
- dlerror();
- void *sym = dlsym(handle, name);
- char *err_str = dlerror();
-
- if(!sym)
- fprintf(stderr, "%s: dlsym(handle, \"%s\") failed, error: %s\n", required ? "error" : "warning", name, err_str ? err_str : "(null)");
-
- return sym;
-}
-
-/* |dlsyms| should be null terminated */
-static bool dlsym_load_list(void *handle, const dlsym_assign *dlsyms) {
- bool success = true;
- for(int i = 0; dlsyms[i].func; ++i) {
- *dlsyms[i].func = dlsym_print_fail(handle, dlsyms[i].name, true);
- if(!*dlsyms[i].func)
- success = false;
- }
- return success;
-}
-
-/* |dlsyms| should be null terminated */
-static void dlsym_load_list_optional(void *handle, const dlsym_assign *dlsyms) {
- for(int i = 0; dlsyms[i].func; ++i) {
- *dlsyms[i].func = dlsym_print_fail(handle, dlsyms[i].name, false);
- }
-} \ No newline at end of file
diff --git a/include/NvFBCLibrary.hpp b/include/NvFBCLibrary.hpp
deleted file mode 100644
index dc7db1f..0000000
--- a/include/NvFBCLibrary.hpp
+++ /dev/null
@@ -1,321 +0,0 @@
-#pragma once
-
-#include "../external/NvFBC.h"
-#include <dlfcn.h>
-#include <string.h>
-#include <stdio.h>
-#include <string.h>
-
-class NvFBCLibrary {
-public:
- ~NvFBCLibrary() {
- if(fbc_handle_created) {
- NVFBC_DESTROY_CAPTURE_SESSION_PARAMS destroy_capture_params;
- memset(&destroy_capture_params, 0, sizeof(destroy_capture_params));
- destroy_capture_params.dwVersion = NVFBC_DESTROY_CAPTURE_SESSION_PARAMS_VER;
- nv_fbc_function_list.nvFBCDestroyCaptureSession(nv_fbc_handle, &destroy_capture_params);
-
- NVFBC_DESTROY_HANDLE_PARAMS destroy_params;
- memset(&destroy_params, 0, sizeof(destroy_params));
- destroy_params.dwVersion = NVFBC_DESTROY_HANDLE_PARAMS_VER;
- nv_fbc_function_list.nvFBCDestroyHandle(nv_fbc_handle, &destroy_params);
- }
-
- if(library)
- dlclose(library);
- }
-
- bool load() {
- if(library)
- return true;
-
- dlerror(); // clear
- void *lib = dlopen("libnvidia-fbc.so.1", RTLD_LAZY);
- if(!lib) {
- fprintf(stderr, "Error: failed to load libnvidia-fbc.so.1, error: %s\n", dlerror());
- return false;
- }
-
- nv_fbc_create_instance = (PNVFBCCREATEINSTANCE)dlsym(lib, "NvFBCCreateInstance");
- if(!nv_fbc_create_instance) {
- fprintf(stderr, "Error: unable to resolve symbol 'NvFBCCreateInstance'\n");
- dlclose(lib);
- return false;
- }
-
- memset(&nv_fbc_function_list, 0, sizeof(nv_fbc_function_list));
- nv_fbc_function_list.dwVersion = NVFBC_VERSION;
- NVFBCSTATUS status = nv_fbc_create_instance(&nv_fbc_function_list);
- if(status != NVFBC_SUCCESS) {
- fprintf(stderr, "Error: failed to create NvFBC instance (status: %d)\n", status);
- dlclose(lib);
- return false;
- }
-
- library = lib;
- return true;
- }
-
- // If |display_to_capture| is "screen", then the entire x11 screen is captured (all displays).
- bool create(const char *display_to_capture, uint32_t fps, /*out*/ uint32_t *display_width, /*out*/ uint32_t *display_height, uint32_t x = 0, uint32_t y = 0, uint32_t width = 0, uint32_t height = 0, bool direct_capture = false) {
- if(!library || !display_to_capture || !display_width || !display_height || fbc_handle_created)
- return false;
-
- this->fps = fps;
- const bool capture_region = (x > 0 || y > 0 || width > 0 || height > 0);
-
- bool supports_direct_cursor = false;
- 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;
- uint32_t output_id = 0;
- fbc_handle_created = false;
-
- NVFBC_CREATE_HANDLE_PARAMS create_params;
- memset(&create_params, 0, sizeof(create_params));
- create_params.dwVersion = NVFBC_CREATE_HANDLE_PARAMS_VER;
-
- status = nv_fbc_function_list.nvFBCCreateHandle(&nv_fbc_handle, &create_params);
- if(status != NVFBC_SUCCESS) {
- // Reverse engineering for interoperability
- const uint8_t enable_key[] = { 0xac, 0x10, 0xc9, 0x2e, 0xa5, 0xe6, 0x87, 0x4f, 0x8f, 0x4b, 0xf4, 0x61, 0xf8, 0x56, 0x27, 0xe9 };
- create_params.privateData = enable_key;
- create_params.privateDataSize = 16;
-
- status = nv_fbc_function_list.nvFBCCreateHandle(&nv_fbc_handle, &create_params);
- if(status != NVFBC_SUCCESS) {
- fprintf(stderr, "Error: %s\n", nv_fbc_function_list.nvFBCGetLastErrorStr(nv_fbc_handle));
- return false;
- }
- }
- fbc_handle_created = true;
-
- NVFBC_GET_STATUS_PARAMS status_params;
- memset(&status_params, 0, sizeof(status_params));
- status_params.dwVersion = NVFBC_GET_STATUS_PARAMS_VER;
-
- status = nv_fbc_function_list.nvFBCGetStatus(nv_fbc_handle, &status_params);
- if(status != NVFBC_SUCCESS) {
- fprintf(stderr, "Error: %s\n", nv_fbc_function_list.nvFBCGetLastErrorStr(nv_fbc_handle));
- goto error_cleanup;
- }
-
- if(status_params.bCanCreateNow == NVFBC_FALSE) {
- fprintf(stderr, "Error: it's not possible to create a capture session on this system\n");
- goto error_cleanup;
- }
-
- tracking_type = strcmp(display_to_capture, "screen") == 0 ? NVFBC_TRACKING_SCREEN : NVFBC_TRACKING_OUTPUT;
- if(tracking_type == NVFBC_TRACKING_OUTPUT) {
- if(!status_params.bXRandRAvailable) {
- fprintf(stderr, "Error: the xrandr extension is not available\n");
- goto error_cleanup;
- }
-
- if(status_params.bInModeset) {
- fprintf(stderr, "Error: the x server is in modeset, unable to record\n");
- goto error_cleanup;
- }
-
- output_id = get_output_id_from_display_name(status_params.outputs, status_params.dwOutputNum, display_to_capture, display_width, display_height);
- if(output_id == 0) {
- fprintf(stderr, "Error: display '%s' not found\n", display_to_capture);
- goto error_cleanup;
- }
- } else {
- *display_width = status_params.screenSize.w;
- *display_height = status_params.screenSize.h;
- }
-
- NVFBC_CREATE_CAPTURE_SESSION_PARAMS create_capture_params;
- 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 = (!direct_capture || supports_direct_cursor) ? NVFBC_TRUE : NVFBC_FALSE;
- if(capture_region) {
- create_capture_params.captureBox = { x, y, width, height };
- *display_width = width;
- *display_height = height;
- }
- create_capture_params.eTrackingType = tracking_type;
- create_capture_params.dwSamplingRateMs = 1000 / (fps + 1);
- create_capture_params.bAllowDirectCapture = direct_capture ? NVFBC_TRUE : NVFBC_FALSE;
- create_capture_params.bPushModel = direct_capture ? NVFBC_TRUE : NVFBC_FALSE;
- if(tracking_type == NVFBC_TRACKING_OUTPUT)
- create_capture_params.dwOutputId = output_id;
-
- status = nv_fbc_function_list.nvFBCCreateCaptureSession(nv_fbc_handle, &create_capture_params);
- if(status != NVFBC_SUCCESS) {
- fprintf(stderr, "Error: %s\n", nv_fbc_function_list.nvFBCGetLastErrorStr(nv_fbc_handle));
- goto error_cleanup;
- }
- capture_session_created = true;
-
- NVFBC_TOCUDA_SETUP_PARAMS setup_params;
- memset(&setup_params, 0, sizeof(setup_params));
- setup_params.dwVersion = NVFBC_TOCUDA_SETUP_PARAMS_VER;
- setup_params.eBufferFormat = NVFBC_BUFFER_FORMAT_BGRA;
-
- status = nv_fbc_function_list.nvFBCToCudaSetUp(nv_fbc_handle, &setup_params);
- if(status != NVFBC_SUCCESS) {
- fprintf(stderr, "Error: %s\n", nv_fbc_function_list.nvFBCGetLastErrorStr(nv_fbc_handle));
- goto error_cleanup;
- }
-
- return true;
-
- error_cleanup:
- if(fbc_handle_created) {
- if(capture_session_created) {
- NVFBC_DESTROY_CAPTURE_SESSION_PARAMS destroy_capture_params;
- memset(&destroy_capture_params, 0, sizeof(destroy_capture_params));
- destroy_capture_params.dwVersion = NVFBC_DESTROY_CAPTURE_SESSION_PARAMS_VER;
- nv_fbc_function_list.nvFBCDestroyCaptureSession(nv_fbc_handle, &destroy_capture_params);
- }
-
- NVFBC_DESTROY_HANDLE_PARAMS destroy_params;
- memset(&destroy_params, 0, sizeof(destroy_params));
- destroy_params.dwVersion = NVFBC_DESTROY_HANDLE_PARAMS_VER;
- nv_fbc_function_list.nvFBCDestroyHandle(nv_fbc_handle, &destroy_params);
- fbc_handle_created = false;
- }
- output_id = 0;
- return false;
- }
-
- bool capture(/*out*/ void *cu_device_ptr, uint32_t *byte_size) {
- if(!library || !fbc_handle_created || !cu_device_ptr || !byte_size)
- return false;
-
- NVFBCSTATUS status;
- NVFBC_FRAME_GRAB_INFO frame_info;
- memset(&frame_info, 0, sizeof(frame_info));
-
- NVFBC_TOCUDA_GRAB_FRAME_PARAMS grab_params;
- memset(&grab_params, 0, sizeof(grab_params));
- grab_params.dwVersion = NVFBC_TOCUDA_GRAB_FRAME_PARAMS_VER;
- grab_params.dwFlags = NVFBC_TOCUDA_GRAB_FLAGS_NOWAIT;// | NVFBC_TOCUDA_GRAB_FLAGS_FORCE_REFRESH;//NVFBC_TOCUDA_GRAB_FLAGS_NOWAIT_IF_NEW_FRAME_READY;
- grab_params.pFrameGrabInfo = &frame_info;
- grab_params.pCUDADeviceBuffer = cu_device_ptr;
- grab_params.dwTimeoutMs = 0;//1000 / (fps + 10);
-
- status = nv_fbc_function_list.nvFBCToCudaGrabFrame(nv_fbc_handle, &grab_params);
- if(status != NVFBC_SUCCESS) {
- fprintf(stderr, "Error: capture: %s\n", nv_fbc_function_list.nvFBCGetLastErrorStr(nv_fbc_handle));
- return false;
- }
-
- *byte_size = frame_info.dwByteSize;
- // TODO: Check bIsNewFrame
- // TODO: Check dwWidth and dwHeight and update size in video output in ffmpeg. This can happen when xrandr is used to change monitor resolution
-
- return true;
- }
-private:
- static char to_upper(char c) {
- if(c >= 'a' && c <= 'z')
- return c - 32;
- else
- return c;
- }
-
- static bool strcase_equals(const char *str1, const char *str2) {
- for(;;) {
- char c1 = to_upper(*str1);
- char c2 = to_upper(*str2);
- if(c1 != c2)
- return false;
- if(c1 == '\0' || c2 == '\0')
- return true;
- ++str1;
- ++str2;
- }
- }
-
- // Returns 0 on failure
- static uint32_t get_output_id_from_display_name(NVFBC_RANDR_OUTPUT_INFO *outputs, uint32_t num_outputs, const char *display_name, uint32_t *display_width, uint32_t *display_height) {
- if(!outputs)
- return 0;
-
- for(uint32_t i = 0; i < num_outputs; ++i) {
- if(strcase_equals(outputs[i].name, display_name)) {
- *display_width = outputs[i].trackedBox.w;
- *display_height = outputs[i].trackedBox.h;
- return outputs[i].dwId;
- }
- }
-
- return 0;
- }
-
- // TODO: Test with optimus and open kernel modules
- static bool get_driver_version(int *major, int *minor) {
- *major = 0;
- *minor = 0;
-
- FILE *f = fopen("/proc/driver/nvidia/version", "rb");
- if(!f) {
- fprintf(stderr, "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 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) {
- *major = driver_major_version;
- *minor = driver_minor_version;
- success = true;
- }
- }
-
- if(!success)
- fprintf(stderr, "Warning: failed to get nvidia driver version\n");
-
- fclose(f);
- 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);
- }
-private:
- void *library = nullptr;
- PNVFBCCREATEINSTANCE nv_fbc_create_instance = nullptr;
- NVFBC_API_FUNCTION_LIST nv_fbc_function_list;
- NVFBC_SESSION_HANDLE nv_fbc_handle;
- bool fbc_handle_created = false;
- int fps = 0;
-};
diff --git a/include/capture/capture.h b/include/capture/capture.h
new file mode 100644
index 0000000..2eb8e42
--- /dev/null
+++ b/include/capture/capture.h
@@ -0,0 +1,68 @@
+#ifndef GSR_CAPTURE_CAPTURE_H
+#define GSR_CAPTURE_CAPTURE_H
+
+#include "../color_conversion.h"
+#include <stdbool.h>
+
+typedef struct AVCodecContext AVCodecContext;
+typedef struct AVFrame AVFrame;
+typedef void* VADisplay;
+typedef struct _VADRMPRIMESurfaceDescriptor VADRMPRIMESurfaceDescriptor;
+typedef struct gsr_cuda gsr_cuda;
+typedef struct AVFrame AVFrame;
+typedef struct CUgraphicsResource_st *CUgraphicsResource;
+typedef struct CUarray_st *CUarray;
+typedef struct CUctx_st *CUcontext;
+typedef struct CUstream_st *CUstream;
+
+typedef struct gsr_capture gsr_capture;
+
+struct gsr_capture {
+ /* These methods should not be called manually. Call gsr_capture_* instead */
+ int (*start)(gsr_capture *cap, AVCodecContext *video_codec_context, AVFrame *frame);
+ void (*tick)(gsr_capture *cap, AVCodecContext *video_codec_context); /* can be NULL */
+ bool (*should_stop)(gsr_capture *cap, bool *err); /* can be NULL */
+ int (*capture)(gsr_capture *cap, AVFrame *frame);
+ void (*capture_end)(gsr_capture *cap, AVFrame *frame); /* can be NULL */
+ void (*destroy)(gsr_capture *cap, AVCodecContext *video_codec_context);
+
+ void *priv; /* can be NULL */
+ bool started;
+};
+
+typedef struct gsr_capture_base gsr_capture_base;
+
+struct gsr_capture_base {
+ gsr_egl *egl;
+
+ unsigned int input_texture;
+ unsigned int target_textures[2];
+ unsigned int cursor_texture;
+
+ gsr_color_conversion color_conversion;
+
+ AVCodecContext *video_codec_context;
+};
+
+typedef struct {
+ gsr_cuda *cuda;
+ CUgraphicsResource *cuda_graphics_resources;
+ CUarray *mapped_arrays;
+} gsr_cuda_context;
+
+int gsr_capture_start(gsr_capture *cap, AVCodecContext *video_codec_context, AVFrame *frame);
+void gsr_capture_tick(gsr_capture *cap, AVCodecContext *video_codec_context);
+bool gsr_capture_should_stop(gsr_capture *cap, bool *err);
+int gsr_capture_capture(gsr_capture *cap, AVFrame *frame);
+void gsr_capture_end(gsr_capture *cap, AVFrame *frame);
+/* Calls |gsr_capture_stop| as well */
+void gsr_capture_destroy(gsr_capture *cap, AVCodecContext *video_codec_context);
+
+bool gsr_capture_base_setup_vaapi_textures(gsr_capture_base *self, AVFrame *frame, VADisplay va_dpy, VADRMPRIMESurfaceDescriptor *prime, gsr_color_range color_range);
+bool gsr_capture_base_setup_cuda_textures(gsr_capture_base *self, AVFrame *frame, gsr_cuda_context *cuda_context, gsr_color_range color_range, gsr_source_color source_color, bool hdr);
+void gsr_capture_base_stop(gsr_capture_base *self);
+
+bool drm_create_codec_context(const char *card_path, AVCodecContext *video_codec_context, int width, int height, bool hdr, VADisplay *va_dpy);
+bool cuda_create_codec_context(CUcontext cu_ctx, AVCodecContext *video_codec_context, int width, int height, bool hdr, CUstream *cuda_stream);
+
+#endif /* GSR_CAPTURE_CAPTURE_H */
diff --git a/include/capture/kms.h b/include/capture/kms.h
new file mode 100644
index 0000000..674813a
--- /dev/null
+++ b/include/capture/kms.h
@@ -0,0 +1,50 @@
+#ifndef GSR_CAPTURE_KMS_H
+#define GSR_CAPTURE_KMS_H
+
+#include "capture.h"
+#include "../../kms/client/kms_client.h"
+#include "../color_conversion.h"
+#include "../vec2.h"
+#include "../defs.h"
+#include <stdbool.h>
+
+typedef struct AVCodecContext AVCodecContext;
+typedef struct AVMasteringDisplayMetadata AVMasteringDisplayMetadata;
+typedef struct AVContentLightMetadata AVContentLightMetadata;
+typedef struct gsr_capture_kms gsr_capture_kms;
+typedef struct gsr_egl gsr_egl;
+typedef struct AVFrame AVFrame;
+
+#define MAX_CONNECTOR_IDS 32
+
+typedef struct {
+ uint32_t connector_ids[MAX_CONNECTOR_IDS];
+ int num_connector_ids;
+} MonitorId;
+
+struct gsr_capture_kms {
+ gsr_capture_base base;
+
+ bool should_stop;
+ bool stop_is_error;
+
+ gsr_kms_client kms_client;
+ gsr_kms_response kms_response;
+
+ vec2i capture_pos;
+ vec2i capture_size;
+ MonitorId monitor_id;
+
+ AVMasteringDisplayMetadata *mastering_display_metadata;
+ AVContentLightMetadata *light_metadata;
+
+ gsr_monitor_rotation monitor_rotation;
+};
+
+/* Returns 0 on success */
+int gsr_capture_kms_start(gsr_capture_kms *self, const char *display_to_capture, gsr_egl *egl, AVCodecContext *video_codec_context, AVFrame *frame);
+void gsr_capture_kms_stop(gsr_capture_kms *self);
+bool gsr_capture_kms_capture(gsr_capture_kms *self, AVFrame *frame, bool hdr, bool screen_plane_use_modifiers, bool cursor_texture_is_external, bool record_cursor);
+void gsr_capture_kms_cleanup_kms_fds(gsr_capture_kms *self);
+
+#endif /* GSR_CAPTURE_KMS_H */
diff --git a/include/capture/kms_cuda.h b/include/capture/kms_cuda.h
new file mode 100644
index 0000000..fd0d396
--- /dev/null
+++ b/include/capture/kms_cuda.h
@@ -0,0 +1,20 @@
+#ifndef GSR_CAPTURE_KMS_CUDA_H
+#define GSR_CAPTURE_KMS_CUDA_H
+
+#include "../vec2.h"
+#include "../utils.h"
+#include "../color_conversion.h"
+#include "capture.h"
+
+typedef struct {
+ gsr_egl *egl;
+ const char *display_to_capture; /* if this is "screen", then the first monitor is captured. A copy is made of this */
+ gsr_gpu_info gpu_inf;
+ bool hdr;
+ gsr_color_range color_range;
+ bool record_cursor;
+} gsr_capture_kms_cuda_params;
+
+gsr_capture* gsr_capture_kms_cuda_create(const gsr_capture_kms_cuda_params *params);
+
+#endif /* GSR_CAPTURE_KMS_CUDA_H */
diff --git a/include/capture/kms_vaapi.h b/include/capture/kms_vaapi.h
new file mode 100644
index 0000000..196b597
--- /dev/null
+++ b/include/capture/kms_vaapi.h
@@ -0,0 +1,20 @@
+#ifndef GSR_CAPTURE_KMS_VAAPI_H
+#define GSR_CAPTURE_KMS_VAAPI_H
+
+#include "../vec2.h"
+#include "../utils.h"
+#include "../color_conversion.h"
+#include "capture.h"
+
+typedef struct {
+ gsr_egl *egl;
+ const char *display_to_capture; /* if this is "screen", then the first monitor is captured. A copy is made of this */
+ gsr_gpu_info gpu_inf;
+ bool hdr;
+ gsr_color_range color_range;
+ bool record_cursor;
+} gsr_capture_kms_vaapi_params;
+
+gsr_capture* gsr_capture_kms_vaapi_create(const gsr_capture_kms_vaapi_params *params);
+
+#endif /* GSR_CAPTURE_KMS_VAAPI_H */
diff --git a/include/capture/nvfbc.h b/include/capture/nvfbc.h
new file mode 100644
index 0000000..36bc2b6
--- /dev/null
+++ b/include/capture/nvfbc.h
@@ -0,0 +1,22 @@
+#ifndef GSR_CAPTURE_NVFBC_H
+#define GSR_CAPTURE_NVFBC_H
+
+#include "capture.h"
+#include "../vec2.h"
+
+typedef struct {
+ gsr_egl *egl;
+ const char *display_to_capture; /* if this is "screen", then the entire x11 screen is captured (all displays). A copy is made of this */
+ int fps;
+ vec2i pos;
+ vec2i size;
+ bool direct_capture;
+ bool overclock;
+ bool hdr;
+ gsr_color_range color_range;
+ bool record_cursor;
+} gsr_capture_nvfbc_params;
+
+gsr_capture* gsr_capture_nvfbc_create(const gsr_capture_nvfbc_params *params);
+
+#endif /* GSR_CAPTURE_NVFBC_H */
diff --git a/include/capture/xcomposite.h b/include/capture/xcomposite.h
new file mode 100644
index 0000000..ce0dbad
--- /dev/null
+++ b/include/capture/xcomposite.h
@@ -0,0 +1,51 @@
+#ifndef GSR_CAPTURE_XCOMPOSITE_H
+#define GSR_CAPTURE_XCOMPOSITE_H
+
+#include "capture.h"
+#include "../egl.h"
+#include "../vec2.h"
+#include "../color_conversion.h"
+#include "../window_texture.h"
+#include "../cursor.h"
+
+typedef struct {
+ gsr_egl *egl;
+ Window window;
+ bool follow_focused; /* If this is set then |window| is ignored */
+ vec2i region_size; /* This is currently only used with |follow_focused| */
+ gsr_color_range color_range;
+ bool record_cursor;
+} gsr_capture_xcomposite_params;
+
+typedef struct {
+ gsr_capture_base base;
+ gsr_capture_xcomposite_params params;
+ XEvent xev;
+
+ bool should_stop;
+ bool stop_is_error;
+ bool window_resized;
+ bool follow_focused_initialized;
+
+ Window window;
+ vec2i window_size;
+ vec2i texture_size;
+ double window_resize_timer;
+
+ WindowTexture window_texture;
+
+ Atom net_active_window_atom;
+
+ gsr_cursor cursor;
+ bool clear_next_frame;
+} gsr_capture_xcomposite;
+
+void gsr_capture_xcomposite_init(gsr_capture_xcomposite *self, const gsr_capture_xcomposite_params *params);
+
+int gsr_capture_xcomposite_start(gsr_capture_xcomposite *self, AVCodecContext *video_codec_context, AVFrame *frame);
+void gsr_capture_xcomposite_stop(gsr_capture_xcomposite *self);
+void gsr_capture_xcomposite_tick(gsr_capture_xcomposite *self, AVCodecContext *video_codec_context);
+bool gsr_capture_xcomposite_should_stop(gsr_capture_xcomposite *self, bool *err);
+int gsr_capture_xcomposite_capture(gsr_capture_xcomposite *self, AVFrame *frame);
+
+#endif /* GSR_CAPTURE_XCOMPOSITE_H */
diff --git a/include/capture/xcomposite_cuda.h b/include/capture/xcomposite_cuda.h
new file mode 100644
index 0000000..b93c6de
--- /dev/null
+++ b/include/capture/xcomposite_cuda.h
@@ -0,0 +1,14 @@
+#ifndef GSR_CAPTURE_XCOMPOSITE_CUDA_H
+#define GSR_CAPTURE_XCOMPOSITE_CUDA_H
+
+#include "capture.h"
+#include "xcomposite.h"
+
+typedef struct {
+ gsr_capture_xcomposite_params base;
+ bool overclock;
+} gsr_capture_xcomposite_cuda_params;
+
+gsr_capture* gsr_capture_xcomposite_cuda_create(const gsr_capture_xcomposite_cuda_params *params);
+
+#endif /* GSR_CAPTURE_XCOMPOSITE_CUDA_H */
diff --git a/include/capture/xcomposite_vaapi.h b/include/capture/xcomposite_vaapi.h
new file mode 100644
index 0000000..5d4b338
--- /dev/null
+++ b/include/capture/xcomposite_vaapi.h
@@ -0,0 +1,13 @@
+#ifndef GSR_CAPTURE_XCOMPOSITE_VAAPI_H
+#define GSR_CAPTURE_XCOMPOSITE_VAAPI_H
+
+#include "capture.h"
+#include "xcomposite.h"
+
+typedef struct {
+ gsr_capture_xcomposite_params base;
+} gsr_capture_xcomposite_vaapi_params;
+
+gsr_capture* gsr_capture_xcomposite_vaapi_create(const gsr_capture_xcomposite_vaapi_params *params);
+
+#endif /* GSR_CAPTURE_XCOMPOSITE_VAAPI_H */
diff --git a/include/color_conversion.h b/include/color_conversion.h
new file mode 100644
index 0000000..d05df6a
--- /dev/null
+++ b/include/color_conversion.h
@@ -0,0 +1,58 @@
+#ifndef GSR_COLOR_CONVERSION_H
+#define GSR_COLOR_CONVERSION_H
+
+#include "shader.h"
+#include "vec2.h"
+#include <stdbool.h>
+
+typedef enum {
+ GSR_COLOR_RANGE_LIMITED,
+ GSR_COLOR_RANGE_FULL
+} gsr_color_range;
+
+typedef enum {
+ GSR_SOURCE_COLOR_RGB,
+ GSR_SOURCE_COLOR_BGR
+} gsr_source_color;
+
+typedef enum {
+ GSR_DESTINATION_COLOR_NV12, /* YUV420, BT709, 8-bit */
+ GSR_DESTINATION_COLOR_P010 /* YUV420, BT2020, 10-bit */
+} gsr_destination_color;
+
+typedef struct {
+ int offset;
+ int rotation;
+} gsr_color_uniforms;
+
+typedef struct {
+ gsr_egl *egl;
+
+ gsr_source_color source_color;
+ gsr_destination_color destination_color;
+
+ unsigned int destination_textures[2];
+ int num_destination_textures;
+
+ gsr_color_range color_range;
+ bool load_external_image_shader;
+} gsr_color_conversion_params;
+
+typedef struct {
+ gsr_color_conversion_params params;
+ gsr_color_uniforms uniforms[4];
+ gsr_shader shaders[4];
+
+ unsigned int framebuffers[2];
+
+ unsigned int vertex_array_object_id;
+ unsigned int vertex_buffer_object_id;
+} gsr_color_conversion;
+
+int gsr_color_conversion_init(gsr_color_conversion *self, const gsr_color_conversion_params *params);
+void gsr_color_conversion_deinit(gsr_color_conversion *self);
+
+void gsr_color_conversion_draw(gsr_color_conversion *self, unsigned int texture_id, vec2i source_pos, vec2i source_size, vec2i texture_pos, vec2i texture_size, float rotation, bool external_texture);
+void gsr_color_conversion_clear(gsr_color_conversion *self);
+
+#endif /* GSR_COLOR_CONVERSION_H */
diff --git a/include/CudaLibrary.hpp b/include/cuda.h
index fe99975..fd1f9f9 100644
--- a/include/CudaLibrary.hpp
+++ b/include/cuda.h
@@ -1,13 +1,15 @@
-#pragma once
+#ifndef GSR_CUDA_H
+#define GSR_CUDA_H
-#include "LibraryLoader.hpp"
-
-#include <dlfcn.h>
-#include <stdio.h>
+#include "overclock.h"
+#include <stddef.h>
+#include <stdbool.h>
// To prevent hwcontext_cuda.h from including cuda.h
#define CUDA_VERSION 11070
+#define CU_CTX_SCHED_AUTO 0
+
#if defined(_WIN64) || defined(__LP64__)
typedef unsigned long long CUdeviceptr_v2;
#else
@@ -22,7 +24,7 @@ typedef struct CUctx_st *CUcontext;
typedef struct CUstream_st *CUstream;
typedef struct CUarray_st *CUarray;
-static const int CUDA_SUCCESS = 0;
+#define CUDA_SUCCESS 0
typedef enum CUgraphicsMapResourceFlags_enum {
CU_GRAPHICS_MAP_RESOURCE_FLAGS_NONE = 0x00,
@@ -69,75 +71,38 @@ typedef struct CUDA_MEMCPY2D_st {
} CUDA_MEMCPY2D_v2;
typedef CUDA_MEMCPY2D_v2 CUDA_MEMCPY2D;
-static const int CU_CTX_SCHED_AUTO = 0;
-
typedef struct CUgraphicsResource_st *CUgraphicsResource;
-struct Cuda {
+typedef struct gsr_cuda gsr_cuda;
+struct gsr_cuda {
+ gsr_overclock overclock;
+ bool do_overclock;
+
+ void *library;
+ CUcontext cu_ctx;
+
CUresult (*cuInit)(unsigned int Flags);
CUresult (*cuDeviceGetCount)(int *count);
CUresult (*cuDeviceGet)(CUdevice *device, int ordinal);
CUresult (*cuCtxCreate_v2)(CUcontext *pctx, unsigned int flags, CUdevice dev);
+ CUresult (*cuCtxDestroy_v2)(CUcontext ctx);
CUresult (*cuCtxPushCurrent_v2)(CUcontext ctx);
CUresult (*cuCtxPopCurrent_v2)(CUcontext *pctx);
CUresult (*cuGetErrorString)(CUresult error, const char **pStr);
- CUresult (*cuMemsetD8_v2)(CUdeviceptr dstDevice, unsigned char uc, size_t N);
CUresult (*cuMemcpy2D_v2)(const CUDA_MEMCPY2D *pCopy);
+ CUresult (*cuMemcpy2DAsync_v2)(const CUDA_MEMCPY2D *pcopy, CUstream hStream);
+ CUresult (*cuStreamSynchronize)(CUstream hStream);
- CUresult (*cuGraphicsGLRegisterImage)(CUgraphicsResource *pCudaResource, unsigned int image, unsigned int target, unsigned int Flags);
+ CUresult (*cuGraphicsGLRegisterImage)(CUgraphicsResource *pCudaResource, unsigned int image, unsigned int target, unsigned int flags);
+ CUresult (*cuGraphicsEGLRegisterImage)(CUgraphicsResource *pCudaResource, void *image, unsigned int flags);
CUresult (*cuGraphicsResourceSetMapFlags)(CUgraphicsResource resource, unsigned int flags);
CUresult (*cuGraphicsMapResources)(unsigned int count, CUgraphicsResource *resources, CUstream hStream);
+ CUresult (*cuGraphicsUnmapResources)(unsigned int count, CUgraphicsResource *resources, CUstream hStream);
CUresult (*cuGraphicsUnregisterResource)(CUgraphicsResource resource);
CUresult (*cuGraphicsSubResourceGetMappedArray)(CUarray *pArray, CUgraphicsResource resource, unsigned int arrayIndex, unsigned int mipLevel);
-
- ~Cuda() {
- if(library)
- dlclose(library);
- }
-
- bool load() {
- if(library)
- return true;
-
- dlerror(); // clear
- void *lib = dlopen("libcuda.so.1", RTLD_LAZY);
- if(!lib) {
- lib = dlopen("libcuda.so", RTLD_LAZY);
- if(!lib) {
- fprintf(stderr, "Error: failed to load libcuda.so/libcuda.so.1, error: %s\n", dlerror());
- return false;
- }
- }
-
- dlsym_assign required_dlsym[] = {
- { (void**)&cuInit, "cuInit" },
- { (void**)&cuDeviceGetCount, "cuDeviceGetCount" },
- { (void**)&cuDeviceGet, "cuDeviceGet" },
- { (void**)&cuCtxCreate_v2, "cuCtxCreate_v2" },
- { (void**)&cuCtxPushCurrent_v2, "cuCtxPushCurrent_v2" },
- { (void**)&cuCtxPopCurrent_v2, "cuCtxPopCurrent_v2" },
- { (void**)&cuGetErrorString, "cuGetErrorString" },
- { (void**)&cuMemsetD8_v2, "cuMemsetD8_v2" },
- { (void**)&cuMemcpy2D_v2, "cuMemcpy2D_v2" },
-
- { (void**)&cuGraphicsGLRegisterImage, "cuGraphicsGLRegisterImage" },
- { (void**)&cuGraphicsResourceSetMapFlags, "cuGraphicsResourceSetMapFlags" },
- { (void**)&cuGraphicsMapResources, "cuGraphicsMapResources" },
- { (void**)&cuGraphicsUnregisterResource, "cuGraphicsUnregisterResource" },
- { (void**)&cuGraphicsSubResourceGetMappedArray, "cuGraphicsSubResourceGetMappedArray" },
-
- { NULL, NULL }
- };
-
- if(dlsym_load_list(lib, required_dlsym)) {
- library = lib;
- return true;
- } else {
- fprintf(stderr, "Error: missing required symbols in libcuda.so\n");
- dlclose(lib);
- return false;
- }
- }
-private:
- void *library = nullptr;
};
+
+bool gsr_cuda_load(gsr_cuda *self, Display *display, bool overclock);
+void gsr_cuda_unload(gsr_cuda *self);
+
+#endif /* GSR_CUDA_H */
diff --git a/include/cursor.h b/include/cursor.h
new file mode 100644
index 0000000..b1ec6bd
--- /dev/null
+++ b/include/cursor.h
@@ -0,0 +1,26 @@
+#ifndef GSR_CURSOR_H
+#define GSR_CURSOR_H
+
+#include "egl.h"
+#include "vec2.h"
+
+typedef struct {
+ gsr_egl *egl;
+ Display *display;
+ int x_fixes_event_base;
+
+ unsigned int texture_id;
+ vec2i size;
+ vec2i hotspot;
+ vec2i position;
+
+ bool cursor_image_set;
+} gsr_cursor;
+
+int gsr_cursor_init(gsr_cursor *self, gsr_egl *egl, Display *display);
+void gsr_cursor_deinit(gsr_cursor *self);
+
+void gsr_cursor_update(gsr_cursor *self, XEvent *xev);
+void gsr_cursor_tick(gsr_cursor *self, Window relative_to);
+
+#endif /* GSR_CURSOR_H */
diff --git a/include/defs.h b/include/defs.h
new file mode 100644
index 0000000..473583c
--- /dev/null
+++ b/include/defs.h
@@ -0,0 +1,28 @@
+#ifndef GSR_DEFS_H
+#define GSR_DEFS_H
+
+typedef enum {
+ GSR_GPU_VENDOR_AMD,
+ GSR_GPU_VENDOR_INTEL,
+ GSR_GPU_VENDOR_NVIDIA
+} gsr_gpu_vendor;
+
+typedef struct {
+ gsr_gpu_vendor vendor;
+ int gpu_version; /* 0 if unknown */
+} gsr_gpu_info;
+
+typedef enum {
+ GSR_MONITOR_ROT_0,
+ GSR_MONITOR_ROT_90,
+ GSR_MONITOR_ROT_180,
+ GSR_MONITOR_ROT_270
+} gsr_monitor_rotation;
+
+typedef enum {
+ GSR_CONNECTION_X11,
+ GSR_CONNECTION_WAYLAND,
+ GSR_CONNECTION_DRM
+} gsr_connection_type;
+
+#endif /* GSR_DEFS_H */
diff --git a/include/egl.h b/include/egl.h
new file mode 100644
index 0000000..afdb5a9
--- /dev/null
+++ b/include/egl.h
@@ -0,0 +1,285 @@
+#ifndef GSR_EGL_H
+#define GSR_EGL_H
+
+/* OpenGL EGL library with a hidden window context (to allow using the opengl functions) */
+
+#include <X11/X.h>
+#include <X11/Xutil.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include "vec2.h"
+#include "defs.h"
+
+#ifdef _WIN64
+typedef signed long long int khronos_intptr_t;
+typedef unsigned long long int khronos_uintptr_t;
+typedef signed long long int khronos_ssize_t;
+typedef unsigned long long int khronos_usize_t;
+#else
+typedef signed long int khronos_intptr_t;
+typedef unsigned long int khronos_uintptr_t;
+typedef signed long int khronos_ssize_t;
+typedef unsigned long int khronos_usize_t;
+#endif
+
+typedef void* EGLDisplay;
+typedef void* EGLNativeDisplayType;
+typedef uintptr_t EGLNativeWindowType;
+typedef uintptr_t EGLNativePixmapType;
+typedef void* EGLConfig;
+typedef void* EGLSurface;
+typedef void* EGLContext;
+typedef void* EGLClientBuffer;
+typedef void* EGLImage;
+typedef void* EGLImageKHR;
+typedef void *GLeglImageOES;
+typedef void (*__eglMustCastToProperFunctionPointerType)(void);
+typedef struct __GLXFBConfigRec *GLXFBConfig;
+typedef struct __GLXcontextRec *GLXContext;
+typedef XID GLXDrawable;
+typedef void(*__GLXextFuncPtr)(void);
+
+#define EGL_SUCCESS 0x3000
+#define EGL_BUFFER_SIZE 0x3020
+#define EGL_RENDERABLE_TYPE 0x3040
+#define EGL_OPENGL_API 0x30A2
+#define EGL_OPENGL_BIT 0x0008
+#define EGL_NONE 0x3038
+#define EGL_CONTEXT_CLIENT_VERSION 0x3098
+#define EGL_BACK_BUFFER 0x3084
+#define EGL_GL_TEXTURE_2D 0x30B1
+#define EGL_TRUE 1
+#define EGL_IMAGE_PRESERVED_KHR 0x30D2
+#define EGL_NATIVE_PIXMAP_KHR 0x30B0
+#define EGL_LINUX_DRM_FOURCC_EXT 0x3271
+#define EGL_WIDTH 0x3057
+#define EGL_HEIGHT 0x3056
+#define EGL_DMA_BUF_PLANE0_FD_EXT 0x3272
+#define EGL_DMA_BUF_PLANE0_OFFSET_EXT 0x3273
+#define EGL_DMA_BUF_PLANE0_PITCH_EXT 0x3274
+#define EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT 0x3443
+#define EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT 0x3444
+#define EGL_LINUX_DMA_BUF_EXT 0x3270
+#define EGL_RED_SIZE 0x3024
+#define EGL_ALPHA_SIZE 0x3021
+#define EGL_BLUE_SIZE 0x3022
+#define EGL_GREEN_SIZE 0x3023
+#define EGL_CONTEXT_PRIORITY_LEVEL_IMG 0x3100
+#define EGL_CONTEXT_PRIORITY_HIGH_IMG 0x3101
+#define EGL_CONTEXT_PRIORITY_MEDIUM_IMG 0x3102
+#define EGL_CONTEXT_PRIORITY_LOW_IMG 0x3103
+#define EGL_DEVICE_EXT 0x322C
+#define EGL_DRM_DEVICE_FILE_EXT 0x3233
+
+#define GL_FLOAT 0x1406
+#define GL_FALSE 0
+#define GL_TRUE 1
+#define GL_TRIANGLES 0x0004
+#define GL_TEXTURE_2D 0x0DE1
+#define GL_TEXTURE_EXTERNAL_OES 0x8D65
+#define GL_RED 0x1903
+#define GL_GREEN 0x1904
+#define GL_BLUE 0x1905
+#define GL_ALPHA 0x1906
+#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46
+#define GL_RG 0x8227
+#define GL_RGB 0x1907
+#define GL_RGBA 0x1908
+#define GL_RGBA8 0x8058
+#define GL_R8 0x8229
+#define GL_RG8 0x822B
+#define GL_R16 0x822A
+#define GL_RG16 0x822C
+#define GL_UNSIGNED_BYTE 0x1401
+#define GL_COLOR_BUFFER_BIT 0x00004000
+#define GL_TEXTURE_WRAP_S 0x2802
+#define GL_TEXTURE_WRAP_T 0x2803
+#define GL_TEXTURE_MAG_FILTER 0x2800
+#define GL_TEXTURE_MIN_FILTER 0x2801
+#define GL_TEXTURE_WIDTH 0x1000
+#define GL_TEXTURE_HEIGHT 0x1001
+#define GL_NEAREST 0x2600
+#define GL_CLAMP_TO_EDGE 0x812F
+#define GL_LINEAR 0x2601
+#define GL_FRAMEBUFFER 0x8D40
+#define GL_COLOR_ATTACHMENT0 0x8CE0
+#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
+#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_DEBUG_OUTPUT 0x92E0
+
+#define GL_VENDOR 0x1F00
+#define GL_RENDERER 0x1F01
+
+#define GL_COMPILE_STATUS 0x8B81
+#define GL_INFO_LOG_LENGTH 0x8B84
+#define GL_FRAGMENT_SHADER 0x8B30
+#define GL_VERTEX_SHADER 0x8B31
+#define GL_COMPILE_STATUS 0x8B81
+#define GL_LINK_STATUS 0x8B82
+
+typedef unsigned int (*FUNC_eglExportDMABUFImageQueryMESA)(EGLDisplay dpy, EGLImageKHR image, int *fourcc, int *num_planes, uint64_t *modifiers);
+typedef unsigned int (*FUNC_eglExportDMABUFImageMESA)(EGLDisplay dpy, EGLImageKHR image, int *fds, int32_t *strides, int32_t *offsets);
+typedef void (*FUNC_glEGLImageTargetTexture2DOES)(unsigned int target, GLeglImageOES image);
+typedef GLXContext (*FUNC_glXCreateContextAttribsARB)(Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list);
+typedef void (*FUNC_glXSwapIntervalEXT)(Display * dpy, GLXDrawable drawable, int interval);
+typedef int (*FUNC_glXSwapIntervalMESA)(unsigned int interval);
+typedef int (*FUNC_glXSwapIntervalSGI)(int interval);
+typedef void (*GLDEBUGPROC)(unsigned int source, unsigned int type, unsigned int id, unsigned int severity, int length, const char *message, const void *userParam);
+typedef int (*FUNC_eglQueryDisplayAttribEXT)(EGLDisplay dpy, int32_t attribute, intptr_t *value);
+typedef const char* (*FUNC_eglQueryDeviceStringEXT)(void *device, int32_t name);
+
+#define GSR_MAX_OUTPUTS 32
+
+typedef struct {
+ Display *dpy;
+ Window window;
+} gsr_x11;
+
+typedef struct {
+ uint32_t wl_name;
+ void *output;
+ vec2i pos;
+ vec2i size;
+ int32_t transform;
+ char *name;
+} gsr_wayland_output;
+
+typedef struct {
+ void *dpy;
+ void *window;
+ void *registry;
+ void *surface;
+ void *compositor;
+ gsr_wayland_output outputs[GSR_MAX_OUTPUTS];
+ int num_outputs;
+} gsr_wayland;
+
+typedef enum {
+ GSR_GL_CONTEXT_TYPE_EGL,
+ GSR_GL_CONTEXT_TYPE_GLX
+} gsr_gl_context_type;
+
+typedef struct gsr_egl gsr_egl;
+struct gsr_egl {
+ void *egl_library;
+ void *glx_library;
+ void *gl_library;
+
+ gsr_gl_context_type context_type;
+
+ EGLDisplay egl_display;
+ EGLSurface egl_surface;
+ EGLContext egl_context;
+ const char *dri_card_path;
+
+ void *glx_context;
+ void *glx_fb_config;
+
+ gsr_gpu_info gpu_info;
+
+ gsr_x11 x11;
+ gsr_wayland wayland;
+ char card_path[128];
+
+ int32_t (*eglGetError)(void);
+ EGLDisplay (*eglGetDisplay)(EGLNativeDisplayType display_id);
+ unsigned int (*eglInitialize)(EGLDisplay dpy, int32_t *major, int32_t *minor);
+ unsigned int (*eglTerminate)(EGLDisplay dpy);
+ unsigned int (*eglChooseConfig)(EGLDisplay dpy, const int32_t *attrib_list, EGLConfig *configs, int32_t config_size, int32_t *num_config);
+ EGLSurface (*eglCreateWindowSurface)(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const int32_t *attrib_list);
+ EGLContext (*eglCreateContext)(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const int32_t *attrib_list);
+ unsigned int (*eglMakeCurrent)(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
+ EGLImage (*eglCreateImage)(EGLDisplay dpy, EGLContext ctx, unsigned int target, EGLClientBuffer buffer, const intptr_t *attrib_list);
+ unsigned int (*eglDestroyContext)(EGLDisplay dpy, EGLContext ctx);
+ unsigned int (*eglDestroySurface)(EGLDisplay dpy, EGLSurface surface);
+ unsigned int (*eglDestroyImage)(EGLDisplay dpy, EGLImage image);
+ unsigned int (*eglSwapInterval)(EGLDisplay dpy, int32_t interval);
+ unsigned int (*eglSwapBuffers)(EGLDisplay dpy, EGLSurface surface);
+ unsigned int (*eglBindAPI)(unsigned int api);
+ __eglMustCastToProperFunctionPointerType (*eglGetProcAddress)(const char *procname);
+
+ FUNC_eglExportDMABUFImageQueryMESA eglExportDMABUFImageQueryMESA;
+ FUNC_eglExportDMABUFImageMESA eglExportDMABUFImageMESA;
+ FUNC_glEGLImageTargetTexture2DOES glEGLImageTargetTexture2DOES;
+ FUNC_eglQueryDisplayAttribEXT eglQueryDisplayAttribEXT;
+ FUNC_eglQueryDeviceStringEXT eglQueryDeviceStringEXT;
+
+ __GLXextFuncPtr (*glXGetProcAddress)(const unsigned char *procName);
+ GLXFBConfig* (*glXChooseFBConfig)(Display *dpy, int screen, const int *attribList, int *nitems);
+ Bool (*glXMakeContextCurrent)(Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx);
+ // TODO: Remove
+ GLXContext (*glXCreateNewContext)(Display *dpy, GLXFBConfig config, int renderType, GLXContext shareList, Bool direct);
+ void (*glXDestroyContext)(Display *dpy, GLXContext ctx);
+ void (*glXSwapBuffers)(Display *dpy, GLXDrawable drawable);
+ FUNC_glXCreateContextAttribsARB glXCreateContextAttribsARB;
+
+ /* Optional */
+ FUNC_glXSwapIntervalEXT glXSwapIntervalEXT;
+ FUNC_glXSwapIntervalMESA glXSwapIntervalMESA;
+ FUNC_glXSwapIntervalSGI glXSwapIntervalSGI;
+
+ unsigned int (*glGetError)(void);
+ const unsigned char* (*glGetString)(unsigned int name);
+ void (*glFlush)(void);
+ void (*glFinish)(void);
+ void (*glClear)(unsigned int mask);
+ void (*glClearColor)(float red, float green, float blue, float alpha);
+ void (*glGenTextures)(int n, unsigned int *textures);
+ void (*glDeleteTextures)(int n, const unsigned int *texture);
+ void (*glBindTexture)(unsigned int target, unsigned int texture);
+ void (*glTexParameteri)(unsigned int target, unsigned int pname, int param);
+ void (*glTexParameteriv)(unsigned int target, unsigned int pname, const int *params);
+ void (*glGetTexLevelParameteriv)(unsigned int target, int level, unsigned int pname, int *params);
+ 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 (*glGenFramebuffers)(int n, unsigned int *framebuffers);
+ void (*glBindFramebuffer)(unsigned int target, unsigned int framebuffer);
+ void (*glDeleteFramebuffers)(int n, const unsigned int *framebuffers);
+ void (*glViewport)(int x, int y, int width, int height);
+ void (*glFramebufferTexture2D)(unsigned int target, unsigned int attachment, unsigned int textarget, unsigned int texture, int level);
+ void (*glDrawBuffers)(int n, const unsigned int *bufs);
+ unsigned int (*glCheckFramebufferStatus)(unsigned int target);
+ 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);
+ void (*glBindAttribLocation)(unsigned int program, unsigned int index, const char *name);
+ void (*glCompileShader)(unsigned int shader);
+ void (*glLinkProgram)(unsigned int program);
+ void (*glShaderSource)(unsigned int shader, int count, const char *const*string, const int *length);
+ void (*glUseProgram)(unsigned int program);
+ void (*glGetProgramInfoLog)(unsigned int program, int bufSize, int *length, char *infoLog);
+ void (*glGetShaderiv)(unsigned int shader, unsigned int pname, int *params);
+ void (*glGetShaderInfoLog)(unsigned int shader, int bufSize, int *length, char *infoLog);
+ void (*glDeleteProgram)(unsigned int program);
+ void (*glDeleteShader)(unsigned int shader);
+ void (*glGetProgramiv)(unsigned int program, unsigned int pname, int *params);
+ void (*glVertexAttribPointer)(unsigned int index, int size, unsigned int type, unsigned char normalized, int stride, const void *pointer);
+ void (*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);
+ void (*glUniform2f)(int location, float v0, float v1);
+ void (*glDebugMessageCallback)(GLDEBUGPROC callback, const void *userParam);
+};
+
+bool gsr_egl_load(gsr_egl *self, Display *dpy, bool wayland, bool is_monitor_capture);
+void gsr_egl_unload(gsr_egl *self);
+
+void gsr_egl_update(gsr_egl *self);
+
+#endif /* GSR_EGL_H */
diff --git a/include/library_loader.h b/include/library_loader.h
new file mode 100644
index 0000000..47bc9f0
--- /dev/null
+++ b/include/library_loader.h
@@ -0,0 +1,17 @@
+#ifndef GSR_LIBRARY_LOADER_H
+#define GSR_LIBRARY_LOADER_H
+
+#include <stdbool.h>
+
+typedef struct {
+ void **func;
+ const char *name;
+} dlsym_assign;
+
+void* dlsym_print_fail(void *handle, const char *name, bool required);
+/* |dlsyms| should be null terminated */
+bool dlsym_load_list(void *handle, const dlsym_assign *dlsyms);
+/* |dlsyms| should be null terminated */
+void dlsym_load_list_optional(void *handle, const dlsym_assign *dlsyms);
+
+#endif /* GSR_LIBRARY_LOADER_H */
diff --git a/include/overclock.h b/include/overclock.h
new file mode 100644
index 0000000..d6ff901
--- /dev/null
+++ b/include/overclock.h
@@ -0,0 +1,17 @@
+#ifndef GSR_OVERCLOCK_H
+#define GSR_OVERCLOCK_H
+
+#include "xnvctrl.h"
+
+typedef struct {
+ gsr_xnvctrl xnvctrl;
+ int num_performance_levels;
+} gsr_overclock;
+
+bool gsr_overclock_load(gsr_overclock *self, Display *display);
+void gsr_overclock_unload(gsr_overclock *self);
+
+bool gsr_overclock_start(gsr_overclock *self);
+void gsr_overclock_stop(gsr_overclock *self);
+
+#endif /* GSR_OVERCLOCK_H */
diff --git a/include/shader.h b/include/shader.h
new file mode 100644
index 0000000..57d1096
--- /dev/null
+++ b/include/shader.h
@@ -0,0 +1,19 @@
+#ifndef GSR_SHADER_H
+#define GSR_SHADER_H
+
+typedef struct gsr_egl gsr_egl;
+
+typedef struct {
+ gsr_egl *egl;
+ unsigned int program_id;
+} gsr_shader;
+
+/* |vertex_shader| or |fragment_shader| may be NULL */
+int gsr_shader_init(gsr_shader *self, gsr_egl *egl, const char *vertex_shader, const char *fragment_shader);
+void gsr_shader_deinit(gsr_shader *self);
+
+int gsr_shader_bind_attribute_location(gsr_shader *self, const char *attribute, int location);
+void gsr_shader_use(gsr_shader *self);
+void gsr_shader_use_none(gsr_shader *self);
+
+#endif /* GSR_SHADER_H */
diff --git a/include/sound.hpp b/include/sound.hpp
index 710533e..77bec99 100644
--- a/include/sound.hpp
+++ b/include/sound.hpp
@@ -31,13 +31,23 @@ struct AudioInput {
std::string description;
};
+struct MergedAudioInputs {
+ std::vector<AudioInput> audio_inputs;
+};
+
+typedef enum {
+ S16,
+ S32,
+ F32
+} AudioFormat;
+
/*
Get a sound device by name, returning the device into the @device parameter.
The device should be closed with @sound_device_close after it has been used
to clean up internal resources.
Returns 0 on success, or a negative value on failure.
*/
-int sound_device_get_by_name(SoundDevice *device, const char *device_name, const char *description, unsigned int num_channels, unsigned int period_frame_size);
+int sound_device_get_by_name(SoundDevice *device, const char *device_name, const char *description, unsigned int num_channels, unsigned int period_frame_size, AudioFormat audio_format);
void sound_device_close(SoundDevice *device);
@@ -45,7 +55,7 @@ void sound_device_close(SoundDevice *device);
Returns the next chunk of audio into @buffer.
Returns the number of frames read, or a negative value on failure.
*/
-int sound_device_read_next_chunk(SoundDevice *device, void **buffer);
+int sound_device_read_next_chunk(SoundDevice *device, void **buffer, double timeout_sec, double *latency_seconds);
std::vector<AudioInput> get_pulseaudio_inputs();
diff --git a/include/utils.h b/include/utils.h
new file mode 100644
index 0000000..74fdd59
--- /dev/null
+++ b/include/utils.h
@@ -0,0 +1,46 @@
+#ifndef GSR_UTILS_H
+#define GSR_UTILS_H
+
+#include "vec2.h"
+#include "../include/egl.h"
+#include "../include/defs.h"
+#include <stdbool.h>
+#include <stdint.h>
+#include <X11/extensions/Xrandr.h>
+
+typedef struct {
+ const char *name;
+ int name_len;
+ vec2i pos;
+ vec2i size;
+ XRRCrtcInfo *crt_info; /* Only on x11 */
+ uint32_t connector_id; /* Only on x11 and drm */
+ gsr_monitor_rotation rotation; /* Only on x11 and wayland */
+ uint32_t monitor_identifier; /* Only on drm and wayland */
+} gsr_monitor;
+
+typedef struct {
+ const char *name;
+ int name_len;
+ gsr_monitor *monitor;
+ bool found_monitor;
+} get_monitor_by_name_userdata;
+
+double clock_get_monotonic_seconds(void);
+
+typedef void (*active_monitor_callback)(const gsr_monitor *monitor, void *userdata);
+void for_each_active_monitor_output_x11(Display *display, active_monitor_callback callback, void *userdata);
+void for_each_active_monitor_output(const gsr_egl *egl, gsr_connection_type connection_type, active_monitor_callback callback, void *userdata);
+bool get_monitor_by_name(const gsr_egl *egl, gsr_connection_type connection_type, const char *name, gsr_monitor *monitor);
+gsr_monitor_rotation drm_monitor_get_display_server_rotation(const gsr_egl *egl, const gsr_monitor *monitor);
+
+bool gl_get_gpu_info(gsr_egl *egl, gsr_gpu_info *info);
+
+/* |output| should be at least 128 bytes in size */
+bool gsr_get_valid_card_path(gsr_egl *egl, char *output);
+/* |render_path| should be at least 128 bytes in size */
+bool gsr_card_path_get_render_path(const char *card_path, char *render_path);
+
+int even_number_ceil(int value);
+
+#endif /* GSR_UTILS_H */
diff --git a/include/vec2.h b/include/vec2.h
new file mode 100644
index 0000000..3e33cfb
--- /dev/null
+++ b/include/vec2.h
@@ -0,0 +1,12 @@
+#ifndef VEC2_H
+#define VEC2_H
+
+typedef struct {
+ int x, y;
+} vec2i;
+
+typedef struct {
+ float x, y;
+} vec2f;
+
+#endif /* VEC2_H */
diff --git a/include/window_texture.h b/include/window_texture.h
new file mode 100644
index 0000000..75bb2a7
--- /dev/null
+++ b/include/window_texture.h
@@ -0,0 +1,27 @@
+#ifndef WINDOW_TEXTURE_H
+#define WINDOW_TEXTURE_H
+
+#include "egl.h"
+
+typedef struct {
+ Display *display;
+ Window window;
+ Pixmap pixmap;
+ unsigned int texture_id;
+ int redirected;
+ gsr_egl *egl;
+} WindowTexture;
+
+/* Returns 0 on success */
+int window_texture_init(WindowTexture *window_texture, Display *display, Window window, gsr_egl *egl);
+void window_texture_deinit(WindowTexture *self);
+
+/*
+ This should ONLY be called when the target window is resized.
+ Returns 0 on success.
+*/
+int window_texture_on_resize(WindowTexture *self);
+
+unsigned int window_texture_get_opengl_texture_id(WindowTexture *self);
+
+#endif /* WINDOW_TEXTURE_H */
diff --git a/include/xnvctrl.h b/include/xnvctrl.h
new file mode 100644
index 0000000..33fc442
--- /dev/null
+++ b/include/xnvctrl.h
@@ -0,0 +1,45 @@
+#ifndef GSR_XNVCTRL_H
+#define GSR_XNVCTRL_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#define NV_CTRL_GPU_NVCLOCK_OFFSET 409
+#define NV_CTRL_GPU_MEM_TRANSFER_RATE_OFFSET 410
+#define NV_CTRL_GPU_NVCLOCK_OFFSET_ALL_PERFORMANCE_LEVELS 424
+#define NV_CTRL_GPU_MEM_TRANSFER_RATE_OFFSET_ALL_PERFORMANCE_LEVELS 425
+
+#define NV_CTRL_TARGET_TYPE_GPU 1
+
+#define NV_CTRL_STRING_PERFORMANCE_MODES 29
+
+typedef struct _XDisplay Display;
+
+typedef struct {
+ int type;
+ union {
+ struct {
+ int64_t min;
+ int64_t max;
+ } range;
+ struct {
+ unsigned int ints;
+ } bits;
+ } u;
+ unsigned int permissions;
+} NVCTRLAttributeValidValuesRec;
+
+typedef struct {
+ Display *display;
+ void *library;
+
+ int (*XNVCTRLQueryExtension)(Display *dpy, int *event_basep, int *error_basep);
+ int (*XNVCTRLSetTargetAttributeAndGetStatus)(Display *dpy, int target_type, int target_id, unsigned int display_mask, unsigned int attribute, int value);
+ int (*XNVCTRLQueryValidTargetAttributeValues)(Display *dpy, int target_type, int target_id, unsigned int display_mask, unsigned int attribute, NVCTRLAttributeValidValuesRec *values);
+ int (*XNVCTRLQueryTargetStringAttribute)(Display *dpy, int target_type, int target_id, unsigned int display_mask, unsigned int attribute, char **ptr);
+} gsr_xnvctrl;
+
+bool gsr_xnvctrl_load(gsr_xnvctrl *self, Display *display);
+void gsr_xnvctrl_unload(gsr_xnvctrl *self);
+
+#endif /* GSR_XNVCTRL_H */