qemu-usb/webcam: cache large allocation of libyuv

This commit is contained in:
Alexander Boettcher 2023-09-15 15:13:00 +02:00 committed by Christian Helmuth
parent 0d868515a5
commit 264160797d

View File

@ -10,15 +10,18 @@
*/
#include <base/allocator.h>
#include <base/attached_ram_dataspace.h>
#include <base/env.h>
#include <capture_session/connection.h>
#include <gui_session/gui_session.h>
#include <os/reporter.h>
#include <util/xml_node.h>
#include <libyuv/libyuv.h>
#include <libyuv/convert_from_argb.h>
extern "C" {
#include <stdlib.h>
#include "webcam-backend.h"
void _type_init_usb_webcam_register_types();
@ -33,10 +36,12 @@ struct Capture_webcam
Gui::Area const _area;
bool const _vflip;
uint8_t const _fps;
bool _force_update { false };
bool _force_update { false };
bool _libyuv_alloc_in_use { false };
Constructible<Capture::Connection> _capture;
Constructible<Attached_dataspace> _ds;
Constructible<Capture::Connection> _capture;
Constructible<Attached_dataspace> _ds;
Constructible<Attached_ram_dataspace> _libyuv_ds;
Gui::Area _setup_area(Gui::Area const area_in, bool const auto_area)
{
@ -130,9 +135,55 @@ struct Capture_webcam
} else {
_ds.destruct();
_capture.destruct();
if (_libyuv_ds.constructed())
libyuv_free(_libyuv_ds->local_addr<void>());
}
}
void * libyuv_alloc(unsigned long const size)
{
if (!size)
return nullptr;
/* heuristic: cache only libyuv::ARGBToYUY2 YUV image allocation */
if (size < _area.count() * 2)
return nullptr;
if (_libyuv_alloc_in_use) {
Genode::error(__func__, " cached libyuv ds already in use");
return nullptr;
}
if (_libyuv_ds.constructed() && _libyuv_ds->size() != size)
_libyuv_ds.destruct();
if (!_libyuv_ds.constructed() || _libyuv_ds->size() != size)
_libyuv_ds.construct(_env.pd(), _env.rm(), size);
_libyuv_alloc_in_use = true;
return _libyuv_ds->local_addr<void>();
}
bool libyuv_free(void *ptr)
{
if (!ptr)
return false;
if (!_libyuv_ds.constructed())
return false;
if (ptr != _libyuv_ds->local_addr<void>())
return false;
_libyuv_alloc_in_use = false;
return true;
}
Capture_webcam(Env &env, Gui::Area area, bool auto_area, bool flip, uint8_t fps)
:
_env(env),
@ -170,6 +221,24 @@ extern "C" void webcam_backend_config(struct webcam_config *config)
config->height = capture->_area.h();
}
static void *malloc_libyuv(unsigned long size)
{
void * ptr = capture->libyuv_alloc(size);
return ptr ? ptr : malloc(size);
}
static void free_libyuv(void *ptr)
{
bool freed = capture->libyuv_free(ptr);
if (!freed)
free(ptr);
}
/*
* Do not use type_init macro because of name mangling
*/
@ -185,4 +254,7 @@ extern "C" void _type_init_host_webcam_register_types(Env &env,
/* register webcam model, which will call webcam_backend_config() */
_type_init_usb_webcam_register_types();
/* install own memory allocators for libyuv to apply dataspace caching */
libyuv::libyuv_init(malloc_libyuv, free_libyuv);
}