pixman-renderer: add weston_renderbuffer and create/destroy interface

Add a create_image_from_ptr vfunc to struct pixman_renderer_interface,
which wraps weston_renderbuffer creation for the pixman renderer via
pixman_image_create_bits(), as well as a renderbuffer_destroy vfunc
to dispose of the pixman image renderbuffer.
Also add create_image_no_clear using pixman_image_create_bits_no_clear()
instead.

Make the backends create and destroy their pixman image renderbuffers
through this interface.

Signed-off-by: Philipp Zabel <philipp.zabel@gmail.com>
This commit is contained in:
Philipp Zabel 2023-01-11 21:53:43 +01:00 committed by Daniel Stone
parent 32c7629516
commit 89e1831cd7
11 changed files with 183 additions and 69 deletions

View file

@ -593,7 +593,7 @@ struct drm_output {
struct drm_output_state *state_last;
struct drm_fb *dumb[2];
pixman_image_t *image[2];
struct weston_renderbuffer *renderbuffer[2];
int current_image;
pixman_region32_t previous_damage;

View file

@ -344,7 +344,7 @@ drm_output_render_pixman(struct drm_output_state *state,
output->current_image ^= 1;
pixman_renderer_output_set_buffer(&output->base,
output->image[output->current_image]);
output->renderbuffer[output->current_image]->image);
pixman_renderer_output_set_hw_extra_damage(&output->base,
&output->previous_damage);
@ -1180,6 +1180,7 @@ static int
drm_output_init_pixman(struct drm_output *output, struct drm_backend *b)
{
struct weston_renderer *renderer = output->base.compositor->renderer;
const struct pixman_renderer_interface *pixman = renderer->pixman;
struct drm_device *device = output->device;
int w = output->base.current_mode->width;
int h = output->base.current_mode->height;
@ -1209,15 +1210,16 @@ drm_output_init_pixman(struct drm_output *output, struct drm_backend *b)
if (!output->dumb[i])
goto err;
output->image[i] =
pixman_image_create_bits(pixman_format, w, h,
output->dumb[i]->map,
output->dumb[i]->strides[0]);
if (!output->image[i])
output->renderbuffer[i] =
pixman->create_image_from_ptr(&output->base,
pixman_format, w, h,
output->dumb[i]->map,
output->dumb[i]->strides[0]);
if (!output->renderbuffer[i])
goto err;
}
if (renderer->pixman->output_create(&output->base, &options) < 0)
if (pixman->output_create(&output->base, &options) < 0)
goto err;
weston_log("DRM: output %s %s shadow framebuffer.\n", output->base.name,
@ -1232,11 +1234,11 @@ err:
for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
if (output->dumb[i])
drm_fb_unref(output->dumb[i]);
if (output->image[i])
pixman_image_unref(output->image[i]);
if (output->renderbuffer[i])
pixman->renderbuffer_destroy(output->renderbuffer[i]);
output->dumb[i] = NULL;
output->image[i] = NULL;
output->renderbuffer[i] = NULL;
}
return -1;
@ -1261,10 +1263,10 @@ drm_output_fini_pixman(struct drm_output *output)
pixman_region32_fini(&output->previous_damage);
for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
pixman_image_unref(output->image[i]);
renderer->pixman->renderbuffer_destroy(output->renderbuffer[i]);
drm_fb_unref(output->dumb[i]);
output->dumb[i] = NULL;
output->image[i] = NULL;
output->renderbuffer[i] = NULL;
}
}

View file

