Compare commits

...

17 Commits

Author SHA1 Message Date
dec05eba
2290f0641c 5.5.10 2025-06-23 12:52:08 +02:00
dec05eba
f9e93467b2 Pipewire: fix transparent windows having incorrect color (disable RGBA video formats) 2025-06-23 12:41:28 +02:00
dec05eba
7d7f986668 Pipewire: dont remove first frame. This fixes window capture/unfocused monitor capture being black until its updated 2025-06-23 12:35:10 +02:00
dec05eba
1b957d5b40 README: update dependency linux-firmware->linux-firmware-intel 2025-06-22 19:28:05 +02:00
dec05eba
8ad6a1f4cb OpenGL ES version correct in README (only requires 3.0) 2025-06-16 22:41:16 +02:00
dec05eba
0cf0a9abf5 Create egl3 context 2025-06-16 22:23:26 +02:00
dec05eba
bc58e382b7 EGL_OPENGL_ES_BIT->EGL_OPENGL_ES2_BIT 2025-06-16 20:57:59 +02:00
dec05eba
630c504241 Limit nvidia-smi to opensuse because it causes huge memory leak on ubuntu/debian. Add example toggle-recording.sh script 2025-06-12 14:42:04 +02:00
dec05eba
0528bc6f31 M 2025-06-10 11:08:43 +02:00
dec05eba
a8b3e38082 Update README and TODO 2025-06-10 11:07:42 +02:00
dec05eba
d0a620a574 5.5.8 2025-06-10 10:58:21 +02:00
dec05eba
ca0be79344 Fix nvidia capture after switch to opengl es 2025-06-10 00:34:21 +02:00
dec05eba
53557133c2 Reapply "Fix screen and portal capture not working on some intel gpus"
This reverts commit 7f00ce22e7.
2025-06-10 00:32:51 +02:00
dec05eba
7f00ce22e7 Revert "Fix screen and portal capture not working on some intel gpus"
This reverts commit 3ba1dbda98.
2025-06-09 22:11:16 +02:00
dec05eba
3ba1dbda98 Fix screen and portal capture not working on some intel gpus 2025-06-09 22:07:52 +02:00
dec05eba
a849d2cdad Add nobara package link 2025-06-08 00:39:26 +02:00
dec05eba
b0b1442a03 Swap flush and memory barrier 2025-06-07 11:51:49 +02:00
20 changed files with 179 additions and 159 deletions

View File

