aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/color_conversion.c683
-rw-r--r--src/egl.c8
-rw-r--r--src/encoder/video/vulkan.c267
-rw-r--r--src/main.cpp41
-rw-r--r--src/shader.c20
-rw-r--r--src/utils.c19
-rw-r--r--src/window/wayland.c10
7 files changed, 732 insertions, 316 deletions
diff --git a/src/color_conversion.c b/src/color_conversion.c
index 1f95fd3..88dc398 100644
--- a/src/color_conversion.c
+++ b/src/color_conversion.c
@@ -5,18 +5,25 @@
#include <string.h>
#include <assert.h>
-#define SHADER_INDEX_Y 0
-#define SHADER_INDEX_UV 1
-#define SHADER_INDEX_Y_EXTERNAL 2
-#define SHADER_INDEX_UV_EXTERNAL 3
-#define SHADER_INDEX_RGB 4
-#define SHADER_INDEX_RGB_EXTERNAL 5
-#define SHADER_INDEX_Y_BLEND 6
-#define SHADER_INDEX_UV_BLEND 7
-#define SHADER_INDEX_Y_EXTERNAL_BLEND 8
-#define SHADER_INDEX_UV_EXTERNAL_BLEND 9
-#define SHADER_INDEX_RGB_BLEND 10
-#define SHADER_INDEX_RGB_EXTERNAL_BLEND 11
+#define COMPUTE_SHADER_INDEX_Y 0
+#define COMPUTE_SHADER_INDEX_UV 1
+#define COMPUTE_SHADER_INDEX_Y_EXTERNAL 2
+#define COMPUTE_SHADER_INDEX_UV_EXTERNAL 3
+#define COMPUTE_SHADER_INDEX_RGB 4
+#define COMPUTE_SHADER_INDEX_RGB_EXTERNAL 5
+#define COMPUTE_SHADER_INDEX_Y_BLEND 6
+#define COMPUTE_SHADER_INDEX_UV_BLEND 7
+#define COMPUTE_SHADER_INDEX_Y_EXTERNAL_BLEND 8
+#define COMPUTE_SHADER_INDEX_UV_EXTERNAL_BLEND 9
+#define COMPUTE_SHADER_INDEX_RGB_BLEND 10
+#define COMPUTE_SHADER_INDEX_RGB_EXTERNAL_BLEND 11
+
+#define GRAPHICS_SHADER_INDEX_Y 0
+#define GRAPHICS_SHADER_INDEX_UV 1
+#define GRAPHICS_SHADER_INDEX_Y_EXTERNAL 2
+#define GRAPHICS_SHADER_INDEX_UV_EXTERNAL 3
+#define GRAPHICS_SHADER_INDEX_RGB 4
+#define GRAPHICS_SHADER_INDEX_RGB_EXTERNAL 5
/* https://en.wikipedia.org/wiki/YCbCr, see study/color_space_transform_matrix.png */
@@ -78,18 +85,35 @@ static const char* color_format_range_get_transform_matrix(gsr_destination_color
return NULL;
}
-static int load_compute_shader_y(gsr_shader *shader, gsr_egl *egl, gsr_color_uniforms *uniforms, int max_local_size_dim, gsr_destination_color color_format, gsr_color_range color_range, bool external_texture, bool alpha_blending) {
+static void get_compute_shader_header(char *header, size_t header_size, bool external_texture) {
+ if(external_texture) {
+ snprintf(header, header_size,
+ "#version 310 es\n"
+ "#extension GL_ARB_compute_shader: enable\n"
+ "#extension GL_OES_EGL_image_external : enable\n"
+ "#extension GL_OES_EGL_image_external_essl3 : require\n"
+ "layout(binding = 0) uniform highp samplerExternalOES img_input;\n"
+ "layout(binding = 1) uniform highp sampler2D img_background;\n");
+ } else {
+ snprintf(header, header_size,
+ "#version 420\n"
+ "#extension GL_ARB_compute_shader: enable\n"
+ "layout(binding = 0) uniform highp sampler2D img_input;\n"
+ "layout(binding = 1) uniform highp sampler2D img_background;\n");
+ }
+}
+
+static int load_compute_shader_y(gsr_shader *shader, gsr_egl *egl, gsr_color_compute_uniforms *uniforms, int max_local_size_dim, gsr_destination_color color_format, gsr_color_range color_range, bool external_texture, bool alpha_blending) {
const char *color_transform_matrix = color_format_range_get_transform_matrix(color_format, color_range);
+ char header[512];
+ get_compute_shader_header(header, sizeof(header), external_texture);
+
char compute_shader[2048];
snprintf(compute_shader, sizeof(compute_shader),
- "#version 310 es\n"
- "#extension GL_OES_EGL_image_external : enable\n"
- "#extension GL_OES_EGL_image_external_essl3 : require\n"
- "precision highp float;\n"
+ "%s"
"layout (local_size_x = %d, local_size_y = %d, local_size_z = 1) in;\n"
- "layout(binding = 0) uniform highp %s img_input;\n"
- "layout(binding = 1) uniform highp sampler2D img_background;\n"
+ "precision highp float;\n"
"uniform ivec2 source_position;\n"
"uniform ivec2 target_position;\n"
"uniform vec2 scale;\n"
@@ -103,13 +127,13 @@ static int load_compute_shader_y(gsr_shader *shader, gsr_egl *egl, gsr_color_uni
" ivec2 output_size = textureSize(img_background, 0);\n"
" vec2 rotated_texel_coord = vec2(texel_coord - source_position - size_shift) * rotation_matrix + vec2(size_shift) + 0.5;\n"
" vec2 output_texel_coord = vec2(texel_coord - source_position + target_position) + 0.5;\n"
- " vec4 source_color = texelFetch(img_input, ivec2(rotated_texel_coord), 0);\n"
+ " vec4 source_color = texture(img_input, rotated_texel_coord/vec2(size));\n"
" vec4 source_color_yuv = RGBtoYUV * vec4(source_color.rgb, 1.0);\n"
" vec4 output_color_yuv = %s;\n"
" float y_color = mix(output_color_yuv.r, source_color_yuv.r, source_color.a);\n"
" imageStore(img_output, texel_coord + target_position, vec4(y_color, 1.0, 1.0, 1.0));\n"
- "}\n", max_local_size_dim, max_local_size_dim, external_texture ? "samplerExternalOES" : "sampler2D", color_transform_matrix,
- alpha_blending ? "texelFetch(img_background, ivec2(output_texel_coord), 0)" : "source_color_yuv");
+ "}\n", header, max_local_size_dim, max_local_size_dim, color_transform_matrix,
+ alpha_blending ? "texture(img_background, output_texel_coord/vec2(output_size))" : "source_color_yuv");
if(gsr_shader_init(shader, egl, NULL, NULL, compute_shader) != 0)
return -1;
@@ -121,18 +145,17 @@ static int load_compute_shader_y(gsr_shader *shader, gsr_egl *egl, gsr_color_uni
return 0;
}
-static int load_compute_shader_uv(gsr_shader *shader, gsr_egl *egl, gsr_color_uniforms *uniforms, int max_local_size_dim, gsr_destination_color color_format, gsr_color_range color_range, bool external_texture, bool alpha_blending) {
+static int load_compute_shader_uv(gsr_shader *shader, gsr_egl *egl, gsr_color_compute_uniforms *uniforms, int max_local_size_dim, gsr_destination_color color_format, gsr_color_range color_range, bool external_texture, bool alpha_blending) {
const char *color_transform_matrix = color_format_range_get_transform_matrix(color_format, color_range);
+ char header[512];
+ get_compute_shader_header(header, sizeof(header), external_texture);
+
char compute_shader[2048];
snprintf(compute_shader, sizeof(compute_shader),
- "#version 310 es\n"
- "#extension GL_OES_EGL_image_external : enable\n"
- "#extension GL_OES_EGL_image_external_essl3 : require\n"
- "precision highp float;\n"
+ "%s"
"layout (local_size_x = %d, local_size_y = %d, local_size_z = 1) in;\n"
- "layout(binding = 0) uniform highp %s img_input;\n"
- "layout(binding = 1) uniform highp sampler2D img_background;\n"
+ "precision highp float;\n"
"uniform ivec2 source_position;\n"
"uniform ivec2 target_position;\n"
"uniform vec2 scale;\n"
@@ -146,13 +169,13 @@ static int load_compute_shader_uv(gsr_shader *shader, gsr_egl *egl, gsr_color_un
" ivec2 output_size = textureSize(img_background, 0);\n"
" vec2 rotated_texel_coord = vec2(texel_coord - source_position - size_shift) * rotation_matrix + vec2(size_shift) + 0.5;\n"
" vec2 output_texel_coord = vec2(texel_coord - source_position + target_position) + 0.5;\n"
- " vec4 source_color = texelFetch(img_input, ivec2(rotated_texel_coord) << 1, 0);\n"
+ " vec4 source_color = texture(img_input, rotated_texel_coord/vec2(size>>1));\n" // size/2
" vec4 source_color_yuv = RGBtoYUV * vec4(source_color.rgb, 1.0);\n"
" vec4 output_color_yuv = %s;\n"
" vec2 uv_color = mix(output_color_yuv.rg, source_color_yuv.gb, source_color.a);\n"
" imageStore(img_output, texel_coord + target_position, vec4(uv_color, 1.0, 1.0));\n"
- "}\n", max_local_size_dim, max_local_size_dim, external_texture ? "samplerExternalOES" : "sampler2D", color_transform_matrix,
- alpha_blending ? "texelFetch(img_background, ivec2(output_texel_coord), 0)" : "source_color_yuv");
+ "}\n", header, max_local_size_dim, max_local_size_dim, color_transform_matrix,
+ alpha_blending ? "texture(img_background, output_texel_coord/vec2(output_size))" : "source_color_yuv");
if(gsr_shader_init(shader, egl, NULL, NULL, compute_shader) != 0)
return -1;
@@ -164,16 +187,14 @@ static int load_compute_shader_uv(gsr_shader *shader, gsr_egl *egl, gsr_color_un
return 0;
}
-static int load_compute_shader_rgb(gsr_shader *shader, gsr_egl *egl, gsr_color_uniforms *uniforms, int max_local_size_dim, bool external_texture, bool alpha_blending) {
+static int load_compute_shader_rgb(gsr_shader *shader, gsr_egl *egl, gsr_color_compute_uniforms *uniforms, int max_local_size_dim, bool external_texture, bool alpha_blending) {
+ char header[512];
+ get_compute_shader_header(header, sizeof(header), external_texture);
+
char compute_shader[2048];
snprintf(compute_shader, sizeof(compute_shader),
- "#version 310 es\n"
- "#extension GL_OES_EGL_image_external : enable\n"
- "#extension GL_OES_EGL_image_external_essl3 : require\n"
- "precision highp float;\n"
+ "%s"
"layout (local_size_x = %d, local_size_y = %d, local_size_z = 1) in;\n"
- "layout(binding = 0) uniform highp %s img_input;\n"
- "layout(binding = 1) uniform highp sampler2D img_background;\n"
"uniform ivec2 source_position;\n"
"uniform ivec2 target_position;\n"
"uniform vec2 scale;\n"
@@ -186,12 +207,12 @@ static int load_compute_shader_rgb(gsr_shader *shader, gsr_egl *egl, gsr_color_u
" ivec2 output_size = textureSize(img_background, 0);\n"
" vec2 rotated_texel_coord = vec2(texel_coord - source_position - size_shift) * rotation_matrix + vec2(size_shift) + 0.5;\n"
" vec2 output_texel_coord = vec2(texel_coord - source_position + target_position) + 0.5;\n"
- " vec4 source_color = texelFetch(img_input, ivec2(rotated_texel_coord), 0);\n"
+ " vec4 source_color = texture(img_input, rotated_texel_coord/vec2(size));\n"
" vec4 output_color = %s;\n"
" vec3 color = mix(output_color.rgb, source_color.rgb, source_color.a);\n"
" imageStore(img_output, texel_coord + target_position, vec4(color, 1.0));\n"
- "}\n", max_local_size_dim, max_local_size_dim, external_texture ? "samplerExternalOES" : "sampler2D",
- alpha_blending ? "texelFetch(img_background, ivec2(output_texel_coord), 0)" : "source_color");
+ "}\n", header, max_local_size_dim, max_local_size_dim,
+ alpha_blending ? "texture(img_background, output_texel_coord/vec2(output_size))" : "source_color");
if(gsr_shader_init(shader, egl, NULL, NULL, compute_shader) != 0)
return -1;
@@ -203,6 +224,190 @@ static int load_compute_shader_rgb(gsr_shader *shader, gsr_egl *egl, gsr_color_u
return 0;
}
+static int load_graphics_shader_y(gsr_shader *shader, gsr_egl *egl, gsr_color_graphics_uniforms *uniforms, gsr_destination_color color_format, gsr_color_range color_range, bool external_texture) {
+ const char *color_transform_matrix = color_format_range_get_transform_matrix(color_format, color_range);
+
+ 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 =
+ main_code =
+ " vec4 pixel = texture(tex1, texcoords_out); \n"
+ " FragColor.x = (RGBtoYUV * vec4(pixel.rgb, 1.0)).x; \n"
+ " FragColor.w = pixel.a; \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"
+ "%s"
+ "void main() \n"
+ "{ \n"
+ "%s"
+ "} \n", color_transform_matrix, 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"
+ "%s"
+ "void main() \n"
+ "{ \n"
+ "%s"
+ "} \n", color_transform_matrix, main_code);
+ }
+
+ if(gsr_shader_init(shader, egl, vertex_shader, fragment_shader, NULL) != 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_uv(gsr_shader *shader, gsr_egl *egl, gsr_color_graphics_uniforms *uniforms, gsr_destination_color color_format, gsr_color_range color_range, bool external_texture) {
+ const char *color_transform_matrix = color_format_range_get_transform_matrix(color_format, color_range);
+
+ 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 =
+ main_code =
+ " vec4 pixel = texture(tex1, texcoords_out); \n"
+ " FragColor.xy = (RGBtoYUV * vec4(pixel.rgb, 1.0)).yz; \n"
+ " FragColor.w = pixel.a; \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"
+ "%s"
+ "void main() \n"
+ "{ \n"
+ "%s"
+ "} \n", color_transform_matrix, 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"
+ "%s"
+ "void main() \n"
+ "{ \n"
+ "%s"
+ "} \n", color_transform_matrix, main_code);
+ }
+
+ if(gsr_shader_init(shader, egl, vertex_shader, fragment_shader, NULL) != 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_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),
+ "#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 =
+ main_code =
+ " vec4 pixel = texture(tex1, texcoords_out); \n"
+ " FragColor = pixel; \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, NULL) != 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 int load_framebuffers(gsr_color_conversion *self) {
/* TODO: Only generate the necessary amount of framebuffers (self->params.num_destination_textures) */
const unsigned int draw_buffer = GL_COLOR_ATTACHMENT0;
@@ -252,97 +457,183 @@ static int create_vertices(gsr_color_conversion *self) {
return 0;
}
-int gsr_color_conversion_init(gsr_color_conversion *self, const gsr_color_conversion_params *params) {
- assert(params);
- assert(params->egl);
- memset(self, 0, sizeof(*self));
- self->params.egl = params->egl;
- self->params = *params;
-
- int max_compute_work_group_invocations = 256;
- self->params.egl->glGetIntegerv(GL_MAX_COMPUTE_FIXED_GROUP_INVOCATIONS, &max_compute_work_group_invocations);
- self->max_local_size_dim = sqrt(max_compute_work_group_invocations);
-
- switch(params->destination_color) {
+static bool gsr_color_conversion_load_compute_shaders(gsr_color_conversion *self) {
+ switch(self->params.destination_color) {
case GSR_DESTINATION_COLOR_NV12:
case GSR_DESTINATION_COLOR_P010: {
- if(self->params.num_destination_textures != 2) {
- fprintf(stderr, "gsr error: gsr_color_conversion_init: expected 2 destination textures for destination color NV12/P010, got %d destination texture(s)\n", self->params.num_destination_textures);
- return -1;
+ if(load_compute_shader_y(&self->compute_shaders[COMPUTE_SHADER_INDEX_Y], self->params.egl, &self->compute_uniforms[COMPUTE_SHADER_INDEX_Y], self->max_local_size_dim, self->params.destination_color, self->params.color_range, false, false) != 0) {
+ fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load Y compute shader\n");
+ return false;
}
- if(load_compute_shader_y(&self->shaders[SHADER_INDEX_Y], self->params.egl, &self->uniforms[SHADER_INDEX_Y], self->max_local_size_dim, params->destination_color, params->color_range, false, false) != 0) {
+ if(load_compute_shader_uv(&self->compute_shaders[COMPUTE_SHADER_INDEX_UV], self->params.egl, &self->compute_uniforms[COMPUTE_SHADER_INDEX_UV], self->max_local_size_dim, self->params.destination_color, self->params.color_range, false, false) != 0) {
+ fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load UV compute shader\n");
+ return false;
+ }
+
+ if(load_compute_shader_y(&self->compute_shaders[COMPUTE_SHADER_INDEX_Y_BLEND], self->params.egl, &self->compute_uniforms[COMPUTE_SHADER_INDEX_Y_BLEND], self->max_local_size_dim, self->params.destination_color, self->params.color_range, false, true) != 0) {
fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load Y compute shader\n");
- goto err;
+ return false;
}
- if(load_compute_shader_uv(&self->shaders[SHADER_INDEX_UV], self->params.egl, &self->uniforms[SHADER_INDEX_UV], self->max_local_size_dim, params->destination_color, params->color_range, false, false) != 0) {
+ if(load_compute_shader_uv(&self->compute_shaders[COMPUTE_SHADER_INDEX_UV_BLEND], self->params.egl, &self->compute_uniforms[COMPUTE_SHADER_INDEX_UV_BLEND], self->max_local_size_dim, self->params.destination_color, self->params.color_range, false, true) != 0) {
fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load UV compute shader\n");
- goto err;
+ return false;
+ }
+ break;
+ }
+ case GSR_DESTINATION_COLOR_RGB8: {
+ if(load_compute_shader_rgb(&self->compute_shaders[COMPUTE_SHADER_INDEX_RGB], self->params.egl, &self->compute_uniforms[COMPUTE_SHADER_INDEX_RGB], self->max_local_size_dim, false, false) != 0) {
+ fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load Y compute shader\n");
+ return false;
}
- if(load_compute_shader_y(&self->shaders[SHADER_INDEX_Y_BLEND], self->params.egl, &self->uniforms[SHADER_INDEX_Y_BLEND], self->max_local_size_dim, params->destination_color, params->color_range, false, true) != 0) {
+ if(load_compute_shader_rgb(&self->compute_shaders[COMPUTE_SHADER_INDEX_RGB_BLEND], self->params.egl, &self->compute_uniforms[COMPUTE_SHADER_INDEX_RGB_BLEND], self->max_local_size_dim, false, true) != 0) {
fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load Y compute shader\n");
- goto err;
+ return false;
}
+ break;
+ }
+ }
+ return true;
+}
- if(load_compute_shader_uv(&self->shaders[SHADER_INDEX_UV_BLEND], self->params.egl, &self->uniforms[SHADER_INDEX_UV_BLEND], self->max_local_size_dim, params->destination_color, params->color_range, false, true) != 0) {
+static bool gsr_color_conversion_load_external_compute_shaders(gsr_color_conversion *self) {
+ switch(self->params.destination_color) {
+ case GSR_DESTINATION_COLOR_NV12:
+ case GSR_DESTINATION_COLOR_P010: {
+ if(load_compute_shader_y(&self->compute_shaders[COMPUTE_SHADER_INDEX_Y_EXTERNAL], self->params.egl, &self->compute_uniforms[COMPUTE_SHADER_INDEX_Y_EXTERNAL], self->max_local_size_dim, self->params.destination_color, self->params.color_range, true, false) != 0) {
+ fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load Y compute shader\n");
+ return false;
+ }
+
+ if(load_compute_shader_uv(&self->compute_shaders[COMPUTE_SHADER_INDEX_UV_EXTERNAL], self->params.egl, &self->compute_uniforms[COMPUTE_SHADER_INDEX_UV_EXTERNAL], self->max_local_size_dim, self->params.destination_color, self->params.color_range, true, false) != 0) {
fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load UV compute shader\n");
- goto err;
+ return false;
+ }
+
+ if(load_compute_shader_y(&self->compute_shaders[COMPUTE_SHADER_INDEX_Y_EXTERNAL_BLEND], self->params.egl, &self->compute_uniforms[COMPUTE_SHADER_INDEX_Y_EXTERNAL_BLEND], self->max_local_size_dim, self->params.destination_color, self->params.color_range, true, true) != 0) {
+ fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load Y compute shader\n");
+ return false;
}
- if(self->params.load_external_image_shader) {
- if(load_compute_shader_y(&self->shaders[SHADER_INDEX_Y_EXTERNAL], self->params.egl, &self->uniforms[SHADER_INDEX_Y_EXTERNAL], self->max_local_size_dim, params->destination_color, params->color_range, true, false) != 0) {
- fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load Y compute shader\n");
- goto err;
- }
-
- if(load_compute_shader_uv(&self->shaders[SHADER_INDEX_UV_EXTERNAL], self->params.egl, &self->uniforms[SHADER_INDEX_UV_EXTERNAL], self->max_local_size_dim, params->destination_color, params->color_range, true, false) != 0) {
- fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load UV compute shader\n");
- goto err;
- }
-
- if(load_compute_shader_y(&self->shaders[SHADER_INDEX_Y_EXTERNAL_BLEND], self->params.egl, &self->uniforms[SHADER_INDEX_Y_EXTERNAL_BLEND], self->max_local_size_dim, params->destination_color, params->color_range, true, true) != 0) {
- fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load Y compute shader\n");
- goto err;
- }
-
- if(load_compute_shader_uv(&self->shaders[SHADER_INDEX_UV_EXTERNAL_BLEND], self->params.egl, &self->uniforms[SHADER_INDEX_UV_EXTERNAL_BLEND], self->max_local_size_dim, params->destination_color, params->color_range, true, true) != 0) {
- fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load UV compute shader\n");
- goto err;
- }
+ if(load_compute_shader_uv(&self->compute_shaders[COMPUTE_SHADER_INDEX_UV_EXTERNAL_BLEND], self->params.egl, &self->compute_uniforms[COMPUTE_SHADER_INDEX_UV_EXTERNAL_BLEND], self->max_local_size_dim, self->params.destination_color, self->params.color_range, true, true) != 0) {
+ fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load UV compute shader\n");
+ return false;
}
break;
}
case GSR_DESTINATION_COLOR_RGB8: {
- if(self->params.num_destination_textures != 1) {
- fprintf(stderr, "gsr error: gsr_color_conversion_init: expected 1 destination textures for destination color RGB8, got %d destination texture(s)\n", self->params.num_destination_textures);
- return -1;
+ if(load_compute_shader_rgb(&self->compute_shaders[COMPUTE_SHADER_INDEX_RGB_EXTERNAL], self->params.egl, &self->compute_uniforms[COMPUTE_SHADER_INDEX_RGB_EXTERNAL], self->max_local_size_dim, true, false) != 0) {
+ fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load Y compute shader\n");
+ return false;
}
- if(load_compute_shader_rgb(&self->shaders[SHADER_INDEX_RGB], self->params.egl, &self->uniforms[SHADER_INDEX_RGB], self->max_local_size_dim, false, false) != 0) {
+ if(load_compute_shader_rgb(&self->compute_shaders[COMPUTE_SHADER_INDEX_RGB_EXTERNAL_BLEND], self->params.egl, &self->compute_uniforms[COMPUTE_SHADER_INDEX_RGB_EXTERNAL_BLEND], self->max_local_size_dim, true, true) != 0) {
fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load Y compute shader\n");
- goto err;
+ return false;
}
+ break;
+ }
+ }
+ return true;
+}
- if(load_compute_shader_rgb(&self->shaders[SHADER_INDEX_RGB_BLEND], self->params.egl, &self->uniforms[SHADER_INDEX_RGB_BLEND], self->max_local_size_dim, false, true) != 0) {
- fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load Y compute shader\n");
- goto err;
+static bool gsr_color_conversion_load_graphics_shaders(gsr_color_conversion *self) {
+ switch(self->params.destination_color) {
+ case GSR_DESTINATION_COLOR_NV12:
+ case GSR_DESTINATION_COLOR_P010: {
+ if(load_graphics_shader_y(&self->graphics_shaders[GRAPHICS_SHADER_INDEX_Y], self->params.egl, &self->graphics_uniforms[GRAPHICS_SHADER_INDEX_Y], self->params.destination_color, self->params.color_range, false) != 0) {
+ fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load Y graphics shader\n");
+ return false;
+ }
+
+ if(load_graphics_shader_uv(&self->graphics_shaders[GRAPHICS_SHADER_INDEX_UV], self->params.egl, &self->graphics_uniforms[GRAPHICS_SHADER_INDEX_UV], self->params.destination_color, self->params.color_range, false) != 0) {
+ fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load UV graphics shader\n");
+ return false;
+ }
+ break;
+ }
+ case GSR_DESTINATION_COLOR_RGB8: {
+ if(load_graphics_shader_rgb(&self->graphics_shaders[GRAPHICS_SHADER_INDEX_RGB], self->params.egl, &self->graphics_uniforms[GRAPHICS_SHADER_INDEX_RGB], false) != 0) {
+ fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load Y graphics shader\n");
+ return false;
}
+ break;
+ }
+ }
+ return true;
+}
- if(self->params.load_external_image_shader) {
- if(load_compute_shader_rgb(&self->shaders[SHADER_INDEX_RGB_EXTERNAL], self->params.egl, &self->uniforms[SHADER_INDEX_RGB_EXTERNAL], self->max_local_size_dim, true, false) != 0) {
- fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load Y compute shader\n");
- goto err;
- }
+static bool gsr_color_conversion_load_external_graphics_shaders(gsr_color_conversion *self) {
+ switch(self->params.destination_color) {
+ case GSR_DESTINATION_COLOR_NV12:
+ case GSR_DESTINATION_COLOR_P010: {
+ if(load_graphics_shader_y(&self->graphics_shaders[GRAPHICS_SHADER_INDEX_Y_EXTERNAL], self->params.egl, &self->graphics_uniforms[GRAPHICS_SHADER_INDEX_Y_EXTERNAL], self->params.destination_color, self->params.color_range, true) != 0) {
+ fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load Y graphics shader\n");
+ return false;
+ }
+
+ if(load_graphics_shader_uv(&self->graphics_shaders[GRAPHICS_SHADER_INDEX_UV_EXTERNAL], self->params.egl, &self->graphics_uniforms[GRAPHICS_SHADER_INDEX_UV_EXTERNAL], self->params.destination_color, self->params.color_range, true) != 0) {
+ fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load UV graphics shader\n");
+ return false;
+ }
+ break;
+ }
+ case GSR_DESTINATION_COLOR_RGB8: {
+ if(load_graphics_shader_rgb(&self->graphics_shaders[GRAPHICS_SHADER_INDEX_RGB_EXTERNAL], self->params.egl, &self->graphics_uniforms[GRAPHICS_SHADER_INDEX_RGB_EXTERNAL], true) != 0) {
+ fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load Y graphics shader\n");
+ return false;
+ }
+ break;
+ }
+ }
+ return true;
+}
+
+int gsr_color_conversion_init(gsr_color_conversion *self, const gsr_color_conversion_params *params) {
+ assert(params);
+ assert(params->egl);
+ memset(self, 0, sizeof(*self));
+ self->params.egl = params->egl;
+ self->params = *params;
+
+ int max_compute_work_group_invocations = 256;
+ self->params.egl->glGetIntegerv(GL_MAX_COMPUTE_FIXED_GROUP_INVOCATIONS, &max_compute_work_group_invocations);
+ self->max_local_size_dim = sqrt(max_compute_work_group_invocations);
- if(load_compute_shader_rgb(&self->shaders[SHADER_INDEX_RGB_EXTERNAL_BLEND], self->params.egl, &self->uniforms[SHADER_INDEX_RGB_EXTERNAL_BLEND], self->max_local_size_dim, true, true) != 0) {
- fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load Y compute shader\n");
- goto err;
- }
+ switch(self->params.destination_color) {
+ case GSR_DESTINATION_COLOR_NV12:
+ case GSR_DESTINATION_COLOR_P010: {
+ if(self->params.num_destination_textures != 2) {
+ fprintf(stderr, "gsr error: gsr_color_conversion_init: expected 2 destination textures for destination color NV12/P010, got %d destination texture(s)\n", self->params.num_destination_textures);
+ goto err;
}
break;
}
+ case GSR_DESTINATION_COLOR_RGB8: {
+ if(self->params.num_destination_textures != 1) {
+ fprintf(stderr, "gsr error: gsr_color_conversion_init: expected 1 destination textures for destination color RGB8, got %d destination texture(s)\n", self->params.num_destination_textures);
+ goto err;
+ }
+ break;
+ }
+ }
+
+ if(!gsr_color_conversion_load_compute_shaders(self)) {
+ self->compute_shaders_failed_to_load = true;
+ fprintf(stderr, "gsr info: failed to load one or more compute shaders, run gpu-screen-recorder with the '-gl-debug yes' option to see why. Falling back to slower graphics shader instead\n");
+ if(!gsr_color_conversion_load_graphics_shaders(self))
+ goto err;
+ }
+
+ if(self->params.load_external_image_shader) {
+ if(!gsr_color_conversion_load_external_compute_shaders(self)) {
+ self->external_compute_shaders_failed_to_load = true;
+ fprintf(stderr, "gsr info: failed to load one or more external compute shaders, run gpu-screen-recorder with the '-gl-debug yes' option to see why. Falling back to slower graphics shader instead\n");
+ if(!gsr_color_conversion_load_external_graphics_shaders(self))
+ goto err;
+ }
}
if(load_framebuffers(self) != 0)
@@ -377,14 +668,18 @@ void gsr_color_conversion_deinit(gsr_color_conversion *self) {
self->framebuffers[i] = 0;
}
- for(int i = 0; i < GSR_COLOR_CONVERSION_MAX_SHADERS; ++i) {
- gsr_shader_deinit(&self->shaders[i]);
+ for(int i = 0; i < GSR_COLOR_CONVERSION_MAX_COMPUTE_SHADERS; ++i) {
+ gsr_shader_deinit(&self->compute_shaders[i]);
+ }
+
+ for(int i = 0; i < GSR_COLOR_CONVERSION_MAX_GRAPHICS_SHADERS; ++i) {
+ gsr_shader_deinit(&self->graphics_shaders[i]);
}
self->params.egl = NULL;
}
-static void gsr_color_conversion_apply_rotation(gsr_rotation rotation, float rotation_matrix[2][2], vec2i *source_position, vec2i texture_size, vec2f scale) {
+static void gsr_color_conversion_apply_rotation(gsr_rotation rotation, float rotation_matrix[2][2]) {
/*
rotation_matrix[0][0] = cos(angle);
rotation_matrix[0][1] = -sin(angle);
@@ -405,8 +700,6 @@ static void gsr_color_conversion_apply_rotation(gsr_rotation rotation, float rot
rotation_matrix[0][1] = -1.0f;
rotation_matrix[1][0] = 1.0f;
rotation_matrix[1][1] = 0.0f;
- source_position->x += (((double)texture_size.x*0.5 - (double)texture_size.y*0.5) * scale.x + 0.5);
- source_position->y += (((double)texture_size.y*0.5 - (double)texture_size.x*0.5) * scale.y + 0.5);
break;
case GSR_ROT_180:
rotation_matrix[0][0] = -1.0f;
@@ -419,8 +712,6 @@ static void gsr_color_conversion_apply_rotation(gsr_rotation rotation, float rot
rotation_matrix[0][1] = 1.0f;
rotation_matrix[1][0] = -1.0f;
rotation_matrix[1][1] = 0.0f;
- source_position->x += (((double)texture_size.x*0.5 - (double)texture_size.y*0.5) * scale.x + 0.5);
- source_position->y += (((double)texture_size.y*0.5 - (double)texture_size.x*0.5) * scale.y + 0.5);
break;
}
}
@@ -465,33 +756,33 @@ static unsigned int color_component_get_color_format(gsr_color_component color_c
return GL_RGBA8;
}
-static int color_component_get_shader_index(gsr_color_component color_component, bool external_texture, bool alpha_blending) {
+static int color_component_get_COMPUTE_SHADER_INDEX(gsr_color_component color_component, bool external_texture, bool alpha_blending) {
switch(color_component) {
case GSR_COLOR_COMP_Y: {
if(external_texture)
- return alpha_blending ? SHADER_INDEX_Y_EXTERNAL_BLEND : SHADER_INDEX_Y_EXTERNAL;
+ return alpha_blending ? COMPUTE_SHADER_INDEX_Y_EXTERNAL_BLEND : COMPUTE_SHADER_INDEX_Y_EXTERNAL;
else
- return alpha_blending ? SHADER_INDEX_Y_BLEND : SHADER_INDEX_Y;
+ return alpha_blending ? COMPUTE_SHADER_INDEX_Y_BLEND : COMPUTE_SHADER_INDEX_Y;
}
case GSR_COLOR_COMP_UV: {
if(external_texture)
- return alpha_blending ? SHADER_INDEX_UV_EXTERNAL_BLEND : SHADER_INDEX_UV_EXTERNAL;
+ return alpha_blending ? COMPUTE_SHADER_INDEX_UV_EXTERNAL_BLEND : COMPUTE_SHADER_INDEX_UV_EXTERNAL;
else
- return alpha_blending ? SHADER_INDEX_UV_BLEND : SHADER_INDEX_UV;
+ return alpha_blending ? COMPUTE_SHADER_INDEX_UV_BLEND : COMPUTE_SHADER_INDEX_UV;
}
case GSR_COLOR_COMP_RGB: {
if(external_texture)
- return alpha_blending ? SHADER_INDEX_RGB_EXTERNAL_BLEND : SHADER_INDEX_RGB_EXTERNAL;
+ return alpha_blending ? COMPUTE_SHADER_INDEX_RGB_EXTERNAL_BLEND : COMPUTE_SHADER_INDEX_RGB_EXTERNAL;
else
- return alpha_blending ? SHADER_INDEX_RGB_BLEND : SHADER_INDEX_RGB;
+ return alpha_blending ? COMPUTE_SHADER_INDEX_RGB_BLEND : COMPUTE_SHADER_INDEX_RGB;
}
}
assert(false);
- return SHADER_INDEX_RGB;
+ return COMPUTE_SHADER_INDEX_RGB;
}
static void gsr_color_conversion_dispatch_compute_shader(gsr_color_conversion *self, bool external_texture, bool alpha_blending, float rotation_matrix[2][2], vec2i source_position, vec2i destination_pos, vec2i destination_size, vec2f scale, bool use_16bit_colors, gsr_color_component color_component) {
- const int shader_index = color_component_get_shader_index(color_component, external_texture, alpha_blending);
+ const int compute_shader_index = color_component_get_COMPUTE_SHADER_INDEX(color_component, external_texture, alpha_blending);
const int destination_texture_index = color_component_get_destination_texture_index(color_component);
const unsigned int color_format = color_component_get_color_format(color_component, use_16bit_colors);
@@ -499,8 +790,8 @@ static void gsr_color_conversion_dispatch_compute_shader(gsr_color_conversion *s
self->params.egl->glBindTexture(GL_TEXTURE_2D, self->params.destination_textures[destination_texture_index]);
self->params.egl->glActiveTexture(GL_TEXTURE0);
- gsr_color_uniforms *uniform = &self->uniforms[shader_index];
- gsr_shader_use(&self->shaders[shader_index]);
+ gsr_color_compute_uniforms *uniform = &self->compute_uniforms[compute_shader_index];
+ gsr_shader_use(&self->compute_shaders[compute_shader_index]);
self->params.egl->glUniformMatrix2fv(uniform->rotation_matrix, 1, GL_TRUE, (const float*)rotation_matrix);
self->params.egl->glUniform2i(uniform->source_position, source_position.x, source_position.y);
self->params.egl->glUniform2i(uniform->target_position, destination_pos.x, destination_pos.y);
@@ -511,34 +802,156 @@ static void gsr_color_conversion_dispatch_compute_shader(gsr_color_conversion *s
self->params.egl->glDispatchCompute(max_int(1, num_groups_x), max_int(1, num_groups_y), 1);
}
+static void gsr_color_conversion_draw_graphics(gsr_color_conversion *self, unsigned int texture_id, bool external_texture, float rotation_matrix[2][2], vec2i source_position, vec2i source_size, vec2i destination_pos, vec2i texture_size, vec2f scale, gsr_source_color source_color) {
+ /* TODO: Do not call this every frame? */
+ vec2i dest_texture_size = {0, 0};
+ self->params.egl->glBindTexture(GL_TEXTURE_2D, self->params.destination_textures[0]);
+ self->params.egl->glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &dest_texture_size.x);
+ self->params.egl->glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &dest_texture_size.y);
+ self->params.egl->glBindTexture(GL_TEXTURE_2D, 0);
+
+ 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);
+
+ const vec2f pos_norm = {
+ ((float)destination_pos.x / (dest_texture_size.x == 0 ? 1.0f : (float)dest_texture_size.x)) * 2.0f,
+ ((float)destination_pos.y / (dest_texture_size.y == 0 ? 1.0f : (float)dest_texture_size.y)) * 2.0f,
+ };
+
+ const vec2f size_norm = {
+ ((float)source_size.x / (dest_texture_size.x == 0 ? 1.0f : (float)dest_texture_size.x)) * 2.0f * scale.x,
+ ((float)source_size.y / (dest_texture_size.y == 0 ? 1.0f : (float)dest_texture_size.y)) * 2.0f * scale.y,
+ };
+
+ const vec2f texture_pos_norm = {
+ (float)source_position.x / (texture_size.x == 0 ? 1.0f : (float)texture_size.x),
+ (float)source_position.y / (texture_size.y == 0 ? 1.0f : (float)texture_size.y),
+ };
+
+ const vec2f texture_size_norm = {
+ (float)source_size.x / (texture_size.x == 0 ? 1.0f : (float)texture_size.x),
+ (float)source_size.y / (texture_size.y == 0 ? 1.0f : (float)texture_size.y),
+ };
+
+ const float vertices[] = {
+ -1.0f + 0.0f, -1.0f + 0.0f + size_norm.y, texture_pos_norm.x, texture_pos_norm.y + texture_size_norm.y,
+ -1.0f + 0.0f, -1.0f + 0.0f, texture_pos_norm.x, texture_pos_norm.y,
+ -1.0f + 0.0f + size_norm.x, -1.0f + 0.0f, texture_pos_norm.x + texture_size_norm.x, texture_pos_norm.y,
+
+ -1.0f + 0.0f, -1.0f + 0.0f + size_norm.y, texture_pos_norm.x, texture_pos_norm.y + texture_size_norm.y,
+ -1.0f + 0.0f + size_norm.x, -1.0f + 0.0f, texture_pos_norm.x + texture_size_norm.x, texture_pos_norm.y,
+ -1.0f + 0.0f + size_norm.x, -1.0f + 0.0f + size_norm.y, texture_pos_norm.x + texture_size_norm.x, texture_pos_norm.y + texture_size_norm.y
+ };
+
+ self->params.egl->glBindVertexArray(self->vertex_array_object_id);
+ self->params.egl->glViewport(0, 0, dest_texture_size.x, dest_texture_size.y);
+
+ /* TODO: this, also cleanup */
+ //self->params.egl->glBindBuffer(GL_ARRAY_BUFFER, self->vertex_buffer_object_id);
+ self->params.egl->glBufferSubData(GL_ARRAY_BUFFER, 0, 24 * sizeof(float), vertices);
+
+ 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)
+
+ int shader_index = external_texture ? GRAPHICS_SHADER_INDEX_Y_EXTERNAL : GRAPHICS_SHADER_INDEX_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_UV_EXTERNAL : GRAPHICS_SHADER_INDEX_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_RGB_EXTERNAL : GRAPHICS_SHADER_INDEX_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;
+ }
+ }
+
+ self->params.egl->glBindVertexArray(0);
+ self->params.egl->glUseProgram(0);
+ gsr_color_conversion_swizzle_reset(self, source_color);
+ self->params.egl->glBindTexture(texture_target, 0);
+ self->params.egl->glBindFramebuffer(GL_FRAMEBUFFER, 0);
+}
+
void gsr_color_conversion_draw(gsr_color_conversion *self, unsigned int texture_id, vec2i destination_pos, vec2i destination_size, vec2i source_pos, vec2i source_size, vec2i texture_size, gsr_rotation rotation, gsr_source_color source_color, bool external_texture, bool alpha_blending) {
+ assert(!external_texture || self->params.load_external_image_shader);
+ if(external_texture && !self->params.load_external_image_shader) {
+ fprintf(stderr, "gsr error: gsr_color_conversion_draw: external texture not loaded\n");
+ return;
+ }
+
vec2f scale = {0.0f, 0.0f};
if(source_size.x > 0 && source_size.y > 0)
scale = (vec2f){ (double)destination_size.x/(double)source_size.x, (double)destination_size.y/(double)source_size.y };
vec2i source_position = {0, 0};
float rotation_matrix[2][2] = {{0, 0}, {0, 0}};
- gsr_color_conversion_apply_rotation(rotation, rotation_matrix, &source_position, texture_size, scale);
-
- source_position.x -= (source_pos.x * scale.x + 0.5);
- source_position.y -= (source_pos.y * scale.y + 0.5);
+ gsr_color_conversion_apply_rotation(rotation, rotation_matrix);
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);
- switch(self->params.destination_color) {
- case GSR_DESTINATION_COLOR_NV12:
- case GSR_DESTINATION_COLOR_P010: {
- const bool use_16bit_colors = self->params.destination_color == GSR_DESTINATION_COLOR_P010;
- gsr_color_conversion_dispatch_compute_shader(self, external_texture, alpha_blending, rotation_matrix, source_position, destination_pos, destination_size, scale, use_16bit_colors, GSR_COLOR_COMP_Y);
- gsr_color_conversion_dispatch_compute_shader(self, external_texture, alpha_blending, rotation_matrix, (vec2i){source_position.x/2, source_position.y/2},
- (vec2i){destination_pos.x/2, destination_pos.y/2}, (vec2i){destination_size.x/2, destination_size.y/2}, scale, use_16bit_colors, GSR_COLOR_COMP_UV);
- break;
+ const bool use_graphics_shader = external_texture ? self->external_compute_shaders_failed_to_load : self->compute_shaders_failed_to_load;
+ if(use_graphics_shader) {
+ source_position.x += source_pos.x;
+ source_position.y += source_pos.y;
+ gsr_color_conversion_draw_graphics(self, texture_id, external_texture, rotation_matrix, source_position, source_size, destination_pos, texture_size, scale, source_color);
+ // TODO: Is glFlush and glFinish needed here for graphics garbage?
+ } else {
+ switch(rotation) {
+ case GSR_ROT_0:
+ break;
+ case GSR_ROT_90:
+ source_position.x += (((double)texture_size.x*0.5 - (double)texture_size.y*0.5) * scale.x);
+ source_position.y += (((double)texture_size.y*0.5 - (double)texture_size.x*0.5) * scale.y);
+ break;
+ case GSR_ROT_180:
+ break;
+ case GSR_ROT_270:
+ source_position.x += (((double)texture_size.x*0.5 - (double)texture_size.y*0.5) * scale.x);
+ source_position.y += (((double)texture_size.y*0.5 - (double)texture_size.x*0.5) * scale.y);
+ break;
}
- case GSR_DESTINATION_COLOR_RGB8: {
- gsr_color_conversion_dispatch_compute_shader(self, external_texture, alpha_blending, rotation_matrix, source_position, destination_pos, destination_size, scale, false, GSR_COLOR_COMP_RGB);
- break;
+ source_position.x -= (source_pos.x * scale.x + 0.5);
+ source_position.y -= (source_pos.y * scale.y + 0.5);
+
+ switch(self->params.destination_color) {
+ case GSR_DESTINATION_COLOR_NV12:
+ case GSR_DESTINATION_COLOR_P010: {
+ const bool use_16bit_colors = self->params.destination_color == GSR_DESTINATION_COLOR_P010;
+ gsr_color_conversion_dispatch_compute_shader(self, external_texture, alpha_blending, rotation_matrix, source_position, destination_pos, destination_size, scale, use_16bit_colors, GSR_COLOR_COMP_Y);
+ gsr_color_conversion_dispatch_compute_shader(self, external_texture, alpha_blending, rotation_matrix, (vec2i){source_position.x/2, source_position.y/2},
+ (vec2i){destination_pos.x/2, destination_pos.y/2}, (vec2i){destination_size.x/2, destination_size.y/2}, scale, use_16bit_colors, GSR_COLOR_COMP_UV);
+ break;
+ }
+ case GSR_DESTINATION_COLOR_RGB8: {
+ gsr_color_conversion_dispatch_compute_shader(self, external_texture, alpha_blending, rotation_matrix, source_position, destination_pos, destination_size, scale, false, GSR_COLOR_COMP_RGB);
+ break;
+ }
}
}
diff --git a/src/egl.c b/src/egl.c
index 446d105..76ab9ec 100644
--- a/src/egl.c
+++ b/src/egl.c
@@ -225,6 +225,14 @@ static bool gsr_egl_proc_load_egl(gsr_egl *self) {
self->eglQueryDeviceStringEXT = (FUNC_eglQueryDeviceStringEXT)self->eglGetProcAddress("eglQueryDeviceStringEXT");
self->eglQueryDmaBufModifiersEXT = (FUNC_eglQueryDmaBufModifiersEXT)self->eglGetProcAddress("eglQueryDmaBufModifiersEXT");
+ self->glCreateMemoryObjectsEXT = (FUNC_glCreateMemoryObjectsEXT)self->eglGetProcAddress("glCreateMemoryObjectsEXT");
+ self->glImportMemoryFdEXT = (FUNC_glImportMemoryFdEXT)self->eglGetProcAddress("glImportMemoryFdEXT");
+ self->glIsMemoryObjectEXT = (FUNC_glIsMemoryObjectEXT)self->eglGetProcAddress("glIsMemoryObjectEXT");
+ self->glTexStorageMem2DEXT = (FUNC_glTexStorageMem2DEXT)self->eglGetProcAddress("glTexStorageMem2DEXT");
+ self->glBufferStorageMemEXT = (FUNC_glBufferStorageMemEXT)self->eglGetProcAddress("glBufferStorageMemEXT");
+ self->glNamedBufferStorageMemEXT = (FUNC_glNamedBufferStorageMemEXT)self->eglGetProcAddress("glNamedBufferStorageMemEXT");
+ self->glMemoryObjectParameterivEXT = (FUNC_glMemoryObjectParameterivEXT)self->eglGetProcAddress("glMemoryObjectParameterivEXT");
+
if(!self->eglExportDMABUFImageQueryMESA) {
fprintf(stderr, "gsr error: gsr_egl_load failed: could not find eglExportDMABUFImageQueryMESA\n");
return false;
diff --git a/src/encoder/video/vulkan.c b/src/encoder/video/vulkan.c
index 7210870..7643ada 100644
--- a/src/encoder/video/vulkan.c
+++ b/src/encoder/video/vulkan.c
@@ -8,26 +8,15 @@
//#include <vulkan/vulkan_core.h>
+#define GL_HANDLE_TYPE_OPAQUE_FD_EXT 0x9586
#define GL_TEXTURE_TILING_EXT 0x9580
#define GL_OPTIMAL_TILING_EXT 0x9584
#define GL_LINEAR_TILING_EXT 0x9585
-#define GL_PIXEL_PACK_BUFFER 0x88EB
-#define GL_PIXEL_UNPACK_BUFFER 0x88EC
-#define GL_STREAM_READ 0x88E1
-#define GL_STREAM_DRAW 0x88E0
-#define GL_READ_ONLY 0x88B8
-#define GL_WRITE_ONLY 0x88B9
-#define GL_READ_FRAMEBUFFER 0x8CA8
-
typedef struct {
gsr_video_encoder_vulkan_params params;
unsigned int target_textures[2];
AVBufferRef *device_ctx;
- AVVulkanDeviceContext* vv;
- unsigned int pbo_y[2];
- unsigned int pbo_uv[2];
- AVFrame *sw_frame;
} gsr_video_encoder_vulkan;
static bool gsr_video_encoder_vulkan_setup_context(gsr_video_encoder_vulkan *self, AVCodecContext *video_codec_context) {
@@ -84,6 +73,24 @@ static AVVulkanDeviceContext* video_codec_context_get_vulkan_data(AVCodecContext
return (AVVulkanDeviceContext*)device_context->hwctx;
}
+static uint32_t get_memory_type_idx(VkPhysicalDevice pdev, const VkMemoryRequirements *mem_reqs, VkMemoryPropertyFlagBits prop_flags, PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties) {
+ VkPhysicalDeviceMemoryProperties pdev_mem_props;
+ uint32_t i;
+
+ vkGetPhysicalDeviceMemoryProperties(pdev, &pdev_mem_props);
+
+ for (i = 0; i < pdev_mem_props.memoryTypeCount; i++) {
+ const VkMemoryType *type = &pdev_mem_props.memoryTypes[i];
+
+ if ((mem_reqs->memoryTypeBits & (1 << i)) &&
+ (type->propertyFlags & prop_flags) == prop_flags) {
+ return i;
+ break;
+ }
+ }
+ return UINT32_MAX;
+}
+
static bool gsr_video_encoder_vulkan_setup_textures(gsr_video_encoder_vulkan *self, AVCodecContext *video_codec_context, AVFrame *frame) {
const int res = av_hwframe_get_buffer(video_codec_context->hw_frames_ctx, frame, 0);
if(res < 0) {
@@ -91,56 +98,133 @@ static bool gsr_video_encoder_vulkan_setup_textures(gsr_video_encoder_vulkan *se
return false;
}
- //AVVkFrame *target_surface_id = (AVVkFrame*)frame->data[0];
- self->vv = video_codec_context_get_vulkan_data(video_codec_context);
+ while(self->params.egl->glGetError()) {}
+
+ AVVkFrame *target_surface_id = (AVVkFrame*)frame->data[0];
+ AVVulkanDeviceContext* vv = video_codec_context_get_vulkan_data(video_codec_context);
+ const size_t luma_size = frame->width * frame->height;
+ if(vv) {
+ PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements = (PFN_vkGetImageMemoryRequirements)vv->get_proc_addr(vv->inst, "vkGetImageMemoryRequirements");
+ PFN_vkAllocateMemory vkAllocateMemory = (PFN_vkAllocateMemory)vv->get_proc_addr(vv->inst, "vkAllocateMemory");
+ PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties = (PFN_vkGetPhysicalDeviceMemoryProperties)vv->get_proc_addr(vv->inst, "vkGetPhysicalDeviceMemoryProperties");
+ PFN_vkGetMemoryFdKHR vkGetMemoryFdKHR = (PFN_vkGetMemoryFdKHR)vv->get_proc_addr(vv->inst, "vkGetMemoryFdKHR");
+
+ VkMemoryRequirements mem_reqs = {0};
+ vkGetImageMemoryRequirements(vv->act_dev, target_surface_id->img[0], &mem_reqs);
+
+ fprintf(stderr, "size: %lu, alignment: %lu, memory bits: 0x%08x\n", mem_reqs.size, mem_reqs.alignment, mem_reqs.memoryTypeBits);
+ VkDeviceMemory mem;
+ {
+ VkExportMemoryAllocateInfo exp_mem_info;
+ VkMemoryAllocateInfo mem_alloc_info;
+ VkMemoryDedicatedAllocateInfoKHR ded_info;
+
+ memset(&exp_mem_info, 0, sizeof(exp_mem_info));
+ exp_mem_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO;
+ exp_mem_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
+
+ memset(&ded_info, 0, sizeof(ded_info));
+ ded_info.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
+ ded_info.image = target_surface_id->img[0];
+
+ exp_mem_info.pNext = &ded_info;
+
+ memset(&mem_alloc_info, 0, sizeof(mem_alloc_info));
+ mem_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+ mem_alloc_info.pNext = &exp_mem_info;
+ mem_alloc_info.allocationSize = target_surface_id->size[0];
+ mem_alloc_info.memoryTypeIndex = get_memory_type_idx(vv->phys_dev, &mem_reqs, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vkGetPhysicalDeviceMemoryProperties);
+
+ if (mem_alloc_info.memoryTypeIndex == UINT32_MAX) {
+ fprintf(stderr, "No suitable memory type index found.\n");
+ return VK_NULL_HANDLE;
+ }
+
+ if (vkAllocateMemory(vv->act_dev, &mem_alloc_info, 0, &mem) !=
+ VK_SUCCESS)
+ return VK_NULL_HANDLE;
+
+ fprintf(stderr, "memory: %p\n", (void*)mem);
- const unsigned int internal_formats_nv12[2] = { GL_RGBA8, GL_RGBA8 }; // TODO: GL_R8, GL_R16
- const unsigned int internal_formats_p010[2] = { GL_R16, GL_RG16 };
- const unsigned int formats[2] = { GL_RED, GL_RG };
- const int div[2] = {1, 2}; // divide UV texture size by 2 because chroma is half size
+ }
- for(int i = 0; i < 2; ++i) {
- self->target_textures[i] = gl_create_texture(self->params.egl, video_codec_context->width / div[i], video_codec_context->height / div[i], self->params.color_depth == GSR_COLOR_DEPTH_8_BITS ? internal_formats_nv12[i] : internal_formats_p010[i], formats[i], GL_NEAREST);
- if(self->target_textures[i] == 0) {
- fprintf(stderr, "gsr error: gsr_video_encoder_cuda_setup_textures: failed to create opengl texture\n");
- return false;
+ fprintf(stderr, "target surface id: %p, %zu, %zu\n", (void*)target_surface_id->mem[0], target_surface_id->offset[0], target_surface_id->offset[1]);
+ fprintf(stderr, "vkGetMemoryFdKHR: %p\n", (void*)vkGetMemoryFdKHR);
+
+ int fd = 0;
+ VkMemoryGetFdInfoKHR fd_info;
+ memset(&fd_info, 0, sizeof(fd_info));
+ fd_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR;
+ fd_info.memory = target_surface_id->mem[0];
+ fd_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
+ if(vkGetMemoryFdKHR(vv->act_dev, &fd_info, &fd) != VK_SUCCESS) {
+ fprintf(stderr, "failed!\n");
+ } else {
+ fprintf(stderr, "fd: %d\n", fd);
}
- }
- self->params.egl->glGenBuffers(2, self->pbo_y);
+ fprintf(stderr, "glImportMemoryFdEXT: %p, size: %zu\n", (void*)self->params.egl->glImportMemoryFdEXT, target_surface_id->size[0]);
+ const int tiling = target_surface_id->tiling == VK_IMAGE_TILING_LINEAR ? GL_LINEAR_TILING_EXT : GL_OPTIMAL_TILING_EXT;
- self->params.egl->glBindBuffer(GL_PIXEL_PACK_BUFFER, self->pbo_y[0]);
- self->params.egl->glBufferData(GL_PIXEL_PACK_BUFFER, frame->width * frame->height, 0, GL_STREAM_READ);
+ if(tiling != GL_OPTIMAL_TILING_EXT) {
+ fprintf(stderr, "tiling %d is not supported, only GL_OPTIMAL_TILING_EXT (%d) is supported\n", tiling, GL_OPTIMAL_TILING_EXT);
+ }
- self->params.egl->glBindBuffer(GL_PIXEL_PACK_BUFFER, self->pbo_y[1]);
- self->params.egl->glBufferData(GL_PIXEL_PACK_BUFFER, frame->width * frame->height, 0, GL_STREAM_READ);
- self->params.egl->glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
+ unsigned int gl_memory_obj = 0;
+ self->params.egl->glCreateMemoryObjectsEXT(1, &gl_memory_obj);
- self->params.egl->glGenBuffers(2, self->pbo_uv);
+ //const int dedicated = GL_TRUE;
+ //self->params.egl->glMemoryObjectParameterivEXT(gl_memory_obj, GL_DEDICATED_MEMORY_OBJECT_EXT, &dedicated);
- self->params.egl->glBindBuffer(GL_PIXEL_PACK_BUFFER, self->pbo_uv[0]);
- self->params.egl->glBufferData(GL_PIXEL_PACK_BUFFER, (frame->width/2 * frame->height/2) * 2, 0, GL_STREAM_READ);
+ self->params.egl->glImportMemoryFdEXT(gl_memory_obj, target_surface_id->size[0], GL_HANDLE_TYPE_OPAQUE_FD_EXT, fd);
+ if(!self->params.egl->glIsMemoryObjectEXT(gl_memory_obj))
+ fprintf(stderr, "failed to create object!\n");
- self->params.egl->glBindBuffer(GL_PIXEL_PACK_BUFFER, self->pbo_uv[1]);
- self->params.egl->glBufferData(GL_PIXEL_PACK_BUFFER, (frame->width/2 * frame->height/2) * 2, 0, GL_STREAM_READ);
+ fprintf(stderr, "gl memory obj: %u, error: %d\n", gl_memory_obj, self->params.egl->glGetError());
- self->params.egl->glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
+ // fprintf(stderr, "0 gl error: %d\n", self->params.egl->glGetError());
+ // unsigned int vertex_buffer = 0;
+ // self->params.egl->glGenBuffers(1, &vertex_buffer);
+ // self->params.egl->glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
+ // self->params.egl->glBufferStorageMemEXT(GL_ARRAY_BUFFER, target_surface_id->size[0], gl_memory_obj, target_surface_id->offset[0]);
+ // fprintf(stderr, "1 gl error: %d\n", self->params.egl->glGetError());
- self->sw_frame = av_frame_alloc();
- self->sw_frame->format = AV_PIX_FMT_NV12;
- self->sw_frame->width = frame->width;
- self->sw_frame->height = frame->height;
+ // fprintf(stderr, "0 gl error: %d\n", self->params.egl->glGetError());
+ // unsigned int buffer = 0;
+ // self->params.egl->glCreateBuffers(1, &buffer);
+ // self->params.egl->glNamedBufferStorageMemEXT(buffer, target_surface_id->size[0], gl_memory_obj, target_surface_id->offset[0]);
+ // fprintf(stderr, "1 gl error: %d\n", self->params.egl->glGetError());
- // TODO: Remove
- if(av_frame_get_buffer(self->sw_frame, 0) < 0) {
- fprintf(stderr, "failed to allocate sw frame\n");
- }
+ self->params.egl->glGenTextures(1, &self->target_textures[0]);
+ self->params.egl->glBindTexture(GL_TEXTURE_2D, self->target_textures[0]);
+
+ fprintf(stderr, "1 gl error: %d\n", self->params.egl->glGetError());
+ self->params.egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_TILING_EXT, tiling);
+
+ fprintf(stderr, "tiling: %d\n", tiling);
+
+ fprintf(stderr, "2 gl error: %d\n", self->params.egl->glGetError());
+ self->params.egl->glTexStorageMem2DEXT(GL_TEXTURE_2D, 1, GL_R8, frame->width, frame->height, gl_memory_obj, target_surface_id->offset[0]);
+
+ fprintf(stderr, "3 gl error: %d\n", self->params.egl->glGetError());
+ self->params.egl->glBindTexture(GL_TEXTURE_2D, 0);
+
+ self->params.egl->glGenTextures(1, &self->target_textures[1]);
+ self->params.egl->glBindTexture(GL_TEXTURE_2D, self->target_textures[1]);
+
+ fprintf(stderr, "1 gl error: %d\n", self->params.egl->glGetError());
+ self->params.egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_TILING_EXT, tiling);
+
+ fprintf(stderr, "tiling: %d\n", tiling);
+
+ fprintf(stderr, "2 gl error: %d\n", self->params.egl->glGetError());
+ self->params.egl->glTexStorageMem2DEXT(GL_TEXTURE_2D, 1, GL_RG8, frame->width/2, frame->height/2, gl_memory_obj, target_surface_id->offset[0] + luma_size);
+
+ fprintf(stderr, "3 gl error: %d\n", self->params.egl->glGetError());
+ self->params.egl->glBindTexture(GL_TEXTURE_2D, 0);
+ }
- // TODO: Remove
- if(av_frame_make_writable(self->sw_frame) < 0) {
- fprintf(stderr, "failed to make writable\n");
- }
return true;
}
@@ -185,91 +269,6 @@ void gsr_video_encoder_vulkan_stop(gsr_video_encoder_vulkan *self, AVCodecContex
av_buffer_unref(&self->device_ctx);
}
-static void nop_free(void *opaque, uint8_t *data) {
-
-}
-
-static void gsr_video_encoder_vulkan_copy_textures_to_frame(gsr_video_encoder *encoder, AVFrame *frame, gsr_color_conversion *color_conversion) {
- gsr_video_encoder_vulkan *self = encoder->priv;
-
- static int counter = 0;
- ++counter;
-
- // AVBufferRef *av_buffer_create(uint8_t *data, size_t size,
- // void (*free)(void *opaque, uint8_t *data),
- // void *opaque, int flags);
-
- while(self->params.egl->glGetError()){}
- self->params.egl->glBindFramebuffer(GL_READ_FRAMEBUFFER, color_conversion->framebuffers[0]);
- //fprintf(stderr, "1 gl err: %d\n", self->params.egl->glGetError());
- self->params.egl->glBindBuffer(GL_PIXEL_PACK_BUFFER, self->pbo_y[counter % 2]);
- self->params.egl->glBufferData(GL_PIXEL_PACK_BUFFER, frame->width * frame->height, 0, GL_STREAM_READ);
- self->params.egl->glReadPixels(0, 0, frame->width, frame->height, GL_RED, GL_UNSIGNED_BYTE, 0);
- //fprintf(stderr, "2 gl err: %d\n", self->params.egl->glGetError());
-
- const int next_pbo_y = (counter + 1) % 2;
- self->params.egl->glBindBuffer(GL_PIXEL_PACK_BUFFER, self->pbo_y[next_pbo_y]);
- self->params.egl->glBufferData(GL_PIXEL_PACK_BUFFER, frame->width * frame->height, 0, GL_STREAM_READ);
- //fprintf(stderr, "3 gl err: %d\n", self->params.egl->glGetError());
- uint8_t *ptr_y = (uint8_t*)self->params.egl->glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
- //fprintf(stderr, "4 gl err: %d\n", self->params.egl->glGetError());
- if(!ptr_y) {
- fprintf(stderr, "failed to map buffer y!\n");
- }
-
- while(self->params.egl->glGetError()){}
- self->params.egl->glBindFramebuffer(GL_READ_FRAMEBUFFER, color_conversion->framebuffers[1]);
- //fprintf(stderr, "5 gl err: %d\n", self->params.egl->glGetError());
- self->params.egl->glBindBuffer(GL_PIXEL_PACK_BUFFER, self->pbo_uv[counter % 2]);
- self->params.egl->glBufferData(GL_PIXEL_PACK_BUFFER, (frame->width/2 * frame->height/2) * 2, 0, GL_STREAM_READ);
- //fprintf(stderr, "5.5 gl err: %d\n", self->params.egl->glGetError());
- self->params.egl->glReadPixels(0, 0, frame->width/2, frame->height/2, GL_RG, GL_UNSIGNED_BYTE, 0);
- //fprintf(stderr, "6 gl err: %d\n", self->params.egl->glGetError());
-
- const int next_pbo_uv = (counter + 1) % 2;
- self->params.egl->glBindBuffer(GL_PIXEL_PACK_BUFFER, self->pbo_uv[next_pbo_uv]);
- self->params.egl->glBufferData(GL_PIXEL_PACK_BUFFER, (frame->width/2 * frame->height/2) * 2, 0, GL_STREAM_READ);
- //fprintf(stderr, "7 gl err: %d\n", self->params.egl->glGetError());
- uint8_t *ptr_uv = (uint8_t*)self->params.egl->glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
- //fprintf(stderr, "8 gl err: %d\n", self->params.egl->glGetError());
- if(!ptr_uv) {
- fprintf(stderr, "failed to map buffer uv!\n");
- }
-
- //self->sw_frame->buf[0] = av_buffer_create(ptr_y, 3840 * 2160, nop_free, NULL, 0);
- //self->sw_frame->buf[1] = av_buffer_create(ptr_uv, 1920 * 1080 * 2, nop_free, NULL, 0);
- //self->sw_frame->data[0] = self->sw_frame->buf[0]->data;
- //self->sw_frame->data[1] = self->sw_frame->buf[1]->data;
- //self->sw_frame->extended_data[0] = self->sw_frame->data[0];
- //self->sw_frame->extended_data[1] = self->sw_frame->data[1];
-
- self->sw_frame->data[0] = ptr_y;
- self->sw_frame->data[1] = ptr_uv;
-
- self->params.egl->glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
- self->params.egl->glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
-
- //self->params.egl->glBindTexture(GL_TEXTURE_2D, self->target_textures[1]);
- //self->params.egl->glGetTexImage(GL_TEXTURE_2D, 0, GL_RG, GL_UNSIGNED_BYTE, sw_frame->data[1]);
-
- //self->params.egl->glBindTexture(GL_TEXTURE_2D, 0);
-
- int ret = av_hwframe_transfer_data(frame, self->sw_frame, 0);
- if(ret < 0) {
- fprintf(stderr, "transfer data failed, error: %s\n", av_err2str(ret));
- }
-
- //av_buffer_unref(&self->sw_frame->buf[0]);
- //av_buffer_unref(&self->sw_frame->buf[1]);
-
- //av_frame_free(&sw_frame);
- self->params.egl->glBindBuffer(GL_PIXEL_PACK_BUFFER, self->pbo_y[next_pbo_y]);
- self->params.egl->glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
- self->params.egl->glBindBuffer(GL_PIXEL_PACK_BUFFER, self->pbo_y[next_pbo_uv]);
- self->params.egl->glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
- self->params.egl->glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
-}
-
static void gsr_video_encoder_vulkan_get_textures(gsr_video_encoder *encoder, unsigned int *textures, int *num_textures, gsr_destination_color *destination_color) {
gsr_video_encoder_vulkan *self = encoder->priv;
textures[0] = self->target_textures[0];
@@ -299,7 +298,7 @@ gsr_video_encoder* gsr_video_encoder_vulkan_create(const gsr_video_encoder_vulka
*encoder = (gsr_video_encoder) {
.start = gsr_video_encoder_vulkan_start,
- .copy_textures_to_frame = gsr_video_encoder_vulkan_copy_textures_to_frame,
+ .copy_textures_to_frame = NULL,
.get_textures = gsr_video_encoder_vulkan_get_textures,
.destroy = gsr_video_encoder_vulkan_destroy,
.priv = encoder_vulkan
diff --git a/src/main.cpp b/src/main.cpp
index 6b3683a..75ed903 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -634,16 +634,16 @@ static AVCodecContext *create_video_codec_context(AVPixelFormat pix_fmt,
if(codec_context->codec_id == AV_CODEC_ID_AV1 || codec_context->codec_id == AV_CODEC_ID_H264 || codec_context->codec_id == AV_CODEC_ID_HEVC) {
switch(video_quality) {
case VideoQuality::MEDIUM:
- codec_context->global_quality = 150 * quality_multiply;
+ codec_context->global_quality = 130 * quality_multiply;
break;
case VideoQuality::HIGH:
- codec_context->global_quality = 120 * quality_multiply;
+ codec_context->global_quality = 110 * quality_multiply;
break;
case VideoQuality::VERY_HIGH:
- codec_context->global_quality = 115 * quality_multiply;
+ codec_context->global_quality = 95 * quality_multiply;
break;
case VideoQuality::ULTRA:
- codec_context->global_quality = 90 * quality_multiply;
+ codec_context->global_quality = 85 * quality_multiply;
break;
}
} else if(codec_context->codec_id == AV_CODEC_ID_VP8) {
@@ -763,7 +763,7 @@ static AVFrame* create_audio_frame(AVCodecContext *audio_codec_context) {
return frame;
}
-static void dict_set_profile(AVCodecContext *codec_context, gsr_gpu_vendor vendor, gsr_color_depth color_depth, AVDictionary **options) {
+static void dict_set_profile(AVCodecContext *codec_context, gsr_gpu_vendor vendor, gsr_color_depth color_depth, VideoCodec video_codec, AVDictionary **options) {
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(61, 17, 100)
if(codec_context->codec_id == AV_CODEC_ID_H264) {
// TODO: Only for vaapi
@@ -785,14 +785,15 @@ static void dict_set_profile(AVCodecContext *codec_context, gsr_gpu_vendor vendo
av_dict_set(options, "profile", "main", 0);
}
#else
+ const bool use_nvidia_values = vendor == GSR_GPU_VENDOR_NVIDIA && !video_codec_is_vulkan(video_codec);
if(codec_context->codec_id == AV_CODEC_ID_H264) {
// TODO: Only for vaapi
//if(color_depth == GSR_COLOR_DEPTH_10_BITS)
// av_dict_set_int(options, "profile", AV_PROFILE_H264_HIGH_10, 0);
//else
- av_dict_set_int(options, "profile", vendor == GSR_GPU_VENDOR_NVIDIA ? 2 : AV_PROFILE_H264_HIGH, 0);
+ av_dict_set_int(options, "profile", use_nvidia_values ? 2 : AV_PROFILE_H264_HIGH, 0);
} else if(codec_context->codec_id == AV_CODEC_ID_AV1) {
- if(vendor == GSR_GPU_VENDOR_NVIDIA) {
+ if(use_nvidia_values) {
if(color_depth == GSR_COLOR_DEPTH_10_BITS)
av_dict_set_int(options, "highbitdepth", 1, 0);
} else {
@@ -800,9 +801,9 @@ static void dict_set_profile(AVCodecContext *codec_context, gsr_gpu_vendor vendo
}
} else if(codec_context->codec_id == AV_CODEC_ID_HEVC) {
if(color_depth == GSR_COLOR_DEPTH_10_BITS)
- av_dict_set_int(options, "profile", vendor == GSR_GPU_VENDOR_NVIDIA ? 1 : AV_PROFILE_HEVC_MAIN_10, 0);
+ av_dict_set_int(options, "profile", use_nvidia_values ? 1 : AV_PROFILE_HEVC_MAIN_10, 0);
else
- av_dict_set_int(options, "profile", vendor == GSR_GPU_VENDOR_NVIDIA ? 0 : AV_PROFILE_HEVC_MAIN, 0);
+ av_dict_set_int(options, "profile", use_nvidia_values ? 0 : AV_PROFILE_HEVC_MAIN, 0);
}
#endif
}
@@ -867,7 +868,7 @@ static void open_video_software(AVCodecContext *codec_context, VideoQuality vide
av_dict_set(&options, "preset", "veryfast", 0);
av_dict_set(&options, "tune", "film", 0);
- dict_set_profile(codec_context, GSR_GPU_VENDOR_INTEL, color_depth, &options);
+ dict_set_profile(codec_context, GSR_GPU_VENDOR_INTEL, color_depth, VideoCodec::H264, &options);
if(codec_context->codec_id == AV_CODEC_ID_H264) {
av_dict_set(&options, "coder", "cabac", 0); // TODO: cavlc is faster than cabac but worse compression. Which to use?
@@ -1043,9 +1044,14 @@ static void open_video_hardware(AVCodecContext *codec_context, VideoQuality vide
// TODO: Enable multipass
- // TODO: Set "usage" option to "record"/"stream" and "content" option to "rendered" for vulkan encoding
+ dict_set_profile(codec_context, vendor, color_depth, video_codec, &options);
- if(vendor == GSR_GPU_VENDOR_NVIDIA) {
+ if(video_codec_is_vulkan(video_codec)) {
+ av_dict_set_int(&options, "async_depth", 3, 0);
+ av_dict_set(&options, "tune", "hq", 0);
+ av_dict_set(&options, "usage", "record", 0); // TODO: Set to stream when streaming
+ av_dict_set(&options, "content", "rendered", 0);
+ } else if(vendor == GSR_GPU_VENDOR_NVIDIA) {
// TODO: These dont seem to be necessary
// av_dict_set_int(&options, "zerolatency", 1, 0);
// if(codec_context->codec_id == AV_CODEC_ID_AV1) {
@@ -1067,8 +1073,6 @@ static void open_video_hardware(AVCodecContext *codec_context, VideoQuality vide
break;
}
- dict_set_profile(codec_context, vendor, color_depth, &options);
-
if(codec_context->codec_id == AV_CODEC_ID_H264) {
// TODO: h264 10bit?
// TODO:
@@ -3465,9 +3469,9 @@ int main(int argc, char **argv) {
video_codec = VideoCodec::VP8;
} else if(strcmp(video_codec_to_use, "vp9") == 0) {
video_codec = VideoCodec::VP9;
- //} else if(strcmp(video_codec_to_use, "h264_vulkan") == 0) {
+ // } else if(strcmp(video_codec_to_use, "h264_vulkan") == 0) {
// video_codec = VideoCodec::H264_VULKAN;
- //} else if(strcmp(video_codec_to_use, "hevc_vulkan") == 0) {
+ // } else if(strcmp(video_codec_to_use, "hevc_vulkan") == 0) {
// video_codec = VideoCodec::HEVC_VULKAN;
} else if(strcmp(video_codec_to_use, "auto") != 0) {
fprintf(stderr, "Error: -k should either be 'auto', 'h264', 'hevc', 'av1', 'vp8', 'vp9', 'hevc_hdr', 'av1_hdr', 'hevc_10bit' or 'av1_10bit', got: '%s'\n", video_codec_to_use);
@@ -3706,6 +3710,11 @@ int main(int argc, char **argv) {
_exit(1);
}
+ gsr_shader_enable_debug_output(gl_debug);
+#ifndef NDEBUG
+ gsr_shader_enable_debug_output(true);
+#endif
+
if(egl.gpu_info.is_steam_deck) {
fprintf(stderr, "gsr warning: steam deck has multiple driver issues. One of them has been reported here: https://github.com/ValveSoftware/SteamOS/issues/1609\n"
"If you have issues with GPU Screen Recorder on steam deck that you don't have on a desktop computer then report the issue to Valve and/or AMD.\n");
diff --git a/src/shader.c b/src/shader.c
index b9fbb62..ba4db80 100644
--- a/src/shader.c
+++ b/src/shader.c
@@ -3,14 +3,16 @@
#include <stdio.h>
#include <assert.h>
+static bool print_compile_errors = false;
+
static int min_int(int a, int b) {
return a < b ? a : b;
}
-static unsigned int loader_shader(gsr_egl *egl, unsigned int type, const char *source) {
+static unsigned int load_shader(gsr_egl *egl, unsigned int type, const char *source) {
unsigned int shader_id = egl->glCreateShader(type);
if(shader_id == 0) {
- fprintf(stderr, "gsr error: loader_shader: failed to create shader, error: %d\n", egl->glGetError());
+ fprintf(stderr, "gsr error: load_shader: failed to create shader, error: %d\n", egl->glGetError());
return 0;
}
@@ -23,10 +25,10 @@ static unsigned int loader_shader(gsr_egl *egl, unsigned int type, const char *s
int info_length = 0;
egl->glGetShaderiv(shader_id, GL_INFO_LOG_LENGTH, &info_length);
- if(info_length > 1) {
+ if(info_length > 1 && print_compile_errors) {
char info_log[4096];
egl->glGetShaderInfoLog(shader_id, min_int(4096, info_length), NULL, info_log);
- fprintf(stderr, "gsr error: loader shader: failed to compile shader, error:\n%s\nshader source:\n%s\n", info_log, source);
+ fprintf(stderr, "gsr error: load_shader: failed to compile shader, error:\n%s\nshader source:\n%s\n", info_log, source);
}
egl->glDeleteShader(shader_id);
@@ -45,19 +47,19 @@ static unsigned int load_program(gsr_egl *egl, const char *vertex_shader, const
bool success = false;
if(vertex_shader) {
- vertex_shader_id = loader_shader(egl, GL_VERTEX_SHADER, vertex_shader);
+ vertex_shader_id = load_shader(egl, GL_VERTEX_SHADER, vertex_shader);
if(vertex_shader_id == 0)
goto done;
}
if(fragment_shader) {
- fragment_shader_id = loader_shader(egl, GL_FRAGMENT_SHADER, fragment_shader);
+ fragment_shader_id = load_shader(egl, GL_FRAGMENT_SHADER, fragment_shader);
if(fragment_shader_id == 0)
goto done;
}
if(compute_shader) {
- compute_shader_id = loader_shader(egl, GL_COMPUTE_SHADER, compute_shader);
+ compute_shader_id = load_shader(egl, GL_COMPUTE_SHADER, compute_shader);
if(compute_shader_id == 0)
goto done;
}
@@ -151,3 +153,7 @@ void gsr_shader_use(gsr_shader *self) {
void gsr_shader_use_none(gsr_shader *self) {
self->egl->glUseProgram(0);
}
+
+void gsr_shader_enable_debug_output(bool enable) {
+ print_compile_errors = enable;
+}
diff --git a/src/utils.c b/src/utils.c
index 4aab138..9b4a4b6 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -362,13 +362,9 @@ bool gl_get_gpu_info(gsr_egl *egl, gsr_gpu_info *info) {
bool supported = true;
const unsigned char *gl_vendor = egl->glGetString(GL_VENDOR);
const unsigned char *gl_renderer = egl->glGetString(GL_RENDERER);
- const unsigned char *gl_version = egl->glGetString(GL_VERSION);
info->gpu_version = 0;
info->is_steam_deck = false;
- info->driver_major = 0;
- info->driver_minor = 0;
- info->driver_patch = 0;
if(!gl_vendor) {
fprintf(stderr, "gsr error: failed to get gpu vendor\n");
@@ -408,21 +404,6 @@ bool gl_get_gpu_info(gsr_egl *egl, gsr_gpu_info *info) {
info->is_steam_deck = strstr((const char*)gl_renderer, "vangogh") != NULL;
}
- if(gl_version) {
- const char *mesa_p = strstr((const char*)gl_version, "Mesa ");
- if(mesa_p) {
- mesa_p += 5;
- int major = 0;
- int minor = 0;
- int patch = 0;
- if(sscanf(mesa_p, "%d.%d.%d", &major, &minor, &patch) == 3) {
- info->driver_major = major;
- info->driver_minor = minor;
- info->driver_patch = patch;
- }
- }
- }
-
end:
return supported;
}
diff --git a/src/window/wayland.c b/src/window/wayland.c
index 7e319fb..efc7bbe 100644
--- a/src/window/wayland.c
+++ b/src/window/wayland.c
@@ -26,11 +26,11 @@ typedef struct {
} gsr_wayland_output;
struct gsr_window_wayland {
- void *display;
- void *window;
- void *registry;
- void *surface;
- void *compositor;
+ struct wl_display *display;
+ struct wl_egl_window *window;
+ struct wl_registry *registry;
+ struct wl_surface *surface;
+ struct wl_compositor *compositor;
gsr_wayland_output outputs[GSR_MAX_OUTPUTS];
int num_outputs;
struct zxdg_output_manager_v1 *xdg_output_manager;