mirror of
https://repo.dec05eba.com/gpu-screen-recorder
synced 2026-03-31 09:07:13 +09:00
Support v4l2 yuyv on nvidia
This commit is contained in:
8
TODO
8
TODO
@@ -378,4 +378,10 @@ Make capture from multiple sources work on nvidia x11 when capturing monitor + w
|
||||
Support v4l2 mplane on devices where it's supported (where it's more efficient). My camera doesn't support mplane.
|
||||
|
||||
Implement v4l2 yuyv nvidia capture by capturing rg88 yuyv to rgb as is done now for screenshot, but also do that for video by creating an intermediate rgb texture for the camera. Then render that rgb texture to the video texture.
|
||||
This is needed to properly scale the yuyv texture without messing it up (the texture indexing).
|
||||
This is needed to properly scale the yuyv texture without messing it up (the texture indexing).
|
||||
|
||||
Set v4l2 camera fps to video output fps (if lower than the camera fps) and the same for resolution.
|
||||
|
||||
Support camera controls, such as white balance. Otherwise tell user to use cameractrl software.
|
||||
|
||||
Camera capture doesn't work perfectly. The image gets glitched, need to properly wait for image to be done.
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "vec2.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#define GSR_COLOR_CONVERSION_MAX_GRAPHICS_SHADERS 8
|
||||
#define GSR_COLOR_CONVERSION_MAX_GRAPHICS_SHADERS 12
|
||||
#define GSR_COLOR_CONVERSION_MAX_FRAMEBUFFERS 2
|
||||
|
||||
typedef enum {
|
||||
|
||||
@@ -40,7 +40,6 @@ typedef struct __GLXFBConfigRec *GLXFBConfig;
|
||||
typedef struct __GLXcontextRec *GLXContext;
|
||||
typedef XID GLXDrawable;
|
||||
typedef void(*__GLXextFuncPtr)(void);
|
||||
typedef struct __GLsync *GLsync;
|
||||
|
||||
#define EGL_SUCCESS 0x3000
|
||||
#define EGL_BUFFER_SIZE 0x3020
|
||||
@@ -152,11 +151,6 @@ typedef struct __GLsync *GLsync;
|
||||
#define GL_COMPILE_STATUS 0x8B81
|
||||
#define GL_LINK_STATUS 0x8B82
|
||||
|
||||
#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117
|
||||
#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001
|
||||
#define GL_CONDITION_SATISFIED 0x911C
|
||||
#define GL_ALREADY_SIGNALED 0x911A
|
||||
|
||||
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);
|
||||
@@ -315,10 +309,6 @@ struct gsr_egl {
|
||||
void* (*glMapBufferRange)(unsigned int target, intptr_t offset, ssize_t length, unsigned int access);
|
||||
unsigned char (*glUnmapBuffer)(unsigned int target);
|
||||
void (*glGetIntegerv)(unsigned int pname, int *params);
|
||||
|
||||
GLsync (*glFenceSync)(unsigned int condition, unsigned int flags);
|
||||
void (*glDeleteSync)(GLsync sync);
|
||||
unsigned int (*glClientWaitSync)(GLsync sync, unsigned int flags, uint64_t timeout);
|
||||
};
|
||||
|
||||
bool gsr_egl_load(gsr_egl *self, gsr_window *window, bool is_monitor_capture, bool enable_debug);
|
||||
|
||||
@@ -628,18 +628,6 @@ static int gsr_capture_kms_capture(gsr_capture *cap, gsr_capture_metadata *captu
|
||||
}
|
||||
}
|
||||
|
||||
// static GLsync sync = NULL;
|
||||
|
||||
// if(sync) {
|
||||
// const unsigned int r = self->params.egl->glClientWaitSync(sync, GL_SYNC_FLUSH_COMMANDS_BIT, 1000 * 1000 * 1000);
|
||||
// if(r != GL_CONDITION_SATISFIED && r != GL_ALREADY_SIGNALED) {
|
||||
// fprintf(stderr, "failed sync: %u\n", r);
|
||||
// }
|
||||
// self->params.egl->glDeleteSync(sync);
|
||||
// }
|
||||
|
||||
// sync = self->params.egl->glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
|
||||
//self->params.egl->glFlush();
|
||||
//self->params.egl->glFinish();
|
||||
|
||||
|
||||
@@ -53,7 +53,8 @@ typedef struct {
|
||||
int fd;
|
||||
int dmabuf_fd[NUM_BUFFERS];
|
||||
EGLImage dma_image[NUM_BUFFERS];
|
||||
unsigned int texture_id;
|
||||
unsigned int texture_id[NUM_BUFFERS];
|
||||
unsigned int prev_texture_index;
|
||||
bool got_first_frame;
|
||||
|
||||
void *dmabuf_map[NUM_BUFFERS];
|
||||
@@ -72,6 +73,8 @@ typedef struct {
|
||||
tjhandle jpeg_decompressor;
|
||||
|
||||
double capture_start_time;
|
||||
|
||||
bool yuyv_conversion_fallback;
|
||||
} gsr_capture_v4l2;
|
||||
|
||||
static int xioctl(int fd, unsigned long request, void *arg) {
|
||||
@@ -90,9 +93,9 @@ static void gsr_capture_v4l2_stop(gsr_capture_v4l2 *self) {
|
||||
self->pbos[i] = 0;
|
||||
}
|
||||
|
||||
if(self->texture_id) {
|
||||
self->params.egl->glDeleteTextures(1, &self->texture_id);
|
||||
self->texture_id = 0;
|
||||
self->params.egl->glDeleteTextures(NUM_BUFFERS, self->texture_id);
|
||||
for(int i = 0; i < NUM_BUFFERS; ++i) {
|
||||
self->texture_id[i] = 0;
|
||||
}
|
||||
|
||||
for(int i = 0; i < NUM_BUFFERS; ++i) {
|
||||
@@ -246,32 +249,48 @@ static bool gsr_capture_v4l2_map_buffer(gsr_capture_v4l2 *self, const struct v4l
|
||||
return false;
|
||||
}
|
||||
case GSR_CAPTURE_V4L2_PIXFMT_YUYV: {
|
||||
self->params.egl->glGenTextures(NUM_BUFFERS, self->texture_id);
|
||||
|
||||
for(int i = 0; i < NUM_BUFFERS; ++i) {
|
||||
self->dma_image[i] = self->params.egl->eglCreateImage(self->params.egl->egl_display, 0, EGL_LINUX_DMA_BUF_EXT, NULL, (intptr_t[]) {
|
||||
EGL_WIDTH, fmt->fmt.pix.width,
|
||||
EGL_HEIGHT, fmt->fmt.pix.height,
|
||||
EGL_LINUX_DRM_FOURCC_EXT, DRM_FORMAT_YUYV, // TODO: Use DRM_FORMAT_RG88 on nvidia and custom shader. Test on intel as well, or use fallback method on every system.
|
||||
EGL_LINUX_DRM_FOURCC_EXT, DRM_FORMAT_YUYV,
|
||||
EGL_DMA_BUF_PLANE0_FD_EXT, self->dmabuf_fd[i],
|
||||
EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0,
|
||||
EGL_DMA_BUF_PLANE0_PITCH_EXT, fmt->fmt.pix.bytesperline,
|
||||
EGL_NONE
|
||||
});
|
||||
|
||||
if(!self->dma_image[i]) {
|
||||
fprintf(stderr, "gsr error: gsr_capture_v4l2_map_buffer: eglCreateImage failed, error: %d\n", self->params.egl->eglGetError());
|
||||
self->yuyv_conversion_fallback = true;
|
||||
self->dma_image[i] = self->params.egl->eglCreateImage(self->params.egl->egl_display, 0, EGL_LINUX_DMA_BUF_EXT, NULL, (intptr_t[]) {
|
||||
EGL_WIDTH, fmt->fmt.pix.width,
|
||||
EGL_HEIGHT, fmt->fmt.pix.height,
|
||||
EGL_LINUX_DRM_FOURCC_EXT, DRM_FORMAT_RG88,
|
||||
EGL_DMA_BUF_PLANE0_FD_EXT, self->dmabuf_fd[i],
|
||||
EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0,
|
||||
EGL_DMA_BUF_PLANE0_PITCH_EXT, fmt->fmt.pix.bytesperline,
|
||||
EGL_NONE
|
||||
});
|
||||
|
||||
if(!self->dma_image[i]) {
|
||||
fprintf(stderr, "gsr error: gsr_capture_v4l2_map_buffer: eglCreateImage failed, error: %d\n", self->params.egl->eglGetError());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
self->params.egl->glBindTexture(GL_TEXTURE_EXTERNAL_OES, self->texture_id[i]);
|
||||
self->params.egl->glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, self->dma_image[i]);
|
||||
self->params.egl->glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
self->params.egl->glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
self->params.egl->glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
|
||||
if(self->texture_id[i] == 0) {
|
||||
fprintf(stderr, "gsr error: gsr_capture_v4l2_map_buffer: failed to create texture\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
self->params.egl->glGenTextures(1, &self->texture_id);
|
||||
self->params.egl->glBindTexture(GL_TEXTURE_EXTERNAL_OES, self->texture_id);
|
||||
self->params.egl->glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
self->params.egl->glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
self->params.egl->glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
|
||||
if(self->texture_id == 0) {
|
||||
fprintf(stderr, "gsr error: gsr_capture_v4l2_map_buffer: failed to create texture\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
self->buffer_type = V4L2_BUFFER_TYPE_DMABUF;
|
||||
break;
|
||||
}
|
||||
@@ -283,13 +302,13 @@ static bool gsr_capture_v4l2_map_buffer(gsr_capture_v4l2 *self, const struct v4l
|
||||
fprintf(stderr, "gsr error: gsr_capture_v4l2_map_buffer: mmap failed, error: %s\n", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// GL_RGBA is intentionally used here instead of GL_RGB, because the performance is much better when using glTexSubImage2D (22% cpu usage compared to 38% cpu usage)
|
||||
self->texture_id = gl_create_texture(self->params.egl, fmt->fmt.pix.width, fmt->fmt.pix.height, GL_RGBA8, GL_RGBA, GL_LINEAR);
|
||||
if(self->texture_id == 0) {
|
||||
fprintf(stderr, "gsr error: gsr_capture_v4l2_map_buffer: failed to create texture\n");
|
||||
return false;
|
||||
// GL_RGBA is intentionally used here instead of GL_RGB, because the performance is much better when using glTexSubImage2D (22% cpu usage compared to 38% cpu usage)
|
||||
self->texture_id[i] = gl_create_texture(self->params.egl, fmt->fmt.pix.width, fmt->fmt.pix.height, GL_RGBA8, GL_RGBA, GL_LINEAR);
|
||||
if(self->texture_id[i] == 0) {
|
||||
fprintf(stderr, "gsr error: gsr_capture_v4l2_map_buffer: failed to create texture\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(!gsr_capture_v4l2_create_pbos(self, fmt->fmt.pix.width, fmt->fmt.pix.height))
|
||||
@@ -377,15 +396,6 @@ static int gsr_capture_v4l2_setup(gsr_capture_v4l2 *self) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Buggy driver paranoia */
|
||||
const uint32_t min_stride = fmt.fmt.pix.width * 2; // * 2 because the stride is width (Y) + width/2 (U) + width/2 (V)
|
||||
if(fmt.fmt.pix.bytesperline < min_stride)
|
||||
fmt.fmt.pix.bytesperline = min_stride;
|
||||
|
||||
const uint32_t min_size = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
|
||||
if(fmt.fmt.pix.sizeimage < min_size)
|
||||
fmt.fmt.pix.sizeimage = min_size;
|
||||
|
||||
self->capture_size.x = fmt.fmt.pix.width;
|
||||
self->capture_size.y = fmt.fmt.pix.height;
|
||||
|
||||
@@ -479,7 +489,7 @@ static void gsr_capture_v4l2_decode_jpeg_to_texture(gsr_capture_v4l2 *self, cons
|
||||
return;
|
||||
}
|
||||
|
||||
self->params.egl->glBindTexture(GL_TEXTURE_2D, self->texture_id);
|
||||
self->params.egl->glBindTexture(GL_TEXTURE_2D, self->texture_id[buf->index]);
|
||||
|
||||
self->pbo_index = (self->pbo_index + 1) % NUM_PBOS;
|
||||
const unsigned int next_pbo_index = (self->pbo_index + 1) % NUM_PBOS;
|
||||
@@ -511,6 +521,8 @@ static int gsr_capture_v4l2_capture(gsr_capture *cap, gsr_capture_metadata *capt
|
||||
};
|
||||
|
||||
xioctl(self->fd, VIDIOC_DQBUF, &buf);
|
||||
unsigned int texture_index = buf.index;
|
||||
|
||||
if(buf.bytesused > 0 && !(buf.flags & V4L2_BUF_FLAG_ERROR)) {
|
||||
if(!self->got_first_frame)
|
||||
fprintf(stderr, "gsr info: gsr_capture_v4l2_capture: camera %s is now ready\n", self->params.device_path);
|
||||
@@ -518,9 +530,9 @@ static int gsr_capture_v4l2_capture(gsr_capture *cap, gsr_capture_metadata *capt
|
||||
|
||||
switch(self->buffer_type) {
|
||||
case V4L2_BUFFER_TYPE_DMABUF: {
|
||||
self->params.egl->glBindTexture(GL_TEXTURE_EXTERNAL_OES, self->texture_id);
|
||||
self->params.egl->glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, self->dma_image[buf.index]);
|
||||
self->params.egl->glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
|
||||
//self->params.egl->glBindTexture(GL_TEXTURE_EXTERNAL_OES, self->texture_id);
|
||||
//self->params.egl->glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, self->dma_image[buf.index]);
|
||||
//self->params.egl->glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
|
||||
break;
|
||||
}
|
||||
case V4L2_BUFFER_TYPE_MMAP: {
|
||||
@@ -530,6 +542,10 @@ static int gsr_capture_v4l2_capture(gsr_capture *cap, gsr_capture_metadata *capt
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
self->prev_texture_index = buf.index;
|
||||
} else {
|
||||
texture_index = self->prev_texture_index;
|
||||
}
|
||||
xioctl(self->fd, VIDIOC_QBUF, &buf);
|
||||
|
||||
@@ -537,13 +553,20 @@ static int gsr_capture_v4l2_capture(gsr_capture *cap, gsr_capture_metadata *capt
|
||||
const vec2i target_pos = gsr_capture_get_target_position(output_size, capture_metadata);
|
||||
|
||||
self->params.egl->glFlush();
|
||||
if(self->params.egl->gpu_info.vendor == GSR_GPU_VENDOR_NVIDIA)
|
||||
self->params.egl->glFinish();
|
||||
|
||||
//if(self->got_first_frame) {
|
||||
gsr_color_conversion_draw(color_conversion, self->texture_id,
|
||||
if(self->buffer_type == V4L2_BUFFER_TYPE_DMABUF) {
|
||||
gsr_color_conversion_draw(color_conversion, self->texture_id[texture_index],
|
||||
target_pos, output_size,
|
||||
(vec2i){0, 0}, self->capture_size, self->capture_size,
|
||||
GSR_ROT_0, capture_metadata->flip, GSR_SOURCE_COLOR_RGB, self->buffer_type == V4L2_BUFFER_TYPE_DMABUF);
|
||||
//}
|
||||
GSR_ROT_0, capture_metadata->flip, self->yuyv_conversion_fallback ? GSR_SOURCE_COLOR_YUYV : GSR_SOURCE_COLOR_RGB, true);
|
||||
} else {
|
||||
gsr_color_conversion_draw(color_conversion, self->texture_id[texture_index],
|
||||
target_pos, output_size,
|
||||
(vec2i){0, 0}, self->capture_size, self->capture_size,
|
||||
GSR_ROT_0, capture_metadata->flip, GSR_SOURCE_COLOR_RGB, false);
|
||||
}
|
||||
|
||||
return self->got_first_frame ? 0 : -1;
|
||||
}
|
||||
|
||||
@@ -10,8 +10,12 @@
|
||||
#define GRAPHICS_SHADER_INDEX_UV_EXTERNAL 3
|
||||
#define GRAPHICS_SHADER_INDEX_RGB 4
|
||||
#define GRAPHICS_SHADER_INDEX_RGB_EXTERNAL 5
|
||||
#define GRAPHICS_SHADER_INDEX_YUYV_TO_RGB 6
|
||||
#define GRAPHICS_SHADER_INDEX_YUYV_TO_RGB_EXTERNAL 7
|
||||
#define GRAPHICS_SHADER_INDEX_YUYV_TO_Y 6
|
||||
#define GRAPHICS_SHADER_INDEX_YUYV_TO_UV 7
|
||||
#define GRAPHICS_SHADER_INDEX_YUYV_TO_Y_EXTERNAL 8
|
||||
#define GRAPHICS_SHADER_INDEX_YUYV_TO_UV_EXTERNAL 9
|
||||
#define GRAPHICS_SHADER_INDEX_YUYV_TO_RGB 10
|
||||
#define GRAPHICS_SHADER_INDEX_YUYV_TO_RGB_EXTERNAL 11
|
||||
|
||||
/* https://en.wikipedia.org/wiki/YCbCr, see study/color_space_transform_matrix.png */
|
||||
|
||||
@@ -250,6 +254,135 @@ static unsigned int load_graphics_shader_rgb(gsr_shader *shader, gsr_egl *egl, g
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int load_graphics_shader_yuyv_to_y(gsr_shader *shader, gsr_egl *egl, gsr_color_graphics_uniforms *uniforms, bool external_texture) {
|
||||
char vertex_shader[2048];
|
||||
snprintf(vertex_shader, sizeof(vertex_shader),
|
||||
"#version 300 es \n"
|
||||
"in vec2 pos; \n"
|
||||
"in vec2 texcoords; \n"
|
||||
"out vec2 texcoords_out; \n"
|
||||
"uniform vec2 offset; \n"
|
||||
"uniform float rotation; \n"
|
||||
"uniform mat2 rotation_matrix; \n"
|
||||
"void main() \n"
|
||||
"{ \n"
|
||||
" texcoords_out = vec2(texcoords.x - 0.5, texcoords.y - 0.5) * rotation_matrix + vec2(0.5, 0.5); \n"
|
||||
" gl_Position = vec4(offset.x, offset.y, 0.0, 0.0) + vec4(pos.x, pos.y, 0.0, 1.0); \n"
|
||||
"} \n");
|
||||
|
||||
const char *main_code =
|
||||
" vec4 pixel = texture(tex1, texcoords_out); \n"
|
||||
" FragColor.x = pixel.r; \n"
|
||||
" FragColor.w = 1.0; \n";
|
||||
|
||||
char fragment_shader[2048];
|
||||
if(external_texture) {
|
||||
snprintf(fragment_shader, sizeof(fragment_shader),
|
||||
"#version 300 es \n"
|
||||
"#extension GL_OES_EGL_image_external : enable \n"
|
||||
"#extension GL_OES_EGL_image_external_essl3 : require \n"
|
||||
"precision highp float; \n"
|
||||
"in vec2 texcoords_out; \n"
|
||||
"uniform samplerExternalOES tex1; \n"
|
||||
"out vec4 FragColor; \n"
|
||||
"void main() \n"
|
||||
"{ \n"
|
||||
"%s"
|
||||
"} \n", main_code);
|
||||
} else {
|
||||
snprintf(fragment_shader, sizeof(fragment_shader),
|
||||
"#version 300 es \n"
|
||||
"precision highp float; \n"
|
||||
"in vec2 texcoords_out; \n"
|
||||
"uniform sampler2D tex1; \n"
|
||||
"out vec4 FragColor; \n"
|
||||
"void main() \n"
|
||||
"{ \n"
|
||||
"%s"
|
||||
"} \n", main_code);
|
||||
}
|
||||
|
||||
if(gsr_shader_init(shader, egl, vertex_shader, fragment_shader) != 0)
|
||||
return -1;
|
||||
|
||||
gsr_shader_bind_attribute_location(shader, "pos", 0);
|
||||
gsr_shader_bind_attribute_location(shader, "texcoords", 1);
|
||||
uniforms->offset = egl->glGetUniformLocation(shader->program_id, "offset");
|
||||
uniforms->rotation_matrix = egl->glGetUniformLocation(shader->program_id, "rotation_matrix");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int load_graphics_shader_yuyv_to_uv(gsr_shader *shader, gsr_egl *egl, gsr_color_graphics_uniforms *uniforms, bool external_texture) {
|
||||
char vertex_shader[2048];
|
||||
snprintf(vertex_shader, sizeof(vertex_shader),
|
||||
"#version 300 es \n"
|
||||
"in vec2 pos; \n"
|
||||
"in vec2 texcoords; \n"
|
||||
"out vec2 texcoords_out; \n"
|
||||
"uniform vec2 offset; \n"
|
||||
"uniform float rotation; \n"
|
||||
"uniform mat2 rotation_matrix; \n"
|
||||
"void main() \n"
|
||||
"{ \n"
|
||||
" texcoords_out = vec2(texcoords.x - 0.5, texcoords.y - 0.5) * rotation_matrix + vec2(0.5, 0.5); \n"
|
||||
" gl_Position = (vec4(offset.x, offset.y, 0.0, 0.0) + vec4(pos.x, pos.y, 0.0, 1.0)) * vec4(0.5, 0.5, 1.0, 1.0) - vec4(0.5, 0.5, 0.0, 0.0); \n"
|
||||
"} \n");
|
||||
|
||||
const char *main_code =
|
||||
" vec2 resolution = vec2(textureSize(tex1, 0));\n"
|
||||
" ivec2 uv = ivec2(texcoords_out * resolution);\n"
|
||||
" float u = 0.0;\n"
|
||||
" float v = 0.0;\n"
|
||||
" vec4 this_color = texelFetch(tex1, uv, 0);\n"
|
||||
" if((uv.x & 1) == 0) {\n"
|
||||
" vec2 next_color = texelFetch(tex1, uv + ivec2(1, 0), 0).rg;\n"
|
||||
" u = this_color.g;\n"
|
||||
" v = next_color.g;\n"
|
||||
" } else {\n"
|
||||
" vec2 prev_color = texelFetch(tex1, uv - ivec2(1, 0), 0).rg;\n"
|
||||
" u = prev_color.g;\n"
|
||||
" v = this_color.g;\n"
|
||||
" }\n"
|
||||
" FragColor.rg = vec2(u, v);\n"
|
||||
" FragColor.w = 1.0;\n";
|
||||
|
||||
char fragment_shader[2048];
|
||||
if(external_texture) {
|
||||
snprintf(fragment_shader, sizeof(fragment_shader),
|
||||
"#version 300 es \n"
|
||||
"#extension GL_OES_EGL_image_external : enable \n"
|
||||
"#extension GL_OES_EGL_image_external_essl3 : require \n"
|
||||
"precision highp float; \n"
|
||||
"in vec2 texcoords_out; \n"
|
||||
"uniform samplerExternalOES tex1; \n"
|
||||
"out vec4 FragColor; \n"
|
||||
"void main() \n"
|
||||
"{ \n"
|
||||
"%s"
|
||||
"} \n", main_code);
|
||||
} else {
|
||||
snprintf(fragment_shader, sizeof(fragment_shader),
|
||||
"#version 300 es \n"
|
||||
"precision highp float; \n"
|
||||
"in vec2 texcoords_out; \n"
|
||||
"uniform sampler2D tex1; \n"
|
||||
"out vec4 FragColor; \n"
|
||||
"void main() \n"
|
||||
"{ \n"
|
||||
"%s"
|
||||
"} \n", main_code);
|
||||
}
|
||||
|
||||
if(gsr_shader_init(shader, egl, vertex_shader, fragment_shader) != 0)
|
||||
return -1;
|
||||
|
||||
gsr_shader_bind_attribute_location(shader, "pos", 0);
|
||||
gsr_shader_bind_attribute_location(shader, "texcoords", 1);
|
||||
uniforms->offset = egl->glGetUniformLocation(shader->program_id, "offset");
|
||||
uniforms->rotation_matrix = egl->glGetUniformLocation(shader->program_id, "rotation_matrix");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int load_graphics_shader_yuyv_to_rgb(gsr_shader *shader, gsr_egl *egl, gsr_color_graphics_uniforms *uniforms, bool external_texture) {
|
||||
char vertex_shader[2048];
|
||||
snprintf(vertex_shader, sizeof(vertex_shader),
|
||||
@@ -268,21 +401,18 @@ static unsigned int load_graphics_shader_yuyv_to_rgb(gsr_shader *shader, gsr_egl
|
||||
|
||||
const char *main_code =
|
||||
" vec2 resolution = vec2(textureSize(tex1, 0));\n"
|
||||
" vec2 uv = texcoords_out * resolution;\n"
|
||||
" ivec2 uv = ivec2(texcoords_out * resolution);\n"
|
||||
" float y = 0.0;\n"
|
||||
" float u = 0.0;\n"
|
||||
" float v = 0.0;\n"
|
||||
" if(mod(uv.x, 2.0) < 1.0) {\n"
|
||||
" vec3 this_color = texture(tex1, texcoords_out).rgb;\n"
|
||||
" vec3 next_color = texture(tex1, texcoords_out + vec2(1.0, 0.0)/resolution).rgb;\n"
|
||||
"\n"
|
||||
" vec4 this_color = texelFetch(tex1, uv, 0);\n"
|
||||
" if((uv.x & 1) == 0) {\n"
|
||||
" vec2 next_color = texelFetch(tex1, uv + ivec2(1, 0), 0).rg;\n"
|
||||
" y = this_color.r;\n"
|
||||
" u = this_color.g;\n"
|
||||
" v = next_color.g;\n"
|
||||
" } else {\n"
|
||||
" vec3 this_color = texture(tex1, texcoords_out).rgb;\n"
|
||||
" vec3 prev_color = texture(tex1, texcoords_out - vec2(1.0, 0.0)/resolution).rgb;\n"
|
||||
"\n"
|
||||
" vec2 prev_color = texelFetch(tex1, uv - ivec2(1, 0), 0).rg;\n"
|
||||
" y = this_color.r;\n"
|
||||
" u = prev_color.g;\n"
|
||||
" v = this_color.g;\n"
|
||||
@@ -392,6 +522,16 @@ static bool gsr_color_conversion_load_graphics_shaders(gsr_color_conversion *sel
|
||||
fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load UV graphics shader\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(load_graphics_shader_yuyv_to_y(&self->graphics_shaders[GRAPHICS_SHADER_INDEX_YUYV_TO_Y], self->params.egl, &self->graphics_uniforms[GRAPHICS_SHADER_INDEX_YUYV_TO_Y], false) != 0) {
|
||||
fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load YUYV to Y graphics shader\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(load_graphics_shader_yuyv_to_uv(&self->graphics_shaders[GRAPHICS_SHADER_INDEX_YUYV_TO_UV], self->params.egl, &self->graphics_uniforms[GRAPHICS_SHADER_INDEX_YUYV_TO_UV], false) != 0) {
|
||||
fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load YUYV to UV graphics shader\n");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GSR_DESTINATION_COLOR_RGB8: {
|
||||
@@ -423,6 +563,16 @@ static bool gsr_color_conversion_load_external_graphics_shaders(gsr_color_conver
|
||||
fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load UV graphics shader (external)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(load_graphics_shader_yuyv_to_y(&self->graphics_shaders[GRAPHICS_SHADER_INDEX_YUYV_TO_Y_EXTERNAL], self->params.egl, &self->graphics_uniforms[GRAPHICS_SHADER_INDEX_YUYV_TO_Y_EXTERNAL], true) != 0) {
|
||||
fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load YUYV to Y graphics shader (external)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(load_graphics_shader_yuyv_to_uv(&self->graphics_shaders[GRAPHICS_SHADER_INDEX_YUYV_TO_UV_EXTERNAL], self->params.egl, &self->graphics_uniforms[GRAPHICS_SHADER_INDEX_YUYV_TO_UV_EXTERNAL], true) != 0) {
|
||||
fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load YUYV to UV graphics shader (external)\n");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GSR_DESTINATION_COLOR_RGB8: {
|
||||
@@ -550,17 +700,17 @@ static void gsr_color_conversion_apply_rotation(gsr_rotation rotation, float rot
|
||||
}
|
||||
}
|
||||
|
||||
static void gsr_color_conversion_swizzle_texture_source(gsr_color_conversion *self, gsr_source_color source_color) {
|
||||
static void gsr_color_conversion_swizzle_texture_source(gsr_color_conversion *self, unsigned int texture_target, gsr_source_color source_color) {
|
||||
if(source_color == GSR_SOURCE_COLOR_BGR) {
|
||||
const int swizzle_mask[] = { GL_BLUE, GL_GREEN, GL_RED, 1 };
|
||||
self->params.egl->glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle_mask);
|
||||
self->params.egl->glTexParameteriv(texture_target, GL_TEXTURE_SWIZZLE_RGBA, swizzle_mask);
|
||||
}
|
||||
}
|
||||
|
||||
static void gsr_color_conversion_swizzle_reset(gsr_color_conversion *self, gsr_source_color source_color) {
|
||||
static void gsr_color_conversion_swizzle_reset(gsr_color_conversion *self, unsigned int texture_target, gsr_source_color source_color) {
|
||||
if(source_color == GSR_SOURCE_COLOR_BGR) {
|
||||
const int swizzle_mask[] = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA };
|
||||
self->params.egl->glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle_mask);
|
||||
self->params.egl->glTexParameteriv(texture_target, GL_TEXTURE_SWIZZLE_RGBA, swizzle_mask);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -569,7 +719,7 @@ static void gsr_color_conversion_draw_graphics(gsr_color_conversion *self, unsig
|
||||
return;
|
||||
|
||||
const vec2i dest_texture_size = self->params.destination_textures_size[0];
|
||||
const int texture_target = external_texture ? GL_TEXTURE_EXTERNAL_OES : GL_TEXTURE_2D;
|
||||
const unsigned int texture_target = external_texture ? GL_TEXTURE_EXTERNAL_OES : GL_TEXTURE_2D;
|
||||
|
||||
if(rotation == GSR_ROT_90 || rotation == GSR_ROT_270) {
|
||||
const float tmp = texture_size.x;
|
||||
@@ -578,7 +728,7 @@ static void gsr_color_conversion_draw_graphics(gsr_color_conversion *self, unsig
|
||||
}
|
||||
|
||||
self->params.egl->glBindTexture(texture_target, texture_id);
|
||||
gsr_color_conversion_swizzle_texture_source(self, source_color);
|
||||
gsr_color_conversion_swizzle_texture_source(self, texture_target, source_color);
|
||||
|
||||
const vec2f pos_norm = {
|
||||
((float)destination_pos.x / (dest_texture_size.x == 0 ? 1.0f : (float)dest_texture_size.x)) * 2.0f,
|
||||
@@ -674,21 +824,49 @@ static void gsr_color_conversion_draw_graphics(gsr_color_conversion *self, unsig
|
||||
break;
|
||||
}
|
||||
case GSR_SOURCE_COLOR_YUYV: {
|
||||
self->params.egl->glBindFramebuffer(GL_FRAMEBUFFER, self->framebuffers[0]);
|
||||
//cap_xcomp->params.egl->glClear(GL_COLOR_BUFFER_BIT); // TODO: Do this in a separate clear_ function. We want to do that when using multiple drm to create the final image (multiple monitors for example)
|
||||
switch(self->params.destination_color) {
|
||||
case GSR_DESTINATION_COLOR_NV12:
|
||||
case GSR_DESTINATION_COLOR_P010: {
|
||||
self->params.egl->glBindFramebuffer(GL_FRAMEBUFFER, self->framebuffers[0]);
|
||||
//cap_xcomp->params.egl->glClear(GL_COLOR_BUFFER_BIT); // TODO: Do this in a separate clear_ function. We want to do that when using multiple drm to create the final image (multiple monitors for example)
|
||||
|
||||
const int shader_index = external_texture ? GRAPHICS_SHADER_INDEX_YUYV_TO_RGB_EXTERNAL : GRAPHICS_SHADER_INDEX_YUYV_TO_RGB;
|
||||
gsr_shader_use(&self->graphics_shaders[shader_index]);
|
||||
self->params.egl->glUniformMatrix2fv(self->graphics_uniforms[shader_index].rotation_matrix, 1, GL_TRUE, (const float*)rotation_matrix);
|
||||
self->params.egl->glUniform2f(self->graphics_uniforms[shader_index].offset, pos_norm.x, pos_norm.y);
|
||||
self->params.egl->glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||
int shader_index = external_texture ? GRAPHICS_SHADER_INDEX_YUYV_TO_Y_EXTERNAL : GRAPHICS_SHADER_INDEX_YUYV_TO_Y;
|
||||
gsr_shader_use(&self->graphics_shaders[shader_index]);
|
||||
self->params.egl->glUniformMatrix2fv(self->graphics_uniforms[shader_index].rotation_matrix, 1, GL_TRUE, (const float*)rotation_matrix);
|
||||
self->params.egl->glUniform2f(self->graphics_uniforms[shader_index].offset, pos_norm.x, pos_norm.y);
|
||||
self->params.egl->glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||
|
||||
if(self->params.num_destination_textures > 1) {
|
||||
self->params.egl->glBindFramebuffer(GL_FRAMEBUFFER, self->framebuffers[1]);
|
||||
//cap_xcomp->params.egl->glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
shader_index = external_texture ? GRAPHICS_SHADER_INDEX_YUYV_TO_UV_EXTERNAL : GRAPHICS_SHADER_INDEX_YUYV_TO_UV;
|
||||
gsr_shader_use(&self->graphics_shaders[shader_index]);
|
||||
self->params.egl->glUniformMatrix2fv(self->graphics_uniforms[shader_index].rotation_matrix, 1, GL_TRUE, (const float*)rotation_matrix);
|
||||
self->params.egl->glUniform2f(self->graphics_uniforms[shader_index].offset, pos_norm.x, pos_norm.y);
|
||||
self->params.egl->glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GSR_DESTINATION_COLOR_RGB8: {
|
||||
self->params.egl->glBindFramebuffer(GL_FRAMEBUFFER, self->framebuffers[0]);
|
||||
//cap_xcomp->params.egl->glClear(GL_COLOR_BUFFER_BIT); // TODO: Do this in a separate clear_ function. We want to do that when using multiple drm to create the final image (multiple monitors for example)
|
||||
|
||||
const int shader_index = external_texture ? GRAPHICS_SHADER_INDEX_YUYV_TO_RGB_EXTERNAL : GRAPHICS_SHADER_INDEX_YUYV_TO_RGB;
|
||||
gsr_shader_use(&self->graphics_shaders[shader_index]);
|
||||
self->params.egl->glUniformMatrix2fv(self->graphics_uniforms[shader_index].rotation_matrix, 1, GL_TRUE, (const float*)rotation_matrix);
|
||||
self->params.egl->glUniform2f(self->graphics_uniforms[shader_index].offset, pos_norm.x, pos_norm.y);
|
||||
self->params.egl->glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
self->params.egl->glBindVertexArray(0);
|
||||
self->params.egl->glUseProgram(0);
|
||||
gsr_color_conversion_swizzle_reset(self, source_color);
|
||||
gsr_color_conversion_swizzle_reset(self, texture_target, source_color);
|
||||
self->params.egl->glBindTexture(texture_target, 0);
|
||||
self->params.egl->glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
@@ -710,7 +888,6 @@ void gsr_color_conversion_draw(gsr_color_conversion *self, unsigned int texture_
|
||||
|
||||
const int texture_target = external_texture ? GL_TEXTURE_EXTERNAL_OES : GL_TEXTURE_2D;
|
||||
self->params.egl->glBindTexture(texture_target, texture_id);
|
||||
gsr_color_conversion_swizzle_texture_source(self, source_color);
|
||||
|
||||
source_position.x += source_pos.x;
|
||||
source_position.y += source_pos.y;
|
||||
@@ -721,7 +898,6 @@ void gsr_color_conversion_draw(gsr_color_conversion *self, unsigned int texture_
|
||||
self->params.egl->glMemoryBarrier(GL_ALL_BARRIER_BITS); // GL_SHADER_IMAGE_ACCESS_BARRIER_BIT
|
||||
self->params.egl->glUseProgram(0);
|
||||
|
||||
gsr_color_conversion_swizzle_reset(self, source_color);
|
||||
self->params.egl->glBindTexture(texture_target, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -333,10 +333,6 @@ static bool gsr_egl_load_gl(gsr_egl *self, void *library) {
|
||||
{ (void**)&self->glUnmapBuffer, "glUnmapBuffer" },
|
||||
{ (void**)&self->glGetIntegerv, "glGetIntegerv" },
|
||||
|
||||
{ (void**)&self->glFenceSync, "glFenceSync" },
|
||||
{ (void**)&self->glDeleteSync, "glDeleteSync" },
|
||||
{ (void**)&self->glClientWaitSync, "glClientWaitSync" },
|
||||
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user