mirror of
https://repo.dec05eba.com/gpu-screen-recorder
synced 2026-03-31 09:07:13 +09:00
Desktop portal capture: support rotated monitor capture on sway
This commit is contained in:
@@ -210,3 +210,7 @@ and on Wayland the external GPU will display the graphics for that monitor.
|
|||||||
In that case you can record the monitor with the external GPU by launching GPU Screen Recorder with [prime-run or by setting the DRI_PRIME environment variable](https://wiki.archlinux.org/title/PRIME) depending on your GPU brand.\
|
In that case you can record the monitor with the external GPU by launching GPU Screen Recorder with [prime-run or by setting the DRI_PRIME environment variable](https://wiki.archlinux.org/title/PRIME) depending on your GPU brand.\
|
||||||
However if you really want to change which GPU you want to record and encode with with then you can instead configure your display server (Xorg or Wayland compositor) to run with that GPU,
|
However if you really want to change which GPU you want to record and encode with with then you can instead configure your display server (Xorg or Wayland compositor) to run with that GPU,
|
||||||
then GPU Screen Recorder will automatically use that same GPU for recording and encoding.
|
then GPU Screen Recorder will automatically use that same GPU for recording and encoding.
|
||||||
|
## The rotation of the video is incorrect when the monitor is rotated when using desktop portal capture
|
||||||
|
This is a bug in kde plasma wayland. When using desktop portal capture and the monitor is rotated and a window is made fullscreen kde plasma wayland will give incorrect rotation to GPU Screen Recorder.
|
||||||
|
This also affects other screen recording software such as obs studio.\
|
||||||
|
Capture a monitor directly instead to workaround this issue until kde plasma devs fix it, or use another wayland compositor that doesn't have this issue.
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
#ifndef GSR_PIPEWIRE_VIDEO_H
|
#ifndef GSR_PIPEWIRE_VIDEO_H
|
||||||
#define GSR_PIPEWIRE_VIDEO_H
|
#define GSR_PIPEWIRE_VIDEO_H
|
||||||
|
|
||||||
|
#include "defs.h"
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
@@ -48,6 +49,17 @@ typedef struct {
|
|||||||
unsigned int cursor_texture_id;
|
unsigned int cursor_texture_id;
|
||||||
} gsr_texture_map;
|
} gsr_texture_map;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
gsr_pipewire_video_region region;
|
||||||
|
gsr_pipewire_video_region cursor_region;
|
||||||
|
gsr_pipewire_video_dmabuf_data dmabuf_data[GSR_PIPEWIRE_VIDEO_DMABUF_MAX_PLANES];
|
||||||
|
int num_dmabuf_data;
|
||||||
|
uint32_t fourcc;
|
||||||
|
uint64_t modifiers;
|
||||||
|
bool using_external_image;
|
||||||
|
gsr_monitor_rotation rotation;
|
||||||
|
} gsr_map_texture_output;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
gsr_egl *egl;
|
gsr_egl *egl;
|
||||||
int fd;
|
int fd;
|
||||||
@@ -98,6 +110,8 @@ typedef struct {
|
|||||||
|
|
||||||
bool paused;
|
bool paused;
|
||||||
double paused_start_secs;
|
double paused_start_secs;
|
||||||
|
|
||||||
|
gsr_monitor_rotation rotation;
|
||||||
} gsr_pipewire_video;
|
} gsr_pipewire_video;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -108,8 +122,7 @@ typedef struct {
|
|||||||
bool gsr_pipewire_video_init(gsr_pipewire_video *self, int pipewire_fd, uint32_t pipewire_node, int fps, bool capture_cursor, gsr_egl *egl);
|
bool gsr_pipewire_video_init(gsr_pipewire_video *self, int pipewire_fd, uint32_t pipewire_node, int fps, bool capture_cursor, gsr_egl *egl);
|
||||||
void gsr_pipewire_video_deinit(gsr_pipewire_video *self);
|
void gsr_pipewire_video_deinit(gsr_pipewire_video *self);
|
||||||
|
|
||||||
/* |dmabuf_data| should be at least GSR_PIPEWIRE_VIDEO_DMABUF_MAX_PLANES in size */
|
bool gsr_pipewire_video_map_texture(gsr_pipewire_video *self, gsr_texture_map texture_map, gsr_map_texture_output *output);
|
||||||
bool gsr_pipewire_video_map_texture(gsr_pipewire_video *self, gsr_texture_map texture_map, gsr_pipewire_video_region *region, gsr_pipewire_video_region *cursor_region, gsr_pipewire_video_dmabuf_data *dmabuf_data, int *num_dmabuf_data, uint32_t *fourcc, uint64_t *modifiers, bool *using_external_image);
|
|
||||||
bool gsr_pipewire_video_is_damaged(gsr_pipewire_video *self);
|
bool gsr_pipewire_video_is_damaged(gsr_pipewire_video *self);
|
||||||
void gsr_pipewire_video_clear_damage(gsr_pipewire_video *self);
|
void gsr_pipewire_video_clear_damage(gsr_pipewire_video *self);
|
||||||
bool gsr_pipewire_video_should_restart(gsr_pipewire_video *self);
|
bool gsr_pipewire_video_should_restart(gsr_pipewire_video *self);
|
||||||
|
|||||||
@@ -30,27 +30,21 @@ typedef struct {
|
|||||||
|
|
||||||
gsr_pipewire_video pipewire;
|
gsr_pipewire_video pipewire;
|
||||||
vec2i capture_size;
|
vec2i capture_size;
|
||||||
gsr_pipewire_video_dmabuf_data dmabuf_data[GSR_PIPEWIRE_VIDEO_DMABUF_MAX_PLANES];
|
|
||||||
int num_dmabuf_data;
|
|
||||||
|
|
||||||
gsr_pipewire_video_region region;
|
gsr_map_texture_output pipewire_data;
|
||||||
gsr_pipewire_video_region cursor_region;
|
|
||||||
uint32_t pipewire_fourcc;
|
|
||||||
uint64_t pipewire_modifiers;
|
|
||||||
bool using_external_image;
|
|
||||||
|
|
||||||
bool should_stop;
|
bool should_stop;
|
||||||
bool stop_is_error;
|
bool stop_is_error;
|
||||||
} gsr_capture_portal;
|
} gsr_capture_portal;
|
||||||
|
|
||||||
static void gsr_capture_portal_cleanup_plane_fds(gsr_capture_portal *self) {
|
static void gsr_capture_portal_cleanup_plane_fds(gsr_capture_portal *self) {
|
||||||
for(int i = 0; i < self->num_dmabuf_data; ++i) {
|
for(int i = 0; i < self->pipewire_data.num_dmabuf_data; ++i) {
|
||||||
if(self->dmabuf_data[i].fd > 0) {
|
if(self->pipewire_data.dmabuf_data[i].fd > 0) {
|
||||||
close(self->dmabuf_data[i].fd);
|
close(self->pipewire_data.dmabuf_data[i].fd);
|
||||||
self->dmabuf_data[i].fd = 0;
|
self->pipewire_data.dmabuf_data[i].fd = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self->num_dmabuf_data = 0;
|
self->pipewire_data.num_dmabuf_data = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gsr_capture_portal_stop(gsr_capture_portal *self) {
|
static void gsr_capture_portal_stop(gsr_capture_portal *self) {
|
||||||
@@ -238,9 +232,9 @@ static bool gsr_capture_portal_get_frame_dimensions(gsr_capture_portal *self) {
|
|||||||
|
|
||||||
const double start_time = clock_get_monotonic_seconds();
|
const double start_time = clock_get_monotonic_seconds();
|
||||||
while(clock_get_monotonic_seconds() - start_time < 5.0) {
|
while(clock_get_monotonic_seconds() - start_time < 5.0) {
|
||||||
if(gsr_pipewire_video_map_texture(&self->pipewire, self->texture_map, &self->region, &self->cursor_region, self->dmabuf_data, &self->num_dmabuf_data, &self->pipewire_fourcc, &self->pipewire_modifiers, &self->using_external_image)) {
|
if(gsr_pipewire_video_map_texture(&self->pipewire, self->texture_map, &self->pipewire_data)) {
|
||||||
self->capture_size.x = self->region.width;
|
self->capture_size.x = self->pipewire_data.region.width;
|
||||||
self->capture_size.y = self->region.height;
|
self->capture_size.y = self->pipewire_data.region.height;
|
||||||
fprintf(stderr, "gsr info: gsr_capture_portal_start: pipewire negotiation finished\n");
|
fprintf(stderr, "gsr info: gsr_capture_portal_start: pipewire negotiation finished\n");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -347,11 +341,11 @@ static int gsr_capture_portal_capture(gsr_capture *cap, gsr_capture_metadata *ca
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: Handle formats other than RGB(A) */
|
/* TODO: Handle formats other than RGB(A) */
|
||||||
if(self->num_dmabuf_data == 0) {
|
if(self->pipewire_data.num_dmabuf_data == 0) {
|
||||||
if(gsr_pipewire_video_map_texture(&self->pipewire, self->texture_map, &self->region, &self->cursor_region, self->dmabuf_data, &self->num_dmabuf_data, &self->pipewire_fourcc, &self->pipewire_modifiers, &self->using_external_image)) {
|
if(gsr_pipewire_video_map_texture(&self->pipewire, self->texture_map, &self->pipewire_data)) {
|
||||||
if(self->region.width != self->capture_size.x || self->region.height != self->capture_size.y) {
|
if(self->pipewire_data.region.width != self->capture_size.x || self->pipewire_data.region.height != self->capture_size.y) {
|
||||||
self->capture_size.x = self->region.width;
|
self->capture_size.x = self->pipewire_data.region.width;
|
||||||
self->capture_size.y = self->region.height;
|
self->capture_size.y = self->pipewire_data.region.height;
|
||||||
gsr_color_conversion_clear(color_conversion);
|
gsr_color_conversion_clear(color_conversion);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -370,32 +364,35 @@ static int gsr_capture_portal_capture(gsr_capture *cap, gsr_capture_metadata *ca
|
|||||||
|
|
||||||
// TODO: Handle region crop
|
// TODO: Handle region crop
|
||||||
|
|
||||||
const bool fourcc_alpha = fourcc_has_alpha(self->pipewire_fourcc);
|
const bool fourcc_alpha = fourcc_has_alpha(self->pipewire_data.fourcc);
|
||||||
if(fourcc_alpha)
|
if(fourcc_alpha)
|
||||||
gsr_color_conversion_clear(color_conversion);
|
gsr_color_conversion_clear(color_conversion);
|
||||||
|
|
||||||
gsr_color_conversion_draw(color_conversion, self->using_external_image ? self->texture_map.external_texture_id : self->texture_map.texture_id,
|
gsr_color_conversion_draw(color_conversion, self->pipewire_data.using_external_image ? self->texture_map.external_texture_id : self->texture_map.texture_id,
|
||||||
target_pos, output_size,
|
target_pos, output_size,
|
||||||
(vec2i){self->region.x, self->region.y}, self->capture_size, self->capture_size,
|
(vec2i){self->pipewire_data.region.x, self->pipewire_data.region.y}, self->capture_size, self->capture_size,
|
||||||
GSR_ROT_0, GSR_SOURCE_COLOR_RGB, self->using_external_image, fourcc_alpha);
|
gsr_monitor_rotation_to_rotation(self->pipewire_data.rotation), GSR_SOURCE_COLOR_RGB, self->pipewire_data.using_external_image, fourcc_alpha);
|
||||||
|
|
||||||
if(self->params.record_cursor && self->texture_map.cursor_texture_id > 0 && self->cursor_region.width > 0) {
|
if(self->params.record_cursor && self->texture_map.cursor_texture_id > 0 && self->pipewire_data.cursor_region.width > 0) {
|
||||||
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,
|
||||||
self->capture_size.y == 0 ? 0 : (double)output_size.y / (double)self->capture_size.y
|
self->capture_size.y == 0 ? 0 : (double)output_size.y / (double)self->capture_size.y
|
||||||
};
|
};
|
||||||
|
|
||||||
const vec2i cursor_pos = {
|
const vec2i cursor_pos = {
|
||||||
target_pos.x + (self->cursor_region.x * scale.x),
|
target_pos.x + (self->pipewire_data.cursor_region.x * scale.x),
|
||||||
target_pos.y + (self->cursor_region.y * scale.y)
|
target_pos.y + (self->pipewire_data.cursor_region.y * scale.y)
|
||||||
};
|
};
|
||||||
|
|
||||||
self->params.egl->glEnable(GL_SCISSOR_TEST);
|
self->params.egl->glEnable(GL_SCISSOR_TEST);
|
||||||
self->params.egl->glScissor(target_pos.x, target_pos.y, output_size.x, output_size.y);
|
self->params.egl->glScissor(target_pos.x, target_pos.y, output_size.x, output_size.y);
|
||||||
gsr_color_conversion_draw(color_conversion, self->texture_map.cursor_texture_id,
|
gsr_color_conversion_draw(color_conversion, self->texture_map.cursor_texture_id,
|
||||||
(vec2i){cursor_pos.x, cursor_pos.y}, (vec2i){self->cursor_region.width * scale.x, self->cursor_region.height * scale.y},
|
(vec2i){cursor_pos.x, cursor_pos.y},
|
||||||
(vec2i){0, 0}, (vec2i){self->cursor_region.width, self->cursor_region.height}, (vec2i){self->cursor_region.width, self->cursor_region.height},
|
(vec2i){self->pipewire_data.cursor_region.width * scale.x, self->pipewire_data.cursor_region.height * scale.y},
|
||||||
GSR_ROT_0, GSR_SOURCE_COLOR_RGB, false, true);
|
(vec2i){0, 0},
|
||||||
|
(vec2i){self->pipewire_data.cursor_region.width, self->pipewire_data.cursor_region.height},
|
||||||
|
(vec2i){self->pipewire_data.cursor_region.width, self->pipewire_data.cursor_region.height},
|
||||||
|
gsr_monitor_rotation_to_rotation(self->pipewire_data.rotation), GSR_SOURCE_COLOR_RGB, false, true);
|
||||||
self->params.egl->glDisable(GL_SCISSOR_TEST);
|
self->params.egl->glDisable(GL_SCISSOR_TEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,29 @@
|
|||||||
#define SPA_POD_PROP_FLAG_DONT_FIXATE (1 << 4)
|
#define SPA_POD_PROP_FLAG_DONT_FIXATE (1 << 4)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !PW_CHECK_VERSION(0, 3, 62)
|
||||||
|
enum spa_meta_videotransform_value {
|
||||||
|
SPA_META_TRANSFORMATION_None = 0, /**< no transform */
|
||||||
|
SPA_META_TRANSFORMATION_90, /**< 90 degree counter-clockwise */
|
||||||
|
SPA_META_TRANSFORMATION_180, /**< 180 degree counter-clockwise */
|
||||||
|
SPA_META_TRANSFORMATION_270, /**< 270 degree counter-clockwise */
|
||||||
|
SPA_META_TRANSFORMATION_Flipped, /**< 180 degree flipped around the vertical axis. Equivalent
|
||||||
|
* to a reflexion through the vertical line splitting the
|
||||||
|
* buffer in two equal sized parts */
|
||||||
|
SPA_META_TRANSFORMATION_Flipped90, /**< flip then rotate around 90 degree counter-clockwise */
|
||||||
|
SPA_META_TRANSFORMATION_Flipped180, /**< flip then rotate around 180 degree counter-clockwise */
|
||||||
|
SPA_META_TRANSFORMATION_Flipped270, /**< flip then rotate around 270 degree counter-clockwise */
|
||||||
|
};
|
||||||
|
|
||||||
|
/** a transformation of the buffer */
|
||||||
|
struct spa_meta_videotransform {
|
||||||
|
uint32_t transform; /**< orientation transformation that was applied to the buffer,
|
||||||
|
* one of enum spa_meta_videotransform_value */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SPA_META_VideoTransform 8
|
||||||
|
#endif
|
||||||
|
|
||||||
#define CURSOR_META_SIZE(width, height) \
|
#define CURSOR_META_SIZE(width, height) \
|
||||||
(sizeof(struct spa_meta_cursor) + sizeof(struct spa_meta_bitmap) + \
|
(sizeof(struct spa_meta_cursor) + sizeof(struct spa_meta_bitmap) + \
|
||||||
width * height * 4)
|
width * height * 4)
|
||||||
@@ -157,6 +180,27 @@ static void on_process_cb(void *user_data) {
|
|||||||
self->crop.valid = false;
|
self->crop.valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct spa_meta_videotransform *video_transform = spa_buffer_find_meta_data(buffer, SPA_META_VideoTransform, sizeof(*video_transform));
|
||||||
|
enum spa_meta_videotransform_value transform = SPA_META_TRANSFORMATION_None;
|
||||||
|
if(video_transform)
|
||||||
|
transform = video_transform->transform;
|
||||||
|
|
||||||
|
self->rotation = GSR_MONITOR_ROT_0;
|
||||||
|
switch(transform) {
|
||||||
|
case SPA_META_TRANSFORMATION_90:
|
||||||
|
self->rotation = GSR_MONITOR_ROT_90;
|
||||||
|
break;
|
||||||
|
case SPA_META_TRANSFORMATION_180:
|
||||||
|
self->rotation = GSR_MONITOR_ROT_180;
|
||||||
|
break;
|
||||||
|
case SPA_META_TRANSFORMATION_270:
|
||||||
|
self->rotation = GSR_MONITOR_ROT_270;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// TODO: Support other rotations. Wayland compositors dont use them yet so it's ok to not support it now
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&self->mutex);
|
pthread_mutex_unlock(&self->mutex);
|
||||||
|
|
||||||
read_metadata:
|
read_metadata:
|
||||||
@@ -246,17 +290,18 @@ static void on_param_changed_cb(void *user_data, uint32_t id, const struct spa_p
|
|||||||
fprintf(stderr, "gsr info: pipewire: Size: %dx%d\n", self->format.info.raw.size.width, self->format.info.raw.size.height);
|
fprintf(stderr, "gsr info: pipewire: Size: %dx%d\n", self->format.info.raw.size.width, self->format.info.raw.size.height);
|
||||||
fprintf(stderr, "gsr info: pipewire: Framerate: %d/%d\n", self->format.info.raw.framerate.num, self->format.info.raw.framerate.denom);
|
fprintf(stderr, "gsr info: pipewire: Framerate: %d/%d\n", self->format.info.raw.framerate.num, self->format.info.raw.framerate.denom);
|
||||||
|
|
||||||
uint8_t params_buffer[1024];
|
uint8_t params_buffer[2048];
|
||||||
struct spa_pod_builder pod_builder = SPA_POD_BUILDER_INIT(params_buffer, sizeof(params_buffer));
|
struct spa_pod_builder pod_builder = SPA_POD_BUILDER_INIT(params_buffer, sizeof(params_buffer));
|
||||||
const struct spa_pod *params[4];
|
const struct spa_pod *params[5];
|
||||||
|
int param_index = 0;
|
||||||
|
|
||||||
params[0] = spa_pod_builder_add_object(
|
params[param_index++] = spa_pod_builder_add_object(
|
||||||
&pod_builder, SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta,
|
&pod_builder, SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta,
|
||||||
SPA_PARAM_META_type, SPA_POD_Id(SPA_META_VideoCrop),
|
SPA_PARAM_META_type, SPA_POD_Id(SPA_META_VideoCrop),
|
||||||
SPA_PARAM_META_size,
|
SPA_PARAM_META_size,
|
||||||
SPA_POD_Int(sizeof(struct spa_meta_region)));
|
SPA_POD_Int(sizeof(struct spa_meta_region)));
|
||||||
|
|
||||||
params[1] = spa_pod_builder_add_object(
|
params[param_index++] = spa_pod_builder_add_object(
|
||||||
&pod_builder, SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta,
|
&pod_builder, SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta,
|
||||||
SPA_PARAM_META_type, SPA_POD_Id(SPA_META_VideoDamage),
|
SPA_PARAM_META_type, SPA_POD_Id(SPA_META_VideoDamage),
|
||||||
SPA_PARAM_META_size, SPA_POD_CHOICE_RANGE_Int(
|
SPA_PARAM_META_size, SPA_POD_CHOICE_RANGE_Int(
|
||||||
@@ -264,7 +309,7 @@ static void on_param_changed_cb(void *user_data, uint32_t id, const struct spa_p
|
|||||||
sizeof(struct spa_meta_region) * 1,
|
sizeof(struct spa_meta_region) * 1,
|
||||||
sizeof(struct spa_meta_region) * 16));
|
sizeof(struct spa_meta_region) * 16));
|
||||||
|
|
||||||
params[2] = spa_pod_builder_add_object(
|
params[param_index++] = spa_pod_builder_add_object(
|
||||||
&pod_builder, SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta,
|
&pod_builder, SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta,
|
||||||
SPA_PARAM_META_type, SPA_POD_Id(SPA_META_Cursor),
|
SPA_PARAM_META_type, SPA_POD_Id(SPA_META_Cursor),
|
||||||
SPA_PARAM_META_size,
|
SPA_PARAM_META_size,
|
||||||
@@ -272,11 +317,22 @@ static void on_param_changed_cb(void *user_data, uint32_t id, const struct spa_p
|
|||||||
CURSOR_META_SIZE(1, 1),
|
CURSOR_META_SIZE(1, 1),
|
||||||
CURSOR_META_SIZE(1024, 1024)));
|
CURSOR_META_SIZE(1024, 1024)));
|
||||||
|
|
||||||
params[3] = spa_pod_builder_add_object(
|
params[param_index++] = spa_pod_builder_add_object(
|
||||||
&pod_builder, SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers,
|
&pod_builder, SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers,
|
||||||
SPA_PARAM_BUFFERS_dataType, SPA_POD_Int(buffer_types));
|
SPA_PARAM_BUFFERS_dataType, SPA_POD_Int(buffer_types));
|
||||||
|
|
||||||
pw_stream_update_params(self->stream, params, 4);
|
#if PW_CHECK_VERSION(0, 3, 62)
|
||||||
|
if (check_pw_version(&self->server_version, 0, 3, 62)) {
|
||||||
|
/* Video transformation */
|
||||||
|
params[param_index++] = spa_pod_builder_add_object(&pod_builder, SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta,
|
||||||
|
SPA_PARAM_META_type,
|
||||||
|
SPA_POD_Id(SPA_META_VideoTransform),
|
||||||
|
SPA_PARAM_META_size,
|
||||||
|
SPA_POD_Int(sizeof(struct spa_meta_videotransform)));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
pw_stream_update_params(self->stream, params, param_index);
|
||||||
self->negotiated = true;
|
self->negotiated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -790,14 +846,15 @@ static void gsr_pipewire_video_update_cursor_texture(gsr_pipewire_video *self, g
|
|||||||
self->cursor.data = NULL;
|
self->cursor.data = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool gsr_pipewire_video_map_texture(gsr_pipewire_video *self, gsr_texture_map texture_map, gsr_pipewire_video_region *region, gsr_pipewire_video_region *cursor_region, gsr_pipewire_video_dmabuf_data *dmabuf_data, int *num_dmabuf_data, uint32_t *fourcc, uint64_t *modifiers, bool *using_external_image) {
|
bool gsr_pipewire_video_map_texture(gsr_pipewire_video *self, gsr_texture_map texture_map, gsr_map_texture_output *output) {
|
||||||
for(int i = 0; i < GSR_PIPEWIRE_VIDEO_DMABUF_MAX_PLANES; ++i) {
|
for(int i = 0; i < GSR_PIPEWIRE_VIDEO_DMABUF_MAX_PLANES; ++i) {
|
||||||
memset(&dmabuf_data[i], 0, sizeof(gsr_pipewire_video_dmabuf_data));
|
memset(&output->dmabuf_data[i], 0, sizeof(gsr_pipewire_video_dmabuf_data));
|
||||||
}
|
}
|
||||||
*num_dmabuf_data = 0;
|
output->num_dmabuf_data = 0;
|
||||||
*using_external_image = self->external_texture_fallback;
|
output->using_external_image = self->external_texture_fallback;
|
||||||
*fourcc = 0;
|
output->fourcc = 0;
|
||||||
*modifiers = 0;
|
output->modifiers = 0;
|
||||||
|
output->rotation = GSR_MONITOR_ROT_0;
|
||||||
pthread_mutex_lock(&self->mutex);
|
pthread_mutex_lock(&self->mutex);
|
||||||
|
|
||||||
if(!self->negotiated || self->dmabuf_data[0].fd <= 0) {
|
if(!self->negotiated || self->dmabuf_data[0].fd <= 0) {
|
||||||
@@ -812,39 +869,47 @@ bool gsr_pipewire_video_map_texture(gsr_pipewire_video *self, gsr_texture_map te
|
|||||||
}
|
}
|
||||||
|
|
||||||
gsr_pipewire_video_bind_image_to_texture_with_fallback(self, texture_map, image);
|
gsr_pipewire_video_bind_image_to_texture_with_fallback(self, texture_map, image);
|
||||||
*using_external_image = self->external_texture_fallback;
|
output->using_external_image = self->external_texture_fallback;
|
||||||
self->egl->eglDestroyImage(self->egl->egl_display, image);
|
self->egl->eglDestroyImage(self->egl->egl_display, image);
|
||||||
|
|
||||||
gsr_pipewire_video_update_cursor_texture(self, texture_map);
|
gsr_pipewire_video_update_cursor_texture(self, texture_map);
|
||||||
|
|
||||||
region->x = 0;
|
output->region.x = 0;
|
||||||
region->y = 0;
|
output->region.y = 0;
|
||||||
|
|
||||||
region->width = self->format.info.raw.size.width;
|
output->region.width = self->format.info.raw.size.width;
|
||||||
region->height = self->format.info.raw.size.height;
|
output->region.height = self->format.info.raw.size.height;
|
||||||
|
|
||||||
if(self->crop.valid) {
|
if(self->crop.valid) {
|
||||||
region->x = self->crop.x;
|
output->region.x = self->crop.x;
|
||||||
region->y = self->crop.y;
|
output->region.y = self->crop.y;
|
||||||
|
|
||||||
region->width = self->crop.width;
|
output->region.width = self->crop.width;
|
||||||
region->height = self->crop.height;
|
output->region.height = self->crop.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Test transform + cropping
|
||||||
|
if(self->rotation == GSR_MONITOR_ROT_90 || self->rotation == GSR_MONITOR_ROT_270) {
|
||||||
|
const int temp = output->region.width;
|
||||||
|
output->region.width = output->region.height;
|
||||||
|
output->region.height = temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: Test if cursor hotspot is correct */
|
/* TODO: Test if cursor hotspot is correct */
|
||||||
cursor_region->x = self->cursor.x - self->cursor.hotspot_x;
|
output->cursor_region.x = self->cursor.x - self->cursor.hotspot_x;
|
||||||
cursor_region->y = self->cursor.y - self->cursor.hotspot_y;
|
output->cursor_region.y = self->cursor.y - self->cursor.hotspot_y;
|
||||||
|
|
||||||
cursor_region->width = self->cursor.width;
|
output->cursor_region.width = self->cursor.width;
|
||||||
cursor_region->height = self->cursor.height;
|
output->cursor_region.height = self->cursor.height;
|
||||||
|
|
||||||
for(size_t i = 0; i < self->dmabuf_num_planes; ++i) {
|
for(size_t i = 0; i < self->dmabuf_num_planes; ++i) {
|
||||||
dmabuf_data[i] = self->dmabuf_data[i];
|
output->dmabuf_data[i] = self->dmabuf_data[i];
|
||||||
self->dmabuf_data[i].fd = -1;
|
self->dmabuf_data[i].fd = -1;
|
||||||
}
|
}
|
||||||
*num_dmabuf_data = self->dmabuf_num_planes;
|
output->num_dmabuf_data = self->dmabuf_num_planes;
|
||||||
*fourcc = spa_video_format_to_drm_format(self->format.info.raw.format);
|
output->fourcc = spa_video_format_to_drm_format(self->format.info.raw.format);
|
||||||
*modifiers = self->format.info.raw.modifier;
|
output->modifiers = self->format.info.raw.modifier;
|
||||||
|
output->rotation = self->rotation;
|
||||||
self->dmabuf_num_planes = 0;
|
self->dmabuf_num_planes = 0;
|
||||||
|
|
||||||
pthread_mutex_unlock(&self->mutex);
|
pthread_mutex_unlock(&self->mutex);
|
||||||
|
|||||||
Reference in New Issue
Block a user