Use a dynamic buffer pool
parent
338ccec704
commit
5f492da3d1
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Andri Yngvason
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "buffer.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct buffer_pool;
|
||||
struct buffer;
|
||||
|
||||
struct buffer_pool* buffer_pool_create(enum buffer_type type, uint16_t width,
|
||||
uint16_t height, uint32_t format, uint16_t stride, int scale);
|
||||
void buffer_pool_destroy(struct buffer_pool* self);
|
||||
|
||||
bool buffer_pool_resize(struct buffer_pool* self, uint16_t width,
|
||||
uint16_t height, uint32_t format, uint16_t stride, int scale);
|
||||
|
||||
struct buffer* buffer_pool_acquire(struct buffer_pool* self);
|
||||
|
||||
void buffer_pool_damage_all(struct buffer_pool* self,
|
||||
struct pixman_region16* damage);
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Andri Yngvason
|
||||
* Copyright (c) 2022 - 2023 Andri Yngvason
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -16,6 +16,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "sys/queue.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
|
@ -31,6 +33,15 @@ enum buffer_type {
|
|||
};
|
||||
|
||||
struct buffer {
|
||||
int ref;
|
||||
int hold;
|
||||
|
||||
LIST_ENTRY(buffer) registry_link;
|
||||
TAILQ_ENTRY(buffer) pool_link;
|
||||
|
||||
void (*release_fn)(struct buffer*, void* ud);
|
||||
void* release_ud;
|
||||
|
||||
enum buffer_type type;
|
||||
|
||||
int width, height;
|
||||
|
@ -38,8 +49,6 @@ struct buffer {
|
|||
size_t size;
|
||||
uint32_t format;
|
||||
struct wl_buffer* wl_buffer;
|
||||
bool is_attached;
|
||||
bool please_clean_up;
|
||||
struct pixman_region16 damage;
|
||||
|
||||
// wl_shm:
|
||||
|
@ -53,3 +62,12 @@ struct buffer {
|
|||
struct buffer* buffer_create_shm(int width, int height, int stride, uint32_t format);
|
||||
struct buffer* buffer_create_dmabuf(int width, int height, uint32_t format);
|
||||
void buffer_destroy(struct buffer* self);
|
||||
|
||||
void buffer_ref(struct buffer*);
|
||||
void buffer_unref(struct buffer*);
|
||||
|
||||
void buffer_set_release_fn(struct buffer*, void (*)(struct buffer*, void* ud),
|
||||
void* userdata);
|
||||
|
||||
void buffer_hold(struct buffer*);
|
||||
void buffer_release(struct buffer*);
|
||||
|
|
|
@ -77,6 +77,7 @@ sources = [
|
|||
'src/renderer.c',
|
||||
'src/renderer-egl.c',
|
||||
'src/buffer.c',
|
||||
'src/buffer-pool.c',
|
||||
'src/open-h264.c',
|
||||
'src/cursor.c',
|
||||
'src/rfbproto.c',
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Andri Yngvason
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "buffer-pool.h"
|
||||
#include "buffer.h"
|
||||
|
||||
#include "sys/queue.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
LIST_HEAD(buffer_list, buffer);
|
||||
TAILQ_HEAD(bufferq, buffer);
|
||||
|
||||
struct buffer_pool {
|
||||
int ref;
|
||||
|
||||
struct buffer_list registry;
|
||||
struct bufferq buffers;
|
||||
|
||||
enum buffer_type type;
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
int32_t stride;
|
||||
uint32_t format;
|
||||
int scale;
|
||||
};
|
||||
|
||||
struct buffer_pool* buffer_pool_create(enum buffer_type type, uint16_t width,
|
||||
uint16_t height, uint32_t format, uint16_t stride, int scale)
|
||||
{
|
||||
struct buffer_pool* self = calloc(1, sizeof(*self));
|
||||
if (!self)
|
||||
return NULL;
|
||||
|
||||
self->ref = 1;
|
||||
|
||||
LIST_INIT(&self->registry);
|
||||
TAILQ_INIT(&self->buffers);
|
||||
self->type = type;
|
||||
self->width = width;
|
||||
self->height = height;
|
||||
self->stride = stride;
|
||||
self->format = format;
|
||||
self->scale = scale;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static void buffer_pool__unref_buffers(struct buffer_pool* self)
|
||||
{
|
||||
while (!LIST_EMPTY(&self->registry)) {
|
||||
struct buffer* buffer = LIST_FIRST(&self->registry);
|
||||
LIST_REMOVE(buffer, registry_link);
|
||||
buffer_set_release_fn(buffer, NULL, NULL);
|
||||
buffer_unref(buffer);
|
||||
}
|
||||
TAILQ_INIT(&self->buffers);
|
||||
}
|
||||
|
||||
void buffer_pool_destroy(struct buffer_pool* self)
|
||||
{
|
||||
buffer_pool__unref_buffers(self);
|
||||
free(self);
|
||||
}
|
||||
|
||||
bool buffer_pool_resize(struct buffer_pool* self, uint16_t width,
|
||||
uint16_t height, uint32_t format, uint16_t stride, int scale)
|
||||
{
|
||||
if (width == self->width && height == self->height &&
|
||||
format == self->format && stride == self->stride &&
|
||||
scale == self->scale)
|
||||
return false;
|
||||
|
||||
buffer_pool__unref_buffers(self);
|
||||
|
||||
self->width = width;
|
||||
self->height = height;
|
||||
self->stride = stride;
|
||||
self->format = format;
|
||||
self->scale = scale;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void buffer_pool__on_buffer_release(struct buffer* buffer, void* userdata)
|
||||
{
|
||||
struct buffer_pool* self = userdata;
|
||||
|
||||
if (buffer->width != self->width || buffer->height != self->height ||
|
||||
buffer->format != self->format ||
|
||||
(buffer->type == BUFFER_WL_SHM && buffer->stride != self->stride) ||
|
||||
buffer->scale != self->scale) {
|
||||
buffer_unref(buffer);
|
||||
} else {
|
||||
TAILQ_INSERT_TAIL(&self->buffers, buffer, pool_link);
|
||||
}
|
||||
}
|
||||
|
||||
static struct buffer* buffer_pool__acquire_new(struct buffer_pool* self)
|
||||
{
|
||||
struct buffer* buffer;
|
||||
switch (self->type) {
|
||||
case BUFFER_WL_SHM:
|
||||
buffer = buffer_create_shm(self->width, self->height,
|
||||
self->stride, self->format);
|
||||
break;
|
||||
case BUFFER_DMABUF:
|
||||
buffer = buffer_create_dmabuf(self->width, self->height,
|
||||
self->format);
|
||||
break;
|
||||
case BUFFER_UNSPEC:
|
||||
abort();
|
||||
}
|
||||
if (!buffer)
|
||||
return NULL;
|
||||
|
||||
buffer->scale = self->scale;
|
||||
|
||||
LIST_INSERT_HEAD(&self->registry, buffer, registry_link);
|
||||
buffer_set_release_fn(buffer, buffer_pool__on_buffer_release, self);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static struct buffer* buffer_pool__acquire_from_list(struct buffer_pool* self)
|
||||
{
|
||||
struct buffer* buffer = TAILQ_FIRST(&self->buffers);
|
||||
assert(buffer);
|
||||
|
||||
TAILQ_REMOVE(&self->buffers, buffer, pool_link);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
struct buffer* buffer_pool_acquire(struct buffer_pool* self)
|
||||
{
|
||||
return TAILQ_EMPTY(&self->buffers) ?
|
||||
buffer_pool__acquire_new(self) :
|
||||
buffer_pool__acquire_from_list(self);
|
||||
}
|
||||
|
||||
void buffer_pool_damage_all(struct buffer_pool* self,
|
||||
struct pixman_region16* damage)
|
||||
{
|
||||
struct buffer* buffer;
|
||||
LIST_FOREACH(buffer, &self->registry, registry_link) {
|
||||
pixman_region_union(&buffer->damage, damage, damage);
|
||||
}
|
||||
}
|
57
src/buffer.c
57
src/buffer.c
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Andri Yngvason
|
||||
* Copyright (c) 2022 - 2023 Andri Yngvason
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -25,24 +25,22 @@
|
|||
#include <gbm.h>
|
||||
#include <assert.h>
|
||||
|
||||
// TODO: Some buffers needn't be wayland buffers.
|
||||
|
||||
/* Origin: main.c */
|
||||
extern struct wl_shm* wl_shm;
|
||||
extern struct gbm_device* gbm_device;
|
||||
extern struct zwp_linux_dmabuf_v1* zwp_linux_dmabuf_v1;
|
||||
|
||||
static void buffer_release(void* data, struct wl_buffer* wl_buffer)
|
||||
static void buffer_wl_release(void* data, struct wl_buffer* wl_buffer)
|
||||
{
|
||||
(void)wl_buffer;
|
||||
struct buffer* self = data;
|
||||
self->is_attached = false;
|
||||
|
||||
if (self->please_clean_up) {
|
||||
buffer_destroy(self);
|
||||
}
|
||||
buffer_release(self);
|
||||
}
|
||||
|
||||
static const struct wl_buffer_listener buffer_listener = {
|
||||
.release = buffer_release,
|
||||
.release = buffer_wl_release,
|
||||
};
|
||||
|
||||
struct buffer* buffer_create_shm(int width, int height, int stride,
|
||||
|
@ -54,6 +52,7 @@ struct buffer* buffer_create_shm(int width, int height, int stride,
|
|||
if (!self)
|
||||
return NULL;
|
||||
|
||||
self->ref = 1;
|
||||
self->type = BUFFER_WL_SHM;
|
||||
self->width = width;
|
||||
self->height = height;
|
||||
|
@ -106,6 +105,7 @@ struct buffer* buffer_create_dmabuf(int width, int height, uint32_t format)
|
|||
if (!self)
|
||||
return NULL;
|
||||
|
||||
self->ref = 1;
|
||||
self->type = BUFFER_DMABUF;
|
||||
self->width = width;
|
||||
self->height = height;
|
||||
|
@ -159,9 +159,6 @@ void buffer_destroy(struct buffer* self)
|
|||
if (!self)
|
||||
return;
|
||||
|
||||
if (self->is_attached)
|
||||
self->please_clean_up = true;
|
||||
|
||||
pixman_region_fini(&self->damage);
|
||||
wl_buffer_destroy(self->wl_buffer);
|
||||
|
||||
|
@ -179,3 +176,41 @@ void buffer_destroy(struct buffer* self)
|
|||
|
||||
free(self);
|
||||
}
|
||||
|
||||
void buffer_ref(struct buffer* self)
|
||||
{
|
||||
++self->ref;
|
||||
}
|
||||
|
||||
void buffer_unref(struct buffer* self)
|
||||
{
|
||||
if (self && --self->ref == 0)
|
||||
buffer_destroy(self);
|
||||
}
|
||||
|
||||
void buffer_set_release_fn(struct buffer* self,
|
||||
void (*fn)(struct buffer*, void* ud), void* userdata)
|
||||
{
|
||||
self->release_fn = fn;
|
||||
self->release_ud = userdata;
|
||||
}
|
||||
|
||||
void buffer_hold(struct buffer* self)
|
||||
{
|
||||
assert(self);
|
||||
++self->hold;
|
||||
}
|
||||
|
||||
void buffer_release(struct buffer* self)
|
||||
{
|
||||
assert(self);
|
||||
|
||||
int hold = --self->hold;
|
||||
if (hold != 0)
|
||||
return;
|
||||
|
||||
if (self->release_fn)
|
||||
self->release_fn(self, self->release_ud);
|
||||
else
|
||||
buffer_unref(self);
|
||||
}
|
||||
|
|
54
src/main.c
54
src/main.c
|
@ -42,6 +42,7 @@
|
|||
#include "pixels.h"
|
||||
#include "region.h"
|
||||
#include "buffer.h"
|
||||
#include "buffer-pool.h"
|
||||
#include "renderer.h"
|
||||
#include "renderer-egl.h"
|
||||
#include "linux-dmabuf-unstable-v1.h"
|
||||
|
@ -63,9 +64,8 @@ struct window {
|
|||
struct xdg_surface* xdg_surface;
|
||||
struct xdg_toplevel* xdg_toplevel;
|
||||
|
||||
struct buffer* buffers[3];
|
||||
struct buffer_pool* buffers;
|
||||
struct buffer* back_buffer;
|
||||
int buffer_index;
|
||||
|
||||
struct pixman_region16 current_damage;
|
||||
|
||||
|
@ -243,8 +243,10 @@ void on_wayland_event(void* obj)
|
|||
}
|
||||
}
|
||||
|
||||
if (wl_display_dispatch_pending(wl_display) < 0)
|
||||
if (wl_display_dispatch_pending(wl_display) < 0) {
|
||||
fprintf(stderr, "Failed to dispatch pending\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static int init_wayland_event_handler(void)
|
||||
|
@ -279,7 +281,7 @@ static int init_signal_handler(void)
|
|||
|
||||
static void window_attach(struct window* w, int x, int y)
|
||||
{
|
||||
w->back_buffer->is_attached = true;
|
||||
buffer_hold(w->back_buffer);
|
||||
wl_surface_attach(w->wl_surface, w->back_buffer->wl_buffer, x, y);
|
||||
wl_surface_set_buffer_scale(window->wl_surface,
|
||||
window->back_buffer->scale);
|
||||
|
@ -370,8 +372,9 @@ static void window_commit(struct window* w)
|
|||
|
||||
static void window_swap(struct window* w)
|
||||
{
|
||||
w->buffer_index = (w->buffer_index + 1) % 3;
|
||||
w->back_buffer = w->buffers[w->buffer_index];
|
||||
buffer_unref(w->back_buffer);
|
||||
w->back_buffer = buffer_pool_acquire(w->buffers);
|
||||
buffer_ref(w->back_buffer);
|
||||
}
|
||||
|
||||
static void window_damage(struct window* w, int x, int y, int width, int height)
|
||||
|
@ -401,24 +404,19 @@ static void window_resize(struct window* w, int width, int height, int scale)
|
|||
if (width == 0 || height == 0 || scale == 0)
|
||||
return;
|
||||
|
||||
if (w->back_buffer && w->back_buffer->width == width &&
|
||||
w->back_buffer->height == height &&
|
||||
w->back_buffer->scale == scale)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < 3; ++i)
|
||||
buffer_destroy(w->buffers[i]);
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
w->buffers[i] = have_egl
|
||||
? buffer_create_dmabuf(scale * width, scale * height,
|
||||
dmabuf_format)
|
||||
: buffer_create_shm(scale * width, scale * height,
|
||||
scale * 4 * width, shm_format);
|
||||
w->buffers[i]->scale = scale;
|
||||
uint32_t format = have_egl ? dmabuf_format : shm_format;
|
||||
if (!w->buffers) {
|
||||
enum buffer_type type = have_egl ? BUFFER_DMABUF : BUFFER_WL_SHM;
|
||||
w->buffers = buffer_pool_create(type, scale * width,
|
||||
scale * height, format, scale * 4 * width,
|
||||
scale);
|
||||
} else {
|
||||
buffer_pool_resize(w->buffers, scale * width, scale * height,
|
||||
format, scale * 4 * width, scale);
|
||||
}
|
||||
|
||||
w->back_buffer = w->buffers[0];
|
||||
w->back_buffer = buffer_pool_acquire(w->buffers);
|
||||
buffer_ref(w->back_buffer);
|
||||
}
|
||||
|
||||
static void xdg_toplevel_configure(void* data, struct xdg_toplevel* toplevel,
|
||||
|
@ -479,9 +477,8 @@ wl_surface_failure:
|
|||
|
||||
static void window_destroy(struct window* w)
|
||||
{
|
||||
for (int i = 0; i < 3; ++i)
|
||||
buffer_destroy(w->buffers[i]);
|
||||
|
||||
buffer_unref(w->back_buffer);
|
||||
buffer_pool_destroy(w->buffers);
|
||||
free(w->vnc_fb);
|
||||
xdg_toplevel_destroy(w->xdg_toplevel);
|
||||
xdg_surface_destroy(w->xdg_surface);
|
||||
|
@ -592,9 +589,7 @@ static void get_frame_damage(struct vnc_client* client,
|
|||
|
||||
static void apply_buffer_damage(struct pixman_region16* damage)
|
||||
{
|
||||
for (int i = 0; i < 3; ++i)
|
||||
pixman_region_union(&window->buffers[i]->damage,
|
||||
&window->buffers[i]->damage, damage);
|
||||
buffer_pool_damage_all(window->buffers, damage);
|
||||
}
|
||||
|
||||
static void window_damage_region(struct window* w,
|
||||
|
@ -636,9 +631,6 @@ static void render_from_vnc(void)
|
|||
if (window->is_frame_committed)
|
||||
return;
|
||||
|
||||
if (window->back_buffer->is_attached)
|
||||
fprintf(stderr, "Oops, back-buffer is still attached.\n");
|
||||
|
||||
window_attach(window, 0, 0);
|
||||
|
||||
double scale;
|
||||
|
|
Loading…
Reference in New Issue