neatvnc/src/fb_pool.c

180 lines
4.0 KiB
C

/*
* 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 <stdlib.h>
#include <assert.h>
#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;
int32_t stride;
uint32_t fourcc_format;
nvnc_fb_alloc_fn alloc_fn;
};
EXPORT
struct nvnc_fb_pool* nvnc_fb_pool_new(uint16_t width, uint16_t height,
uint32_t fourcc_format, uint16_t stride)
{
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->stride = stride;
self->fourcc_format = fourcc_format;
self->alloc_fn = nvnc_fb_new;
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);
free(item);
}
}
static void nvnc_fb_pool__destroy(struct nvnc_fb_pool* self)
{
nvnc_fb_pool__destroy_fbs(self);
free(self);
}
EXPORT
bool nvnc_fb_pool_resize(struct nvnc_fb_pool* self, uint16_t width,
uint16_t height, uint32_t fourcc_format, uint16_t stride)
{
if (width == self->width && height == self->height &&
fourcc_format == self->fourcc_format &&
stride == self->stride)
return false;
nvnc_fb_pool__destroy_fbs(self);
self->width = width;
self->height = height;
self->stride = stride;
self->fourcc_format = fourcc_format;
return true;
}
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 = self->alloc_fn(self->width, self->height,
self->fourcc_format, self->stride);
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);
nvnc_fb_pool_ref(self);
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 ||
fb->stride != self->stride) {
return;
}
nvnc_fb_ref(fb);
struct fbq_item* item = calloc(1, sizeof(*item));
assert(item);
item->fb = fb;
TAILQ_INSERT_TAIL(&self->fbs, item, link);
}
EXPORT
void nvnc_fb_pool_set_alloc_fn(struct nvnc_fb_pool* self, nvnc_fb_alloc_fn fn)
{
self->alloc_fn = fn;
}