@ -70,7 +70,7 @@ struct headless_output {
struct weston_mode mode;
struct wl_event_source *finish_frame_timer;
pixman_image_t *image;
struct weston_renderbuffer *renderbuffer;
struct frame *frame;
struct {
@ -191,7 +191,7 @@ headless_output_disable_pixman(struct headless_output *output)
struct weston_renderer *renderer = output->base.compositor->renderer;
renderer->pixman->output_destroy(&output->base);
pixman_image_unref(output->image);
renderer->pixman->renderbuffer_destroy(output->renderbuffer);
}
static int
@ -304,23 +304,24 @@ headless_output_enable_pixman(struct headless_output *output)
pixman = output->base.compositor->renderer->pixman;
pfmt = pixel_format_get_info(headless_formats[0]);
output->image =
pixman_image_create_bits_no_clear(pfmt->pixman_format,
output->base.current_mode->width,
output->base.current_mode->height,
NULL, 0);
if (!output->image)
output->renderbuffer =
pixman->create_image_no_clear(&output->base,
pfmt->pixman_format,
output->base.current_mode->width,
output->base.current_mode->height);
if (!output->renderbuffer)
return -1;
if (pixman->output_create(&output->base, &options) < 0)
goto err_renderer;
pixman_renderer_output_set_buffer(&output->base, output->image);
pixman_renderer_output_set_buffer(&output->base,
output->renderbuffer->image);
return 0;
err_renderer:
pixman_image_unref(output->image);
pixman->renderbuffer_destroy(output->renderbuffer);
return -1;
}

View file

