mirror of
https://repo.dec05eba.com/gpu-screen-recorder
synced 2026-05-05 22:40:42 +09:00
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:
6
TODO
6
TODO
@@ -117,3 +117,9 @@ Instead of sending a big list of drm data back to kms client, send the monitor w
|
|||||||
|
|
||||||
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)
|
||||||
@@ -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];
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 }
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|||||||
146
src/utils.c
146
src/utils.c
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user