diff --git a/include/neatvnc.h b/include/neatvnc.h index 92e2d79..0824e90 100644 --- a/include/neatvnc.h +++ b/include/neatvnc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 - 2020 Andri Yngvason + * Copyright (c) 2019 - 2021 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 @@ -23,6 +23,7 @@ struct nvnc; struct nvnc_client; struct nvnc_display; struct nvnc_fb; +struct nvnc_fb_pool; struct pixman_region16; enum nvnc_button_mask { @@ -96,6 +97,17 @@ uint16_t nvnc_fb_get_width(const struct nvnc_fb* fb); uint16_t nvnc_fb_get_height(const struct nvnc_fb* fb); uint32_t nvnc_fb_get_fourcc_format(const struct nvnc_fb* fb); +struct nvnc_fb_pool* nvnc_fb_pool_new(uint16_t width, uint16_t height, + uint32_t fourcc_format); +void nvnc_fb_pool_resize(struct nvnc_fb_pool*, uint16_t width, uint16_t height, + uint32_t fourcc_format); + +void nvnc_fb_pool_ref(struct nvnc_fb_pool*); +void nvnc_fb_pool_unref(struct nvnc_fb_pool*); + +struct nvnc_fb* nvnc_fb_pool_acquire(struct nvnc_fb_pool*); +void nvnc_fb_pool_release(struct nvnc_fb_pool*, struct nvnc_fb*); + struct nvnc_display* nvnc_display_new(uint16_t x_pos, uint16_t y_pos); void nvnc_display_ref(struct nvnc_display*); void nvnc_display_unref(struct nvnc_display*); diff --git a/meson.build b/meson.build index 9964892..d846d4d 100644 --- a/meson.build +++ b/meson.build @@ -66,6 +66,7 @@ sources = [ 'src/pixels.c', 'src/damage.c', 'src/fb.c', + 'src/fb_pool.c', 'src/rcbuf.c', 'src/stream.c', 'src/display.c', diff --git a/src/fb_pool.c b/src/fb_pool.c new file mode 100644 index 0000000..1f86e01 --- /dev/null +++ b/src/fb_pool.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2021 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 "fb.h" +#include "neatvnc.h" + +#include "sys/queue.h" + +#include +#include + +#define EXPORT __attribute__((visibility("default"))) + +struct fbq_item { + struct nvnc_fb* fb; + TAILQ_ENTRY(fbq_item) link; +}; + +TAILQ_HEAD(fbq, fbq_item); + +struct nvnc_fb_pool { + int ref; + + struct fbq fbs; + + uint16_t width; + uint16_t height; + uint32_t fourcc_format; +}; + +EXPORT +struct nvnc_fb_pool* nvnc_fb_pool_new(uint16_t width, uint16_t height, + uint32_t fourcc_format) +{ + struct nvnc_fb_pool* self = calloc(1, sizeof(*self)); + if (!self) + return NULL; + + self->ref = 1; + + TAILQ_INIT(&self->fbs); + self->width = width; + self->height = height; + self->fourcc_format = fourcc_format; + + return self; +} + +static void nvnc_fb_pool__destroy_fbs(struct nvnc_fb_pool* self) +{ + while (!TAILQ_EMPTY(&self->fbs)) { + struct fbq_item* item = TAILQ_FIRST(&self->fbs); + TAILQ_REMOVE(&self->fbs, item, link); + nvnc_fb_unref(item->fb); + } +} + +static void nvnc_fb_pool__destroy(struct nvnc_fb_pool* self) +{ + nvnc_fb_pool__destroy_fbs(self); + free(self); +} + +EXPORT +void nvnc_fb_pool_resize(struct nvnc_fb_pool* self, uint16_t width, + uint16_t height, uint32_t fourcc_format) +{ + if (width == self->width && height == self->height && + fourcc_format == self->fourcc_format) + return; + + nvnc_fb_pool__destroy_fbs(self); + + self->width = width; + self->height = height; + self->fourcc_format = fourcc_format; +} + +EXPORT +void nvnc_fb_pool_ref(struct nvnc_fb_pool* self) +{ + self->ref++; +} + +EXPORT +void nvnc_fb_pool_unref(struct nvnc_fb_pool* self) +{ + if (--self->ref == 0) + nvnc_fb_pool__destroy(self); +} + +static void nvnc_fb_pool__on_fb_release(struct nvnc_fb* fb, void* userdata) +{ + struct nvnc_fb_pool* pool = userdata; + + nvnc_fb_pool_release(pool, fb); + nvnc_fb_pool_unref(pool); +} + +static struct nvnc_fb* nvnc_fb_pool__acquire_new(struct nvnc_fb_pool* self) +{ + struct nvnc_fb* fb = nvnc_fb_new(self->width, self->height, + self->fourcc_format); + if (!fb) + return NULL; + + nvnc_fb_set_release_fn(fb, nvnc_fb_pool__on_fb_release, self); + nvnc_fb_pool_ref(self); + + return fb; +} + +static struct nvnc_fb* nvnc_fb_pool__acquire_from_list(struct nvnc_fb_pool* self) +{ + struct fbq_item* item = TAILQ_FIRST(&self->fbs); + struct nvnc_fb* fb = item->fb; + assert(item && fb); + + TAILQ_REMOVE(&self->fbs, item, link); + free(item); + + return fb; +} + +EXPORT +struct nvnc_fb* nvnc_fb_pool_acquire(struct nvnc_fb_pool* self) +{ + return TAILQ_EMPTY(&self->fbs) ? + nvnc_fb_pool__acquire_new(self) : + nvnc_fb_pool__acquire_from_list(self); +} + +EXPORT +void nvnc_fb_pool_release(struct nvnc_fb_pool* self, struct nvnc_fb* fb) +{ + if (fb->width != self->width || fb->height != self->height || + fb->fourcc_format != self->fourcc_format) { + nvnc_fb_unref(fb); + return; + } + + struct fbq_item* item = calloc(1, sizeof(*item)); + assert(item); + item->fb = fb; + TAILQ_INSERT_TAIL(&self->fbs, item, link); +}