@ -249,11 +249,11 @@ rdp_peer_refresh_region(pixman_region32_t *region, freerdp_peer *peer)
rdpSettings *settings = peer->context->settings;
if (settings->RemoteFxCodec)
rdp_peer_refresh_rfx(region, output->shadow_surface, peer);
rdp_peer_refresh_rfx(region, output->renderbuffer->image, peer);
else if (settings->NSCodec)
rdp_peer_refresh_nsc(region, output->shadow_surface, peer);
rdp_peer_refresh_nsc(region, output->renderbuffer->image, peer);
else
rdp_peer_refresh_raw(region, output->shadow_surface, peer);
rdp_peer_refresh_raw(region, output->renderbuffer->image, peer);
}
static int
@ -295,7 +295,8 @@ rdp_output_repaint(struct weston_output *output_base, pixman_region32_t *damage)
assert(output);
pixman_renderer_output_set_buffer(output_base, output->shadow_surface);
pixman_renderer_output_set_buffer(output_base,
output->renderbuffer->image);
ec->renderer->repaint_output(&output->base, damage);
if (pixman_region32_not_empty(damage)) {
@ -391,7 +392,7 @@ rdp_output_set_mode(struct weston_output *base, struct weston_mode *mode)
struct weston_output *output = base;
struct rdp_peers_item *rdpPeer;
rdpSettings *settings;
pixman_image_t *new_shadow_buffer;
struct weston_renderbuffer *new_renderbuffer;
mode->refresh = b->rdp_monitor_refresh_rate;
cur = ensure_single_mode(base, mode);
@ -399,16 +400,24 @@ rdp_output_set_mode(struct weston_output *base, struct weston_mode *mode)
base->current_mode = cur;
base->native_mode = cur;
if (base->enabled) {
const struct pixman_renderer_interface *pixman;
weston_renderer_resize_output(output, &(struct weston_size){
.width = output->current_mode->width,
.height = output->current_mode->height }, NULL);
new_shadow_buffer = pixman_image_create_bits(PIXMAN_x8r8g8b8, mode->width,
mode->height, 0, mode->width * 4);
pixman_image_composite32(PIXMAN_OP_SRC, rdpOutput->shadow_surface, 0, new_shadow_buffer,
0, 0, 0, 0, 0, 0, mode->width, mode->height);
pixman_image_unref(rdpOutput->shadow_surface);
rdpOutput->shadow_surface = new_shadow_buffer;
pixman = b->compositor->renderer->pixman;
new_renderbuffer =
pixman->create_image_from_ptr(output, PIXMAN_x8r8g8b8,
mode->width, mode->height,
0, mode->width * 4);
pixman_image_composite32(PIXMAN_OP_SRC,
rdpOutput->renderbuffer->image, 0,
new_renderbuffer->image,
0, 0, 0, 0, 0, 0,
mode->width, mode->height);
pixman->renderbuffer_destroy(rdpOutput->renderbuffer);
rdpOutput->renderbuffer = new_renderbuffer;
}
/* Apparently settings->DesktopWidth is supposed to be primary only.
@ -457,7 +466,8 @@ rdp_head_get_monitor(struct weston_head *base,
static int
rdp_output_enable(struct weston_output *base)
{
struct weston_renderer *renderer = base->compositor->renderer;
const struct weston_renderer *renderer = base->compositor->renderer;
const struct pixman_renderer_interface *pixman = renderer->pixman;
struct rdp_output *output = to_rdp_output(base);
struct rdp_backend *b;
struct wl_event_loop *loop;
@ -472,18 +482,19 @@ rdp_output_enable(struct weston_output *base)
b = output->backend;
output->shadow_surface = pixman_image_create_bits(PIXMAN_x8r8g8b8,
output->base.current_mode->width,
output->base.current_mode->height,
NULL,
output->base.current_mode->width * 4);
if (output->shadow_surface == NULL) {
output->renderbuffer =
pixman->create_image_from_ptr(&output->base, PIXMAN_x8r8g8b8,
output->base.current_mode->width,
output->base.current_mode->height,
NULL,
output->base.current_mode->width * 4);
if (output->renderbuffer == NULL) {
weston_log("Failed to create surface for frame buffer.\n");
return -1;
}
if (renderer->pixman->output_create(&output->base, &options) < 0) {
pixman_image_unref(output->shadow_surface);
renderer->pixman->renderbuffer_destroy(output->renderbuffer);
return -1;
}
@ -504,7 +515,7 @@ rdp_output_disable(struct weston_output *base)
if (!output->base.enabled)
return 0;
pixman_image_unref(output->shadow_surface);
renderer->pixman->renderbuffer_destroy(output->renderbuffer);
renderer->pixman->output_destroy(&output->base);
wl_event_source_remove(output->finish_frame_timer);

View file

@ -125,7 +125,7 @@ struct rdp_output {
struct weston_output base;
struct rdp_backend *backend;
struct wl_event_source *finish_frame_timer;
pixman_image_t *shadow_surface;
struct weston_renderbuffer *renderbuffer;
};
struct rdp_peer_context {

View file

@ -99,7 +99,8 @@ struct vnc_head {
};
struct fb_side_data {
pixman_image_t *pixman_image;
struct weston_renderer *renderer;
struct weston_renderbuffer *renderbuffer;
pixman_region32_t damage;
struct wl_list link;
};
@ -447,10 +448,11 @@ static void
fb_side_data_destroy(void *userdata)
{
struct fb_side_data *fb_side_data = userdata;
struct weston_renderer *renderer = fb_side_data->renderer;
wl_list_remove(&fb_side_data->link);
pixman_region32_fini(&fb_side_data->damage);
pixman_image_unref(fb_side_data->pixman_image);
renderer->pixman->renderbuffer_destroy(fb_side_data->renderbuffer);
free(fb_side_data);
}
@ -501,17 +503,21 @@ vnc_update_buffer(struct nvnc_display *display, struct pixman_region32 *damage)
fb_side_data = nvnc_get_userdata(fb);
if (!fb_side_data) {
const struct pixman_renderer_interface *pixman;
const struct pixel_format_info *pfmt;
fb_side_data = xzalloc(sizeof(*fb_side_data));
pixman = ec->renderer->pixman;
pfmt = pixel_format_get_info(DRM_FORMAT_XRGB8888);
fb_side_data->pixman_image =
pixman_image_create_bits(pfmt->pixman_format,
output->base.width,
output->base.height,
nvnc_fb_get_addr(fb),
output->base.width * 4);
fb_side_data->renderer = ec->renderer;
fb_side_data->renderbuffer =
pixman->create_image_from_ptr(&output->base,
pfmt->pixman_format,
output->base.width,
output->base.height,
nvnc_fb_get_addr(fb),
output->base.width * 4);
/* This is a new buffer, so the whole surface is damaged. */
pixman_region32_copy(&fb_side_data->damage,
@ -522,7 +528,7 @@ vnc_update_buffer(struct nvnc_display *display, struct pixman_region32 *damage)
}
pixman_renderer_output_set_buffer(&output->base,
fb_side_data->pixman_image);
fb_side_data->renderbuffer->image);
ec->renderer->repaint_output(&output->base, &fb_side_data->damage);

View file