@@ -70,6 +70,7 @@ Here are some known unofficial packages:
* Fedora: [Copr](https://copr.fedorainfracloud.org/coprs/brycensranch/gpu-screen-recorder-git/)
* OpenMandriva: [gpu-screen-recorder](https://github.com/OpenMandrivaAssociation/gpu-screen-recorder)
* Solus: [gpu-screen-recorder](https://github.com/getsolus/packages/tree/main/packages/g/gpu-screen-recorder)
* Nobara: [Nobara wiki](https://wiki.nobaraproject.org/en/general-usage/additional-software/GPU-Screen-Recorder)
# Dependencies
GPU Screen Recorder uses meson build system so you need to install `meson` to build GPU Screen Recorder.
@@ -77,7 +78,6 @@ GPU Screen Recorder uses meson build system so you need to install `meson` to bu
## Build dependencies
These are the dependencies needed to build GPU Screen Recorder:
* libglvnd (which provides libgl, libglx and libegl)
* vulkan-headers
* ffmpeg (libavcodec, libavformat, libavutil, libswresample, libavfilter)
* x11 (libx11, libxcomposite, libxrandr, libxfixes, libxdamage)
@@ -88,6 +88,8 @@ These are the dependencies needed to build GPU Screen Recorder:
* wayland (wayland-client, wayland-egl, wayland-scanner)
## Runtime dependencies
* libglvnd (which provides libgl, libglx and libegl) is needed. Your system needs to support at least OpenGL ES 3.0 (released in 2012)
There are also additional dependencies needed at runtime depending on your GPU vendor:
### AMD
@@ -96,7 +98,7 @@ There are also additional dependencies needed at runtime depending on your GPU v
### Intel
* mesa
* vaapi (intel-media-driver/libva-intel-driver/linux-firmware, depending on which intel iGPU you have)
* vaapi (intel-media-driver/libva-intel-driver/linux-firmware-intel, depending on which intel iGPU you have)
### NVIDIA
* cuda runtime (libcuda.so.1) (libnvidia-compute)

4
TODO
View File

@@ -302,3 +302,7 @@ Allow medium, high, very_high and ultra quality for -bm cbr. If that is used the
Maybe do this in the ui instead (or both?), to show estimated file size.
Maybe remove shader compute code. It doesn't seem necessary anymore now that glSwapBuffer/glFinish isn't used. dbus server isn't needed anymore either, the code can be moved back to the gpu screen recorder process.
Add proper check if opengl functions are supported. dlsym for the symbol will return a no-op function if it's not supported, so it silently fails if used.
Colors are offset to bottom left by 1 pixel or so on steam deck in landscape mode.

View File

@@ -50,6 +50,7 @@ typedef struct {
gsr_color_range color_range;
bool load_external_image_shader;
bool force_graphics_shader;
} gsr_color_conversion_params;
typedef struct {
@@ -77,6 +78,7 @@ void gsr_color_conversion_deinit(gsr_color_conversion *self);
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);
void gsr_color_conversion_clear(gsr_color_conversion *self);
void gsr_color_conversion_read_destination_texture(gsr_color_conversion *self, int destination_texture_index, int x, int y, int width, int height, unsigned int color_format, unsigned int data_format, void *pixels);
gsr_rotation gsr_monitor_rotation_to_rotation(gsr_monitor_rotation monitor_rotation);

View File

@@ -48,6 +48,8 @@ typedef void(*__GLXextFuncPtr)(void);
#define EGL_OPENGL_ES_API 0x30A0
#define EGL_OPENGL_BIT 0x0008
#define EGL_OPENGL_ES_BIT 0x0001
#define EGL_OPENGL_ES2_BIT 0x0004
#define EGL_OPENGL_ES3_BIT 0x00000040
#define EGL_NONE 0x3038
#define EGL_CONTEXT_CLIENT_VERSION 0x3098
#define EGL_BACK_BUFFER 0x3084
@@ -141,8 +143,6 @@ typedef void(*__GLXextFuncPtr)(void);
#define GL_MAX_COMPUTE_FIXED_GROUP_INVOCATIONS 0x90EB
#define GL_TEXTURE0 0x84C0
#define GL_TEXTURE1 0x84C1
#define GL_CLAMP_TO_BORDER 0x812D
#define GL_TEXTURE_BORDER_COLOR 0x1004
#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020
#define GL_ALL_BARRIER_BITS 0xFFFFFFFF
@@ -265,6 +265,7 @@ struct gsr_egl {
void (*glGetTexLevelParameteriv)(unsigned int target, int level, unsigned int pname, int *params);
void (*glTexImage2D)(unsigned int target, int level, int internalFormat, int width, int height, int border, unsigned int format, unsigned int type, const void *pixels);
void (*glTexSubImage2D)(unsigned int target, int level, int xoffset, int yoffset, int width, int height, unsigned format, unsigned type, const void *pixels);
void (*glTexStorage2D)(unsigned int target, int levels, unsigned int internalformat, int width, int height);
void (*glGetTexImage)(unsigned int target, int level, unsigned int format, unsigned int type, void *pixels);
void (*glGenFramebuffers)(int n, unsigned int *framebuffers);
void (*glBindFramebuffer)(unsigned int target, unsigned int framebuffer);

View File

@@ -9,7 +9,7 @@
#include <spa/param/video/format.h>
#define GSR_PIPEWIRE_VIDEO_MAX_MODIFIERS 1024
#define GSR_PIPEWIRE_VIDEO_MAX_VIDEO_FORMATS 12
#define GSR_PIPEWIRE_VIDEO_MAX_VIDEO_FORMATS 6
#define GSR_PIPEWIRE_VIDEO_DMABUF_MAX_PLANES 4
typedef struct gsr_egl gsr_egl;
@@ -65,6 +65,7 @@ typedef struct {
struct spa_video_info format;
int server_version_sync;
bool negotiated;
bool renegotiated;
bool damaged;
struct {

View File

@@ -1,4 +1,4 @@
project('gpu-screen-recorder', ['c', 'cpp'], version : '5.5.6', default_options : ['warning_level=2'])
project('gpu-screen-recorder', ['c', 'cpp'], version : '5.5.10', default_options : ['warning_level=2'])
add_project_arguments('-Wshadow', language : ['c', 'cpp'])
if get_option('buildtype') == 'debug'

View File

@@ -1,7 +1,7 @@
[package]
name = "gpu-screen-recorder"
type = "executable"
version = "5.5.6"
version = "5.5.10"
platforms = ["posix"]
[config]

6
scripts/toggle-recording.sh Executable file
View File

@@ -0,0 +1,6 @@
#!/bin/sh -e
killall -SIGINT gpu-screen-recorder && sleep 0.5 && notify-send -t 1500 -u low 'GPU Screen Recorder' 'Stopped recording' && exit 0;
video="$HOME/Videos/$(date +"Video_%Y-%m-%d_%H-%M-%S.mp4")"
notify-send -t 1500 -u low 'GPU Screen Recorder' "Started recording video to $video"
gpu-screen-recorder -w screen -f 60 -a "default_output" -o "$video"

View File

@@ -12,7 +12,7 @@
#include <fcntl.h>
#include <xf86drm.h>
#include <libdrm/drm_fourcc.h>
#include <drm_fourcc.h>
#include <libavutil/mastering_display_metadata.h>
@@ -108,22 +108,14 @@ static int max_int(int a, int b) {
}
static void gsr_capture_kms_create_input_texture_ids(gsr_capture_kms *self) {
const float border_color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
self->params.egl->glGenTextures(1, &self->input_texture_id);
self->params.egl->glBindTexture(GL_TEXTURE_2D, self->input_texture_id);
self->params.egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
self->params.egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
self->params.egl->glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
self->params.egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
self->params.egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
self->params.egl->glBindTexture(GL_TEXTURE_2D, 0);
self->params.egl->glGenTextures(1, &self->external_input_texture_id);
self->params.egl->glBindTexture(GL_TEXTURE_EXTERNAL_OES, self->external_input_texture_id);
self->params.egl->glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
self->params.egl->glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
self->params.egl->glTexParameterfv(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_BORDER_COLOR, border_color);
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);
@@ -133,9 +125,6 @@ static void gsr_capture_kms_create_input_texture_ids(gsr_capture_kms *self) {
self->params.egl->glGenTextures(1, &self->cursor_texture_id);
self->params.egl->glBindTexture(cursor_texture_id_target, self->cursor_texture_id);
self->params.egl->glTexParameteri(cursor_texture_id_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
self->params.egl->glTexParameteri(cursor_texture_id_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
self->params.egl->glTexParameterfv(cursor_texture_id_target, GL_TEXTURE_BORDER_COLOR, border_color);
self->params.egl->glTexParameteri(cursor_texture_id_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
self->params.egl->glTexParameteri(cursor_texture_id_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
self->params.egl->glBindTexture(cursor_texture_id_target, 0);

View File

@@ -23,6 +23,12 @@ typedef struct {
vec2i capture_size;
gsr_pipewire_video_dmabuf_data dmabuf_data[GSR_PIPEWIRE_VIDEO_DMABUF_MAX_PLANES];
int num_dmabuf_data;
gsr_pipewire_video_region region;
gsr_pipewire_video_region cursor_region;
uint32_t pipewire_fourcc;
uint64_t pipewire_modifiers;
bool using_external_image;
} gsr_capture_portal;
static void gsr_capture_portal_cleanup_plane_fds(gsr_capture_portal *self) {
@@ -57,31 +63,20 @@ static void gsr_capture_portal_stop(gsr_capture_portal *self) {
}
static void gsr_capture_portal_create_input_textures(gsr_capture_portal *self) {
const float border_color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
self->params.egl->glGenTextures(1, &self->texture_map.texture_id);
self->params.egl->glBindTexture(GL_TEXTURE_2D, self->texture_map.texture_id);
self->params.egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
self->params.egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
self->params.egl->glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
self->params.egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
self->params.egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
self->params.egl->glBindTexture(GL_TEXTURE_2D, 0);
self->params.egl->glGenTextures(1, &self->texture_map.external_texture_id);
self->params.egl->glBindTexture(GL_TEXTURE_EXTERNAL_OES, self->texture_map.external_texture_id);
self->params.egl->glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
self->params.egl->glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
self->params.egl->glTexParameterfv(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_BORDER_COLOR, border_color);
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);
self->params.egl->glGenTextures(1, &self->texture_map.cursor_texture_id);
self->params.egl->glBindTexture(GL_TEXTURE_2D, self->texture_map.cursor_texture_id);
self->params.egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
self->params.egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
self->params.egl->glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
self->params.egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
self->params.egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
self->params.egl->glBindTexture(GL_TEXTURE_2D, 0);
@@ -227,19 +222,13 @@ static int gsr_capture_portal_setup_dbus(gsr_capture_portal *self, int *pipewire
}
static bool gsr_capture_portal_get_frame_dimensions(gsr_capture_portal *self) {
gsr_pipewire_video_region region = {0, 0, 0, 0};
gsr_pipewire_video_region cursor_region = {0, 0, 0, 0};
fprintf(stderr, "gsr info: gsr_capture_portal_start: waiting for pipewire negotiation\n");
const double start_time = clock_get_monotonic_seconds();
while(clock_get_monotonic_seconds() - start_time < 5.0) {
bool uses_external_image = false;
uint32_t fourcc = 0;
uint64_t modifiers = 0;
if(gsr_pipewire_video_map_texture(&self->pipewire, self->texture_map, &region, &cursor_region, self->dmabuf_data, &self->num_dmabuf_data, &fourcc, &modifiers, &uses_external_image)) {
gsr_capture_portal_cleanup_plane_fds(self);
self->capture_size.x = region.width;
self->capture_size.y = region.height;
if(gsr_pipewire_video_map_texture(&self->pipewire, self->texture_map, &self->region, &self->cursor_region, self->dmabuf_data, &self->num_dmabuf_data, &self->pipewire_fourcc, &self->pipewire_modifiers, &self->using_external_image)) {
self->capture_size.x = self->region.width;
self->capture_size.y = self->region.height;
fprintf(stderr, "gsr info: gsr_capture_portal_start: pipewire negotiation finished\n");
return true;
}
@@ -311,20 +300,17 @@ static int gsr_capture_portal_capture(gsr_capture *cap, gsr_capture_metadata *ca
(void)color_conversion;
gsr_capture_portal *self = cap->priv;
/* TODO: Handle formats other than RGB(a) */
gsr_pipewire_video_region region = {0, 0, 0, 0};
gsr_pipewire_video_region cursor_region = {0, 0, 0, 0};
uint32_t pipewire_fourcc = 0;
uint64_t pipewire_modifiers = 0;
bool using_external_image = false;
if(gsr_pipewire_video_map_texture(&self->pipewire, self->texture_map, &region, &cursor_region, self->dmabuf_data, &self->num_dmabuf_data, &pipewire_fourcc, &pipewire_modifiers, &using_external_image)) {
if(region.width != self->capture_size.x || region.height != self->capture_size.y) {
self->capture_size.x = region.width;
self->capture_size.y = region.height;
gsr_color_conversion_clear(color_conversion);
/* TODO: Handle formats other than RGB(A) */
if(self->num_dmabuf_data == 0) {
if(gsr_pipewire_video_map_texture(&self->pipewire, self->texture_map, &self->region, &self->cursor_region, self->dmabuf_data, &self->num_dmabuf_data, &self->pipewire_fourcc, &self->pipewire_modifiers, &self->using_external_image)) {
if(self->region.width != self->capture_size.x || self->region.height != self->capture_size.y) {
self->capture_size.x = self->region.width;
self->capture_size.y = self->region.height;
gsr_color_conversion_clear(color_conversion);
}
} else {
return -1;
}
} else {
return 0;
}
const bool is_scaled = self->params.output_resolution.x > 0 && self->params.output_resolution.y > 0;
@@ -338,27 +324,27 @@ static int gsr_capture_portal_capture(gsr_capture *cap, gsr_capture_metadata *ca
// TODO: Handle region crop
gsr_color_conversion_draw(color_conversion, using_external_image ? self->texture_map.external_texture_id : self->texture_map.texture_id,
gsr_color_conversion_draw(color_conversion, self->using_external_image ? self->texture_map.external_texture_id : self->texture_map.texture_id,
target_pos, output_size,
(vec2i){region.x, region.y}, self->capture_size, self->capture_size,
GSR_ROT_0, GSR_SOURCE_COLOR_RGB, using_external_image, false);
(vec2i){self->region.x, self->region.y}, self->capture_size, self->capture_size,
GSR_ROT_0, GSR_SOURCE_COLOR_RGB, self->using_external_image, false);
if(self->params.record_cursor && self->texture_map.cursor_texture_id > 0 && cursor_region.width > 0) {
if(self->params.record_cursor && self->texture_map.cursor_texture_id > 0 && self->cursor_region.width > 0) {
const vec2d scale = {
self->capture_size.x == 0 ? 0 : (double)output_size.x / (double)self->capture_size.x,
self->capture_size.y == 0 ? 0 : (double)output_size.y / (double)self->capture_size.y
};
const vec2i cursor_pos = {
target_pos.x + (cursor_region.x * scale.x),
target_pos.y + (cursor_region.y * scale.y)
target_pos.x + (self->cursor_region.x * scale.x),
target_pos.y + (self->cursor_region.y * scale.y)
};
self->params.egl->glEnable(GL_SCISSOR_TEST);
self->params.egl->glScissor(target_pos.x, target_pos.y, output_size.x, output_size.y);
gsr_color_conversion_draw(color_conversion, self->texture_map.cursor_texture_id,
(vec2i){cursor_pos.x, cursor_pos.y}, (vec2i){cursor_region.width * scale.x, cursor_region.height * scale.y},
(vec2i){0, 0}, (vec2i){cursor_region.width, cursor_region.height}, (vec2i){cursor_region.width, cursor_region.height},
(vec2i){cursor_pos.x, cursor_pos.y}, (vec2i){self->cursor_region.width * scale.x, self->cursor_region.height * scale.y},
(vec2i){0, 0}, (vec2i){self->cursor_region.width, self->cursor_region.height}, (vec2i){self->cursor_region.width, self->cursor_region.height},
GSR_ROT_0, GSR_SOURCE_COLOR_RGB, false, true);
self->params.egl->glDisable(GL_SCISSOR_TEST);
}

View File

@@ -89,15 +89,13 @@ static void get_compute_shader_header(char *header, size_t header_size, bool ext
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"
"#version 310 es\n"
"layout(binding = 0) uniform highp sampler2D img_input;\n"
"layout(binding = 1) uniform highp sampler2D img_background;\n");
}
@@ -109,7 +107,7 @@ static int load_compute_shader_y(gsr_shader *shader, gsr_egl *egl, gsr_color_com
char header[512];
get_compute_shader_header(header, sizeof(header), external_texture);
char compute_shader[2048];
char compute_shader[4096];
snprintf(compute_shader, sizeof(compute_shader),
"%s"
"layout (local_size_x = %d, local_size_y = %d, local_size_z = 1) in;\n"
@@ -127,12 +125,16 @@ static int load_compute_shader_y(gsr_shader *shader, gsr_egl *egl, gsr_color_com
" 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 = texture(img_input, rotated_texel_coord/vec2(size));\n"
" vec2 source_color_coords = rotated_texel_coord/vec2(size);\n"
" vec4 source_color = texture(img_input, source_color_coords);\n"
" if(source_color_coords.x > 1.0 || source_color_coords.y > 1.0)\n"
" source_color.rgba = vec4(0.0, 0.0, 0.0, %s);\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", header, max_local_size_dim, max_local_size_dim, color_transform_matrix,
alpha_blending ? "0.0" : "1.0",
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)
@@ -151,7 +153,7 @@ static int load_compute_shader_uv(gsr_shader *shader, gsr_egl *egl, gsr_color_co
char header[512];
get_compute_shader_header(header, sizeof(header), external_texture);
char compute_shader[2048];
char compute_shader[4096];
snprintf(compute_shader, sizeof(compute_shader),
"%s"
"layout (local_size_x = %d, local_size_y = %d, local_size_z = 1) in;\n"
@@ -169,12 +171,16 @@ static int load_compute_shader_uv(gsr_shader *shader, gsr_egl *egl, gsr_color_co
" 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 = texture(img_input, rotated_texel_coord/vec2(size>>1));\n" // size/2
" vec2 source_color_coords = rotated_texel_coord/vec2(size>>1);\n"
" vec4 source_color = texture(img_input, source_color_coords);\n" // size/2
" if(source_color_coords.x > 1.0 || source_color_coords.y > 1.0)\n"
" source_color.rgba = vec4(0.0, 0.0, 0.0, %s);\n"
" 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", header, max_local_size_dim, max_local_size_dim, color_transform_matrix,
alpha_blending ? "0.0" : "1.0",
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)
@@ -191,10 +197,11 @@ static int load_compute_shader_rgb(gsr_shader *shader, gsr_egl *egl, gsr_color_c
char header[512];
get_compute_shader_header(header, sizeof(header), external_texture);
char compute_shader[2048];
char compute_shader[4096];
snprintf(compute_shader, sizeof(compute_shader),
"%s"
"layout (local_size_x = %d, local_size_y = %d, local_size_z = 1) in;\n"
"precision highp float;\n"
"uniform ivec2 source_position;\n"
"uniform ivec2 target_position;\n"
"uniform vec2 scale;\n"
@@ -207,11 +214,15 @@ static int load_compute_shader_rgb(gsr_shader *shader, gsr_egl *egl, gsr_color_c
" 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 = texture(img_input, rotated_texel_coord/vec2(size));\n"
" vec2 source_color_coords = rotated_texel_coord/vec2(size);\n"
" vec4 source_color = texture(img_input, source_color_coords);\n"
" if(source_color_coords.x > 1.0 || source_color_coords.y > 1.0)\n"
" source_color.rgba = vec4(0.0, 0.0, 0.0, %s);\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", header, max_local_size_dim, max_local_size_dim,
alpha_blending ? "0.0" : "1.0",
alpha_blending ? "texture(img_background, output_texel_coord/vec2(output_size))" : "source_color");
if(gsr_shader_init(shader, egl, NULL, NULL, compute_shader) != 0)
@@ -620,20 +631,33 @@ int gsr_color_conversion_init(gsr_color_conversion *self, const gsr_color_conver
}
}
if(!gsr_color_conversion_load_compute_shaders(self)) {
if(self->params.force_graphics_shader) {
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");
self->external_compute_shaders_failed_to_load = true;
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(self->params.load_external_image_shader) {
if(!gsr_color_conversion_load_external_graphics_shaders(self))
goto err;
}
} else {
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)
@@ -920,7 +944,6 @@ void gsr_color_conversion_draw(gsr_color_conversion *self, unsigned int texture_
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:
@@ -955,13 +978,13 @@ void gsr_color_conversion_draw(gsr_color_conversion *self, unsigned int texture_
}
}
self->params.egl->glFlush();
// TODO: Use the minimal barrier required
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);
self->params.egl->glFlush();
}
void gsr_color_conversion_clear(gsr_color_conversion *self) {
@@ -999,6 +1022,13 @@ void gsr_color_conversion_clear(gsr_color_conversion *self) {
self->params.egl->glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void gsr_color_conversion_read_destination_texture(gsr_color_conversion *self, int destination_texture_index, int x, int y, int width, int height, unsigned int color_format, unsigned int data_format, void *pixels) {
assert(destination_texture_index >= 0 && destination_texture_index < self->params.num_destination_textures);
self->params.egl->glBindFramebuffer(GL_FRAMEBUFFER, self->framebuffers[destination_texture_index]);
self->params.egl->glReadPixels(x, y, width, height, color_format, data_format, pixels);
self->params.egl->glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
gsr_rotation gsr_monitor_rotation_to_rotation(gsr_monitor_rotation monitor_rotation) {
return (gsr_rotation)monitor_rotation;
}

View File

@@ -56,10 +56,6 @@ static bool gsr_cursor_set_from_x11_cursor_image(gsr_cursor *self, XFixesCursorI
self->egl->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, self->size.x, self->size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, cursor_data);
free(cursor_data);
const float border_color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
self->egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
self->egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
self->egl->glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
self->egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
self->egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

View File

@@ -33,10 +33,9 @@ static bool gsr_egl_create_window(gsr_egl *self) {
EGLConfig ecfg;
int32_t num_config = 0;
// TODO: Use EGL_OPENGL_ES_BIT as amd requires that for external texture, but that breaks software encoding
const int32_t attr[] = {
EGL_BUFFER_SIZE, 24,
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT,
EGL_NONE, EGL_NONE
};
@@ -45,8 +44,7 @@ static bool gsr_egl_create_window(gsr_egl *self) {
EGL_NONE, EGL_NONE
};
// TODO: Use EGL_OPENGL_ES_API as amd requires that for external texture, but that breaks software encoding
self->eglBindAPI(EGL_OPENGL_API);
self->eglBindAPI(EGL_OPENGL_ES_API);
self->egl_display = self->eglGetDisplay((EGLNativeDisplayType)gsr_window_get_display(self->window));
if(!self->egl_display) {
@@ -279,6 +277,7 @@ static bool gsr_egl_load_gl(gsr_egl *self, void *library) {
{ (void**)&self->glGetTexLevelParameteriv, "glGetTexLevelParameteriv" },
{ (void**)&self->glTexImage2D, "glTexImage2D" },
{ (void**)&self->glTexSubImage2D, "glTexSubImage2D" },
{ (void**)&self->glTexStorage2D, "glTexStorage2D" },
{ (void**)&self->glGetTexImage, "glGetTexImage" },
{ (void**)&self->glGenFramebuffers, "glGenFramebuffers" },
{ (void**)&self->glBindFramebuffer, "glBindFramebuffer" },
@@ -460,9 +459,9 @@ bool gsr_egl_load(gsr_egl *self, gsr_window *window, bool is_monitor_capture, bo
/* This fixes nvenc codecs unable to load on openSUSE tumbleweed because of a cuda error. Don't ask me why */
const bool inside_flatpak = getenv("FLATPAK_ID") != NULL;
if(inside_flatpak)
system("flatpak-spawn --host -- nvidia-smi -f /dev/null");
system("flatpak-spawn --host -- sh -c 'grep -q openSUSE /etc/os-release && nvidia-smi -f /dev/null'");
else
system("nvidia-smi -f /dev/null");
system("sh -c 'grep -q openSUSE /etc/os-release && nvidia-smi -f /dev/null'");
}
return true;
@@ -517,15 +516,7 @@ void gsr_egl_unload(gsr_egl *self) {
}
void gsr_egl_swap_buffers(gsr_egl *self) {
/* This uses less cpu than swap buffer on nvidia */
// TODO: Do these and remove swap
self->glFlush();
// self->glFinish();
// if(self->egl_display) {
// self->eglSwapBuffers(self->egl_display, self->egl_surface);
// } else if(gsr_window_get_display_server(self->window) == GSR_DISPLAY_SERVER_X11) {
// Display *display = gsr_window_get_display(self->window);
// const Window window = (Window)gsr_window_get_window(self->window);
// self->glXSwapBuffers(display, window);
// }
// TODO: Use the minimal barrier required
self->glMemoryBarrier(GL_ALL_BARRIER_BITS); // GL_SHADER_IMAGE_ACCESS_BARRIER_BIT
}

View File

@@ -71,16 +71,15 @@ void gsr_video_encoder_software_stop(gsr_video_encoder_software *self, AVCodecCo
}
static void gsr_video_encoder_software_copy_textures_to_frame(gsr_video_encoder *encoder, AVFrame *frame, gsr_color_conversion *color_conversion) {
gsr_video_encoder_software *self = encoder->priv;
(void)encoder;
//gsr_video_encoder_software *self = encoder->priv;
// TODO: hdr support
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->params.egl->glBindTexture(GL_TEXTURE_2D, self->target_textures[i]);
// We could use glGetTexSubImage and then we wouldn't have to use a specific linesize (LINESIZE_ALIGNMENT) that adds padding,
// but glGetTexSubImage is only available starting from opengl 4.5.
self->params.egl->glGetTexImage(GL_TEXTURE_2D, 0, formats[i], GL_UNSIGNED_BYTE, frame->data[i]);
// TODO: Use glPixelStore?
gsr_color_conversion_read_destination_texture(color_conversion, i, 0, 0, frame->width / div[i], frame->height / div[i], formats[i], GL_UNSIGNED_BYTE, frame->data[i]);
}
self->params.egl->glBindTexture(GL_TEXTURE_2D, 0);
// cap_kms->kms.base.egl->eglSwapBuffers(cap_kms->kms.base.egl->egl_display, cap_kms->kms.base.egl->egl_surface);
//self->params.egl->glFlush();

View File

@@ -92,10 +92,6 @@ static bool gsr_video_encoder_vaapi_setup_textures(gsr_video_encoder_vaapi *self
if(self->prime.fourcc == VA_FOURCC_NV12 || self->prime.fourcc == VA_FOURCC_P010) {
const uint32_t *formats = self->prime.fourcc == VA_FOURCC_NV12 ? formats_nv12 : formats_p010;
const int div[2] = {1, 2}; // divide UV texture size by 2 because chroma is half size
const float border_colors[2][4] = {
{0.0f, 0.0f, 0.0f, 1.0f},
{0.5f, 0.5f, 0.0f, 1.0f}
};
self->params.egl->glGenTextures(2, self->target_textures);
for(int i = 0; i < 2; ++i) {
@@ -125,9 +121,6 @@ static bool gsr_video_encoder_vaapi_setup_textures(gsr_video_encoder_vaapi *self
}
self->params.egl->glBindTexture(GL_TEXTURE_2D, self->target_textures[i]);
self->params.egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
self->params.egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
self->params.egl->glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_colors[i]);
self->params.egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
self->params.egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

View File

@@ -71,11 +71,15 @@ static bool gsr_image_writer_write_opengl_texture_to_file(gsr_image_writer *self
return false;
}
// TODO: hdr support
self->egl->glBindTexture(GL_TEXTURE_2D, self->texture);
// We could use glGetTexSubImage, but it's only available starting from opengl 4.5
self->egl->glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, frame_data);
self->egl->glBindTexture(GL_TEXTURE_2D, 0);
unsigned int fbo = 0;
self->egl->glGenFramebuffers(1, &fbo);
self->egl->glBindFramebuffer(GL_FRAMEBUFFER, fbo);
self->egl->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self->texture, 0);
self->egl->glReadPixels(0, 0, self->width, self->height, GL_RGBA, GL_UNSIGNED_BYTE, frame_data);
self->egl->glBindFramebuffer(GL_FRAMEBUFFER, 0);
self->egl->glDeleteFramebuffers(1, &fbo);
self->egl->glFlush();
self->egl->glFinish();

View File

@@ -663,7 +663,6 @@ static void open_video_software(AVCodecContext *codec_context, const args_parser
av_dict_set(&options, "preset", "veryfast", 0);
av_dict_set(&options, "tune", "film", 0);
av_dict_set(&options, "profile", "high", 0);
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?

View File

@@ -6,7 +6,7 @@
#include <spa/param/video/format-utils.h>
#include <spa/debug/types.h>
#include <libdrm/drm_fourcc.h>
#include <drm_fourcc.h>
#include <fcntl.h>
#include <unistd.h>
@@ -346,19 +346,19 @@ static int64_t spa_video_format_to_drm_format(const enum spa_video_format format
switch(format) {
case SPA_VIDEO_FORMAT_RGBx: return DRM_FORMAT_XBGR8888;
case SPA_VIDEO_FORMAT_BGRx: return DRM_FORMAT_XRGB8888;
case SPA_VIDEO_FORMAT_RGBA: return DRM_FORMAT_ABGR8888;
case SPA_VIDEO_FORMAT_BGRA: return DRM_FORMAT_ARGB8888;
// case SPA_VIDEO_FORMAT_RGBA: return DRM_FORMAT_ABGR8888;
//case SPA_VIDEO_FORMAT_BGRA: return DRM_FORMAT_ARGB8888;
case SPA_VIDEO_FORMAT_RGB: return DRM_FORMAT_XBGR8888;
case SPA_VIDEO_FORMAT_BGR: return DRM_FORMAT_XRGB8888;
case SPA_VIDEO_FORMAT_ARGB: return DRM_FORMAT_XRGB8888;
case SPA_VIDEO_FORMAT_ABGR: return DRM_FORMAT_XRGB8888;
//case SPA_VIDEO_FORMAT_ARGB: return DRM_FORMAT_XRGB8888;
//case SPA_VIDEO_FORMAT_ABGR: return DRM_FORMAT_XRGB8888;
#if PW_CHECK_VERSION(0, 3, 41)
case SPA_VIDEO_FORMAT_xRGB_210LE: return DRM_FORMAT_XRGB2101010;
case SPA_VIDEO_FORMAT_xBGR_210LE: return DRM_FORMAT_XBGR2101010;
case SPA_VIDEO_FORMAT_ARGB_210LE: return DRM_FORMAT_ARGB2101010;
case SPA_VIDEO_FORMAT_ABGR_210LE: return DRM_FORMAT_ABGR2101010;
// case SPA_VIDEO_FORMAT_ARGB_210LE: return DRM_FORMAT_ARGB2101010;
// case SPA_VIDEO_FORMAT_ABGR_210LE: return DRM_FORMAT_ABGR2101010;
#endif
default: break;
default: break;
}
return DRM_FORMAT_INVALID;
}
@@ -366,23 +366,23 @@ static int64_t spa_video_format_to_drm_format(const enum spa_video_format format
#if PW_CHECK_VERSION(0, 3, 41)
#define GSR_PIPEWIRE_VIDEO_NUM_VIDEO_FORMATS GSR_PIPEWIRE_VIDEO_MAX_VIDEO_FORMATS
#else
#define GSR_PIPEWIRE_VIDEO_NUM_VIDEO_FORMATS 8
#define GSR_PIPEWIRE_VIDEO_NUM_VIDEO_FORMATS 4
#endif
static const enum spa_video_format video_formats[GSR_PIPEWIRE_VIDEO_MAX_VIDEO_FORMATS] = {
SPA_VIDEO_FORMAT_BGRA,
// SPA_VIDEO_FORMAT_BGRA,
SPA_VIDEO_FORMAT_BGRx,
SPA_VIDEO_FORMAT_BGR,
SPA_VIDEO_FORMAT_RGBx,
SPA_VIDEO_FORMAT_RGBA,
// SPA_VIDEO_FORMAT_RGBA,
SPA_VIDEO_FORMAT_RGB,
SPA_VIDEO_FORMAT_ARGB,
SPA_VIDEO_FORMAT_ABGR,
// SPA_VIDEO_FORMAT_ARGB,
// SPA_VIDEO_FORMAT_ABGR,
#if PW_CHECK_VERSION(0, 3, 41)
SPA_VIDEO_FORMAT_xRGB_210LE,
SPA_VIDEO_FORMAT_xBGR_210LE,
SPA_VIDEO_FORMAT_ARGB_210LE,
SPA_VIDEO_FORMAT_ABGR_210LE
// SPA_VIDEO_FORMAT_ARGB_210LE,
// SPA_VIDEO_FORMAT_ABGR_210LE
#endif
};
@@ -471,6 +471,27 @@ static void gsr_pipewire_video_init_modifiers(gsr_pipewire_video *self) {
spa_video_format_get_modifiers(self, self->supported_video_formats[i].format, self->modifiers + self->num_modifiers, GSR_PIPEWIRE_VIDEO_MAX_MODIFIERS - self->num_modifiers, &num_modifiers);
self->supported_video_formats[i].modifiers_index = self->num_modifiers;
self->supported_video_formats[i].modifiers_size = num_modifiers;
self->num_modifiers += num_modifiers;
}
}
static void gsr_pipewire_video_format_remove_modifier(gsr_pipewire_video *self, gsr_video_format *video_format, uint64_t modifier) {
for(size_t i = 0; i < video_format->modifiers_size; ++i) {
if(self->modifiers[video_format->modifiers_index + i] != modifier)
continue;
for(size_t j = i + 1; j < video_format->modifiers_size; ++j) {
self->modifiers[j - 1] = self->modifiers[j];
}
--video_format->modifiers_size;
return;
}
}
static void gsr_pipewire_video_remove_modifier(gsr_pipewire_video *self, uint64_t modifier) {
for(size_t i = 0; i < GSR_PIPEWIRE_VIDEO_NUM_VIDEO_FORMATS; i++) {
gsr_video_format *video_format = &self->supported_video_formats[i];
gsr_pipewire_video_format_remove_modifier(self, video_format, modifier);
}
}
@@ -651,6 +672,7 @@ void gsr_pipewire_video_deinit(gsr_pipewire_video *self) {
self->dmabuf_num_planes = 0;
self->negotiated = false;
self->renegotiated = false;
if(self->mutex_initialized) {
pthread_mutex_destroy(&self->mutex);
@@ -702,9 +724,19 @@ static EGLImage gsr_pipewire_video_create_egl_image_with_fallback(gsr_pipewire_v
} else {
image = gsr_pipewire_video_create_egl_image(self, fds, offsets, pitches, modifiers, true);
if(!image) {
fprintf(stderr, "gsr error: gsr_pipewire_video_create_egl_image_with_fallback: failed to create egl image with modifiers, trying without modifiers\n");
self->no_modifiers_fallback = true;
image = gsr_pipewire_video_create_egl_image(self, fds, offsets, pitches, modifiers, false);
if(self->renegotiated) {
fprintf(stderr, "gsr error: gsr_pipewire_video_create_egl_image_with_fallback: failed to create egl image with modifiers, trying without modifiers\n");
self->no_modifiers_fallback = true;
image = gsr_pipewire_video_create_egl_image(self, fds, offsets, pitches, modifiers, false);
} else {
fprintf(stderr, "gsr error: gsr_pipewire_video_create_egl_image_with_fallback: failed to create egl image with modifiers, renegotiating with a different modifier\n");
self->negotiated = false;
self->renegotiated = true;
gsr_pipewire_video_remove_modifier(self, self->format.info.raw.modifier);
pw_thread_loop_lock(self->thread_loop);
pw_loop_signal_event(pw_thread_loop_get_loop(self->thread_loop), self->reneg);
pw_thread_loop_unlock(self->thread_loop);
}
}
}
return image;
@@ -736,13 +768,9 @@ static void gsr_pipewire_video_update_cursor_texture(gsr_pipewire_video *self, g
if(!self->cursor.data)
return;
const float border_color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
self->egl->glBindTexture(GL_TEXTURE_2D, texture_map.cursor_texture_id);
// TODO: glTextureSubImage2D if same size
self->egl->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, self->cursor.width, self->cursor.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, self->cursor.data);
self->egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
self->egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
self->egl->glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
self->egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
self->egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
self->egl->glBindTexture(GL_TEXTURE_2D, 0);
@@ -767,12 +795,15 @@ bool gsr_pipewire_video_map_texture(gsr_pipewire_video *self, gsr_texture_map te
}
EGLImage image = gsr_pipewire_video_create_egl_image_with_fallback(self);
if(image) {
gsr_pipewire_video_bind_image_to_texture_with_fallback(self, texture_map, image);
*using_external_image = self->external_texture_fallback;
self->egl->eglDestroyImage(self->egl->egl_display, image);
if(!image) {
pthread_mutex_unlock(&self->mutex);
return false;
}
gsr_pipewire_video_bind_image_to_texture_with_fallback(self, texture_map, image);
*using_external_image = self->external_texture_fallback;
self->egl->eglDestroyImage(self->egl->egl_display, image);
gsr_pipewire_video_update_cursor_texture(self, texture_map);
region->x = 0;

View File

@@ -598,22 +598,12 @@ vec2i scale_keep_aspect_ratio(vec2i from, vec2i to) {
}
unsigned int gl_create_texture(gsr_egl *egl, int width, int height, int internal_format, unsigned int format, int filter) {
float border_color[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
if(format == GL_RG) { // UV
border_color[0] = 0.5f;
border_color[1] = 0.5f;
border_color[2] = 0.0f;
border_color[3] = 1.0f;
}
unsigned int texture_id = 0;
egl->glGenTextures(1, &texture_id);
egl->glBindTexture(GL_TEXTURE_2D, texture_id);
egl->glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, format, GL_UNSIGNED_BYTE, NULL);
//egl->glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, format, GL_UNSIGNED_BYTE, NULL);
egl->glTexStorage2D(GL_TEXTURE_2D, 1, internal_format, width, height);
egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
egl->glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);

View File

@@ -85,10 +85,6 @@ int window_texture_on_resize(WindowTexture *self) {
texture_id = self->texture_id;
}
const float border_color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
self->egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
self->egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
self->egl->glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
self->egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
self->egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);