Remove unused code

This commit is contained in:
dec05eba 2023-03-19 18:02:40 +01:00
parent 8592a46929
commit d4b8833fdd
4 changed files with 51 additions and 424 deletions

View File

@ -39,8 +39,6 @@ typedef void (*__eglMustCastToProperFunctionPointerType)(void);
#define EGL_OPENGL_ES2_BIT 0x0004 #define EGL_OPENGL_ES2_BIT 0x0004
#define EGL_NONE 0x3038 #define EGL_NONE 0x3038
#define EGL_CONTEXT_CLIENT_VERSION 0x3098 #define EGL_CONTEXT_CLIENT_VERSION 0x3098
#define EGL_BACK_BUFFER 0x3084
#define EGL_GL_TEXTURE_2D 0x30B1
#define GL_TEXTURE_2D 0x0DE1 #define GL_TEXTURE_2D 0x0DE1
#define GL_RGB 0x1907 #define GL_RGB 0x1907
@ -64,32 +62,6 @@ typedef void (*__eglMustCastToProperFunctionPointerType)(void);
#define GL_VENDOR 0x1F00 #define GL_VENDOR 0x1F00
#define GL_RENDERER 0x1F01 #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
typedef struct { typedef struct {
void *egl_library; void *egl_library;
void *gl_library; void *gl_library;
@ -107,18 +79,14 @@ typedef struct {
EGLSurface (*eglCreateWindowSurface)(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const int32_t *attrib_list); 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); 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); unsigned int (*eglMakeCurrent)(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
EGLSurface (*eglCreatePixmapSurface)(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const int32_t *attrib_list);
EGLImage (*eglCreateImage)(EGLDisplay dpy, EGLContext ctx, unsigned int target, EGLClientBuffer buffer, const intptr_t *attrib_list); 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 (*eglDestroyContext)(EGLDisplay dpy, EGLContext ctx);
unsigned int (*eglDestroySurface)(EGLDisplay dpy, EGLSurface surface); unsigned int (*eglDestroySurface)(EGLDisplay dpy, EGLSurface surface);
unsigned int (*eglDestroyImage)(EGLDisplay dpy, EGLImage image); unsigned int (*eglDestroyImage)(EGLDisplay dpy, EGLImage image);
unsigned int (*eglBindTexImage)(EGLDisplay dpy, EGLSurface surface, int32_t buffer);
unsigned int (*eglSwapInterval)(EGLDisplay dpy, int32_t interval); unsigned int (*eglSwapInterval)(EGLDisplay dpy, int32_t interval);
unsigned int (*eglSwapBuffers)(EGLDisplay dpy, EGLSurface surface); unsigned int (*eglSwapBuffers)(EGLDisplay dpy, EGLSurface surface);
__eglMustCastToProperFunctionPointerType (*eglGetProcAddress)(const char *procname); __eglMustCastToProperFunctionPointerType (*eglGetProcAddress)(const char *procname);
unsigned int (*eglExportDMABUFImageQueryMESA)(EGLDisplay dpy, EGLImageKHR image, int *fourcc, int *num_planes, uint64_t *modifiers);
unsigned int (*eglExportDMABUFImageMESA)(EGLDisplay dpy, EGLImageKHR image, int *fds, int32_t *strides, int32_t *offsets);
void (*glEGLImageTargetTexture2DOES)(unsigned int target, GLeglImageOES image); void (*glEGLImageTargetTexture2DOES)(unsigned int target, GLeglImageOES image);
unsigned int (*glGetError)(void); unsigned int (*glGetError)(void);
@ -142,7 +110,6 @@ typedef struct {
void (*glBindBuffer)(unsigned int target, unsigned int buffer); void (*glBindBuffer)(unsigned int target, unsigned int buffer);
void (*glGenBuffers)(int n, unsigned int *buffers); void (*glGenBuffers)(int n, unsigned int *buffers);
void (*glBufferData)(unsigned int target, khronos_ssize_t size, const void *data, unsigned int usage); void (*glBufferData)(unsigned int target, khronos_ssize_t size, const void *data, unsigned int usage);
int (*glGetUniformLocation)(unsigned int program, const char *name);
void (*glGenVertexArrays)(int n, unsigned int *arrays); void (*glGenVertexArrays)(int n, unsigned int *arrays);
void (*glBindVertexArray)(unsigned int array); void (*glBindVertexArray)(unsigned int array);
@ -157,18 +124,12 @@ typedef struct {
void (*glGetProgramInfoLog)(unsigned int program, int bufSize, int *length, char *infoLog); void (*glGetProgramInfoLog)(unsigned int program, int bufSize, int *length, char *infoLog);
void (*glGetShaderiv)(unsigned int shader, unsigned int pname, int *params); void (*glGetShaderiv)(unsigned int shader, unsigned int pname, int *params);
void (*glGetShaderInfoLog)(unsigned int shader, int bufSize, int *length, char *infoLog); void (*glGetShaderInfoLog)(unsigned int shader, int bufSize, int *length, char *infoLog);
void (*glGetShaderSource)(unsigned int shader, int bufSize, int *length, char *source);
void (*glDeleteProgram)(unsigned int program); void (*glDeleteProgram)(unsigned int program);
void (*glDeleteShader)(unsigned int shader); void (*glDeleteShader)(unsigned int shader);
void (*glGetProgramiv)(unsigned int program, unsigned int pname, int *params); void (*glGetProgramiv)(unsigned int program, unsigned int pname, int *params);
void (*glVertexAttribPointer)(unsigned int index, int size, unsigned int type, unsigned char normalized, int stride, const void *pointer); void (*glVertexAttribPointer)(unsigned int index, int size, unsigned int type, unsigned char normalized, int stride, const void *pointer);
void (*glEnableVertexAttribArray)(unsigned int index); void (*glEnableVertexAttribArray)(unsigned int index);
void (*glDrawArrays)(unsigned int mode, int first, int count ); void (*glDrawArrays)(unsigned int mode, int first, int count );
void (*glReadBuffer)( unsigned int mode );
void (*glReadPixels)(int x, int y,
int width, int height,
unsigned int format, unsigned int type,
void *pixels );
} gsr_egl; } gsr_egl;
bool gsr_egl_load(gsr_egl *self, Display *dpy); bool gsr_egl_load(gsr_egl *self, Display *dpy);

View File

@ -3,7 +3,6 @@
#include "../../include/cuda.h" #include "../../include/cuda.h"
#include "../../include/window_texture.h" #include "../../include/window_texture.h"
#include "../../include/time.h" #include "../../include/time.h"
#include <X11/extensions/Xcomposite.h>
#include <libavutil/hwcontext.h> #include <libavutil/hwcontext.h>
#include <libavutil/hwcontext_cuda.h> #include <libavutil/hwcontext_cuda.h>
#include <libavutil/frame.h> #include <libavutil/frame.h>

View File

@ -6,12 +6,10 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <X11/extensions/Xcomposite.h>
#include <libavutil/hwcontext.h> #include <libavutil/hwcontext.h>
#include <libavutil/hwcontext_vaapi.h> #include <libavutil/hwcontext_vaapi.h>
#include <libavutil/frame.h> #include <libavutil/frame.h>
#include <libavcodec/avcodec.h> #include <libavcodec/avcodec.h>
//#include <drm_fourcc.h>
#include <assert.h> #include <assert.h>
/* TODO: Proper error checks and cleanups */ /* TODO: Proper error checks and cleanups */
@ -31,18 +29,11 @@ typedef struct {
gsr_egl egl; gsr_egl egl;
gsr_vaapi vaapi; gsr_vaapi vaapi;
int fourcc;
int num_planes;
uint64_t modifiers;
int dmabuf_fd;
int32_t stride;
int32_t offset;
unsigned int target_textures[2]; unsigned int target_textures[2];
unsigned int FramebufferNameY; unsigned int framebuffer_y;
unsigned int FramebufferNameUV; // TODO: Remove unsigned int framebuffer_uv;
unsigned int quadVAO; unsigned int vao;
unsigned int shader_y; unsigned int shader_y;
unsigned int shader_uv; unsigned int shader_uv;
@ -54,12 +45,7 @@ static int max_int(int a, int b) {
return a > b ? a : 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) { static bool drm_create_codec_context(gsr_capture_xcomposite_drm *cap_xcomp, AVCodecContext *video_codec_context) {
// TODO: "/dev/dri/card0"
AVBufferRef *device_ctx; AVBufferRef *device_ctx;
if(av_hwdevice_ctx_create(&device_ctx, AV_HWDEVICE_TYPE_VAAPI, "/dev/dri/card0", NULL, 0) < 0) { 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"); fprintf(stderr, "Error: Failed to create hardware device context\n");
@ -77,7 +63,7 @@ static bool drm_create_codec_context(gsr_capture_xcomposite_drm *cap_xcomp, AVCo
(AVHWFramesContext *)frame_context->data; (AVHWFramesContext *)frame_context->data;
hw_frame_context->width = video_codec_context->width; hw_frame_context->width = video_codec_context->width;
hw_frame_context->height = video_codec_context->height; hw_frame_context->height = video_codec_context->height;
hw_frame_context->sw_format = AV_PIX_FMT_NV12;//AV_PIX_FMT_0RGB32;//AV_PIX_FMT_YUV420P;//AV_PIX_FMT_0RGB32;//AV_PIX_FMT_NV12; hw_frame_context->sw_format = AV_PIX_FMT_NV12;
hw_frame_context->format = video_codec_context->pix_fmt; hw_frame_context->format = video_codec_context->pix_fmt;
hw_frame_context->device_ref = device_ctx; hw_frame_context->device_ref = device_ctx;
hw_frame_context->device_ctx = (AVHWDeviceContext*)device_ctx->data; hw_frame_context->device_ctx = (AVHWDeviceContext*)device_ctx->data;
@ -88,8 +74,7 @@ static bool drm_create_codec_context(gsr_capture_xcomposite_drm *cap_xcomp, AVCo
cap_xcomp->va_dpy = vactx->display; cap_xcomp->va_dpy = vactx->display;
if (av_hwframe_ctx_init(frame_context) < 0) { if (av_hwframe_ctx_init(frame_context) < 0) {
fprintf(stderr, "Error: Failed to initialize hardware frame context " fprintf(stderr, "Error: Failed to initialize hardware frame context (note: ffmpeg version needs to be > 4.0)\n");
"(note: ffmpeg version needs to be > 4.0)\n");
av_buffer_unref(&device_ctx); av_buffer_unref(&device_ctx);
//av_buffer_unref(&frame_context); //av_buffer_unref(&frame_context);
return false; return false;
@ -221,131 +206,34 @@ unsigned int esLoadProgram ( gsr_capture_xcomposite_drm *cap_xcomp, const char *
return programObject; return programObject;
} }
#define RGB_TO_YUV "const mat4 RGBtoYUV = mat4(0.257, 0.439, -0.148, 0.0,\n" \
" 0.504, -0.368, -0.291, 0.0,\n" \
" 0.098, -0.071, 0.439, 0.0,\n" \
" 0.0625, 0.500, 0.500, 1.0);"
static unsigned int LoadShadersY(gsr_capture_xcomposite_drm *cap_xcomp) { static unsigned int LoadShadersY(gsr_capture_xcomposite_drm *cap_xcomp) {
char vShaderStr[] = char vShaderStr[] =
"#version 300 es \n" "#version 300 es \n"
"in vec2 pos; \n" "in vec2 pos; \n"
"in vec2 texcoords; \n" "in vec2 texcoords; \n"
"out vec2 texcoords_out; \n" "out vec2 texcoords_out; \n"
"void main() \n" "void main() \n"
"{ \n" "{ \n"
" texcoords_out = texcoords; \n" " texcoords_out = texcoords; \n"
" gl_Position = vec4(pos.x, pos.y, 0.0, 1.0); \n" " gl_Position = vec4(pos.x, pos.y, 0.0, 1.0); \n"
"} \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[] = char fShaderStr[] =
"#version 300 es \n" "#version 300 es \n"
"precision mediump float; \n" "precision mediump float; \n"
"in vec2 texcoords_out; \n" "in vec2 texcoords_out; \n"
"uniform sampler2D tex1; \n" "uniform sampler2D tex1; \n"
//"uniform sampler2D tex2; \n" "out vec4 FragColor; \n"
"out vec4 FragColor; \n" RGB_TO_YUV
//"out vec4 FragColor2; \n" "void main() \n"
"mat4 RGBtoYUV() {\n" "{ \n"
" return mat4(\n" " FragColor.x = (RGBtoYUV * vec4(texture(tex1, texcoords_out).rgb, 1.0)).x; \n"
" vec4(0.257, 0.439, -0.148, 0.0),\n" "} \n";
" vec4(0.504, -0.368, -0.291, 0.0),\n"
" vec4(0.098, -0.071, 0.439, 0.0),\n"
" vec4(0.0625, 0.500, 0.500, 1.0)\n"
" );\n"
"}\n"
"void main() \n"
"{ \n"
//" vec3 yuv = rgb2yuv(texture(tex1, texcoords_out).rgb); \n"
//" FragColor.x = yuv.x; \n"
//" FragColor2.xy = yuv.xy; \n"
//" vec3 rgb = texture(tex1, texcoords_out).rgb;\n"
"FragColor.x = (RGBtoYUV() * vec4(texture(tex1, texcoords_out).rgb, 1.0)).x;\n"
//"FragColor2.xy = (RGBtoYUV() * vec4(texture(tex1, texcoords_out*2.0).rgb, 1.0)).zy;\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
unsigned int shader_program = esLoadProgram(cap_xcomp, vShaderStr, fShaderStr); unsigned int shader_program = esLoadProgram(cap_xcomp, vShaderStr, fShaderStr);
if (shader_program == 0) { if (shader_program == 0) {
@ -370,119 +258,17 @@ static unsigned int LoadShadersUV(gsr_capture_xcomposite_drm *cap_xcomp) {
" gl_Position = vec4(pos.x, pos.y, 0.0, 1.0); \n" " gl_Position = vec4(pos.x, pos.y, 0.0, 1.0); \n"
"} \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[] = char fShaderStr[] =
"#version 300 es \n" "#version 300 es \n"
"precision mediump float; \n" "precision mediump float; \n"
"in vec2 texcoords_out; \n" "in vec2 texcoords_out; \n"
"uniform sampler2D tex1; \n" "uniform sampler2D tex1; \n"
//"uniform sampler2D tex2; \n" "out vec4 FragColor; \n"
"out vec4 FragColor; \n" RGB_TO_YUV
//"out vec4 FragColor2; \n" "void main() \n"
"mat4 RGBtoYUV() {\n" "{ \n"
" return mat4(\n" " FragColor.xy = (RGBtoYUV * vec4(texture(tex1, texcoords_out*2.0).rgb, 1.0)).zy; \n"
" vec4(0.257, 0.439, -0.148, 0.0),\n" "} \n";
" vec4(0.504, -0.368, -0.291, 0.0),\n"
" vec4(0.098, -0.071, 0.439, 0.0),\n"
" vec4(0.0625, 0.500, 0.500, 1.0)\n"
" );\n"
"}\n"
"void main() \n"
"{ \n"
//" vec3 yuv = rgb2yuv(texture(tex1, texcoords_out).rgb); \n"
//" FragColor.x = yuv.x; \n"
//" FragColor2.xy = yuv.xy; \n"
//" vec3 rgb = texture(tex1, texcoords_out).rgb;\n"
//"FragColor.x = (RGBtoYUV() * vec4(texture(tex1, texcoords_out).rgb, 1.0)).x;\n"
"FragColor.xy = (RGBtoYUV() * vec4(texture(tex1, texcoords_out*2.0).rgb, 1.0)).zy;\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
unsigned int shader_program = esLoadProgram(cap_xcomp, vShaderStr, fShaderStr); unsigned int shader_program = esLoadProgram(cap_xcomp, vShaderStr, fShaderStr);
if (shader_program == 0) { if (shader_program == 0) {
@ -531,18 +317,6 @@ static int gsr_capture_xcomposite_drm_start(gsr_capture *cap, AVCodecContext *vi
return -1; return -1;
} }
if(!cap_xcomp->egl.eglExportDMABUFImageQueryMESA) {
fprintf(stderr, "gsr error: gsr_capture_xcomposite_drm_start: could not find eglExportDMABUFImageQueryMESA\n");
gsr_egl_unload(&cap_xcomp->egl);
return -1;
}
if(!cap_xcomp->egl.eglExportDMABUFImageMESA) {
fprintf(stderr, "gsr error: gsr_capture_xcomposite_drm_start: could not find eglExportDMABUFImageMESA\n");
gsr_egl_unload(&cap_xcomp->egl);
return -1;
}
if(!gsr_vaapi_load(&cap_xcomp->vaapi)) { if(!gsr_vaapi_load(&cap_xcomp->vaapi)) {
fprintf(stderr, "gsr error: gsr_capture_xcomposite_drm_start: failed to load vaapi\n"); fprintf(stderr, "gsr error: gsr_capture_xcomposite_drm_start: failed to load vaapi\n");
gsr_egl_unload(&cap_xcomp->egl); gsr_egl_unload(&cap_xcomp->egl);
@ -551,37 +325,7 @@ static int gsr_capture_xcomposite_drm_start(gsr_capture *cap, AVCodecContext *vi
/* Disable vsync */ /* Disable vsync */
cap_xcomp->egl.eglSwapInterval(cap_xcomp->egl.egl_display, 0); 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 // TODO: Fallback to composite window
if(window_texture_init(&cap_xcomp->window_texture, cap_xcomp->dpy, cap_xcomp->params.window, &cap_xcomp->egl) != 0) { 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); fprintf(stderr, "gsr error: gsr_capture_xcomposite_drm_start: failed get window texture for window %ld\n", cap_xcomp->params.window);
@ -602,47 +346,13 @@ static int gsr_capture_xcomposite_drm_start(gsr_capture *cap, AVCodecContext *vi
video_codec_context->width = cap_xcomp->texture_size.x; video_codec_context->width = cap_xcomp->texture_size.x;
video_codec_context->height = cap_xcomp->texture_size.y; video_codec_context->height = cap_xcomp->texture_size.y;
{
const intptr_t pixmap_attrs[] = {
EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
EGL_NONE,
};
EGLImage img = cap_xcomp->egl.eglCreateImage(cap_xcomp->egl.egl_display, cap_xcomp->egl.egl_context, EGL_GL_TEXTURE_2D, (EGLClientBuffer)(uint64_t)window_texture_get_opengl_texture_id(&cap_xcomp->window_texture), pixmap_attrs);
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)) {
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", window_texture_get_opengl_texture_id(&cap_xcomp->window_texture), 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);
}
if(!drm_create_codec_context(cap_xcomp, video_codec_context)) { if(!drm_create_codec_context(cap_xcomp, video_codec_context)) {
fprintf(stderr, "failed to create hw codec context\n"); fprintf(stderr, "failed to create hw codec context\n");
gsr_egl_unload(&cap_xcomp->egl); gsr_egl_unload(&cap_xcomp->egl);
return -1; return -1;
} }
//fprintf(stderr, "sneed: %u\n", cap_xcomp->FramebufferName);
return 0; return 0;
#endif
} }
static void gsr_capture_xcomposite_drm_tick(gsr_capture *cap, AVCodecContext *video_codec_context, AVFrame **frame) { static void gsr_capture_xcomposite_drm_tick(gsr_capture *cap, AVCodecContext *video_codec_context, AVFrame **frame) {
@ -670,9 +380,6 @@ static void gsr_capture_xcomposite_drm_tick(gsr_capture *cap, AVCodecContext *vi
return; return;
} }
fprintf(stderr, "fourcc: %u\n", cap_xcomp->fourcc);
fprintf(stderr, "va surface id: %u\n", (VASurfaceID)(uintptr_t)(*frame)->data[3]);
VADRMPRIMESurfaceDescriptor prime; VADRMPRIMESurfaceDescriptor prime;
VASurfaceID surface_id = (uintptr_t)(*frame)->data[3]; VASurfaceID surface_id = (uintptr_t)(*frame)->data[3];
@ -749,11 +456,10 @@ static void gsr_capture_xcomposite_drm_tick(gsr_capture *cap, AVCodecContext *vi
cap_xcomp->egl.glGenFramebuffers(1, &cap_xcomp->FramebufferNameY); cap_xcomp->egl.glGenFramebuffers(1, &cap_xcomp->framebuffer_y);
cap_xcomp->egl.glBindFramebuffer(GL_FRAMEBUFFER, cap_xcomp->FramebufferNameY); cap_xcomp->egl.glBindFramebuffer(GL_FRAMEBUFFER, cap_xcomp->framebuffer_y);
cap_xcomp->egl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, cap_xcomp->target_textures[0], 0); cap_xcomp->egl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, cap_xcomp->target_textures[0], 0);
// cap_xcomp->egl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, cap_xcomp->target_textures[1], 0);
// Set the list of draw buffers. // Set the list of draw buffers.
unsigned int DrawBuffers[1] = {GL_COLOR_ATTACHMENT0}; unsigned int DrawBuffers[1] = {GL_COLOR_ATTACHMENT0};
@ -766,11 +472,10 @@ static void gsr_capture_xcomposite_drm_tick(gsr_capture *cap, AVCodecContext *vi
cap_xcomp->egl.glBindFramebuffer(GL_FRAMEBUFFER, 0); cap_xcomp->egl.glBindFramebuffer(GL_FRAMEBUFFER, 0);
cap_xcomp->egl.glGenFramebuffers(1, &cap_xcomp->FramebufferNameUV); cap_xcomp->egl.glGenFramebuffers(1, &cap_xcomp->framebuffer_uv);
cap_xcomp->egl.glBindFramebuffer(GL_FRAMEBUFFER, cap_xcomp->FramebufferNameUV); cap_xcomp->egl.glBindFramebuffer(GL_FRAMEBUFFER, cap_xcomp->framebuffer_uv);
cap_xcomp->egl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, cap_xcomp->target_textures[1], 0); cap_xcomp->egl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, cap_xcomp->target_textures[1], 0);
// cap_xcomp->egl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, cap_xcomp->target_textures[1], 0);
// Set the list of draw buffers. // Set the list of draw buffers.
cap_xcomp->egl.glDrawBuffers(1, DrawBuffers); // "1" is the size of DrawBuffers cap_xcomp->egl.glDrawBuffers(1, DrawBuffers); // "1" is the size of DrawBuffers
@ -782,31 +487,9 @@ static void gsr_capture_xcomposite_drm_tick(gsr_capture *cap, AVCodecContext *vi
cap_xcomp->egl.glBindFramebuffer(GL_FRAMEBUFFER, 0); 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
cap_xcomp->shader_y = LoadShadersY(cap_xcomp); cap_xcomp->shader_y = LoadShadersY(cap_xcomp);
cap_xcomp->shader_uv = LoadShadersUV(cap_xcomp); cap_xcomp->shader_uv = LoadShadersUV(cap_xcomp);
//int tex1 = cap_xcomp->egl.glGetUniformLocation(cap_xcomp->shader_y, "tex1");
//cap_xcomp->egl.glUniform1i(tex1, 0);
//tex1 = cap_xcomp->egl.glGetUniformLocation(cap_xcomp->shader_uv, "tex1");
//cap_xcomp->egl.glUniform1i(tex1, 0);
//int tex2 = cap_xcomp->egl.glGetUniformLocation(shader_program, "tex2");
//fprintf(stderr, "uniform id: %u\n", tex1);
float vVertices[] = { float vVertices[] = {
-1.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f,
@ -819,9 +502,9 @@ static void gsr_capture_xcomposite_drm_tick(gsr_capture *cap, AVCodecContext *vi
}; };
unsigned int quadVBO; unsigned int quadVBO;
cap_xcomp->egl.glGenVertexArrays(1, &cap_xcomp->quadVAO); cap_xcomp->egl.glGenVertexArrays(1, &cap_xcomp->vao);
cap_xcomp->egl.glGenBuffers(1, &quadVBO); cap_xcomp->egl.glGenBuffers(1, &quadVBO);
cap_xcomp->egl.glBindVertexArray(cap_xcomp->quadVAO); cap_xcomp->egl.glBindVertexArray(cap_xcomp->vao);
cap_xcomp->egl.glBindBuffer(GL_ARRAY_BUFFER, quadVBO); cap_xcomp->egl.glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
cap_xcomp->egl.glBufferData(GL_ARRAY_BUFFER, sizeof(vVertices), &vVertices, GL_STATIC_DRAW); cap_xcomp->egl.glBufferData(GL_ARRAY_BUFFER, sizeof(vVertices), &vVertices, GL_STATIC_DRAW);
@ -832,17 +515,9 @@ static void gsr_capture_xcomposite_drm_tick(gsr_capture *cap, AVCodecContext *vi
cap_xcomp->egl.glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float))); 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.glBindVertexArray(0);
} else {
//cap_xcomp->egl.glUniform1i(tex1, 0);
//cap_xcomp->egl.glUniform1i(tex2, 1);
//cap_xcomp->egl.glViewport(0, 0, 1920, 1080);
//cap_xcomp->egl.glBindBuffer(GL_ARRAY_BUFFER, 0);
//cap_xcomp->egl.glBindVertexArray(0);
} else { // This happens on intel
fprintf(stderr, "unexpected fourcc: %u, expected nv12\n", prime.fourcc); fprintf(stderr, "unexpected fourcc: %u, expected nv12\n", prime.fourcc);
abort(); return;
} }
// Clear texture with black background because the source texture (window_texture_get_opengl_texture_id(&cap_xcomp->window_texture)) // Clear texture with black background because the source texture (window_texture_get_opengl_texture_id(&cap_xcomp->window_texture))
@ -865,12 +540,12 @@ static int gsr_capture_xcomposite_drm_capture(gsr_capture *cap, AVFrame *frame)
gsr_capture_xcomposite_drm *cap_xcomp = cap->priv; gsr_capture_xcomposite_drm *cap_xcomp = cap->priv;
vec2i source_size = cap_xcomp->texture_size; vec2i source_size = cap_xcomp->texture_size;
cap_xcomp->egl.glBindVertexArray(cap_xcomp->quadVAO); cap_xcomp->egl.glBindVertexArray(cap_xcomp->vao);
cap_xcomp->egl.glViewport(0, 0, source_size.x, source_size.y); cap_xcomp->egl.glViewport(0, 0, source_size.x, source_size.y);
cap_xcomp->egl.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->egl.glBindFramebuffer(GL_FRAMEBUFFER, cap_xcomp->FramebufferNameY); cap_xcomp->egl.glBindFramebuffer(GL_FRAMEBUFFER, cap_xcomp->framebuffer_y);
//cap_xcomp->egl.glClear(GL_COLOR_BUFFER_BIT); //cap_xcomp->egl.glClear(GL_COLOR_BUFFER_BIT);
cap_xcomp->egl.glUseProgram(cap_xcomp->shader_y); cap_xcomp->egl.glUseProgram(cap_xcomp->shader_y);
@ -878,7 +553,7 @@ static int gsr_capture_xcomposite_drm_capture(gsr_capture *cap, AVFrame *frame)
} }
{ {
cap_xcomp->egl.glBindFramebuffer(GL_FRAMEBUFFER, cap_xcomp->FramebufferNameUV); cap_xcomp->egl.glBindFramebuffer(GL_FRAMEBUFFER, cap_xcomp->framebuffer_uv);
//cap_xcomp->egl.glClear(GL_COLOR_BUFFER_BIT); //cap_xcomp->egl.glClear(GL_COLOR_BUFFER_BIT);
cap_xcomp->egl.glUseProgram(cap_xcomp->shader_uv); cap_xcomp->egl.glUseProgram(cap_xcomp->shader_uv);

View File

@ -90,12 +90,10 @@ static bool gsr_egl_load_egl(gsr_egl *self, void *library) {
{ (void**)&self->eglCreateWindowSurface, "eglCreateWindowSurface" }, { (void**)&self->eglCreateWindowSurface, "eglCreateWindowSurface" },
{ (void**)&self->eglCreateContext, "eglCreateContext" }, { (void**)&self->eglCreateContext, "eglCreateContext" },
{ (void**)&self->eglMakeCurrent, "eglMakeCurrent" }, { (void**)&self->eglMakeCurrent, "eglMakeCurrent" },
{ (void**)&self->eglCreatePixmapSurface, "eglCreatePixmapSurface" }, { (void**)&self->eglCreateImage, "eglCreateImage" },
{ (void**)&self->eglCreateImage, "eglCreateImage" }, /* TODO: use eglCreateImageKHR instead? */
{ (void**)&self->eglDestroyContext, "eglDestroyContext" }, { (void**)&self->eglDestroyContext, "eglDestroyContext" },
{ (void**)&self->eglDestroySurface, "eglDestroySurface" }, { (void**)&self->eglDestroySurface, "eglDestroySurface" },
{ (void**)&self->eglDestroyImage, "eglDestroyImage" }, { (void**)&self->eglDestroyImage, "eglDestroyImage" },
{ (void**)&self->eglBindTexImage, "eglBindTexImage" },
{ (void**)&self->eglSwapInterval, "eglSwapInterval" }, { (void**)&self->eglSwapInterval, "eglSwapInterval" },
{ (void**)&self->eglSwapBuffers, "eglSwapBuffers" }, { (void**)&self->eglSwapBuffers, "eglSwapBuffers" },
{ (void**)&self->eglGetProcAddress, "eglGetProcAddress" }, { (void**)&self->eglGetProcAddress, "eglGetProcAddress" },
@ -112,8 +110,6 @@ static bool gsr_egl_load_egl(gsr_egl *self, void *library) {
} }
static bool gsr_egl_proc_load_egl(gsr_egl *self) { static bool gsr_egl_proc_load_egl(gsr_egl *self) {
self->eglExportDMABUFImageQueryMESA = self->eglGetProcAddress("eglExportDMABUFImageQueryMESA");
self->eglExportDMABUFImageMESA = self->eglGetProcAddress("eglExportDMABUFImageMESA");
self->glEGLImageTargetTexture2DOES = self->eglGetProcAddress("glEGLImageTargetTexture2DOES"); self->glEGLImageTargetTexture2DOES = self->eglGetProcAddress("glEGLImageTargetTexture2DOES");
if(!self->glEGLImageTargetTexture2DOES) { if(!self->glEGLImageTargetTexture2DOES) {
@ -147,7 +143,6 @@ static bool gsr_egl_load_gl(gsr_egl *self, void *library) {
{ (void**)&self->glBindBuffer, "glBindBuffer" }, { (void**)&self->glBindBuffer, "glBindBuffer" },
{ (void**)&self->glGenBuffers, "glGenBuffers" }, { (void**)&self->glGenBuffers, "glGenBuffers" },
{ (void**)&self->glBufferData, "glBufferData" }, { (void**)&self->glBufferData, "glBufferData" },
{ (void**)&self->glGetUniformLocation, "glGetUniformLocation" },
{ (void**)&self->glGenVertexArrays, "glGenVertexArrays" }, { (void**)&self->glGenVertexArrays, "glGenVertexArrays" },
{ (void**)&self->glBindVertexArray, "glBindVertexArray" }, { (void**)&self->glBindVertexArray, "glBindVertexArray" },
{ (void**)&self->glCreateProgram, "glCreateProgram" }, { (void**)&self->glCreateProgram, "glCreateProgram" },
@ -161,15 +156,12 @@ static bool gsr_egl_load_gl(gsr_egl *self, void *library) {
{ (void**)&self->glGetProgramInfoLog, "glGetProgramInfoLog" }, { (void**)&self->glGetProgramInfoLog, "glGetProgramInfoLog" },
{ (void**)&self->glGetShaderiv, "glGetShaderiv" }, { (void**)&self->glGetShaderiv, "glGetShaderiv" },
{ (void**)&self->glGetShaderInfoLog, "glGetShaderInfoLog" }, { (void**)&self->glGetShaderInfoLog, "glGetShaderInfoLog" },
{ (void**)&self->glGetShaderSource, "glGetShaderSource" },
{ (void**)&self->glDeleteProgram, "glDeleteProgram" }, { (void**)&self->glDeleteProgram, "glDeleteProgram" },
{ (void**)&self->glDeleteShader, "glDeleteShader" }, { (void**)&self->glDeleteShader, "glDeleteShader" },
{ (void**)&self->glGetProgramiv, "glGetProgramiv" }, { (void**)&self->glGetProgramiv, "glGetProgramiv" },
{ (void**)&self->glVertexAttribPointer, "glVertexAttribPointer" }, { (void**)&self->glVertexAttribPointer, "glVertexAttribPointer" },
{ (void**)&self->glEnableVertexAttribArray, "glEnableVertexAttribArray" }, { (void**)&self->glEnableVertexAttribArray, "glEnableVertexAttribArray" },
{ (void**)&self->glDrawArrays, "glDrawArrays" }, { (void**)&self->glDrawArrays, "glDrawArrays" },
{ (void**)&self->glReadBuffer, "glReadBuffer" },
{ (void**)&self->glReadPixels, "glReadPixels" },
{ NULL, NULL } { NULL, NULL }
}; };