@ -182,6 +182,7 @@ struct wayland_shm_buffer {
pixman_region32_t damage; /**< in global coords */
int frame_damaged;
struct weston_renderbuffer *renderbuffer;
pixman_image_t *pm_image;
cairo_surface_t *c_surface;
};
@ -257,7 +258,14 @@ static void
wayland_shm_buffer_destroy(struct wayland_shm_buffer *buffer)
{
cairo_surface_destroy(buffer->c_surface);
pixman_image_unref(buffer->pm_image);
if (buffer->pm_image)
pixman_image_unref(buffer->pm_image);
if (buffer->output) {
const struct pixman_renderer_interface *pixman;
pixman = buffer->output->base.compositor->renderer->pixman;
pixman->renderbuffer_destroy(buffer->renderbuffer);
}
wl_buffer_destroy(buffer->buffer);
munmap(buffer->data, buffer->size);
@ -288,6 +296,8 @@ static const struct wl_buffer_listener buffer_listener = {
static struct wayland_shm_buffer *
wayland_output_get_shm_buffer(struct wayland_output *output)
{
const struct weston_renderer *renderer;
const struct pixman_renderer_interface *pixman;
struct wayland_backend *b = output->backend;
struct wl_shm *shm = b->parent.shm;
struct wayland_shm_buffer *sb;
@ -380,11 +390,23 @@ wayland_output_get_shm_buffer(struct wayland_output *output)
area.height = output->base.current_mode->height;
}
renderer = b->compositor->renderer;
pixman = renderer->pixman;
/* Address only the interior, excluding output decorations */
sb->pm_image =
pixman_image_create_bits(PIXMAN_a8r8g8b8, area.width, area.height,
(uint32_t *)(data + area.y * stride) + area.x,
stride);
if (renderer->type == WESTON_RENDERER_PIXMAN) {
sb->renderbuffer =
pixman->create_image_from_ptr(&output->base, PIXMAN_a8r8g8b8,
area.width, area.height,
(uint32_t *)(data + area.y * stride) + area.x,
stride);
} else {
sb->pm_image =
pixman_image_create_bits(PIXMAN_a8r8g8b8,
area.width, area.height,
(uint32_t *)(data + area.y * stride) + area.x,
stride);
}
return sb;
}
@ -608,7 +630,7 @@ wayland_output_repaint_pixman(struct weston_output *output_base,
sb = wayland_output_get_shm_buffer(output);
wayland_output_update_shm_border(sb);
pixman_renderer_output_set_buffer(output_base, sb->pm_image);
pixman_renderer_output_set_buffer(output_base, sb->renderbuffer->image);
b->compositor->renderer->repaint_output(output_base, &sb->damage);
wayland_shm_buffer_attach(sb);

View file

@ -136,7 +136,7 @@ struct x11_output {
xcb_gc_t gc;
xcb_shm_seg_t segment;
pixman_image_t *hw_surface;
struct weston_renderbuffer *renderbuffer;
int shm_id;
void *buf;
uint8_t depth;
@ -501,6 +501,7 @@ x11_output_repaint_shm(struct weston_output *output_base,
pixman_region32_t *damage)
{
struct x11_output *output = to_x11_output(output_base);
pixman_image_t *image = output->renderbuffer->image;
struct weston_compositor *ec;
struct x11_backend *b;
xcb_void_cookie_t cookie;
@ -511,18 +512,18 @@ x11_output_repaint_shm(struct weston_output *output_base,
ec = output->base.compositor;
b = output->backend;
pixman_renderer_output_set_buffer(output_base, output->hw_surface);
pixman_renderer_output_set_buffer(output_base, image);
ec->renderer->repaint_output(output_base, damage);
pixman_region32_subtract(&ec->primary_plane.damage,
&ec->primary_plane.damage, damage);
set_clip_for_output(output_base, damage);
cookie = xcb_shm_put_image_checked(b->conn, output->window, output->gc,
pixman_image_get_width(output->hw_surface),
pixman_image_get_height(output->hw_surface),
pixman_image_get_width(image),
pixman_image_get_height(image),
0, 0,
pixman_image_get_width(output->hw_surface),
pixman_image_get_height(output->hw_surface),
pixman_image_get_width(image),
pixman_image_get_height(image),
0, 0, output->depth, XCB_IMAGE_FORMAT_Z_PIXMAP,
0, output->segment, 0);
err = xcb_request_check(b->conn, cookie);
@ -550,12 +551,13 @@ finish_frame_handler(void *data)
static void
x11_output_deinit_shm(struct x11_backend *b, struct x11_output *output)
{
const struct weston_renderer *renderer = b->compositor->renderer;
xcb_void_cookie_t cookie;
xcb_generic_error_t *err;
xcb_free_gc(b->conn, output->gc);
pixman_image_unref(output->hw_surface);
output->hw_surface = NULL;
renderer->pixman->renderbuffer_destroy(output->renderbuffer);
output->renderbuffer = NULL;
cookie = xcb_shm_detach_checked(b->conn, output->segment);
err = xcb_request_check(b->conn, cookie);
if (err) {
@ -719,6 +721,7 @@ static int
x11_output_init_shm(struct x11_backend *b, struct x11_output *output,
int width, int height)
{
struct weston_renderer *renderer = output->base.compositor->renderer;
xcb_visualtype_t *visual_type;
xcb_screen_t *screen;
xcb_format_iterator_t fmt;
@ -806,8 +809,11 @@ x11_output_init_shm(struct x11_backend *b, struct x11_output *output,
shmctl(output->shm_id, IPC_RMID, NULL);
/* Now create pixman image */
output->hw_surface = pixman_image_create_bits(pixman_format, width, height, output->buf,
width * (bitsperpixel / 8));
output->renderbuffer =
renderer->pixman->create_image_from_ptr(&output->base,
pixman_format, width,
height, output->buf,
width * (bitsperpixel / 8));
output->gc = xcb_generate_id(b->conn);
xcb_create_gc(b->conn, output->gc, output->window, 0, NULL);

View file

@ -46,6 +46,10 @@
/* compositor <-> renderer interface */
struct weston_renderbuffer {
pixman_image_t *image;
};
struct weston_renderer_options {
};

View file

@ -1110,7 +1110,56 @@ pixman_renderer_output_destroy(struct weston_output *output)
free(po);
}
static struct weston_renderbuffer *
pixman_renderer_create_image_from_ptr(struct weston_output *output,
pixman_format_code_t format, int width,
int height, uint32_t *ptr, int rowstride)
{
struct weston_renderbuffer *renderbuffer;
renderbuffer = xzalloc(sizeof(*renderbuffer));
renderbuffer->image = pixman_image_create_bits(format, width, height,
ptr, rowstride);
if (!renderbuffer->image) {
free(renderbuffer);
return NULL;
}
return renderbuffer;
}
static struct weston_renderbuffer *
pixman_renderer_create_image_no_clear(struct weston_output *output,
pixman_format_code_t format, int width,
int height)
{
struct weston_renderbuffer *renderbuffer;
renderbuffer = xzalloc(sizeof(*renderbuffer));
renderbuffer->image =
pixman_image_create_bits_no_clear(format, width, height,
NULL, 0);
if (!renderbuffer->image) {
free(renderbuffer);
return NULL;
}
return renderbuffer;
}
static void
pixman_renderer_renderbuffer_destroy(struct weston_renderbuffer *renderbuffer)
{
pixman_image_unref(renderbuffer->image);
free(renderbuffer);
}
static struct pixman_renderer_interface pixman_renderer_interface = {
.output_create = pixman_renderer_output_create,
.output_destroy = pixman_renderer_output_destroy,
.create_image_from_ptr = pixman_renderer_create_image_from_ptr,
.create_image_no_clear = pixman_renderer_create_image_no_clear,
.renderbuffer_destroy = pixman_renderer_renderbuffer_destroy,
};

View file

@ -28,6 +28,7 @@
#include <libweston/libweston.h>
#include "backend.h"
#include "libweston-internal.h"
#include "pixman.h"
int
pixman_renderer_init(struct weston_compositor *ec);
@ -51,4 +52,16 @@ struct pixman_renderer_interface {
int (*output_create)(struct weston_output *output,
const struct pixman_renderer_output_options *options);
void (*output_destroy)(struct weston_output *output);
struct weston_renderbuffer *(*create_image_from_ptr)(struct weston_output *output,
pixman_format_code_t format,
int width,
int height,
uint32_t *ptr,
int stride);
struct weston_renderbuffer *(*create_image_no_clear)(struct weston_output *output,
pixman_format_code_t format,
int width,
int height);
void (*renderbuffer_destroy)(struct weston_renderbuffer *renderbuffer);
};