Skip to content
Commits on Source (13)
......@@ -58,7 +58,6 @@ deps_drm = [
]
if get_option('renderer-gl')
dep_gbm = dependency('gbm', required: false, version: '>= 21.1.1')
if not dep_gbm.found()
error('drm-backend with GL renderer requires gbm which was not found. Or, you can use \'-Drenderer-gl=false\'.')
endif
......
......@@ -54,6 +54,7 @@
#include "shared/xalloc.h"
#include <libweston/libweston.h>
#include <libweston/backend-pipewire.h>
#include <libweston/linux-dmabuf.h>
#include <libweston/weston-log.h>
#include "pixel-formats.h"
#include "pixman-renderer.h"
......@@ -100,6 +101,8 @@ struct pipewire_head {
struct pipewire_frame_data {
struct weston_renderbuffer *renderbuffer;
struct pipewire_memfd *memfd;
struct pipewire_dmabuf *dmabuf;
};
/* Pipewire default configuration for heads */
......@@ -201,41 +204,82 @@ spa_video_format_from_drm_fourcc(uint32_t fourcc)
}
}
static bool
pipewire_backend_has_dmabuf_allocator(struct pipewire_backend *backend)
{
struct weston_renderer *renderer = backend->compositor->renderer;
return renderer->dmabuf_alloc != NULL;
}
static struct spa_pod *
spa_pod_build_format(struct spa_pod_builder *builder,
int width, int height, int framerate,
uint32_t format, uint64_t *modifier)
{
struct spa_pod_frame f;
spa_pod_builder_push_object(builder, &f,
SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat);
spa_pod_builder_add(builder,
SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video), 0);
spa_pod_builder_add(builder,
SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), 0);
spa_pod_builder_add(builder,
SPA_FORMAT_VIDEO_format,
SPA_POD_Id(spa_video_format_from_drm_fourcc(format)), 0);
if (modifier) {
spa_pod_builder_prop(builder,
SPA_FORMAT_VIDEO_modifier, SPA_POD_PROP_FLAG_MANDATORY);
spa_pod_builder_long(builder, *modifier);
}
spa_pod_builder_prop(builder, SPA_FORMAT_VIDEO_size, 0);
spa_pod_builder_rectangle(builder, width, height);
spa_pod_builder_add(builder,
SPA_FORMAT_VIDEO_framerate,
SPA_POD_Fraction(&SPA_FRACTION(0, 1)), 0);
spa_pod_builder_add(builder,
SPA_FORMAT_VIDEO_maxFramerate,
SPA_POD_CHOICE_RANGE_Fraction(
&SPA_FRACTION(framerate,1),
&SPA_FRACTION(1,1),
&SPA_FRACTION(framerate,1)), 0);
return spa_pod_builder_pop(builder, &f);
}
static int
pipewire_output_connect(struct pipewire_output *output)
{
uint8_t buffer[1024];
struct spa_pod_builder builder =
SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
const struct spa_pod *params[1];
int framerate;
int width;
int height;
enum spa_video_format format;
const struct spa_pod *params[2];
int i = 0;
int ret;
framerate = output->base.current_mode->refresh / 1000;
width = output->base.width;
height = output->base.height;
format = spa_video_format_from_drm_fourcc(output->pixel_format->format);
if (pipewire_backend_has_dmabuf_allocator(output->backend)) {
/* TODO: Add support for modifier discovery and negotiation. */
uint64_t modifier[] = { DRM_FORMAT_MOD_LINEAR };
params[i++] = spa_pod_build_format(&builder,
output->base.width, output->base.height,
output->base.current_mode->refresh / 1000,
output->pixel_format->format,
modifier);
}
params[0] = spa_pod_builder_add_object(&builder,
SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video),
SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
SPA_FORMAT_VIDEO_format, SPA_POD_Id(format),
SPA_FORMAT_VIDEO_size, SPA_POD_Rectangle(&SPA_RECTANGLE(width, height)),
SPA_FORMAT_VIDEO_framerate, SPA_POD_Fraction(&SPA_FRACTION (0, 1)),
SPA_FORMAT_VIDEO_maxFramerate,
SPA_POD_CHOICE_RANGE_Fraction(&SPA_FRACTION(framerate, 1),
&SPA_FRACTION(1, 1),
&SPA_FRACTION(framerate, 1)));
params[i++] = spa_pod_build_format(&builder,
output->base.width, output->base.height,
output->base.current_mode->refresh / 1000,
output->pixel_format->format, NULL);
ret = pw_stream_connect(output->stream, PW_DIRECTION_OUTPUT, PW_ID_ANY,
PW_STREAM_FLAG_DRIVER |
PW_STREAM_FLAG_MAP_BUFFERS,
params, 1);
PW_STREAM_FLAG_ALLOC_BUFFERS,
params, i);
if (ret != 0) {
weston_log("Failed to connect PipeWire stream: %s",
spa_strerror(ret));
......@@ -427,6 +471,51 @@ pipewire_output_stream_state_changed(void *data, enum pw_stream_state old,
}
}
struct pipewire_dmabuf {
struct linux_dmabuf_memory *linux_dmabuf_memory;
unsigned int size;
};
static struct pipewire_dmabuf *
pipewire_output_create_dmabuf(struct pipewire_output *output)
{
struct pipewire_backend *b = output->backend;
struct weston_renderer *renderer = b->compositor->renderer;
struct linux_dmabuf_memory *linux_dmabuf_memory;
struct pipewire_dmabuf *dmabuf;
const struct pixel_format_info *format;
unsigned int width;
unsigned int height;
uint64_t modifier[] = { DRM_FORMAT_MOD_LINEAR };
format = output->pixel_format;
width = output->base.width;
height = output->base.height;
linux_dmabuf_memory = renderer->dmabuf_alloc(renderer, width, height,
format->format,
modifier,
ARRAY_LENGTH(modifier));
if (!linux_dmabuf_memory) {
weston_log("Failed to allocate DMABUF (%ux%u %s)\n",
width, height, format->drm_format_name);
return NULL;
}
dmabuf = xzalloc(sizeof(*dmabuf));
dmabuf->linux_dmabuf_memory = linux_dmabuf_memory;
dmabuf->size = linux_dmabuf_memory->attributes->stride[0] * height;
return dmabuf;
}
static void
pipewire_destroy_dmabuf(struct pipewire_output *output,
struct pipewire_dmabuf *dmabuf)
{
free(dmabuf);
}
static void
pipewire_output_stream_param_changed(void *data, uint32_t id,
const struct spa_pod *format)
......@@ -437,6 +526,7 @@ pipewire_output_stream_param_changed(void *data, uint32_t id,
SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
const struct spa_pod *params[2];
struct spa_video_info video_info;
uint32_t buffertype;
int32_t width;
int32_t height;
int32_t stride;
......@@ -454,24 +544,45 @@ pipewire_output_stream_param_changed(void *data, uint32_t id,
spa_format_video_raw_parse(format, &video_info.info.raw);
pipewire_output_debug(output, "param changed: %dx%d@(%d/%d) (%s)",
width = video_info.info.raw.size.width;
height = video_info.info.raw.size.height;
/* Default to MemFd */
buffertype = SPA_DATA_MemFd;
stride = width * output->pixel_format->bpp / 8;
size = height * stride;
/* Use DmaBuf if requested and supported */
if (spa_pod_find_prop(format, NULL, SPA_FORMAT_VIDEO_modifier)) {
struct pipewire_dmabuf *dmabuf;
dmabuf = pipewire_output_create_dmabuf(output);
if (dmabuf) {
buffertype = SPA_DATA_DmaBuf;
stride = dmabuf->linux_dmabuf_memory->attributes->stride[0];
size = dmabuf->size;
dmabuf->linux_dmabuf_memory->destroy(dmabuf->linux_dmabuf_memory);
pipewire_destroy_dmabuf(output, dmabuf);
}
}
pipewire_output_debug(output, "param changed: %dx%d@(%d/%d) (%s) (%s)",
video_info.info.raw.size.width,
video_info.info.raw.size.height,
video_info.info.raw.max_framerate.num,
video_info.info.raw.max_framerate.denom,
spa_debug_type_find_short_name(spa_type_video_format,
video_info.info.raw.format));
width = video_info.info.raw.size.width;
height = video_info.info.raw.size.height;
stride = width * output->pixel_format->bpp / 8;
size = height * stride;
video_info.info.raw.format),
spa_debug_type_find_short_name(spa_type_data_type,
buffertype));
params[0] = spa_pod_builder_add_object(&builder,
SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers,
SPA_PARAM_BUFFERS_size, SPA_POD_Int(size),
SPA_PARAM_BUFFERS_stride, SPA_POD_Int(stride),
SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(4, 2, 8));
SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(4, 2, 8),
SPA_PARAM_BUFFERS_dataType, SPA_POD_CHOICE_FLAGS_Int(1u << buffertype));
params[1] = spa_pod_builder_add_object(&builder,
SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta,
......@@ -518,6 +629,12 @@ pipewire_output_stream_add_buffer_gl(struct pipewire_output *output,
unsigned int width;
unsigned int height;
void *ptr;
struct pipewire_frame_data *frame_data = buffer->user_data;
struct pipewire_dmabuf *dmabuf = frame_data->dmabuf;
if (dmabuf)
return renderer->create_renderbuffer_dmabuf(&output->base,
dmabuf->linux_dmabuf_memory);
format = output->pixel_format;
width = output->base.width;
......@@ -528,11 +645,98 @@ pipewire_output_stream_add_buffer_gl(struct pipewire_output *output,
format, width, height, ptr);
}
struct pipewire_memfd {
int fd;
unsigned int size;
};
static struct pipewire_memfd *
pipewire_output_create_memfd(struct pipewire_output *output)
{
struct pipewire_memfd *memfd;
const struct pixel_format_info *format;
unsigned int width;
unsigned int height;
unsigned int stride;
size_t size;
int fd;
memfd = xzalloc(sizeof *memfd);
format = output->pixel_format;
width = output->base.width;
height = output->base.height;
stride = width * format->bpp / 8;
size = height * stride;
fd = memfd_create("weston-pipewire", MFD_CLOEXEC);
if (fd == -1)
return NULL;
if (ftruncate(fd, size) == -1)
return NULL;
memfd->fd = fd;
memfd->size = size;
return memfd;
}
static void
pipewire_destroy_memfd(struct pipewire_output *output,
struct pipewire_memfd *memfd)
{
close(memfd->fd);
free(memfd);
}
static void
pipewire_output_setup_memfd(struct pipewire_output *output,
struct pw_buffer *buffer,
struct pipewire_memfd *memfd)
{
struct spa_buffer *buf = buffer->buffer;
struct spa_data *d = buf->datas;
d[0].type = SPA_DATA_MemFd;
d[0].flags = SPA_DATA_FLAG_READWRITE;
d[0].fd = memfd->fd;
d[0].mapoffset = 0;
d[0].maxsize = memfd->size;
d[0].data = mmap(NULL, d[0].maxsize,
PROT_READ|PROT_WRITE, MAP_SHARED,
d[0].fd, d[0].mapoffset);
buf->n_datas = 1;
}
static void
pipewire_output_setup_dmabuf(struct pipewire_output *output,
struct pw_buffer *buffer,
struct pipewire_dmabuf *dmabuf)
{
struct spa_buffer *buf = buffer->buffer;
struct spa_data *d = buf->datas;
struct linux_dmabuf_memory *linux_dmabuf_memory = dmabuf->linux_dmabuf_memory;
d[0].type = SPA_DATA_DmaBuf;
d[0].flags = SPA_DATA_FLAG_READWRITE;
d[0].fd = linux_dmabuf_memory->attributes->fd[0];
d[0].mapoffset = 0;
d[0].maxsize = dmabuf->size;
d[0].data = NULL;
d[0].chunk->offset = linux_dmabuf_memory->attributes->offset[0];
d[0].chunk->stride = linux_dmabuf_memory->attributes->stride[0];
d[0].chunk->size = dmabuf->size;
buffer->buffer->n_datas = 1;
}
static void
pipewire_output_stream_add_buffer(void *data, struct pw_buffer *buffer)
{
struct pipewire_output *output = data;
struct weston_renderer *renderer = output->base.compositor->renderer;
struct spa_buffer *buf = buffer->buffer;
struct spa_data *d = buf->datas;
unsigned int buffertype = d[0].type;
struct pipewire_frame_data *frame_data;
pipewire_output_debug(output, "add buffer: %p", buffer);
......@@ -540,6 +744,30 @@ pipewire_output_stream_add_buffer(void *data, struct pw_buffer *buffer)
frame_data = xzalloc(sizeof *frame_data);
buffer->user_data = frame_data;
if (buffertype & (1u << SPA_DATA_DmaBuf)) {
struct pipewire_dmabuf *dmabuf;
dmabuf = pipewire_output_create_dmabuf(output);
if (!dmabuf) {
pw_stream_set_error(output->stream, -ENOMEM,
"failed to allocate DMABUF buffer");
return;
}
pipewire_output_setup_dmabuf(output, buffer, dmabuf);
frame_data->dmabuf = dmabuf;
} else if (buffertype & (1u << SPA_DATA_MemFd)) {
struct pipewire_memfd *memfd;
memfd = pipewire_output_create_memfd(output);
if (!memfd) {
pw_stream_set_error(output->stream, -ENOMEM,
"failed to allocate MemFd buffer");
return;
}
pipewire_output_setup_memfd(output, buffer, memfd);
frame_data->memfd = memfd;
}
switch (renderer->type) {
case WESTON_RENDERER_PIXMAN:
frame_data->renderbuffer = pipewire_output_stream_add_buffer_pixman(output, buffer);
......@@ -557,10 +785,26 @@ pipewire_output_stream_remove_buffer(void *data, struct pw_buffer *buffer)
{
struct pipewire_output *output = data;
struct pipewire_frame_data *frame_data = buffer->user_data;
struct spa_buffer *buf = buffer->buffer;
struct spa_data *d = buf->datas;
pipewire_output_debug(output, "remove buffer: %p", buffer);
weston_renderbuffer_unref(frame_data->renderbuffer);
if (frame_data->dmabuf) {
struct weston_compositor *ec = output->base.compositor;
const struct weston_renderer *renderer = ec->renderer;
renderer->remove_renderbuffer_dmabuf(&output->base,
frame_data->renderbuffer);
pipewire_destroy_dmabuf(output, frame_data->dmabuf);
}
if (frame_data->memfd) {
munmap(d[0].data, d[0].maxsize);
pipewire_destroy_memfd(output, frame_data->memfd);
}
if (frame_data->renderbuffer)
weston_renderbuffer_unref(frame_data->renderbuffer);
free(frame_data);
}
......@@ -683,6 +927,8 @@ static void
pipewire_submit_buffer(struct pipewire_output *output,
struct pw_buffer *buffer)
{
struct pipewire_frame_data *frame_data = buffer->user_data;
struct pipewire_dmabuf *dmabuf = frame_data->dmabuf;
struct spa_buffer *spa_buffer;
struct spa_meta_header *h;
const struct pixel_format_info *pixel_format;
......@@ -690,7 +936,10 @@ pipewire_submit_buffer(struct pipewire_output *output,
size_t size;
pixel_format = output->pixel_format;
stride = output->base.width * pixel_format->bpp / 8;
if (dmabuf)
stride = dmabuf->linux_dmabuf_memory->attributes->stride[0];
else
stride = output->base.width * pixel_format->bpp / 8;
size = output->base.height * stride;
spa_buffer = buffer->buffer;
......@@ -746,7 +995,10 @@ pipewire_output_repaint(struct weston_output *base)
pipewire_output_debug(output, "dequeued buffer: %p", buffer);
frame_data = buffer->user_data;
ec->renderer->repaint_output(&output->base, &damage, frame_data->renderbuffer);
if (frame_data->renderbuffer)
ec->renderer->repaint_output(&output->base, &damage, frame_data->renderbuffer);
else
output->base.full_repaint_needed = true;
pipewire_submit_buffer(output, buffer);
......
......@@ -62,6 +62,12 @@ weston_renderbuffer_unref(struct weston_renderbuffer *renderbuffer);
struct weston_renderer_options {
};
struct linux_dmabuf_memory {
struct dmabuf_attributes *attributes;
void (*destroy)(struct linux_dmabuf_memory *dmabuf);
};
struct weston_renderer {
int (*read_pixels)(struct weston_output *output,
const struct pixel_format_info *format, void *pixels,
......@@ -102,6 +108,60 @@ struct weston_renderer {
void (*buffer_init)(struct weston_compositor *ec,
struct weston_buffer *buffer);
/**
* Add DMABUF as renderbuffer to the output
*
* \param output The output to add the DMABUF renderbuffer for.
* \param dmabuf The description object of the DMABUF to import.
* \return A weston_renderbuffer on success, NULL on failure.
*
* This function imports the DMABUF memory as renderbuffer and adds
* it to the output. The returned weston_renderbuffer can be passed to
* repaint_output() to render into the DMABUF.
*
* The ownership of the linux_dmabuf_memory is transferred to the
* returned weston_renderbuffer. The linux_dmabuf_memory will be
* destroyed automatically when the weston_renderbuffer is destroyed.
*/
struct weston_renderbuffer *
(*create_renderbuffer_dmabuf)(struct weston_output *output,
struct linux_dmabuf_memory *dmabuf);
/**
* Remove the DAMBUF renderbuffer from the output
*
* \param output The output to remove a DMABUF renderbuffer from.
* \param renderbuffer The weston_renderbuffer that shall be removed
*
* This function removes the DMABUF renderbuffer from the output.
*
* This allows the backend to signal the renderer that it will no longer
* use the renderbuffer for rendering and the renderer may free the
* resources of the renderbuffer.
*/
void (*remove_renderbuffer_dmabuf)(struct weston_output *output,
struct weston_renderbuffer *renderbuffer);
/* Allocate a DMABUF that can be imported as renderbuffer
*
* \param renderer The renderer that allocated the DMABUF
* \param width The width of the allocated DMABUF
* \param height The height of the allocated DMABUF
* \param format The pixel format of the allocated DMABUF
* \param modifiers The suggested modifiers for the allocated DMABUF
* \param count The number of suggested modifiers for the allocated DMABUF
* \return A linux_dmabuf_memory object that may be imported as renderbuffer
*
* Request a DMABUF from the renderer. The returned DMABUF can be
* imported into the renderer as a renderbuffer and exported to other
* processes.
*/
struct linux_dmabuf_memory *
(*dmabuf_alloc)(struct weston_renderer *renderer,
unsigned int width, unsigned int height,
uint32_t format,
const uint64_t *modifiers, unsigned int count);
enum weston_renderer_type type;
const struct gl_renderer_interface *gl;
const struct pixman_renderer_interface *pixman;
......
......@@ -87,6 +87,8 @@ srcs_libweston = [
subdir('desktop')
subdir('shell-utils')
dep_gbm = dependency('gbm', required: false, version: '>= 21.1.1')
if get_option('backend-vnc')
dep_pam = dependency('pam', required: false)
if not dep_pam.found()
......
......@@ -113,6 +113,7 @@ static_assert(sizeof(struct gl_shader_requirements) ==
struct gl_shader;
struct weston_color_transform;
struct dmabuf_allocator;
#define GL_SHADER_INPUT_TEX_MAX 3
#define GL_SHADER_WIREFRAME_TEX_UNIT GL_SHADER_INPUT_TEX_MAX
......@@ -193,6 +194,7 @@ struct gl_renderer {
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d;
PFNGLTEXIMAGE3DOESPROC tex_image_3d;
PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC image_target_renderbuffer_storage;
PFNEGLCREATEIMAGEKHRPROC create_image;
PFNEGLDESTROYIMAGEKHRPROC destroy_image;
PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC swap_buffers_with_damage;
......@@ -275,6 +277,8 @@ struct gl_renderer {
*/
struct wl_list shader_list;
struct weston_log_scope *shader_scope;
struct dmabuf_allocator *allocator;
};
static inline struct gl_renderer *
......
This diff is collapsed.
......@@ -30,6 +30,7 @@ srcs_renderer_gl = [
]
deps_renderer_gl = [
dep_gbm,
dep_libm,
dep_pixman,
dep_libweston_private,
......