mirror of
https://github.com/hyprwm/wlroots-hyprland.git
synced 2024-11-02 11:55:59 +01:00
screencopy: Implement copying into linux-dmabuf
This commit is contained in:
parent
909b0213b3
commit
ea83957ecc
2 changed files with 113 additions and 27 deletions
|
@ -38,6 +38,7 @@ struct wlr_screencopy_frame_v1 {
|
||||||
struct wl_list link;
|
struct wl_list link;
|
||||||
|
|
||||||
enum wl_shm_format format;
|
enum wl_shm_format format;
|
||||||
|
uint32_t fourcc;
|
||||||
struct wlr_box box;
|
struct wlr_box box;
|
||||||
int stride;
|
int stride;
|
||||||
|
|
||||||
|
@ -45,7 +46,9 @@ struct wlr_screencopy_frame_v1 {
|
||||||
|
|
||||||
bool with_damage;
|
bool with_damage;
|
||||||
|
|
||||||
struct wl_shm_buffer *buffer;
|
struct wl_shm_buffer *shm_buffer;
|
||||||
|
struct wlr_dmabuf_v1_buffer *dma_buffer;
|
||||||
|
|
||||||
struct wl_listener buffer_destroy;
|
struct wl_listener buffer_destroy;
|
||||||
|
|
||||||
struct wlr_output *output;
|
struct wlr_output *output;
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <drm_fourcc.h>
|
||||||
#include <wlr/render/wlr_renderer.h>
|
#include <wlr/render/wlr_renderer.h>
|
||||||
#include <wlr/types/wlr_output.h>
|
#include <wlr/types/wlr_output.h>
|
||||||
|
#include <wlr/types/wlr_linux_dmabuf_v1.h>
|
||||||
#include <wlr/types/wlr_screencopy_v1.h>
|
#include <wlr/types/wlr_screencopy_v1.h>
|
||||||
#include <wlr/backend.h>
|
#include <wlr/backend.h>
|
||||||
#include <wlr/util/log.h>
|
#include <wlr/util/log.h>
|
||||||
#include "wlr-screencopy-unstable-v1-protocol.h"
|
#include "wlr-screencopy-unstable-v1-protocol.h"
|
||||||
#include "util/signal.h"
|
#include "util/signal.h"
|
||||||
|
|
||||||
#define SCREENCOPY_MANAGER_VERSION 2
|
#define SCREENCOPY_MANAGER_VERSION 3
|
||||||
|
|
||||||
struct screencopy_damage {
|
struct screencopy_damage {
|
||||||
struct wl_list link;
|
struct wl_list link;
|
||||||
|
@ -132,7 +134,8 @@ static void frame_destroy(struct wlr_screencopy_frame_v1 *frame) {
|
||||||
if (frame == NULL) {
|
if (frame == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (frame->output != NULL && frame->buffer != NULL) {
|
if (frame->output != NULL &&
|
||||||
|
(frame->shm_buffer != NULL || frame->dma_buffer != NULL)) {
|
||||||
wlr_output_lock_attach_render(frame->output, false);
|
wlr_output_lock_attach_render(frame->output, false);
|
||||||
if (frame->cursor_locked) {
|
if (frame->cursor_locked) {
|
||||||
wlr_output_lock_software_cursors(frame->output, false);
|
wlr_output_lock_software_cursors(frame->output, false);
|
||||||
|
@ -179,20 +182,34 @@ static void frame_handle_output_precommit(struct wl_listener *listener,
|
||||||
int x = frame->box.x;
|
int x = frame->box.x;
|
||||||
int y = frame->box.y;
|
int y = frame->box.y;
|
||||||
|
|
||||||
struct wl_shm_buffer *buffer = frame->buffer;
|
bool ok = false;
|
||||||
assert(buffer != NULL);
|
|
||||||
|
|
||||||
enum wl_shm_format fmt = wl_shm_buffer_get_format(buffer);
|
|
||||||
int32_t width = wl_shm_buffer_get_width(buffer);
|
|
||||||
int32_t height = wl_shm_buffer_get_height(buffer);
|
|
||||||
int32_t stride = wl_shm_buffer_get_stride(buffer);
|
|
||||||
|
|
||||||
wl_shm_buffer_begin_access(buffer);
|
|
||||||
void *data = wl_shm_buffer_get_data(buffer);
|
|
||||||
uint32_t flags = 0;
|
uint32_t flags = 0;
|
||||||
bool ok = wlr_renderer_read_pixels(renderer, fmt, &flags, stride,
|
|
||||||
|
struct wl_shm_buffer *shm_buffer = frame->shm_buffer;
|
||||||
|
struct wlr_dmabuf_v1_buffer *dma_buffer = frame->dma_buffer;
|
||||||
|
assert(shm_buffer || dma_buffer);
|
||||||
|
|
||||||
|
if (shm_buffer) {
|
||||||
|
enum wl_shm_format fmt = wl_shm_buffer_get_format(shm_buffer);
|
||||||
|
int32_t width = wl_shm_buffer_get_width(shm_buffer);
|
||||||
|
int32_t height = wl_shm_buffer_get_height(shm_buffer);
|
||||||
|
int32_t stride = wl_shm_buffer_get_stride(shm_buffer);
|
||||||
|
|
||||||
|
wl_shm_buffer_begin_access(shm_buffer);
|
||||||
|
void *data = wl_shm_buffer_get_data(shm_buffer);
|
||||||
|
flags = 0;
|
||||||
|
ok = wlr_renderer_read_pixels(renderer, fmt, &flags, stride,
|
||||||
width, height, x, y, 0, 0, data);
|
width, height, x, y, 0, 0, data);
|
||||||
wl_shm_buffer_end_access(buffer);
|
wl_shm_buffer_end_access(shm_buffer);
|
||||||
|
} else if (dma_buffer) {
|
||||||
|
struct wlr_dmabuf_attributes attr = { 0 };
|
||||||
|
ok = wlr_output_export_dmabuf(frame->output, &attr);
|
||||||
|
ok = ok && wlr_renderer_blit_dmabuf(renderer,
|
||||||
|
&dma_buffer->attributes, &attr);
|
||||||
|
flags |= attr.flags & WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT ?
|
||||||
|
ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT : 0;
|
||||||
|
wlr_dmabuf_attributes_finish(&attr);
|
||||||
|
}
|
||||||
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
zwlr_screencopy_frame_v1_send_failed(frame->resource);
|
zwlr_screencopy_frame_v1_send_failed(frame->resource);
|
||||||
|
@ -269,35 +286,78 @@ static void frame_handle_copy(struct wl_client *wl_client,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wl_shm_buffer *buffer = wl_shm_buffer_get(buffer_resource);
|
struct wlr_dmabuf_v1_buffer *dma_buffer = NULL;
|
||||||
if (buffer == NULL) {
|
struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get(buffer_resource);
|
||||||
|
if (shm_buffer == NULL &&
|
||||||
|
wlr_dmabuf_v1_resource_is_buffer(buffer_resource)) {
|
||||||
|
dma_buffer =
|
||||||
|
wlr_dmabuf_v1_buffer_from_buffer_resource(buffer_resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shm_buffer == NULL && dma_buffer == NULL) {
|
||||||
wl_resource_post_error(frame->resource,
|
wl_resource_post_error(frame->resource,
|
||||||
ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER,
|
ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER,
|
||||||
"unsupported buffer type");
|
"unsupported buffer type");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum wl_shm_format fmt = wl_shm_buffer_get_format(buffer);
|
int32_t width = 0;
|
||||||
int32_t width = wl_shm_buffer_get_width(buffer);
|
int32_t height = 0;
|
||||||
int32_t height = wl_shm_buffer_get_height(buffer);
|
|
||||||
int32_t stride = wl_shm_buffer_get_stride(buffer);
|
if (shm_buffer) {
|
||||||
if (fmt != frame->format || width != frame->box.width ||
|
enum wl_shm_format fmt = wl_shm_buffer_get_format(shm_buffer);
|
||||||
height != frame->box.height || stride != frame->stride) {
|
if (fmt != frame->format) {
|
||||||
wl_resource_post_error(frame->resource,
|
wl_resource_post_error(frame->resource,
|
||||||
ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER,
|
ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER,
|
||||||
"invalid buffer attributes");
|
"invalid buffer format");
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t stride = wl_shm_buffer_get_stride(shm_buffer);
|
||||||
|
if (stride != frame->stride) {
|
||||||
|
wl_resource_post_error(frame->resource,
|
||||||
|
ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER,
|
||||||
|
"invalid buffer stride");
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
width = wl_shm_buffer_get_width(shm_buffer);
|
||||||
|
height = wl_shm_buffer_get_height(shm_buffer);
|
||||||
|
} else if (dma_buffer) {
|
||||||
|
uint32_t fourcc = dma_buffer->attributes.format;
|
||||||
|
if (fourcc != frame->fourcc) {
|
||||||
|
wl_resource_post_error(frame->resource,
|
||||||
|
ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER,
|
||||||
|
"invalid buffer format");
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
width = dma_buffer->attributes.width;
|
||||||
|
height = dma_buffer->attributes.height;
|
||||||
|
} else {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (width != frame->box.width || height != frame->box.height) {
|
||||||
|
wl_resource_post_error(frame->resource,
|
||||||
|
ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER,
|
||||||
|
"invalid buffer dimensions");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!wl_list_empty(&frame->output_precommit.link) ||
|
if (!wl_list_empty(&frame->output_precommit.link) ||
|
||||||
frame->buffer != NULL) {
|
frame->shm_buffer != NULL || frame->dma_buffer != NULL) {
|
||||||
wl_resource_post_error(frame->resource,
|
wl_resource_post_error(frame->resource,
|
||||||
ZWLR_SCREENCOPY_FRAME_V1_ERROR_ALREADY_USED,
|
ZWLR_SCREENCOPY_FRAME_V1_ERROR_ALREADY_USED,
|
||||||
"frame already used");
|
"frame already used");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
frame->buffer = buffer;
|
frame->shm_buffer = shm_buffer;
|
||||||
|
frame->dma_buffer = dma_buffer;
|
||||||
|
|
||||||
wl_signal_add(&output->events.precommit, &frame->output_precommit);
|
wl_signal_add(&output->events.precommit, &frame->output_precommit);
|
||||||
frame->output_precommit.notify = frame_handle_output_precommit;
|
frame->output_precommit.notify = frame_handle_output_precommit;
|
||||||
|
@ -359,6 +419,16 @@ static struct wlr_screencopy_v1_client *client_from_resource(
|
||||||
return wl_resource_get_user_data(resource);
|
return wl_resource_get_user_data(resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t get_output_fourcc(struct wlr_output *output) {
|
||||||
|
struct wlr_dmabuf_attributes attr = { 0 };
|
||||||
|
if (!wlr_output_export_dmabuf(output, &attr)) {
|
||||||
|
return DRM_FORMAT_INVALID;
|
||||||
|
}
|
||||||
|
uint32_t format = attr.format;
|
||||||
|
wlr_dmabuf_attributes_finish(&attr);
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
static void capture_output(struct wl_client *wl_client,
|
static void capture_output(struct wl_client *wl_client,
|
||||||
struct wlr_screencopy_v1_client *client, uint32_t version,
|
struct wlr_screencopy_v1_client *client, uint32_t version,
|
||||||
uint32_t id, int32_t overlay_cursor, struct wlr_output *output,
|
uint32_t id, int32_t overlay_cursor, struct wlr_output *output,
|
||||||
|
@ -412,6 +482,8 @@ static void capture_output(struct wl_client *wl_client,
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
frame->fourcc = get_output_fourcc(output);
|
||||||
|
|
||||||
struct wlr_box buffer_box = {0};
|
struct wlr_box buffer_box = {0};
|
||||||
if (box == NULL) {
|
if (box == NULL) {
|
||||||
buffer_box.width = output->width;
|
buffer_box.width = output->width;
|
||||||
|
@ -434,6 +506,17 @@ static void capture_output(struct wl_client *wl_client,
|
||||||
|
|
||||||
zwlr_screencopy_frame_v1_send_buffer(frame->resource, frame->format,
|
zwlr_screencopy_frame_v1_send_buffer(frame->resource, frame->format,
|
||||||
buffer_box.width, buffer_box.height, frame->stride);
|
buffer_box.width, buffer_box.height, frame->stride);
|
||||||
|
|
||||||
|
if (version >= 3) {
|
||||||
|
if (frame->fourcc != DRM_FORMAT_INVALID) {
|
||||||
|
zwlr_screencopy_frame_v1_send_linux_dmabuf(
|
||||||
|
frame->resource, frame->fourcc,
|
||||||
|
buffer_box.width, buffer_box.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
zwlr_screencopy_frame_v1_send_buffer_done(frame->resource);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
|
Loading…
Reference in a new issue