mirror of
https://repo.dec05eba.com/gpu-screen-recorder
synced 2026-03-31 09:07:13 +09:00
kms capture: fix incorrect rotation on wayland (kde plasma) when monitor is rotated when a window is fullscreen
Add support for drm plane rotation.
This commit is contained in:
@@ -5,7 +5,7 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <drm_mode.h>
|
#include <drm_mode.h>
|
||||||
|
|
||||||
#define GSR_KMS_PROTOCOL_VERSION 4
|
#define GSR_KMS_PROTOCOL_VERSION 5
|
||||||
|
|
||||||
#define GSR_KMS_MAX_ITEMS 8
|
#define GSR_KMS_MAX_ITEMS 8
|
||||||
#define GSR_KMS_MAX_DMA_BUFS 4
|
#define GSR_KMS_MAX_DMA_BUFS 4
|
||||||
@@ -39,6 +39,13 @@ struct gsr_kms_response_dma_buf {
|
|||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
KMS_ROT_0,
|
||||||
|
KMS_ROT_90,
|
||||||
|
KMS_ROT_180,
|
||||||
|
KMS_ROT_270
|
||||||
|
} gsr_kms_rotation;
|
||||||
|
|
||||||
struct gsr_kms_response_item {
|
struct gsr_kms_response_item {
|
||||||
gsr_kms_response_dma_buf dma_buf[GSR_KMS_MAX_DMA_BUFS];
|
gsr_kms_response_dma_buf dma_buf[GSR_KMS_MAX_DMA_BUFS];
|
||||||
int num_dma_bufs;
|
int num_dma_bufs;
|
||||||
@@ -49,10 +56,11 @@ struct gsr_kms_response_item {
|
|||||||
uint32_t connector_id; /* 0 if unknown */
|
uint32_t connector_id; /* 0 if unknown */
|
||||||
bool is_cursor;
|
bool is_cursor;
|
||||||
bool has_hdr_metadata;
|
bool has_hdr_metadata;
|
||||||
|
gsr_kms_rotation rotation;
|
||||||
int x;
|
int x;
|
||||||
int y;
|
int y;
|
||||||
int src_w;
|
int crtc_w;
|
||||||
int src_h;
|
int crtc_h;
|
||||||
struct hdr_output_metadata hdr_metadata;
|
struct hdr_output_metadata hdr_metadata;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -141,20 +141,22 @@ typedef enum {
|
|||||||
PLANE_PROPERTY_Y = 1 << 1,
|
PLANE_PROPERTY_Y = 1 << 1,
|
||||||
PLANE_PROPERTY_SRC_X = 1 << 2,
|
PLANE_PROPERTY_SRC_X = 1 << 2,
|
||||||
PLANE_PROPERTY_SRC_Y = 1 << 3,
|
PLANE_PROPERTY_SRC_Y = 1 << 3,
|
||||||
PLANE_PROPERTY_SRC_W = 1 << 4,
|
PLANE_PROPERTY_CRTC_W = 1 << 4,
|
||||||
PLANE_PROPERTY_SRC_H = 1 << 5,
|
PLANE_PROPERTY_CRTC_H = 1 << 5,
|
||||||
PLANE_PROPERTY_IS_CURSOR = 1 << 6,
|
PLANE_PROPERTY_IS_CURSOR = 1 << 6,
|
||||||
PLANE_PROPERTY_IS_PRIMARY = 1 << 7,
|
PLANE_PROPERTY_IS_PRIMARY = 1 << 7,
|
||||||
|
PLANE_PROPERTY_ROTATION = 1 << 8,
|
||||||
} plane_property_mask;
|
} plane_property_mask;
|
||||||
|
|
||||||
/* Returns plane_property_mask */
|
/* Returns plane_property_mask */
|
||||||
static uint32_t plane_get_properties(int drmfd, uint32_t plane_id, int *x, int *y, int *src_x, int *src_y, int *src_w, int *src_h) {
|
static uint32_t plane_get_properties(int drmfd, uint32_t plane_id, int *x, int *y, int *src_x, int *src_y, int *crtc_w, int *crtc_h, gsr_kms_rotation *rotation) {
|
||||||
*x = 0;
|
*x = 0;
|
||||||
*y = 0;
|
*y = 0;
|
||||||
*src_x = 0;
|
*src_x = 0;
|
||||||
*src_y = 0;
|
*src_y = 0;
|
||||||
*src_w = 0;
|
*crtc_w = 0;
|
||||||
*src_h = 0;
|
*crtc_h = 0;
|
||||||
|
*rotation = KMS_ROT_0;
|
||||||
|
|
||||||
plane_property_mask property_mask = 0;
|
plane_property_mask property_mask = 0;
|
||||||
|
|
||||||
@@ -182,12 +184,12 @@ static uint32_t plane_get_properties(int drmfd, uint32_t plane_id, int *x, int *
|
|||||||
} else if((type & DRM_MODE_PROP_RANGE) && strcmp(prop->name, "SRC_Y") == 0) {
|
} else if((type & DRM_MODE_PROP_RANGE) && strcmp(prop->name, "SRC_Y") == 0) {
|
||||||
*src_y = (int)(props->prop_values[i] >> 16);
|
*src_y = (int)(props->prop_values[i] >> 16);
|
||||||
property_mask |= PLANE_PROPERTY_SRC_Y;
|
property_mask |= PLANE_PROPERTY_SRC_Y;
|
||||||
} else if((type & DRM_MODE_PROP_RANGE) && strcmp(prop->name, "SRC_W") == 0) {
|
} else if((type & DRM_MODE_PROP_RANGE) && strcmp(prop->name, "CRTC_W") == 0) {
|
||||||
*src_w = (int)(props->prop_values[i] >> 16);
|
*crtc_w = props->prop_values[i];
|
||||||
property_mask |= PLANE_PROPERTY_SRC_W;
|
property_mask |= PLANE_PROPERTY_CRTC_W;
|
||||||
} else if((type & DRM_MODE_PROP_RANGE) && strcmp(prop->name, "SRC_H") == 0) {
|
} else if((type & DRM_MODE_PROP_RANGE) && strcmp(prop->name, "CRTC_H") == 0) {
|
||||||
*src_h = (int)(props->prop_values[i] >> 16);
|
*crtc_h = props->prop_values[i];
|
||||||
property_mask |= PLANE_PROPERTY_SRC_H;
|
property_mask |= PLANE_PROPERTY_CRTC_H;
|
||||||
} else if((type & DRM_MODE_PROP_ENUM) && strcmp(prop->name, "type") == 0) {
|
} else if((type & DRM_MODE_PROP_ENUM) && strcmp(prop->name, "type") == 0) {
|
||||||
const uint64_t current_enum_value = props->prop_values[i];
|
const uint64_t current_enum_value = props->prop_values[i];
|
||||||
for(int j = 0; j < prop->count_enums; ++j) {
|
for(int j = 0; j < prop->count_enums; ++j) {
|
||||||
@@ -199,6 +201,15 @@ static uint32_t plane_get_properties(int drmfd, uint32_t plane_id, int *x, int *
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if((type & DRM_MODE_PROP_BITMASK) && strcmp(prop->name, "rotation") == 0) {
|
||||||
|
const uint64_t rotation_bitmask = props->prop_values[i];
|
||||||
|
*rotation = KMS_ROT_0;
|
||||||
|
if(rotation_bitmask & 2)
|
||||||
|
*rotation = (*rotation + KMS_ROT_90) % 4;
|
||||||
|
if(rotation_bitmask & 4)
|
||||||
|
*rotation = (*rotation + KMS_ROT_180) % 4;
|
||||||
|
if(rotation_bitmask & 8)
|
||||||
|
*rotation = (*rotation + KMS_ROT_270) % 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
drmModeFreeProperty(prop);
|
drmModeFreeProperty(prop);
|
||||||
@@ -340,8 +351,9 @@ static int kms_get_fb(gsr_drm *drm, gsr_kms_response *response) {
|
|||||||
// TODO: Check if dimensions have changed by comparing width and height to previous time this was called.
|
// TODO: Check if dimensions have changed by comparing width and height to previous time this was called.
|
||||||
// TODO: Support other plane formats than rgb (with multiple planes, such as direct YUV420 on wayland).
|
// TODO: Support other plane formats than rgb (with multiple planes, such as direct YUV420 on wayland).
|
||||||
|
|
||||||
int x = 0, y = 0, src_x = 0, src_y = 0, src_w = 0, src_h = 0;
|
int x = 0, y = 0, src_x = 0, src_y = 0, crtc_w = 0, crtc_h = 0;
|
||||||
plane_property_mask property_mask = plane_get_properties(drm->drmfd, plane->plane_id, &x, &y, &src_x, &src_y, &src_w, &src_h);
|
gsr_kms_rotation rotation = KMS_ROT_0;
|
||||||
|
const uint32_t property_mask = plane_get_properties(drm->drmfd, plane->plane_id, &x, &y, &src_x, &src_y, &crtc_w, &crtc_h, &rotation);
|
||||||
if(!(property_mask & PLANE_PROPERTY_IS_PRIMARY) && !(property_mask & PLANE_PROPERTY_IS_CURSOR))
|
if(!(property_mask & PLANE_PROPERTY_IS_PRIMARY) && !(property_mask & PLANE_PROPERTY_IS_CURSOR))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -375,17 +387,18 @@ static int kms_get_fb(gsr_drm *drm, gsr_kms_response *response) {
|
|||||||
response->items[item_index].pixel_format = drmfb->pixel_format;
|
response->items[item_index].pixel_format = drmfb->pixel_format;
|
||||||
response->items[item_index].modifier = drmfb->flags & DRM_MODE_FB_MODIFIERS ? drmfb->modifier : DRM_FORMAT_MOD_INVALID;
|
response->items[item_index].modifier = drmfb->flags & DRM_MODE_FB_MODIFIERS ? drmfb->modifier : DRM_FORMAT_MOD_INVALID;
|
||||||
response->items[item_index].connector_id = crtc_pair ? crtc_pair->connector_id : 0;
|
response->items[item_index].connector_id = crtc_pair ? crtc_pair->connector_id : 0;
|
||||||
|
response->items[item_index].rotation = rotation;
|
||||||
response->items[item_index].is_cursor = property_mask & PLANE_PROPERTY_IS_CURSOR;
|
response->items[item_index].is_cursor = property_mask & PLANE_PROPERTY_IS_CURSOR;
|
||||||
if(property_mask & PLANE_PROPERTY_IS_CURSOR) {
|
if(property_mask & PLANE_PROPERTY_IS_CURSOR) {
|
||||||
response->items[item_index].x = x;
|
response->items[item_index].x = x;
|
||||||
response->items[item_index].y = y;
|
response->items[item_index].y = y;
|
||||||
response->items[item_index].src_w = 0;
|
response->items[item_index].crtc_w = 0;
|
||||||
response->items[item_index].src_h = 0;
|
response->items[item_index].crtc_h = 0;
|
||||||
} else {
|
} else {
|
||||||
response->items[item_index].x = src_x;
|
response->items[item_index].x = src_x;
|
||||||
response->items[item_index].y = src_y;
|
response->items[item_index].y = src_y;
|
||||||
response->items[item_index].src_w = src_w;
|
response->items[item_index].crtc_w = crtc_w;
|
||||||
response->items[item_index].src_h = src_h;
|
response->items[item_index].crtc_h = crtc_h;
|
||||||
}
|
}
|
||||||
++response->num_items;
|
++response->num_items;
|
||||||
|
|
||||||
|
|||||||
@@ -418,6 +418,19 @@ static gsr_kms_response_item* find_cursor_drm_if_on_monitor(gsr_capture_kms *sel
|
|||||||
return cursor_drm_fd;
|
return cursor_drm_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gsr_monitor_rotation kms_rotation_to_gsr_monitor_rotation(gsr_kms_rotation rotation) {
|
||||||
|
// Right now both enums have the same values
|
||||||
|
return (gsr_monitor_rotation)rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int remainder_int(int a, int b) {
|
||||||
|
return a - (a / b) * b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gsr_monitor_rotation sub_rotations(gsr_monitor_rotation rot1, gsr_monitor_rotation rot2) {
|
||||||
|
return remainder_int(rot1 - rot2, 4);
|
||||||
|
}
|
||||||
|
|
||||||
static void render_drm_cursor(gsr_capture_kms *self, gsr_color_conversion *color_conversion, const gsr_kms_response_item *cursor_drm_fd, vec2i target_pos, vec2i output_size, vec2i framebuffer_size) {
|
static void render_drm_cursor(gsr_capture_kms *self, gsr_color_conversion *color_conversion, const gsr_kms_response_item *cursor_drm_fd, vec2i target_pos, vec2i output_size, vec2i framebuffer_size) {
|
||||||
const vec2d scale = {
|
const vec2d scale = {
|
||||||
self->capture_size.x == 0 ? 0 : (double)output_size.x / (double)self->capture_size.x,
|
self->capture_size.x == 0 ? 0 : (double)output_size.x / (double)self->capture_size.x,
|
||||||
@@ -427,8 +440,11 @@ static void render_drm_cursor(gsr_capture_kms *self, gsr_color_conversion *color
|
|||||||
const bool cursor_texture_id_is_external = self->params.egl->gpu_info.vendor == GSR_GPU_VENDOR_NVIDIA;
|
const bool cursor_texture_id_is_external = self->params.egl->gpu_info.vendor == GSR_GPU_VENDOR_NVIDIA;
|
||||||
const vec2i cursor_size = {cursor_drm_fd->width, cursor_drm_fd->height};
|
const vec2i cursor_size = {cursor_drm_fd->width, cursor_drm_fd->height};
|
||||||
|
|
||||||
|
const gsr_monitor_rotation cursor_plane_rotation = kms_rotation_to_gsr_monitor_rotation(cursor_drm_fd->rotation);
|
||||||
|
const gsr_monitor_rotation rotation = sub_rotations(self->monitor_rotation, cursor_plane_rotation);
|
||||||
|
|
||||||
vec2i cursor_pos = {cursor_drm_fd->x, cursor_drm_fd->y};
|
vec2i cursor_pos = {cursor_drm_fd->x, cursor_drm_fd->y};
|
||||||
switch(self->monitor_rotation) {
|
switch(rotation) {
|
||||||
case GSR_MONITOR_ROT_0:
|
case GSR_MONITOR_ROT_0:
|
||||||
break;
|
break;
|
||||||
case GSR_MONITOR_ROT_90:
|
case GSR_MONITOR_ROT_90:
|
||||||
@@ -492,7 +508,7 @@ static void render_drm_cursor(gsr_capture_kms *self, gsr_color_conversion *color
|
|||||||
gsr_color_conversion_draw(color_conversion, self->cursor_texture_id,
|
gsr_color_conversion_draw(color_conversion, self->cursor_texture_id,
|
||||||
cursor_pos, (vec2i){cursor_size.x * scale.x, cursor_size.y * scale.y},
|
cursor_pos, (vec2i){cursor_size.x * scale.x, cursor_size.y * scale.y},
|
||||||
(vec2i){0, 0}, cursor_size, cursor_size,
|
(vec2i){0, 0}, cursor_size, cursor_size,
|
||||||
gsr_monitor_rotation_to_rotation(self->monitor_rotation), GSR_SOURCE_COLOR_RGB, cursor_texture_id_is_external, true);
|
gsr_monitor_rotation_to_rotation(rotation), GSR_SOURCE_COLOR_RGB, cursor_texture_id_is_external, true);
|
||||||
|
|
||||||
self->params.egl->glDisable(GL_SCISSOR_TEST);
|
self->params.egl->glDisable(GL_SCISSOR_TEST);
|
||||||
}
|
}
|
||||||
@@ -526,7 +542,7 @@ static void render_x11_cursor(gsr_capture_kms *self, gsr_color_conversion *color
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void gsr_capture_kms_update_capture_size_change(gsr_capture_kms *self, gsr_color_conversion *color_conversion, vec2i target_pos, const gsr_kms_response_item *drm_fd) {
|
static void gsr_capture_kms_update_capture_size_change(gsr_capture_kms *self, gsr_color_conversion *color_conversion, vec2i target_pos, const gsr_kms_response_item *drm_fd) {
|
||||||
if(target_pos.x != self->prev_target_pos.x || target_pos.y != self->prev_target_pos.y || drm_fd->src_w != self->prev_plane_size.x || drm_fd->src_h != self->prev_plane_size.y) {
|
if(target_pos.x != self->prev_target_pos.x || target_pos.y != self->prev_target_pos.y || drm_fd->crtc_w != self->prev_plane_size.x || drm_fd->crtc_h != self->prev_plane_size.y) {
|
||||||
self->prev_target_pos = target_pos;
|
self->prev_target_pos = target_pos;
|
||||||
self->prev_plane_size = self->capture_size;
|
self->prev_plane_size = self->capture_size;
|
||||||
gsr_color_conversion_clear(color_conversion);
|
gsr_color_conversion_clear(color_conversion);
|
||||||
@@ -605,7 +621,7 @@ static int gsr_capture_kms_capture(gsr_capture *cap, gsr_capture_metadata *captu
|
|||||||
if(drm_fd->has_hdr_metadata && self->params.hdr && hdr_metadata_is_supported_format(&drm_fd->hdr_metadata))
|
if(drm_fd->has_hdr_metadata && self->params.hdr && hdr_metadata_is_supported_format(&drm_fd->hdr_metadata))
|
||||||
gsr_kms_set_hdr_metadata(self, drm_fd);
|
gsr_kms_set_hdr_metadata(self, drm_fd);
|
||||||
|
|
||||||
self->capture_size = rotate_capture_size_if_rotated(self, (vec2i){ drm_fd->src_w, drm_fd->src_h });
|
self->capture_size = rotate_capture_size_if_rotated(self, (vec2i){ drm_fd->crtc_w, drm_fd->crtc_h });
|
||||||
const vec2i original_frame_size = self->capture_size;
|
const vec2i original_frame_size = self->capture_size;
|
||||||
if(self->params.region_size.x > 0 && self->params.region_size.y > 0)
|
if(self->params.region_size.x > 0 && self->params.region_size.y > 0)
|
||||||
self->capture_size = self->params.region_size;
|
self->capture_size = self->params.region_size;
|
||||||
@@ -633,10 +649,13 @@ static int gsr_capture_kms_capture(gsr_capture *cap, gsr_capture_metadata *captu
|
|||||||
self->params.egl->eglDestroyImage(self->params.egl->egl_display, image);
|
self->params.egl->eglDestroyImage(self->params.egl->egl_display, image);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const gsr_monitor_rotation plane_rotation = kms_rotation_to_gsr_monitor_rotation(drm_fd->rotation);
|
||||||
|
const gsr_monitor_rotation rotation = sub_rotations(self->monitor_rotation, plane_rotation);
|
||||||
|
|
||||||
gsr_color_conversion_draw(color_conversion, self->external_texture_fallback ? self->external_input_texture_id : self->input_texture_id,
|
gsr_color_conversion_draw(color_conversion, self->external_texture_fallback ? self->external_input_texture_id : self->input_texture_id,
|
||||||
target_pos, output_size,
|
target_pos, output_size,
|
||||||
capture_pos, self->capture_size, original_frame_size,
|
capture_pos, self->capture_size, original_frame_size,
|
||||||
gsr_monitor_rotation_to_rotation(self->monitor_rotation), GSR_SOURCE_COLOR_RGB, self->external_texture_fallback, false);
|
gsr_monitor_rotation_to_rotation(rotation), GSR_SOURCE_COLOR_RGB, self->external_texture_fallback, false);
|
||||||
|
|
||||||
if(self->params.record_cursor) {
|
if(self->params.record_cursor) {
|
||||||
gsr_kms_response_item *cursor_drm_fd = find_cursor_drm_if_on_monitor(self, drm_fd->connector_id, capture_is_combined_plane);
|
gsr_kms_response_item *cursor_drm_fd = find_cursor_drm_if_on_monitor(self, drm_fd->connector_id, capture_is_combined_plane);
|
||||||
@@ -650,7 +669,7 @@ static int gsr_capture_kms_capture(gsr_capture *cap, gsr_capture_metadata *captu
|
|||||||
cursor_monitor_offset.y += self->params.region_position.y;
|
cursor_monitor_offset.y += self->params.region_position.y;
|
||||||
render_x11_cursor(self, color_conversion, cursor_monitor_offset, target_pos, output_size);
|
render_x11_cursor(self, color_conversion, cursor_monitor_offset, target_pos, output_size);
|
||||||
} else if(cursor_drm_fd) {
|
} else if(cursor_drm_fd) {
|
||||||
const vec2i framebuffer_size = rotate_capture_size_if_rotated(self, (vec2i){ drm_fd->src_w, drm_fd->src_h });
|
const vec2i framebuffer_size = rotate_capture_size_if_rotated(self, (vec2i){ drm_fd->crtc_w, drm_fd->crtc_h });
|
||||||
render_drm_cursor(self, color_conversion, cursor_drm_fd, target_pos, output_size, framebuffer_size);
|
render_drm_cursor(self, color_conversion, cursor_drm_fd, target_pos, output_size, framebuffer_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user