Add screen rotation support (tested on amd/intel)

screen rotation in wayland is best effort,
wayland doesn't give the necessary information to make it robust.
This commit is contained in:
dec05eba
2024-02-10 02:47:01 +01:00
parent ac73d9cb13
commit b8843395ac
10 changed files with 330 additions and 56 deletions

8
TODO
View File

@@ -116,4 +116,10 @@ Support low power option (does it even work with vaapi in ffmpeg??). Would be ve
Instead of sending a big list of drm data back to kms client, send the monitor we want to record to kms server and the server should respond with only the matching monitor, and cursor. Instead of sending a big list of drm data back to kms client, send the monitor we want to record to kms server and the server should respond with only the matching monitor, and cursor.
Tonemap hdr to sdr when hdr is enabled and when hevc_hdr/av1_hdr is not used. Tonemap hdr to sdr when hdr is enabled and when hevc_hdr/av1_hdr is not used.
Support hdr capture with kms cuda. Support hdr capture with kms cuda.
Mention known issue, capture on intel wayland compressed data glitch.
Add 10 bit record option, h264_10bit, hevc_10bit and av1_10bit.
Rotate cursor texture properly (around top left origin)

View File

@@ -19,6 +19,11 @@ typedef enum {
GSR_DESTINATION_COLOR_P010 /* YUV420, BT2020, 10-bit */ GSR_DESTINATION_COLOR_P010 /* YUV420, BT2020, 10-bit */
} gsr_destination_color; } gsr_destination_color;
typedef struct {
int offset;
int rotation;
} gsr_color_uniforms;
typedef struct { typedef struct {
gsr_egl *egl; gsr_egl *egl;
@@ -33,7 +38,7 @@ typedef struct {
typedef struct { typedef struct {
gsr_color_conversion_params params; gsr_color_conversion_params params;
int rotation_uniforms[2]; gsr_color_uniforms uniforms[2];
gsr_shader shaders[2]; gsr_shader shaders[2];
unsigned int framebuffers[2]; unsigned int framebuffers[2];

View File

@@ -119,6 +119,7 @@ typedef struct {
void *output; void *output;
vec2i pos; vec2i pos;
vec2i size; vec2i size;
int32_t transform;
char *name; char *name;
} gsr_wayland_output; } gsr_wayland_output;
@@ -215,6 +216,7 @@ typedef struct {
void (*glBlendFunc)(unsigned int sfactor, unsigned int dfactor); void (*glBlendFunc)(unsigned int sfactor, unsigned int dfactor);
int (*glGetUniformLocation)(unsigned int program, const char *name); int (*glGetUniformLocation)(unsigned int program, const char *name);
void (*glUniform1f)(int location, float v0); void (*glUniform1f)(int location, float v0);
void (*glUniform2f)(int location, float v0, float v1);
} gsr_egl; } gsr_egl;
bool gsr_egl_load(gsr_egl *self, Display *dpy, bool wayland); bool gsr_egl_load(gsr_egl *self, Display *dpy, bool wayland);

View File

@@ -18,13 +18,22 @@ typedef struct {
int gpu_version; /* 0 if unknown */ int gpu_version; /* 0 if unknown */
} gsr_gpu_info; } gsr_gpu_info;
typedef enum {
GSR_MONITOR_ROT_0,
GSR_MONITOR_ROT_90,
GSR_MONITOR_ROT_180,
GSR_MONITOR_ROT_270
} gsr_monitor_rotation;
typedef struct { typedef struct {
const char *name; const char *name;
int name_len; int name_len;
vec2i pos; vec2i pos;
vec2i size; vec2i size;
XRRCrtcInfo *crt_info; /* Only on x11 */ XRRCrtcInfo *crt_info; /* Only on x11 */
uint32_t connector_id; /* Only on drm */ uint32_t connector_id; /* Only on x11 and drm */
gsr_monitor_rotation rotation; /* Only on x11 and wayland */
uint32_t monitor_identifier; /* Only on drm and wayland */
} gsr_monitor; } gsr_monitor;
typedef enum { typedef enum {
@@ -46,6 +55,7 @@ typedef void (*active_monitor_callback)(const gsr_monitor *monitor, void *userda
void for_each_active_monitor_output_x11(Display *display, active_monitor_callback callback, void *userdata); void for_each_active_monitor_output_x11(Display *display, active_monitor_callback callback, void *userdata);
void for_each_active_monitor_output(const gsr_egl *egl, gsr_connection_type connection_type, active_monitor_callback callback, void *userdata); void for_each_active_monitor_output(const gsr_egl *egl, gsr_connection_type connection_type, active_monitor_callback callback, void *userdata);
bool get_monitor_by_name(const gsr_egl *egl, gsr_connection_type connection_type, const char *name, gsr_monitor *monitor); bool get_monitor_by_name(const gsr_egl *egl, gsr_connection_type connection_type, const char *name, gsr_monitor *monitor);
gsr_monitor_rotation drm_monitor_get_display_server_rotation(const gsr_egl *egl, const gsr_monitor *monitor);
bool gl_get_gpu_info(gsr_egl *egl, gsr_gpu_info *info); bool gl_get_gpu_info(gsr_egl *egl, gsr_gpu_info *info);

View File

@@ -50,6 +50,8 @@ typedef struct {
unsigned int target_texture; unsigned int target_texture;
gsr_color_conversion color_conversion; gsr_color_conversion color_conversion;
gsr_monitor_rotation monitor_rotation;
} gsr_capture_kms_cuda; } gsr_capture_kms_cuda;
static int max_int(int a, int b) { static int max_int(int a, int b) {
@@ -162,8 +164,16 @@ static int gsr_capture_kms_cuda_start(gsr_capture *cap, AVCodecContext *video_co
return -1; return -1;
} }
monitor.name = cap_kms->params.display_to_capture;
cap_kms->monitor_rotation = drm_monitor_get_display_server_rotation(cap_kms->params.egl, &monitor);
cap_kms->capture_pos = monitor.pos; cap_kms->capture_pos = monitor.pos;
cap_kms->capture_size = monitor.size; if(cap_kms->monitor_rotation == GSR_MONITOR_ROT_90 || cap_kms->monitor_rotation == GSR_MONITOR_ROT_270) {
cap_kms->capture_size.x = monitor.size.y;
cap_kms->capture_size.y = monitor.size.x;
} else {
cap_kms->capture_size = monitor.size;
}
video_codec_context->width = max_int(2, cap_kms->capture_size.x & ~1); video_codec_context->width = max_int(2, cap_kms->capture_size.x & ~1);
video_codec_context->height = max_int(2, cap_kms->capture_size.y & ~1); video_codec_context->height = max_int(2, cap_kms->capture_size.y & ~1);
@@ -316,6 +326,16 @@ static bool gsr_capture_kms_cuda_should_stop(gsr_capture *cap, bool *err) {
return false; return false;
} }
static float monitor_rotation_to_radians(gsr_monitor_rotation rot) {
switch(rot) {
case GSR_MONITOR_ROT_0: return 0.0f;
case GSR_MONITOR_ROT_90: return M_PI_2;
case GSR_MONITOR_ROT_180: return M_PI;
case GSR_MONITOR_ROT_270: return M_PI + M_PI_2;
}
return 0.0f;
}
/* Prefer non combined planes */ /* Prefer non combined planes */
static gsr_kms_response_fd* find_drm_by_connector_id(gsr_kms_response *kms_response, uint32_t connector_id) { static gsr_kms_response_fd* find_drm_by_connector_id(gsr_kms_response *kms_response, uint32_t connector_id) {
int index_combined = -1; int index_combined = -1;
@@ -381,6 +401,13 @@ static gsr_kms_response_fd* find_cursor_drm(gsr_kms_response *kms_response) {
return NULL; return NULL;
} }
static vec2i swap_vec2i(vec2i value) {
int tmp = value.x;
value.x = value.y;
value.y = tmp;
return value;
}
static int gsr_capture_kms_cuda_capture(gsr_capture *cap, AVFrame *frame) { static int gsr_capture_kms_cuda_capture(gsr_capture *cap, AVFrame *frame) {
(void)frame; (void)frame;
gsr_capture_kms_cuda *cap_kms = cap->priv; gsr_capture_kms_cuda *cap_kms = cap->priv;
@@ -457,12 +484,40 @@ static int gsr_capture_kms_cuda_capture(gsr_capture *cap, AVFrame *frame) {
if(!capture_is_combined_plane) if(!capture_is_combined_plane)
capture_pos = (vec2i){drm_fd->x, drm_fd->y}; capture_pos = (vec2i){drm_fd->x, drm_fd->y};
const float texture_rotation = monitor_rotation_to_radians(cap_kms->monitor_rotation);
gsr_color_conversion_draw(&cap_kms->color_conversion, cap_kms->input_texture, gsr_color_conversion_draw(&cap_kms->color_conversion, cap_kms->input_texture,
(vec2i){0, 0}, cap_kms->capture_size, (vec2i){0, 0}, cap_kms->capture_size,
capture_pos, cap_kms->capture_size, capture_pos, cap_kms->capture_size,
0.0f, false); texture_rotation, false);
if(cursor_drm_fd) { if(cursor_drm_fd) {
const vec2i cursor_size = {cursor_drm_fd->width, cursor_drm_fd->height};
vec2i cursor_pos = {cursor_drm_fd->x, cursor_drm_fd->y};
switch(cap_kms->monitor_rotation) {
case GSR_MONITOR_ROT_0:
break;
case GSR_MONITOR_ROT_90:
cursor_pos = swap_vec2i(cursor_pos);
cursor_pos.x = cap_kms->capture_size.x - cursor_pos.x;
// TODO: Remove this horrible hack
cursor_pos.x -= cursor_size.x;
break;
case GSR_MONITOR_ROT_180:
cursor_pos.x = cap_kms->capture_size.x - cursor_pos.x;
cursor_pos.y = cap_kms->capture_size.y - cursor_pos.y;
// TODO: Remove this horrible hack
cursor_pos.x -= cursor_size.x;
cursor_pos.y -= cursor_size.y;
break;
case GSR_MONITOR_ROT_270:
cursor_pos = swap_vec2i(cursor_pos);
cursor_pos.y = cap_kms->capture_size.y - cursor_pos.y;
// TODO: Remove this horrible hack
cursor_pos.y -= cursor_size.y;
break;
}
const intptr_t img_attr_cursor[] = { const intptr_t img_attr_cursor[] = {
EGL_LINUX_DRM_FOURCC_EXT, cursor_drm_fd->pixel_format, EGL_LINUX_DRM_FOURCC_EXT, cursor_drm_fd->pixel_format,
EGL_WIDTH, cursor_drm_fd->width, EGL_WIDTH, cursor_drm_fd->width,
@@ -481,11 +536,10 @@ static int gsr_capture_kms_cuda_capture(gsr_capture *cap, AVFrame *frame) {
cap_kms->params.egl->eglDestroyImage(cap_kms->params.egl->egl_display, cursor_image); cap_kms->params.egl->eglDestroyImage(cap_kms->params.egl->egl_display, cursor_image);
cap_kms->params.egl->glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0); cap_kms->params.egl->glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
vec2i cursor_size = {cursor_drm_fd->width, cursor_drm_fd->height};
gsr_color_conversion_draw(&cap_kms->color_conversion, cap_kms->cursor_texture, gsr_color_conversion_draw(&cap_kms->color_conversion, cap_kms->cursor_texture,
(vec2i){cursor_drm_fd->x, cursor_drm_fd->y}, cursor_size, cursor_pos, cursor_size,
(vec2i){0, 0}, cursor_size, (vec2i){0, 0}, cursor_size,
0.0f, true); texture_rotation, true);
} }
cap_kms->params.egl->eglSwapBuffers(cap_kms->params.egl->egl_display, cap_kms->params.egl->egl_surface); cap_kms->params.egl->eglSwapBuffers(cap_kms->params.egl->egl_display, cap_kms->params.egl->egl_surface);

View File

@@ -46,6 +46,8 @@ typedef struct {
AVCodecContext *video_codec_context; AVCodecContext *video_codec_context;
AVMasteringDisplayMetadata *mastering_display_metadata; AVMasteringDisplayMetadata *mastering_display_metadata;
AVContentLightMetadata *light_metadata; AVContentLightMetadata *light_metadata;
gsr_monitor_rotation monitor_rotation;
} gsr_capture_kms_vaapi; } gsr_capture_kms_vaapi;
static int max_int(int a, int b) { static int max_int(int a, int b) {
@@ -156,8 +158,16 @@ static int gsr_capture_kms_vaapi_start(gsr_capture *cap, AVCodecContext *video_c
return -1; return -1;
} }
monitor.name = cap_kms->params.display_to_capture;
cap_kms->monitor_rotation = drm_monitor_get_display_server_rotation(cap_kms->params.egl, &monitor);
cap_kms->capture_pos = monitor.pos; cap_kms->capture_pos = monitor.pos;
cap_kms->capture_size = monitor.size; if(cap_kms->monitor_rotation == GSR_MONITOR_ROT_90 || cap_kms->monitor_rotation == GSR_MONITOR_ROT_270) {
cap_kms->capture_size.x = monitor.size.y;
cap_kms->capture_size.y = monitor.size.x;
} else {
cap_kms->capture_size = monitor.size;
}
/* Disable vsync */ /* Disable vsync */
cap_kms->params.egl->eglSwapInterval(cap_kms->params.egl->egl_display, 0); cap_kms->params.egl->eglSwapInterval(cap_kms->params.egl->egl_display, 0);
@@ -338,6 +348,16 @@ static bool gsr_capture_kms_vaapi_should_stop(gsr_capture *cap, bool *err) {
return false; return false;
} }
static float monitor_rotation_to_radians(gsr_monitor_rotation rot) {
switch(rot) {
case GSR_MONITOR_ROT_0: return 0.0f;
case GSR_MONITOR_ROT_90: return M_PI_2;
case GSR_MONITOR_ROT_180: return M_PI;
case GSR_MONITOR_ROT_270: return M_PI + M_PI_2;
}
return 0.0f;
}
/* Prefer non combined planes */ /* Prefer non combined planes */
static gsr_kms_response_fd* find_drm_by_connector_id(gsr_kms_response *kms_response, uint32_t connector_id) { static gsr_kms_response_fd* find_drm_by_connector_id(gsr_kms_response *kms_response, uint32_t connector_id) {
int index_combined = -1; int index_combined = -1;
@@ -426,6 +446,13 @@ static void gsr_capture_kms_vaapi_set_hdr_metadata(gsr_capture_kms_vaapi *cap_km
} }
} }
static vec2i swap_vec2i(vec2i value) {
int tmp = value.x;
value.x = value.y;
value.y = tmp;
return value;
}
static int gsr_capture_kms_vaapi_capture(gsr_capture *cap, AVFrame *frame) { static int gsr_capture_kms_vaapi_capture(gsr_capture *cap, AVFrame *frame) {
gsr_capture_kms_vaapi *cap_kms = cap->priv; gsr_capture_kms_vaapi *cap_kms = cap->priv;
@@ -518,12 +545,15 @@ static int gsr_capture_kms_vaapi_capture(gsr_capture *cap, AVFrame *frame) {
cap_kms->params.egl->eglDestroyImage(cap_kms->params.egl->egl_display, image); cap_kms->params.egl->eglDestroyImage(cap_kms->params.egl->egl_display, image);
cap_kms->params.egl->glBindTexture(GL_TEXTURE_2D, 0); cap_kms->params.egl->glBindTexture(GL_TEXTURE_2D, 0);
vec2i capture_pos = cap_kms->capture_pos; // TODO: Test rotation with multiple monitors, different rotation setups
// TODO: Make rotation work on wayland
// TODO: Apply these changes to kms cuda too, and test that
vec2i capture_pos = cap_kms->capture_pos;
if(!capture_is_combined_plane) if(!capture_is_combined_plane)
capture_pos = (vec2i){drm_fd->x, drm_fd->y}; capture_pos = (vec2i){drm_fd->x, drm_fd->y};
float texture_rotation = 0.0f; const float texture_rotation = monitor_rotation_to_radians(cap_kms->monitor_rotation);
gsr_color_conversion_draw(&cap_kms->color_conversion, cap_kms->input_texture, gsr_color_conversion_draw(&cap_kms->color_conversion, cap_kms->input_texture,
(vec2i){0, 0}, cap_kms->capture_size, (vec2i){0, 0}, cap_kms->capture_size,
@@ -531,6 +561,32 @@ static int gsr_capture_kms_vaapi_capture(gsr_capture *cap, AVFrame *frame) {
texture_rotation, false); texture_rotation, false);
if(cursor_drm_fd) { if(cursor_drm_fd) {
const vec2i cursor_size = {cursor_drm_fd->width, cursor_drm_fd->height};
vec2i cursor_pos = {cursor_drm_fd->x, cursor_drm_fd->y};
switch(cap_kms->monitor_rotation) {
case GSR_MONITOR_ROT_0:
break;
case GSR_MONITOR_ROT_90:
cursor_pos = swap_vec2i(cursor_pos);
cursor_pos.x = cap_kms->capture_size.x - cursor_pos.x;
// TODO: Remove this horrible hack
cursor_pos.x -= cursor_size.x;
break;
case GSR_MONITOR_ROT_180:
cursor_pos.x = cap_kms->capture_size.x - cursor_pos.x;
cursor_pos.y = cap_kms->capture_size.y - cursor_pos.y;
// TODO: Remove this horrible hack
cursor_pos.x -= cursor_size.x;
cursor_pos.y -= cursor_size.y;
break;
case GSR_MONITOR_ROT_270:
cursor_pos = swap_vec2i(cursor_pos);
cursor_pos.y = cap_kms->capture_size.y - cursor_pos.y;
// TODO: Remove this horrible hack
cursor_pos.y -= cursor_size.y;
break;
}
const intptr_t img_attr_cursor[] = { const intptr_t img_attr_cursor[] = {
EGL_LINUX_DRM_FOURCC_EXT, cursor_drm_fd->pixel_format, EGL_LINUX_DRM_FOURCC_EXT, cursor_drm_fd->pixel_format,
EGL_WIDTH, cursor_drm_fd->width, EGL_WIDTH, cursor_drm_fd->width,
@@ -549,11 +605,10 @@ static int gsr_capture_kms_vaapi_capture(gsr_capture *cap, AVFrame *frame) {
cap_kms->params.egl->eglDestroyImage(cap_kms->params.egl->egl_display, cursor_image); cap_kms->params.egl->eglDestroyImage(cap_kms->params.egl->egl_display, cursor_image);
cap_kms->params.egl->glBindTexture(GL_TEXTURE_2D, 0); cap_kms->params.egl->glBindTexture(GL_TEXTURE_2D, 0);
vec2i cursor_size = {cursor_drm_fd->width, cursor_drm_fd->height};
gsr_color_conversion_draw(&cap_kms->color_conversion, cap_kms->cursor_texture, gsr_color_conversion_draw(&cap_kms->color_conversion, cap_kms->cursor_texture,
(vec2i){cursor_drm_fd->x, cursor_drm_fd->y}, cursor_size, cursor_pos, cursor_size,
(vec2i){0, 0}, cursor_size, (vec2i){0, 0}, cursor_size,
0.0f, false); texture_rotation, false);
} }
cap_kms->params.egl->eglSwapBuffers(cap_kms->params.egl->egl_display, cap_kms->params.egl->egl_surface); cap_kms->params.egl->eglSwapBuffers(cap_kms->params.egl->egl_display, cap_kms->params.egl->egl_surface);

View File

@@ -33,7 +33,7 @@ static float abs_f(float v) {
#define RGB_TO_P010_LIMITED "const mat4 RGBtoYUV = mat4(0.225613, -0.119918, 0.429412, 0.000000,\n" \ #define RGB_TO_P010_LIMITED "const mat4 RGBtoYUV = mat4(0.225613, -0.119918, 0.429412, 0.000000,\n" \
" 0.582282, -0.309494, -0.394875, 0.000000,\n" \ " 0.582282, -0.309494, -0.394875, 0.000000,\n" \
" 0.050928, 0.429412, -0.034537, 0.000000,\n" \ " 0.050928, 0.429412, -0.034537, 0.000000,\n" \
" 0.062745, 0.500000, 0.500000, 1.000000)"; " 0.062745, 0.500000, 0.500000, 1.000000);"
/* ITU-R BT709, full */ /* ITU-R BT709, full */
/* https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.709-6-201506-I!!PDF-E.pdf */ /* https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.709-6-201506-I!!PDF-E.pdf */
@@ -74,19 +74,20 @@ static const char* color_format_range_get_transform_matrix(gsr_destination_color
return NULL; return NULL;
} }
static int load_shader_bgr(gsr_shader *shader, gsr_egl *egl, int *rotation_uniform) { static int load_shader_bgr(gsr_shader *shader, gsr_egl *egl, gsr_color_uniforms *uniforms) {
char vertex_shader[2048]; char vertex_shader[2048];
snprintf(vertex_shader, sizeof(vertex_shader), snprintf(vertex_shader, sizeof(vertex_shader),
"#version 300 es \n" "#version 300 es \n"
"in vec2 pos; \n" "in vec2 pos; \n"
"in vec2 texcoords; \n" "in vec2 texcoords; \n"
"out vec2 texcoords_out; \n" "out vec2 texcoords_out; \n"
"uniform vec2 offset; \n"
"uniform float rotation; \n" "uniform float rotation; \n"
ROTATE_Z ROTATE_Z
"void main() \n" "void main() \n"
"{ \n" "{ \n"
" texcoords_out = texcoords; \n" " texcoords_out = (vec4(texcoords.x - 0.5, texcoords.y - 0.5, 0.0, 0.0) * rotate_z(rotation)).xy + vec2(0.5, 0.5); \n"
" gl_Position = vec4(pos.x, pos.y, 0.0, 1.0) * rotate_z(rotation); \n" " gl_Position = vec4(offset.x, offset.y, 0.0, 0.0) + vec4(pos.x, pos.y, 0.0, 1.0); \n"
"} \n"); "} \n");
char fragment_shader[] = char fragment_shader[] =
@@ -105,23 +106,25 @@ static int load_shader_bgr(gsr_shader *shader, gsr_egl *egl, int *rotation_unifo
gsr_shader_bind_attribute_location(shader, "pos", 0); gsr_shader_bind_attribute_location(shader, "pos", 0);
gsr_shader_bind_attribute_location(shader, "texcoords", 1); gsr_shader_bind_attribute_location(shader, "texcoords", 1);
*rotation_uniform = egl->glGetUniformLocation(shader->program_id, "rotation"); uniforms->offset = egl->glGetUniformLocation(shader->program_id, "offset");
uniforms->rotation = egl->glGetUniformLocation(shader->program_id, "rotation");
return 0; return 0;
} }
static int load_shader_bgr_external_texture(gsr_shader *shader, gsr_egl *egl, int *rotation_uniform) { static int load_shader_bgr_external_texture(gsr_shader *shader, gsr_egl *egl, gsr_color_uniforms *uniforms) {
char vertex_shader[2048]; char vertex_shader[2048];
snprintf(vertex_shader, sizeof(vertex_shader), snprintf(vertex_shader, sizeof(vertex_shader),
"#version 300 es \n" "#version 300 es \n"
"in vec2 pos; \n" "in vec2 pos; \n"
"in vec2 texcoords; \n" "in vec2 texcoords; \n"
"out vec2 texcoords_out; \n" "out vec2 texcoords_out; \n"
"uniform vec2 offset; \n"
"uniform float rotation; \n" "uniform float rotation; \n"
ROTATE_Z ROTATE_Z
"void main() \n" "void main() \n"
"{ \n" "{ \n"
" texcoords_out = texcoords; \n" " texcoords_out = (vec4(texcoords.x - 0.5, texcoords.y - 0.5, 0.0, 0.0) * rotate_z(rotation)).xy + vec2(0.5, 0.5); \n"
" gl_Position = vec4(pos.x, pos.y, 0.0, 1.0) * rotate_z(rotation); \n" " gl_Position = vec4(offset.x, offset.y, 0.0, 0.0) + vec4(pos.x, pos.y, 0.0, 1.0); \n"
"} \n"); "} \n");
char fragment_shader[] = char fragment_shader[] =
@@ -142,11 +145,12 @@ static int load_shader_bgr_external_texture(gsr_shader *shader, gsr_egl *egl, in
gsr_shader_bind_attribute_location(shader, "pos", 0); gsr_shader_bind_attribute_location(shader, "pos", 0);
gsr_shader_bind_attribute_location(shader, "texcoords", 1); gsr_shader_bind_attribute_location(shader, "texcoords", 1);
*rotation_uniform = egl->glGetUniformLocation(shader->program_id, "rotation"); uniforms->offset = egl->glGetUniformLocation(shader->program_id, "offset");
uniforms->rotation = egl->glGetUniformLocation(shader->program_id, "rotation");
return 0; return 0;
} }
static int load_shader_y(gsr_shader *shader, gsr_egl *egl, int *rotation_uniform, gsr_destination_color color_format, gsr_color_range color_range) { static int load_shader_y(gsr_shader *shader, gsr_egl *egl, gsr_color_uniforms *uniforms, gsr_destination_color color_format, gsr_color_range color_range) {
const char *color_transform_matrix = color_format_range_get_transform_matrix(color_format, color_range); const char *color_transform_matrix = color_format_range_get_transform_matrix(color_format, color_range);
char vertex_shader[2048]; char vertex_shader[2048];
@@ -155,12 +159,13 @@ static int load_shader_y(gsr_shader *shader, gsr_egl *egl, int *rotation_uniform
"in vec2 pos; \n" "in vec2 pos; \n"
"in vec2 texcoords; \n" "in vec2 texcoords; \n"
"out vec2 texcoords_out; \n" "out vec2 texcoords_out; \n"
"uniform vec2 offset; \n"
"uniform float rotation; \n" "uniform float rotation; \n"
ROTATE_Z ROTATE_Z
"void main() \n" "void main() \n"
"{ \n" "{ \n"
" texcoords_out = texcoords; \n" " texcoords_out = (vec4(texcoords.x - 0.5, texcoords.y - 0.5, 0.0, 0.0) * rotate_z(rotation)).xy + vec2(0.5, 0.5); \n"
" gl_Position = vec4(pos.x, pos.y, 0.0, 1.0) * rotate_z(rotation); \n" " gl_Position = vec4(offset.x, offset.y, 0.0, 0.0) + vec4(pos.x, pos.y, 0.0, 1.0); \n"
"} \n"); "} \n");
char fragment_shader[2048]; char fragment_shader[2048];
@@ -183,11 +188,12 @@ static int load_shader_y(gsr_shader *shader, gsr_egl *egl, int *rotation_uniform
gsr_shader_bind_attribute_location(shader, "pos", 0); gsr_shader_bind_attribute_location(shader, "pos", 0);
gsr_shader_bind_attribute_location(shader, "texcoords", 1); gsr_shader_bind_attribute_location(shader, "texcoords", 1);
*rotation_uniform = egl->glGetUniformLocation(shader->program_id, "rotation"); uniforms->offset = egl->glGetUniformLocation(shader->program_id, "offset");
uniforms->rotation = egl->glGetUniformLocation(shader->program_id, "rotation");
return 0; return 0;
} }
static unsigned int load_shader_uv(gsr_shader *shader, gsr_egl *egl, int *rotation_uniform, gsr_destination_color color_format, gsr_color_range color_range) { static unsigned int load_shader_uv(gsr_shader *shader, gsr_egl *egl, gsr_color_uniforms *uniforms, gsr_destination_color color_format, gsr_color_range color_range) {
const char *color_transform_matrix = color_format_range_get_transform_matrix(color_format, color_range); const char *color_transform_matrix = color_format_range_get_transform_matrix(color_format, color_range);
char vertex_shader[2048]; char vertex_shader[2048];
@@ -196,12 +202,13 @@ static unsigned int load_shader_uv(gsr_shader *shader, gsr_egl *egl, int *rotati
"in vec2 pos; \n" "in vec2 pos; \n"
"in vec2 texcoords; \n" "in vec2 texcoords; \n"
"out vec2 texcoords_out; \n" "out vec2 texcoords_out; \n"
"uniform vec2 offset; \n"
"uniform float rotation; \n" "uniform float rotation; \n"
ROTATE_Z ROTATE_Z
"void main() \n" "void main() \n"
"{ \n" "{ \n"
" texcoords_out = texcoords; \n" " texcoords_out = (vec4(texcoords.x - 0.5, texcoords.y - 0.5, 0.0, 0.0) * rotate_z(rotation)).xy + vec2(0.5, 0.5); \n"
" gl_Position = vec4(pos.x, pos.y, 0.0, 1.0) * rotate_z(rotation) * vec4(0.5, 0.5, 1.0, 1.0) - vec4(0.5, 0.5, 0.0, 0.0); \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"); "} \n");
char fragment_shader[2048]; char fragment_shader[2048];
@@ -224,7 +231,8 @@ static unsigned int load_shader_uv(gsr_shader *shader, gsr_egl *egl, int *rotati
gsr_shader_bind_attribute_location(shader, "pos", 0); gsr_shader_bind_attribute_location(shader, "pos", 0);
gsr_shader_bind_attribute_location(shader, "texcoords", 1); gsr_shader_bind_attribute_location(shader, "texcoords", 1);
*rotation_uniform = egl->glGetUniformLocation(shader->program_id, "rotation"); uniforms->offset = egl->glGetUniformLocation(shader->program_id, "offset");
uniforms->rotation = egl->glGetUniformLocation(shader->program_id, "rotation");
return 0; return 0;
} }
@@ -291,12 +299,12 @@ int gsr_color_conversion_init(gsr_color_conversion *self, const gsr_color_conver
return -1; return -1;
} }
if(load_shader_bgr(&self->shaders[0], self->params.egl, &self->rotation_uniforms[0]) != 0) { if(load_shader_bgr(&self->shaders[0], self->params.egl, &self->uniforms[0]) != 0) {
fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load bgr shader\n"); fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load bgr shader\n");
goto err; goto err;
} }
if(load_shader_bgr_external_texture(&self->shaders[1], self->params.egl, &self->rotation_uniforms[1]) != 0) { if(load_shader_bgr_external_texture(&self->shaders[1], self->params.egl, &self->uniforms[1]) != 0) {
fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load bgr shader (external texture)\n"); fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load bgr shader (external texture)\n");
goto err; goto err;
} }
@@ -309,12 +317,12 @@ int gsr_color_conversion_init(gsr_color_conversion *self, const gsr_color_conver
return -1; return -1;
} }
if(load_shader_y(&self->shaders[0], self->params.egl, &self->rotation_uniforms[0], params->destination_color, params->color_range) != 0) { if(load_shader_y(&self->shaders[0], self->params.egl, &self->uniforms[0], params->destination_color, params->color_range) != 0) {
fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load Y shader\n"); fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load Y shader\n");
goto err; goto err;
} }
if(load_shader_uv(&self->shaders[1], self->params.egl, &self->rotation_uniforms[1], params->destination_color, params->color_range) != 0) { if(load_shader_uv(&self->shaders[1], self->params.egl, &self->uniforms[1], params->destination_color, params->color_range) != 0) {
fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load UV shader\n"); fprintf(stderr, "gsr error: gsr_color_conversion_init: failed to load UV shader\n");
goto err; goto err;
} }
@@ -363,6 +371,9 @@ void gsr_color_conversion_deinit(gsr_color_conversion *self) {
/* |source_pos| is in pixel coordinates and |source_size| */ /* |source_pos| is in pixel coordinates and |source_size| */
void gsr_color_conversion_draw(gsr_color_conversion *self, unsigned int texture_id, vec2i source_pos, vec2i source_size, vec2i texture_pos, vec2i texture_size, float rotation, bool external_texture) { void gsr_color_conversion_draw(gsr_color_conversion *self, unsigned int texture_id, vec2i source_pos, vec2i source_size, vec2i texture_pos, vec2i texture_size, float rotation, bool external_texture) {
// TODO: Remove this crap
rotation = M_PI*2.0f - rotation;
/* TODO: Do not call this every frame? */ /* TODO: Do not call this every frame? */
vec2i dest_texture_size = {0, 0}; vec2i dest_texture_size = {0, 0};
self->params.egl->glBindTexture(GL_TEXTURE_2D, self->params.destination_textures[0]); self->params.egl->glBindTexture(GL_TEXTURE_2D, self->params.destination_textures[0]);
@@ -383,6 +394,7 @@ void gsr_color_conversion_draw(gsr_color_conversion *self, unsigned int texture_
self->params.egl->glGetTexLevelParameteriv(texture_target, 0, GL_TEXTURE_HEIGHT, &source_texture_size.y); self->params.egl->glGetTexLevelParameteriv(texture_target, 0, GL_TEXTURE_HEIGHT, &source_texture_size.y);
} }
// TODO: Remove this crap
if(abs_f(M_PI * 0.5f - rotation) <= 0.001f || abs_f(M_PI * 1.5f - rotation) <= 0.001f) { if(abs_f(M_PI * 0.5f - rotation) <= 0.001f || abs_f(M_PI * 1.5f - rotation) <= 0.001f) {
float tmp = source_texture_size.x; float tmp = source_texture_size.x;
source_texture_size.x = source_texture_size.y; source_texture_size.x = source_texture_size.y;
@@ -410,13 +422,13 @@ void gsr_color_conversion_draw(gsr_color_conversion *self, unsigned int texture_
}; };
const float vertices[] = { const float vertices[] = {
-1.0f + pos_norm.x, -1.0f + pos_norm.y + size_norm.y, texture_pos_norm.x, texture_pos_norm.y + texture_size_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 + pos_norm.x, -1.0f + pos_norm.y, texture_pos_norm.x, texture_pos_norm.y, -1.0f + 0.0f, -1.0f + 0.0f, texture_pos_norm.x, texture_pos_norm.y,
-1.0f + pos_norm.x + size_norm.x, -1.0f + pos_norm.y, texture_pos_norm.x + texture_size_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 + pos_norm.x, -1.0f + pos_norm.y + size_norm.y, texture_pos_norm.x, texture_pos_norm.y + texture_size_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 + pos_norm.x + size_norm.x, -1.0f + pos_norm.y, texture_pos_norm.x + texture_size_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 + pos_norm.x + size_norm.x, -1.0f + pos_norm.y + size_norm.y, texture_pos_norm.x + texture_size_norm.x, texture_pos_norm.y + texture_size_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->glBindVertexArray(self->vertex_array_object_id);
@@ -432,10 +444,12 @@ void gsr_color_conversion_draw(gsr_color_conversion *self, unsigned int texture_
if(external_texture) { if(external_texture) {
gsr_shader_use(&self->shaders[1]); gsr_shader_use(&self->shaders[1]);
self->params.egl->glUniform1f(self->rotation_uniforms[1], rotation); self->params.egl->glUniform1f(self->uniforms[1].rotation, rotation);
self->params.egl->glUniform2f(self->uniforms[1].offset, pos_norm.x, pos_norm.y);
} else { } else {
gsr_shader_use(&self->shaders[0]); gsr_shader_use(&self->shaders[0]);
self->params.egl->glUniform1f(self->rotation_uniforms[0], rotation); self->params.egl->glUniform1f(self->uniforms[0].rotation, rotation);
self->params.egl->glUniform2f(self->uniforms[0].offset, pos_norm.x, pos_norm.y);
} }
self->params.egl->glDrawArrays(GL_TRIANGLES, 0, 6); self->params.egl->glDrawArrays(GL_TRIANGLES, 0, 6);
} }
@@ -445,7 +459,8 @@ void gsr_color_conversion_draw(gsr_color_conversion *self, unsigned int texture_
//cap_xcomp->params.egl->glClear(GL_COLOR_BUFFER_BIT); //cap_xcomp->params.egl->glClear(GL_COLOR_BUFFER_BIT);
gsr_shader_use(&self->shaders[1]); gsr_shader_use(&self->shaders[1]);
self->params.egl->glUniform1f(self->rotation_uniforms[1], rotation); self->params.egl->glUniform1f(self->uniforms[1].rotation, rotation);
self->params.egl->glUniform2f(self->uniforms[1].offset, pos_norm.x, pos_norm.y);
self->params.egl->glDrawArrays(GL_TRIANGLES, 0, 6); self->params.egl->glDrawArrays(GL_TRIANGLES, 0, 6);
} }

View File

@@ -23,10 +23,10 @@ static void output_handle_geometry(void *data, struct wl_output *wl_output,
(void)subpixel; (void)subpixel;
(void)make; (void)make;
(void)model; (void)model;
(void)transform;
gsr_wayland_output *gsr_output = data; gsr_wayland_output *gsr_output = data;
gsr_output->pos.x = x; gsr_output->pos.x = x;
gsr_output->pos.y = y; gsr_output->pos.y = y;
gsr_output->transform = transform;
} }
static void output_handle_mode(void *data, struct wl_output *wl_output, uint32_t flags, int32_t width, int32_t height, int32_t refresh) { static void output_handle_mode(void *data, struct wl_output *wl_output, uint32_t flags, int32_t width, int32_t height, int32_t refresh) {
@@ -101,6 +101,7 @@ static void registry_add_object(void *data, struct wl_registry *registry, uint32
.output = wl_registry_bind(registry, name, &wl_output_interface, 4), .output = wl_registry_bind(registry, name, &wl_output_interface, 4),
.pos = { .x = 0, .y = 0 }, .pos = { .x = 0, .y = 0 },
.size = { .x = 0, .y = 0 }, .size = { .x = 0, .y = 0 },
.transform = 0,
.name = NULL, .name = NULL,
}; };
wl_output_add_listener(gsr_output->output, &output_listener, gsr_output); wl_output_add_listener(gsr_output->output, &output_listener, gsr_output);
@@ -322,6 +323,7 @@ static bool gsr_egl_load_gl(gsr_egl *self, void *library) {
{ (void**)&self->glBlendFunc, "glBlendFunc" }, { (void**)&self->glBlendFunc, "glBlendFunc" },
{ (void**)&self->glGetUniformLocation, "glGetUniformLocation" }, { (void**)&self->glGetUniformLocation, "glGetUniformLocation" },
{ (void**)&self->glUniform1f, "glUniform1f" }, { (void**)&self->glUniform1f, "glUniform1f" },
{ (void**)&self->glUniform2f, "glUniform2f" },
{ NULL, NULL } { NULL, NULL }
}; };

View File

@@ -851,6 +851,7 @@ static void usage_full() {
fprintf(stderr, "\n"); fprintf(stderr, "\n");
fprintf(stderr, " -cr Color range. Should be either 'limited' (aka mpeg) or 'full' (aka jpeg). Defaults to 'limited'.\n"); fprintf(stderr, " -cr Color range. Should be either 'limited' (aka mpeg) or 'full' (aka jpeg). Defaults to 'limited'.\n");
fprintf(stderr, " Limited color range means that colors are in range 16-235 while full color range means that colors are in range 0-255 (when not recording with hdr).\n"); fprintf(stderr, " Limited color range means that colors are in range 16-235 while full color range means that colors are in range 0-255 (when not recording with hdr).\n");
fprintf(stderr, " Note that some buggy video players (such as vlc) are unable to correctly display videos in full color range.\n");
fprintf(stderr, "\n"); fprintf(stderr, "\n");
fprintf(stderr, " -v Prints per second, fps updates. Optional, set to 'yes' by default.\n"); fprintf(stderr, " -v Prints per second, fps updates. Optional, set to 'yes' by default.\n");
fprintf(stderr, "\n"); fprintf(stderr, "\n");

View File

@@ -7,6 +7,14 @@
#include <xf86drmMode.h> #include <xf86drmMode.h>
#include <xf86drm.h> #include <xf86drm.h>
#include <stdlib.h> #include <stdlib.h>
#include <X11/Xatom.h>
typedef enum {
X11_ROT_0 = 1 << 0,
X11_ROT_90 = 1 << 1,
X11_ROT_180 = 1 << 2,
X11_ROT_270 = 1 << 3
} X11Rotation;
double clock_get_monotonic_seconds(void) { double clock_get_monotonic_seconds(void) {
struct timespec ts; struct timespec ts;
@@ -24,11 +32,49 @@ static const XRRModeInfo* get_mode_info(const XRRScreenResources *sr, RRMode id)
return NULL; return NULL;
} }
static gsr_monitor_rotation x11_rotation_to_gsr_rotation(X11Rotation rot) {
switch(rot) {
case X11_ROT_0: return GSR_MONITOR_ROT_0;
case X11_ROT_90: return GSR_MONITOR_ROT_90;
case X11_ROT_180: return GSR_MONITOR_ROT_180;
case X11_ROT_270: return GSR_MONITOR_ROT_270;
}
return GSR_MONITOR_ROT_0;
}
static gsr_monitor_rotation wayland_transform_to_gsr_rotation(int32_t rot) {
switch(rot) {
case 0: return GSR_MONITOR_ROT_0;
case 1: return GSR_MONITOR_ROT_90;
case 2: return GSR_MONITOR_ROT_180;
case 3: return GSR_MONITOR_ROT_270;
}
return GSR_MONITOR_ROT_0;
}
static uint32_t x11_output_get_connector_id(Display *dpy, RROutput output, Atom randr_connector_id_atom) {
Atom type = 0;
int format = 0;
unsigned long bytes_after = 0;
unsigned long nitems = 0;
unsigned char *prop = NULL;
XRRGetOutputProperty(dpy, output, randr_connector_id_atom, 0, 128, false, false, AnyPropertyType, &type, &format, &nitems, &bytes_after, &prop);
long result = 0;
if(type == XA_INTEGER && format == 32)
result = *(long*)prop;
free(prop);
return result;
}
void for_each_active_monitor_output_x11(Display *display, active_monitor_callback callback, void *userdata) { void for_each_active_monitor_output_x11(Display *display, active_monitor_callback callback, void *userdata) {
XRRScreenResources *screen_res = XRRGetScreenResources(display, DefaultRootWindow(display)); XRRScreenResources *screen_res = XRRGetScreenResources(display, DefaultRootWindow(display));
if(!screen_res) if(!screen_res)
return; return;
const Atom randr_connector_id_atom = XInternAtom(display, "CONNECTOR_ID", False);
char display_name[256]; char display_name[256];
for(int i = 0; i < screen_res->noutput; ++i) { for(int i = 0; i < screen_res->noutput; ++i) {
XRROutputInfo *out_info = XRRGetOutputInfo(display, screen_res, screen_res->outputs[i]); XRROutputInfo *out_info = XRRGetOutputInfo(display, screen_res, screen_res->outputs[i]);
@@ -40,13 +86,15 @@ void for_each_active_monitor_output_x11(Display *display, active_monitor_callbac
memcpy(display_name, out_info->name, out_info->nameLen); memcpy(display_name, out_info->name, out_info->nameLen);
display_name[out_info->nameLen] = '\0'; display_name[out_info->nameLen] = '\0';
gsr_monitor monitor = { const gsr_monitor monitor = {
.name = display_name, .name = display_name,
.name_len = out_info->nameLen, .name_len = out_info->nameLen,
.pos = { .x = crt_info->x, .y = crt_info->y }, .pos = { .x = crt_info->x, .y = crt_info->y },
.size = { .x = (int)crt_info->width, .y = (int)crt_info->height }, .size = { .x = (int)crt_info->width, .y = (int)crt_info->height },
.crt_info = crt_info, .crt_info = crt_info,
.connector_id = 0 // TODO: Get connector id .connector_id = x11_output_get_connector_id(display, screen_res->outputs[i], randr_connector_id_atom),
.rotation = x11_rotation_to_gsr_rotation(crt_info->rotation),
.monitor_identifier = 0
}; };
callback(&monitor, userdata); callback(&monitor, userdata);
} }
@@ -64,6 +112,7 @@ void for_each_active_monitor_output_x11(Display *display, active_monitor_callbac
typedef struct { typedef struct {
int type; int type;
int count; int count;
int count_active;
} drm_connector_type_count; } drm_connector_type_count;
#define CONNECTOR_TYPE_COUNTS 32 #define CONNECTOR_TYPE_COUNTS 32
@@ -80,6 +129,7 @@ static drm_connector_type_count* drm_connector_types_get_index(drm_connector_typ
const int index = *num_type_counts; const int index = *num_type_counts;
type_counts[index].type = connector_type; type_counts[index].type = connector_type;
type_counts[index].count = 0; type_counts[index].count = 0;
type_counts[index].count_active = 0;
++*num_type_counts; ++*num_type_counts;
return &type_counts[index]; return &type_counts[index];
} }
@@ -99,18 +149,51 @@ static bool connector_get_property_by_name(int drmfd, drmModeConnectorPtr props,
return false; return false;
} }
/* TODO: Support more connector types*/
static int get_connector_type_by_name(const char *name) {
int len = strlen(name);
if(len >= 5 && strncmp(name, "HDMI-", 5) == 0)
return 1;
else if(len >= 3 && strncmp(name, "DP-", 3) == 0)
return 2;
else if(len >= 12 && strncmp(name, "DisplayPort-", 12) == 0)
return 3;
else
return -1;
}
static uint32_t monitor_identifier_from_type_and_count(int monitor_type_index, int monitor_type_count) {
return ((uint32_t)monitor_type_index << 16) | ((uint32_t)monitor_type_count);
}
static void for_each_active_monitor_output_wayland(const gsr_egl *egl, active_monitor_callback callback, void *userdata) { static void for_each_active_monitor_output_wayland(const gsr_egl *egl, active_monitor_callback callback, void *userdata) {
drm_connector_type_count type_counts[CONNECTOR_TYPE_COUNTS];
int num_type_counts = 0;
for(int i = 0; i < egl->wayland.num_outputs; ++i) { for(int i = 0; i < egl->wayland.num_outputs; ++i) {
if(!egl->wayland.outputs[i].name) const gsr_wayland_output *output = &egl->wayland.outputs[i];
if(!output->name)
continue; continue;
gsr_monitor monitor = { const int connector_type_index = get_connector_type_by_name(output->name);
.name = egl->wayland.outputs[i].name, drm_connector_type_count *connector_type = NULL;
.name_len = strlen(egl->wayland.outputs[i].name), if(connector_type_index != -1)
.pos = { .x = egl->wayland.outputs[i].pos.x, .y = egl->wayland.outputs[i].pos.y }, connector_type = drm_connector_types_get_index(type_counts, &num_type_counts, connector_type_index);
.size = { .x = egl->wayland.outputs[i].size.x, .y = egl->wayland.outputs[i].size.y },
if(connector_type) {
++connector_type->count;
++connector_type->count_active;
}
const gsr_monitor monitor = {
.name = output->name,
.name_len = strlen(output->name),
.pos = { .x = output->pos.x, .y = output->pos.y },
.size = { .x = output->size.x, .y = output->size.y },
.crt_info = NULL, .crt_info = NULL,
.connector_id = 0 .connector_id = 0,
.rotation = wayland_transform_to_gsr_rotation(output->transform),
.monitor_identifier = connector_type ? monitor_identifier_from_type_and_count(connector_type_index, connector_type->count_active) : 0
}; };
callback(&monitor, userdata); callback(&monitor, userdata);
} }
@@ -145,19 +228,25 @@ static void for_each_active_monitor_output_drm(const gsr_egl *egl, active_monito
continue; continue;
} }
if(connector_type)
++connector_type->count_active;
uint64_t crtc_id = 0; uint64_t crtc_id = 0;
connector_get_property_by_name(fd, connector, "CRTC_ID", &crtc_id); connector_get_property_by_name(fd, connector, "CRTC_ID", &crtc_id);
drmModeCrtcPtr crtc = drmModeGetCrtc(fd, crtc_id); drmModeCrtcPtr crtc = drmModeGetCrtc(fd, crtc_id);
if(connector_type && crtc_id > 0 && crtc && connection_name_len + 5 < (int)sizeof(display_name)) { if(connector_type && crtc_id > 0 && crtc && connection_name_len + 5 < (int)sizeof(display_name)) {
const int display_name_len = snprintf(display_name, sizeof(display_name), "%s-%d", connection_name, connector_type->count); const int display_name_len = snprintf(display_name, sizeof(display_name), "%s-%d", connection_name, connector_type->count);
gsr_monitor monitor = { const int connector_type_index_name = get_connector_type_by_name(display_name);
const gsr_monitor monitor = {
.name = display_name, .name = display_name,
.name_len = display_name_len, .name_len = display_name_len,
.pos = { .x = crtc->x, .y = crtc->y }, .pos = { .x = crtc->x, .y = crtc->y },
.size = { .x = (int)crtc->width, .y = (int)crtc->height }, .size = { .x = (int)crtc->width, .y = (int)crtc->height },
.crt_info = NULL, .crt_info = NULL,
.connector_id = connector->connector_id .connector_id = connector->connector_id,
.rotation = GSR_MONITOR_ROT_0,
.monitor_identifier = connector_type_index_name != -1 ? monitor_identifier_from_type_and_count(connector_type_index_name, connector_type->count_active) : 0
}; };
callback(&monitor, userdata); callback(&monitor, userdata);
} }
@@ -192,6 +281,9 @@ static void get_monitor_by_name_callback(const gsr_monitor *monitor, void *userd
if(!data->found_monitor && strcmp(data->name, monitor->name) == 0) { if(!data->found_monitor && strcmp(data->name, monitor->name) == 0) {
data->monitor->pos = monitor->pos; data->monitor->pos = monitor->pos;
data->monitor->size = monitor->size; data->monitor->size = monitor->size;
data->monitor->connector_id = monitor->connector_id;
data->monitor->rotation = monitor->rotation;
data->monitor->monitor_identifier = monitor->monitor_identifier;
data->found_monitor = true; data->found_monitor = true;
} }
} }
@@ -206,6 +298,38 @@ bool get_monitor_by_name(const gsr_egl *egl, gsr_connection_type connection_type
return userdata.found_monitor; return userdata.found_monitor;
} }
typedef struct {
const gsr_monitor *monitor;
gsr_monitor_rotation rotation;
} get_monitor_by_connector_id_userdata;
static void get_monitor_by_connector_id_callback(const gsr_monitor *monitor, void *userdata) {
get_monitor_by_connector_id_userdata *data = (get_monitor_by_connector_id_userdata*)userdata;
if(monitor->connector_id == data->monitor->connector_id ||
(!monitor->connector_id && monitor->monitor_identifier == data->monitor->monitor_identifier))
{
data->rotation = monitor->rotation;
}
}
gsr_monitor_rotation drm_monitor_get_display_server_rotation(const gsr_egl *egl, const gsr_monitor *monitor) {
if(egl->wayland.dpy) {
get_monitor_by_connector_id_userdata userdata;
userdata.monitor = monitor;
userdata.rotation = GSR_MONITOR_ROT_0;
for_each_active_monitor_output_wayland(egl, get_monitor_by_connector_id_callback, &userdata);
return userdata.rotation;
} else {
get_monitor_by_connector_id_userdata userdata;
userdata.monitor = monitor;
userdata.rotation = GSR_MONITOR_ROT_0;
for_each_active_monitor_output_x11(egl->x11.dpy, get_monitor_by_connector_id_callback, &userdata);
return userdata.rotation;
}
return GSR_MONITOR_ROT_0;
}
bool gl_get_gpu_info(gsr_egl *egl, gsr_gpu_info *info) { bool gl_get_gpu_info(gsr_egl *egl, gsr_gpu_info *info) {
const char *software_renderers[] = { "llvmpipe", "SWR", "softpipe", NULL }; const char *software_renderers[] = { "llvmpipe", "SWR", "softpipe", NULL };
bool supported = true; bool supported = true;