mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
imlib: Refactor framebuffer API to accept a context.
Updated all framebuffer functions to take a framebuffer_t argument. Signed-off-by: iabdalkader <i.abdalkader@gmail.com>
This commit is contained in:
parent
ab39043bf9
commit
c122c9dfc2
@ -33,27 +33,216 @@
|
|||||||
#define FB_ALIGN_SIZE_ROUND_UP(x) FB_ALIGN_SIZE_ROUND_DOWN(((x) + FRAMEBUFFER_ALIGNMENT - 1))
|
#define FB_ALIGN_SIZE_ROUND_UP(x) FB_ALIGN_SIZE_ROUND_DOWN(((x) + FRAMEBUFFER_ALIGNMENT - 1))
|
||||||
#define OMV_JPEG_BUFFER_SIZE_MAX ((&_jpeg_memory_end - &_jpeg_memory_start) - sizeof(jpegbuffer_t))
|
#define OMV_JPEG_BUFFER_SIZE_MAX ((&_jpeg_memory_end - &_jpeg_memory_start) - sizeof(jpegbuffer_t))
|
||||||
|
|
||||||
extern char _fb_memory_start;
|
extern char _fb_memory_start[];
|
||||||
extern char _fb_memory_end;
|
extern char _fb_memory_end[];
|
||||||
framebuffer_t *framebuffer = (framebuffer_t *) &_fb_memory_start;
|
static framebuffer_t *framebuffer = (framebuffer_t *) &_fb_memory_start;
|
||||||
|
|
||||||
extern char _jpeg_memory_start;
|
extern char _jpeg_memory_start;
|
||||||
extern char _jpeg_memory_end;
|
extern char _jpeg_memory_end;
|
||||||
jpegbuffer_t *jpeg_framebuffer = (jpegbuffer_t *) &_jpeg_memory_start;
|
jpegbuffer_t *jpegbuffer = (jpegbuffer_t *) &_jpeg_memory_start;
|
||||||
|
|
||||||
void fb_set_streaming_enabled(bool enable) {
|
void framebuffer_init0() {
|
||||||
framebuffer->streaming_enabled = enable;
|
// Save fb_enabled flag state
|
||||||
|
int fb_enabled = jpegbuffer->enabled;
|
||||||
|
|
||||||
|
// Clear framebuffers
|
||||||
|
memset(framebuffer, 0, sizeof(*framebuffer));
|
||||||
|
memset(jpegbuffer, 0, sizeof(*jpegbuffer));
|
||||||
|
|
||||||
|
mutex_init0(&jpegbuffer->lock);
|
||||||
|
|
||||||
|
// Enable streaming.
|
||||||
|
framebuffer->streaming_enabled = true; // controlled by the OpenMV Cam.
|
||||||
|
|
||||||
|
// Set default quality
|
||||||
|
jpegbuffer->quality = ((OMV_JPEG_QUALITY_HIGH - OMV_JPEG_QUALITY_LOW) / 2) + OMV_JPEG_QUALITY_LOW;
|
||||||
|
|
||||||
|
// Set fb_enabled
|
||||||
|
jpegbuffer->enabled = fb_enabled; // controlled by the IDE.
|
||||||
|
|
||||||
|
// Setup buffering.
|
||||||
|
framebuffer_set_buffers(framebuffer, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fb_get_streaming_enabled() {
|
void framebuffer_init_image(framebuffer_t *fb, image_t *img) {
|
||||||
return framebuffer->streaming_enabled;
|
if (img != NULL) {
|
||||||
|
img->w = fb->w;
|
||||||
|
img->h = fb->h;
|
||||||
|
img->size = fb->size;
|
||||||
|
img->pixfmt = fb->pixfmt;
|
||||||
|
img->pixels = framebuffer_get_buffer(fb, fb->head)->data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int fb_encode_for_ide_new_size(image_t *img) {
|
void framebuffer_init_from_image(framebuffer_t *fb, image_t *img) {
|
||||||
return (((img->size * 8) + 5) / 6) + 2;
|
fb->w = img->w;
|
||||||
|
fb->h = img->h;
|
||||||
|
fb->size = img->size;
|
||||||
|
fb->pixfmt = img->pixfmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fb_encode_for_ide(uint8_t *ptr, image_t *img) {
|
static void jpegbuffer_init_from_image(framebuffer_t *fb, image_t *img) {
|
||||||
|
if (img == NULL) {
|
||||||
|
jpegbuffer->w = 0;
|
||||||
|
jpegbuffer->h = 0;
|
||||||
|
jpegbuffer->size = 0;
|
||||||
|
} else {
|
||||||
|
jpegbuffer->w = img->w;
|
||||||
|
jpegbuffer->h = img->h;
|
||||||
|
jpegbuffer->size = img->size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void framebuffer_update_jpeg_buffer(framebuffer_t *fb) {
|
||||||
|
static int overflow_count = 0;
|
||||||
|
|
||||||
|
image_t main_fb_src;
|
||||||
|
framebuffer_init_image(fb, &main_fb_src);
|
||||||
|
image_t *src = &main_fb_src;
|
||||||
|
|
||||||
|
if (src->pixfmt != PIXFORMAT_INVALID &&
|
||||||
|
fb->streaming_enabled && jpegbuffer->enabled) {
|
||||||
|
if (src->is_compressed) {
|
||||||
|
bool does_not_fit = false;
|
||||||
|
|
||||||
|
if (mutex_try_lock_alternate(&jpegbuffer->lock, MUTEX_TID_OMV)) {
|
||||||
|
if (OMV_JPEG_BUFFER_SIZE_MAX < src->size) {
|
||||||
|
jpegbuffer_init_from_image(fb, NULL);
|
||||||
|
does_not_fit = true;
|
||||||
|
} else {
|
||||||
|
jpegbuffer_init_from_image(fb, src);
|
||||||
|
memcpy(jpegbuffer->pixels, src->pixels, src->size);
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&jpegbuffer->lock, MUTEX_TID_OMV);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (does_not_fit) {
|
||||||
|
printf("Warning: JPEG/PNG too big! Trying framebuffer transfer using fallback method!\n");
|
||||||
|
int new_size = framebuffer_encoded_size(fb, src);
|
||||||
|
fb_alloc_mark();
|
||||||
|
uint8_t *temp = fb_alloc(new_size, FB_ALLOC_NO_HINT);
|
||||||
|
framebuffer_encode(fb, temp, src);
|
||||||
|
(MP_PYTHON_PRINTER)->print_strn((MP_PYTHON_PRINTER)->data, (const char *) temp, new_size);
|
||||||
|
fb_alloc_free_till_mark();
|
||||||
|
}
|
||||||
|
} else if (src->pixfmt != PIXFORMAT_INVALID) {
|
||||||
|
if (mutex_try_lock_alternate(&jpegbuffer->lock, MUTEX_TID_OMV)) {
|
||||||
|
image_t dst = {
|
||||||
|
.w = src->w,
|
||||||
|
.h = src->h,
|
||||||
|
.pixfmt = PIXFORMAT_JPEG,
|
||||||
|
.size = OMV_JPEG_BUFFER_SIZE_MAX,
|
||||||
|
.pixels = jpegbuffer->pixels
|
||||||
|
};
|
||||||
|
|
||||||
|
bool compress = true;
|
||||||
|
bool overflow = false;
|
||||||
|
|
||||||
|
#if OMV_RAW_PREVIEW_ENABLE
|
||||||
|
if (src->is_mutable) {
|
||||||
|
// Down-scale the frame (if necessary) and send the raw frame.
|
||||||
|
dst.size = src->bpp;
|
||||||
|
dst.pixfmt = src->pixfmt;
|
||||||
|
if (src->w <= OMV_RAW_PREVIEW_WIDTH && src->h <= OMV_RAW_PREVIEW_HEIGHT) {
|
||||||
|
if (image_size(&dst) <= OMV_JPEG_BUFFER_SIZE_MAX) {
|
||||||
|
memcpy(dst.pixels, src->pixels, image_size(src));
|
||||||
|
compress = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
float x_scale = OMV_RAW_PREVIEW_WIDTH / (float) src->w;
|
||||||
|
float y_scale = OMV_RAW_PREVIEW_HEIGHT / (float) src->h;
|
||||||
|
float scale = IM_MIN(x_scale, y_scale);
|
||||||
|
dst.w = fast_floorf(src->w * scale);
|
||||||
|
dst.h = fast_floorf(src->h * scale);
|
||||||
|
if (image_size(&dst) <= OMV_JPEG_BUFFER_SIZE_MAX) {
|
||||||
|
imlib_draw_image(&dst, src, 0, 0, scale, scale, NULL, -1, 255, NULL, NULL,
|
||||||
|
IMAGE_HINT_BILINEAR | IMAGE_HINT_BLACK_BACKGROUND, NULL, NULL, NULL);
|
||||||
|
compress = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (compress) {
|
||||||
|
// For all other formats, send a compressed frame.
|
||||||
|
overflow = jpeg_compress(src, &dst, jpegbuffer->quality, false, JPEG_SUBSAMPLING_AUTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (overflow) {
|
||||||
|
// JPEG buffer overflowed, reduce JPEG quality for the next frame
|
||||||
|
// and skip the current frame. The IDE doesn't receive this frame.
|
||||||
|
if (jpegbuffer->quality > 1) {
|
||||||
|
// Keep this quality for the next n frames
|
||||||
|
overflow_count = 60;
|
||||||
|
jpegbuffer->quality = IM_MAX(1, (jpegbuffer->quality / 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
jpegbuffer_init_from_image(fb, NULL);
|
||||||
|
} else {
|
||||||
|
if (overflow_count) {
|
||||||
|
overflow_count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dynamically adjust our quality if the image is huge.
|
||||||
|
bool big_frame_buffer = image_size(src) > OMV_JPEG_QUALITY_THRESHOLD;
|
||||||
|
int jpeg_quality_max = big_frame_buffer ? OMV_JPEG_QUALITY_LOW : OMV_JPEG_QUALITY_HIGH;
|
||||||
|
|
||||||
|
// No buffer overflow, increase quality up to max quality based on frame size...
|
||||||
|
if ((!overflow_count) && (jpegbuffer->quality < jpeg_quality_max)) {
|
||||||
|
jpegbuffer->quality++;
|
||||||
|
}
|
||||||
|
|
||||||
|
jpegbuffer_init_from_image(fb, &dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&jpegbuffer->lock, MUTEX_TID_OMV);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
framebuffer_t *framebuffer_get(size_t id) {
|
||||||
|
return framebuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t framebuffer_get_x(framebuffer_t *fb) {
|
||||||
|
return fb->x;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t framebuffer_get_y(framebuffer_t *fb) {
|
||||||
|
return fb->y;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t framebuffer_get_u(framebuffer_t *fb) {
|
||||||
|
return fb->u;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t framebuffer_get_v(framebuffer_t *fb) {
|
||||||
|
return fb->v;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t framebuffer_get_width(framebuffer_t *fb) {
|
||||||
|
return fb->w;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t framebuffer_get_height(framebuffer_t *fb) {
|
||||||
|
return fb->h;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t framebuffer_get_depth(framebuffer_t *fb) {
|
||||||
|
return fb->bpp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void framebuffer_set_streaming(framebuffer_t *fb, bool enable) {
|
||||||
|
fb->streaming_enabled = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool framebuffer_get_streaming(framebuffer_t *fb) {
|
||||||
|
return fb->streaming_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void framebuffer_encode(framebuffer_t *fb, uint8_t *ptr, image_t *img) {
|
||||||
*ptr++ = 0xFE;
|
*ptr++ = 0xFE;
|
||||||
|
|
||||||
for (int i = 0, j = (img->size / 3) * 3; i < j; i += 3) {
|
for (int i = 0, j = (img->size / 3) * 3; i < j; i += 3) {
|
||||||
@ -88,211 +277,26 @@ void fb_encode_for_ide(uint8_t *ptr, image_t *img) {
|
|||||||
*ptr++ = 0xFE;
|
*ptr++ = 0xFE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void framebuffer_init0() {
|
int framebuffer_encoded_size(framebuffer_t *fb, image_t *img) {
|
||||||
// Save fb_enabled flag state
|
return (((img->size * 8) + 5) / 6) + 2;
|
||||||
int fb_enabled = JPEG_FB()->enabled;
|
|
||||||
|
|
||||||
// Clear framebuffers
|
|
||||||
memset(MAIN_FB(), 0, sizeof(*MAIN_FB()));
|
|
||||||
memset(JPEG_FB(), 0, sizeof(*JPEG_FB()));
|
|
||||||
|
|
||||||
mutex_init0(&JPEG_FB()->lock);
|
|
||||||
|
|
||||||
// Enable streaming.
|
|
||||||
MAIN_FB()->streaming_enabled = true; // controlled by the OpenMV Cam.
|
|
||||||
|
|
||||||
// Set default quality
|
|
||||||
JPEG_FB()->quality = ((OMV_JPEG_QUALITY_HIGH - OMV_JPEG_QUALITY_LOW) / 2) + OMV_JPEG_QUALITY_LOW;
|
|
||||||
|
|
||||||
// Set fb_enabled
|
|
||||||
JPEG_FB()->enabled = fb_enabled; // controlled by the IDE.
|
|
||||||
|
|
||||||
// Setup buffering.
|
|
||||||
framebuffer_set_buffers(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void framebuffer_init_image(image_t *img) {
|
|
||||||
if (img != NULL) {
|
|
||||||
img->w = framebuffer->w;
|
|
||||||
img->h = framebuffer->h;
|
|
||||||
img->size = framebuffer->size;
|
|
||||||
img->pixfmt = framebuffer->pixfmt;
|
|
||||||
img->pixels = framebuffer_get_buffer(framebuffer->head)->data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void framebuffer_init_from_image(image_t *img) {
|
|
||||||
framebuffer->w = img->w;
|
|
||||||
framebuffer->h = img->h;
|
|
||||||
framebuffer->size = img->size;
|
|
||||||
framebuffer->pixfmt = img->pixfmt;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void jpegbuffer_init_from_image(image_t *img) {
|
|
||||||
if (img == NULL) {
|
|
||||||
jpeg_framebuffer->w = 0;
|
|
||||||
jpeg_framebuffer->h = 0;
|
|
||||||
jpeg_framebuffer->size = 0;
|
|
||||||
} else {
|
|
||||||
jpeg_framebuffer->w = img->w;
|
|
||||||
jpeg_framebuffer->h = img->h;
|
|
||||||
jpeg_framebuffer->size = img->size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void framebuffer_update_jpeg_buffer() {
|
|
||||||
static int overflow_count = 0;
|
|
||||||
|
|
||||||
image_t main_fb_src;
|
|
||||||
framebuffer_init_image(&main_fb_src);
|
|
||||||
image_t *src = &main_fb_src;
|
|
||||||
|
|
||||||
if (src->pixfmt != PIXFORMAT_INVALID &&
|
|
||||||
framebuffer->streaming_enabled && jpeg_framebuffer->enabled) {
|
|
||||||
if (src->is_compressed) {
|
|
||||||
bool does_not_fit = false;
|
|
||||||
|
|
||||||
if (mutex_try_lock_alternate(&jpeg_framebuffer->lock, MUTEX_TID_OMV)) {
|
|
||||||
if (OMV_JPEG_BUFFER_SIZE_MAX < src->size) {
|
|
||||||
jpegbuffer_init_from_image(NULL);
|
|
||||||
does_not_fit = true;
|
|
||||||
} else {
|
|
||||||
jpegbuffer_init_from_image(src);
|
|
||||||
memcpy(jpeg_framebuffer->pixels, src->pixels, src->size);
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_unlock(&jpeg_framebuffer->lock, MUTEX_TID_OMV);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (does_not_fit) {
|
|
||||||
printf("Warning: JPEG/PNG too big! Trying framebuffer transfer using fallback method!\n");
|
|
||||||
int new_size = fb_encode_for_ide_new_size(src);
|
|
||||||
fb_alloc_mark();
|
|
||||||
uint8_t *temp = fb_alloc(new_size, FB_ALLOC_NO_HINT);
|
|
||||||
fb_encode_for_ide(temp, src);
|
|
||||||
(MP_PYTHON_PRINTER)->print_strn((MP_PYTHON_PRINTER)->data, (const char *) temp, new_size);
|
|
||||||
fb_alloc_free_till_mark();
|
|
||||||
}
|
|
||||||
} else if (src->pixfmt != PIXFORMAT_INVALID) {
|
|
||||||
if (mutex_try_lock_alternate(&jpeg_framebuffer->lock, MUTEX_TID_OMV)) {
|
|
||||||
image_t dst = {
|
|
||||||
.w = src->w,
|
|
||||||
.h = src->h,
|
|
||||||
.pixfmt = PIXFORMAT_JPEG,
|
|
||||||
.size = OMV_JPEG_BUFFER_SIZE_MAX,
|
|
||||||
.pixels = jpeg_framebuffer->pixels
|
|
||||||
};
|
|
||||||
|
|
||||||
bool compress = true;
|
|
||||||
bool overflow = false;
|
|
||||||
|
|
||||||
#if OMV_RAW_PREVIEW_ENABLE
|
|
||||||
if (src->is_mutable) {
|
|
||||||
// Down-scale the frame (if necessary) and send the raw frame.
|
|
||||||
dst.size = src->bpp;
|
|
||||||
dst.pixfmt = src->pixfmt;
|
|
||||||
if (src->w <= OMV_RAW_PREVIEW_WIDTH && src->h <= OMV_RAW_PREVIEW_HEIGHT) {
|
|
||||||
if (image_size(&dst) <= OMV_JPEG_BUFFER_SIZE_MAX) {
|
|
||||||
memcpy(dst.pixels, src->pixels, image_size(src));
|
|
||||||
compress = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
float x_scale = OMV_RAW_PREVIEW_WIDTH / (float) src->w;
|
|
||||||
float y_scale = OMV_RAW_PREVIEW_HEIGHT / (float) src->h;
|
|
||||||
float scale = IM_MIN(x_scale, y_scale);
|
|
||||||
dst.w = fast_floorf(src->w * scale);
|
|
||||||
dst.h = fast_floorf(src->h * scale);
|
|
||||||
if (image_size(&dst) <= OMV_JPEG_BUFFER_SIZE_MAX) {
|
|
||||||
imlib_draw_image(&dst, src, 0, 0, scale, scale, NULL, -1, 255, NULL, NULL,
|
|
||||||
IMAGE_HINT_BILINEAR | IMAGE_HINT_BLACK_BACKGROUND, NULL, NULL, NULL);
|
|
||||||
compress = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (compress) {
|
|
||||||
// For all other formats, send a compressed frame.
|
|
||||||
overflow = jpeg_compress(src, &dst, jpeg_framebuffer->quality, false, JPEG_SUBSAMPLING_AUTO);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (overflow) {
|
|
||||||
// JPEG buffer overflowed, reduce JPEG quality for the next frame
|
|
||||||
// and skip the current frame. The IDE doesn't receive this frame.
|
|
||||||
if (jpeg_framebuffer->quality > 1) {
|
|
||||||
// Keep this quality for the next n frames
|
|
||||||
overflow_count = 60;
|
|
||||||
jpeg_framebuffer->quality = IM_MAX(1, (jpeg_framebuffer->quality / 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
jpegbuffer_init_from_image(NULL);
|
|
||||||
} else {
|
|
||||||
if (overflow_count) {
|
|
||||||
overflow_count--;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dynamically adjust our quality if the image is huge.
|
|
||||||
bool big_frame_buffer = image_size(src) > OMV_JPEG_QUALITY_THRESHOLD;
|
|
||||||
int jpeg_quality_max = big_frame_buffer ? OMV_JPEG_QUALITY_LOW : OMV_JPEG_QUALITY_HIGH;
|
|
||||||
|
|
||||||
// No buffer overflow, increase quality up to max quality based on frame size...
|
|
||||||
if ((!overflow_count) && (jpeg_framebuffer->quality < jpeg_quality_max)) {
|
|
||||||
jpeg_framebuffer->quality++;
|
|
||||||
}
|
|
||||||
|
|
||||||
jpegbuffer_init_from_image(&dst);
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_unlock(&jpeg_framebuffer->lock, MUTEX_TID_OMV);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t framebuffer_get_x() {
|
|
||||||
return framebuffer->x;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t framebuffer_get_y() {
|
|
||||||
return framebuffer->y;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t framebuffer_get_u() {
|
|
||||||
return framebuffer->u;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t framebuffer_get_v() {
|
|
||||||
return framebuffer->v;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t framebuffer_get_width() {
|
|
||||||
return framebuffer->w;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t framebuffer_get_height() {
|
|
||||||
return framebuffer->h;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t framebuffer_get_depth() {
|
|
||||||
return framebuffer->bpp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the current frame buffer size, factoring in the space taken by fb_alloc.
|
// Returns the current frame buffer size, factoring in the space taken by fb_alloc.
|
||||||
static uint32_t framebuffer_max_buffer_size() {
|
static uint32_t framebuffer_max_buffer_size(framebuffer_t *fb) {
|
||||||
uint32_t fb_total_size = FB_ALIGN_SIZE_ROUND_DOWN(&_fb_memory_end - (char *) framebuffer->data);
|
uint32_t fb_total_size = FB_ALIGN_SIZE_ROUND_DOWN((char *) &_fb_memory_end - (char *) fb->data);
|
||||||
uint32_t fb_avail_size = FB_ALIGN_SIZE_ROUND_DOWN(fb_alloc_stack_pointer() - (char *) framebuffer->data);
|
uint32_t fb_avail_size = FB_ALIGN_SIZE_ROUND_DOWN(fb_alloc_stack_pointer() - (char *) fb->data);
|
||||||
return IM_MIN(fb_total_size, fb_avail_size);
|
return IM_MIN(fb_total_size, fb_avail_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t framebuffer_get_buffer_size() {
|
uint32_t framebuffer_get_buffer_size(framebuffer_t *fb) {
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
|
|
||||||
if (framebuffer->n_buffers == 1) {
|
if (fb->n_buffers == 1) {
|
||||||
// With only 1 vbuffer the frame buffer size can change given fb_alloc().
|
// With only 1 vbuffer the frame buffer size can change given fb_alloc().
|
||||||
size = framebuffer_max_buffer_size();
|
size = framebuffer_max_buffer_size(fb);
|
||||||
} else {
|
} else {
|
||||||
// Whatever the raw size was when the number of buffers were set is locked in.
|
// Whatever the raw size was when the number of buffers were set is locked in.
|
||||||
size = framebuffer->buff_size;
|
size = fb->buff_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the size of the state header plus alignment padding.
|
// Remove the size of the state header plus alignment padding.
|
||||||
@ -304,28 +308,29 @@ uint32_t framebuffer_get_buffer_size() {
|
|||||||
|
|
||||||
// Each raw frame buffer is split into two parts. The vbuffer_t struct followed by
|
// Each raw frame buffer is split into two parts. The vbuffer_t struct followed by
|
||||||
// padding and then the pixel array starting at the next 32-byte offset.
|
// padding and then the pixel array starting at the next 32-byte offset.
|
||||||
vbuffer_t *framebuffer_get_buffer(int32_t index) {
|
vbuffer_t *framebuffer_get_buffer(framebuffer_t *fb, int32_t index) {
|
||||||
uint32_t offset = (sizeof(vbuffer_t) + framebuffer_get_buffer_size()) * index;
|
uint32_t fbsize = framebuffer_get_buffer_size(fb);
|
||||||
return (vbuffer_t *) (framebuffer->data + offset);
|
uint32_t offset = (sizeof(vbuffer_t) + fbsize) * index;
|
||||||
|
return (vbuffer_t *) (fb->data + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void framebuffer_flush_buffers(bool fifo_flush) {
|
void framebuffer_flush_buffers(framebuffer_t *fb, bool fifo_flush) {
|
||||||
if (fifo_flush) {
|
if (fifo_flush) {
|
||||||
// Drop all frame buffers.
|
// Drop all frame buffers.
|
||||||
for (uint32_t i = 0; i < framebuffer->n_buffers; i++) {
|
for (uint32_t i = 0; i < fb->n_buffers; i++) {
|
||||||
memset(framebuffer_get_buffer(i), 0, sizeof(vbuffer_t));
|
memset(framebuffer_get_buffer(fb, i), 0, sizeof(vbuffer_t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Move the tail pointer to the head which empties the virtual fifo while keeping the same
|
// Move the tail pointer to the head which empties the virtual fifo while keeping the same
|
||||||
// position of the current frame for the rest of the code.
|
// position of the current frame for the rest of the code.
|
||||||
framebuffer->tail = framebuffer->head;
|
fb->tail = fb->head;
|
||||||
framebuffer->check_head = true;
|
fb->check_head = true;
|
||||||
framebuffer->sampled_head = 0;
|
fb->sampled_head = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int framebuffer_set_buffers(int32_t n_buffers) {
|
int framebuffer_set_buffers(framebuffer_t *fb, int32_t n_buffers) {
|
||||||
uint32_t avail_size = FB_ALIGN_SIZE_ROUND_DOWN(framebuffer_max_buffer_size());
|
uint32_t avail_size = FB_ALIGN_SIZE_ROUND_DOWN(framebuffer_max_buffer_size(fb));
|
||||||
uint32_t frame_size = FB_ALIGN_SIZE_ROUND_UP(framebuffer->frame_size + sizeof(vbuffer_t));
|
uint32_t frame_size = FB_ALIGN_SIZE_ROUND_UP(fb->frame_size + sizeof(vbuffer_t));
|
||||||
uint32_t vbuff_size = (n_buffers == 1) ? avail_size : frame_size;
|
uint32_t vbuff_size = (n_buffers == 1) ? avail_size : frame_size;
|
||||||
uint32_t vbuff_count = IM_MIN((avail_size / vbuff_size), (n_buffers == -1) ? 3 : (uint32_t) n_buffers);
|
uint32_t vbuff_count = IM_MIN((avail_size / vbuff_size), (n_buffers == -1) ? 3 : (uint32_t) n_buffers);
|
||||||
|
|
||||||
@ -333,141 +338,142 @@ int framebuffer_set_buffers(int32_t n_buffers) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
framebuffer->head = 0;
|
fb->head = 0;
|
||||||
framebuffer->buff_size = vbuff_size;
|
fb->buff_size = vbuff_size;
|
||||||
framebuffer->n_buffers = vbuff_count;
|
fb->n_buffers = vbuff_count;
|
||||||
framebuffer->pixfmt = PIXFORMAT_INVALID;
|
fb->pixfmt = PIXFORMAT_INVALID;
|
||||||
|
|
||||||
framebuffer_flush_buffers(true);
|
framebuffer_flush_buffers(fb, true);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the real size of bytes in the frame buffer.
|
// Returns the real size of bytes in the frame buffer.
|
||||||
static uint32_t framebuffer_total_buffer_size() {
|
static uint32_t framebuffer_total_buffer_size(framebuffer_t *fb) {
|
||||||
if (framebuffer->n_buffers == 1) {
|
if (fb->n_buffers == 1) {
|
||||||
// Allow fb_alloc to use frame buffer space up until the image size.
|
// Allow fb_alloc to use frame buffer space up until the image size.
|
||||||
image_t img;
|
image_t img;
|
||||||
framebuffer_init_image(&img);
|
framebuffer_init_image(fb, &img);
|
||||||
return sizeof(vbuffer_t) + FB_ALIGN_SIZE_ROUND_UP(image_size(&img));
|
return sizeof(vbuffer_t) + FB_ALIGN_SIZE_ROUND_UP(image_size(&img));
|
||||||
} else {
|
} else {
|
||||||
// fb_alloc may only use up to the size of all the virtual buffers...
|
// fb_alloc may only use up to the size of all the virtual buffers.
|
||||||
return (sizeof(vbuffer_t) + framebuffer_get_buffer_size()) * framebuffer->n_buffers;
|
uint32_t fbsize = framebuffer_get_buffer_size(fb);
|
||||||
|
return (sizeof(vbuffer_t) + fbsize) * fb->n_buffers;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void framebuffer_free_current_buffer() {
|
void framebuffer_free_current_buffer(framebuffer_t *fb) {
|
||||||
vbuffer_t *buffer = framebuffer_get_buffer(framebuffer->head);
|
vbuffer_t *buffer = framebuffer_get_buffer(fb, fb->head);
|
||||||
|
|
||||||
#ifdef __DCACHE_PRESENT
|
#ifdef __DCACHE_PRESENT
|
||||||
// Make sure all cached CPU writes are discarded before returning the buffer.
|
// Make sure all cached CPU writes are discarded before returning the buffer.
|
||||||
SCB_InvalidateDCache_by_Addr(buffer->data, framebuffer_get_buffer_size());
|
SCB_InvalidateDCache_by_Addr(buffer->data, framebuffer_get_buffer_size(fb));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Invalidate frame.
|
// Invalidate frame.
|
||||||
framebuffer->pixfmt = PIXFORMAT_INVALID;
|
fb->pixfmt = PIXFORMAT_INVALID;
|
||||||
|
|
||||||
// Allow frame to be updated in single buffer mode...
|
// Allow frame to be updated in single buffer mode...
|
||||||
if (framebuffer->n_buffers == 1) {
|
if (fb->n_buffers == 1) {
|
||||||
buffer->waiting_for_data = true;
|
buffer->waiting_for_data = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void framebuffer_setup_buffers() {
|
void framebuffer_setup_buffers(framebuffer_t *fb) {
|
||||||
#ifdef __DCACHE_PRESENT
|
#ifdef __DCACHE_PRESENT
|
||||||
for (int32_t i = 0; i < framebuffer->n_buffers; i++) {
|
for (int32_t i = 0; i < fb->n_buffers; i++) {
|
||||||
if (i != framebuffer->head) {
|
if (i != fb->head) {
|
||||||
vbuffer_t *buffer = framebuffer_get_buffer(i);
|
vbuffer_t *buffer = framebuffer_get_buffer(fb, i);
|
||||||
// Make sure all cached CPU writes are discarded before returning the buffer.
|
// Make sure all cached CPU writes are discarded before returning the buffer.
|
||||||
SCB_InvalidateDCache_by_Addr(buffer->data, framebuffer_get_buffer_size());
|
SCB_InvalidateDCache_by_Addr(buffer->data, framebuffer_get_buffer_size(fb));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
vbuffer_t *framebuffer_get_head(framebuffer_flags_t flags) {
|
vbuffer_t *framebuffer_get_head(framebuffer_t *fb, framebuffer_flags_t flags) {
|
||||||
int32_t new_head = (framebuffer->head + 1) % framebuffer->n_buffers;
|
int32_t new_head = (fb->head + 1) % fb->n_buffers;
|
||||||
|
|
||||||
// Single Buffer Mode.
|
// Single Buffer Mode.
|
||||||
if (framebuffer->n_buffers == 1) {
|
if (fb->n_buffers == 1) {
|
||||||
if (framebuffer_get_buffer(framebuffer->head)->waiting_for_data) {
|
if (framebuffer_get_buffer(fb, fb->head)->waiting_for_data) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
// Double Buffer Mode.
|
// Double Buffer Mode.
|
||||||
} else if (framebuffer->n_buffers == 2) {
|
} else if (fb->n_buffers == 2) {
|
||||||
if (framebuffer->head == framebuffer->tail) {
|
if (fb->head == fb->tail) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
// Triple Buffer Mode.
|
// Triple Buffer Mode.
|
||||||
} else if (framebuffer->n_buffers == 3) {
|
} else if (fb->n_buffers == 3) {
|
||||||
int32_t sampled_tail = framebuffer->tail;
|
int32_t sampled_tail = fb->tail;
|
||||||
if (framebuffer->head == sampled_tail) {
|
if (fb->head == sampled_tail) {
|
||||||
return NULL;
|
return NULL;
|
||||||
} else {
|
} else {
|
||||||
new_head = sampled_tail;
|
new_head = sampled_tail;
|
||||||
}
|
}
|
||||||
// Video FIFO Mode.
|
// Video FIFO Mode.
|
||||||
} else {
|
} else {
|
||||||
if (framebuffer->head == framebuffer->tail) {
|
if (fb->head == fb->tail) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(flags & FB_PEEK)) {
|
if (!(flags & FB_PEEK)) {
|
||||||
framebuffer->head = new_head;
|
fb->head = new_head;
|
||||||
}
|
}
|
||||||
|
|
||||||
vbuffer_t *buffer = framebuffer_get_buffer(new_head);
|
vbuffer_t *buffer = framebuffer_get_buffer(fb, new_head);
|
||||||
|
|
||||||
#ifdef __DCACHE_PRESENT
|
#ifdef __DCACHE_PRESENT
|
||||||
if (flags & FB_INVALIDATE) {
|
if (flags & FB_INVALIDATE) {
|
||||||
// Make sure any cached CPU reads are dropped before returning the buffer.
|
// Make sure any cached CPU reads are dropped before returning the buffer.
|
||||||
SCB_InvalidateDCache_by_Addr(buffer->data, framebuffer_get_buffer_size());
|
SCB_InvalidateDCache_by_Addr(buffer->data, framebuffer_get_buffer_size(fb));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
vbuffer_t *framebuffer_get_tail(framebuffer_flags_t flags) {
|
vbuffer_t *framebuffer_get_tail(framebuffer_t *fb, framebuffer_flags_t flags) {
|
||||||
// Sample head on the first line of a new frame.
|
// Sample head on the first line of a new frame.
|
||||||
if (framebuffer->check_head) {
|
if (fb->check_head) {
|
||||||
framebuffer->check_head = false;
|
fb->check_head = false;
|
||||||
framebuffer->sampled_head = framebuffer->head;
|
fb->sampled_head = fb->head;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t new_tail = (framebuffer->tail + 1) % framebuffer->n_buffers;
|
int32_t new_tail = (fb->tail + 1) % fb->n_buffers;
|
||||||
|
|
||||||
// Single Buffer Mode.
|
// Single Buffer Mode.
|
||||||
if (framebuffer->n_buffers == 1) {
|
if (fb->n_buffers == 1) {
|
||||||
if (!framebuffer_get_buffer(new_tail)->waiting_for_data) {
|
if (!framebuffer_get_buffer(fb, new_tail)->waiting_for_data) {
|
||||||
// Setup to check head again.
|
// Setup to check head again.
|
||||||
framebuffer->check_head = true;
|
fb->check_head = true;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
// Double Buffer Mode.
|
// Double Buffer Mode.
|
||||||
} else if (framebuffer->n_buffers == 2) {
|
} else if (fb->n_buffers == 2) {
|
||||||
if (new_tail == framebuffer->sampled_head) {
|
if (new_tail == fb->sampled_head) {
|
||||||
// Setup to check head again.
|
// Setup to check head again.
|
||||||
framebuffer->check_head = true;
|
fb->check_head = true;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
// Triple Buffer Mode.
|
// Triple Buffer Mode.
|
||||||
} else if (framebuffer->n_buffers == 3) {
|
} else if (fb->n_buffers == 3) {
|
||||||
// For triple buffering we are never writing where tail or head
|
// For triple buffering we are never writing where tail or head
|
||||||
// (which may instantly update to be equal to tail) is.
|
// (which may instantly update to be equal to tail) is.
|
||||||
if (new_tail == framebuffer->sampled_head) {
|
if (new_tail == fb->sampled_head) {
|
||||||
new_tail = (new_tail + 1) % framebuffer->n_buffers;
|
new_tail = (new_tail + 1) % fb->n_buffers;
|
||||||
}
|
}
|
||||||
// Video FIFO Mode.
|
// Video FIFO Mode.
|
||||||
} else {
|
} else {
|
||||||
if (new_tail == framebuffer->sampled_head) {
|
if (new_tail == fb->sampled_head) {
|
||||||
// Setup to check head again.
|
// Setup to check head again.
|
||||||
framebuffer->check_head = true;
|
fb->check_head = true;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vbuffer_t *buffer = framebuffer_get_buffer(new_tail);
|
vbuffer_t *buffer = framebuffer_get_buffer(fb, new_tail);
|
||||||
|
|
||||||
// Reset on start versus the end so offset and jpeg_buffer_overflow are valid after FB_COMMIT.
|
// Reset on start versus the end so offset and jpeg_buffer_overflow are valid after FB_COMMIT.
|
||||||
if (buffer->reset_state) {
|
if (buffer->reset_state) {
|
||||||
@ -481,18 +487,18 @@ vbuffer_t *framebuffer_get_tail(framebuffer_flags_t flags) {
|
|||||||
buffer->reset_state = true;
|
buffer->reset_state = true;
|
||||||
|
|
||||||
// Mark the frame buffer ready in single buffer mode.
|
// Mark the frame buffer ready in single buffer mode.
|
||||||
if (framebuffer->n_buffers == 1) {
|
if (fb->n_buffers == 1) {
|
||||||
buffer->waiting_for_data = false;
|
buffer->waiting_for_data = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
framebuffer->tail = new_tail;
|
fb->tail = new_tail;
|
||||||
|
|
||||||
// Setup to check head again.
|
// Setup to check head again.
|
||||||
framebuffer->check_head = true;
|
fb->check_head = true;
|
||||||
}
|
}
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *framebuffer_get_buffers_end() {
|
char *framebuffer_get_buffers_end(framebuffer_t *fb) {
|
||||||
return (char *) (framebuffer->data + framebuffer_total_buffer_size());
|
return (char *) (fb->data + framebuffer_total_buffer_size(fb));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -53,8 +53,6 @@ typedef struct framebuffer {
|
|||||||
OMV_ATTR_ALIGNED(uint8_t data[], FRAMEBUFFER_ALIGNMENT);
|
OMV_ATTR_ALIGNED(uint8_t data[], FRAMEBUFFER_ALIGNMENT);
|
||||||
} framebuffer_t;
|
} framebuffer_t;
|
||||||
|
|
||||||
extern framebuffer_t *framebuffer;
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
FB_NO_FLAGS = (0 << 0),
|
FB_NO_FLAGS = (0 << 0),
|
||||||
FB_PEEK = (1 << 0), // If set, will not move the head/tail.
|
FB_PEEK = (1 << 0), // If set, will not move the head/tail.
|
||||||
@ -81,72 +79,73 @@ typedef struct jpegbuffer {
|
|||||||
OMV_ATTR_ALIGNED(uint8_t pixels[], FRAMEBUFFER_ALIGNMENT);
|
OMV_ATTR_ALIGNED(uint8_t pixels[], FRAMEBUFFER_ALIGNMENT);
|
||||||
} jpegbuffer_t;
|
} jpegbuffer_t;
|
||||||
|
|
||||||
extern jpegbuffer_t *jpeg_framebuffer;
|
extern jpegbuffer_t *jpegbuffer;
|
||||||
|
|
||||||
// Force fb streaming to the IDE off.
|
|
||||||
void fb_set_streaming_enabled(bool enable);
|
|
||||||
bool fb_get_streaming_enabled();
|
|
||||||
|
|
||||||
// Encode jpeg data for transmission over a text channel.
|
|
||||||
int fb_encode_for_ide_new_size(image_t *img);
|
|
||||||
void fb_encode_for_ide(uint8_t *ptr, image_t *img);
|
|
||||||
|
|
||||||
void framebuffer_init0();
|
void framebuffer_init0();
|
||||||
|
|
||||||
int32_t framebuffer_get_x();
|
framebuffer_t *framebuffer_get(size_t id);
|
||||||
int32_t framebuffer_get_y();
|
|
||||||
int32_t framebuffer_get_u();
|
|
||||||
int32_t framebuffer_get_v();
|
|
||||||
|
|
||||||
int32_t framebuffer_get_width();
|
int32_t framebuffer_get_x(framebuffer_t *fb);
|
||||||
int32_t framebuffer_get_height();
|
int32_t framebuffer_get_y(framebuffer_t *fb);
|
||||||
int32_t framebuffer_get_depth();
|
int32_t framebuffer_get_u(framebuffer_t *fb);
|
||||||
|
int32_t framebuffer_get_v(framebuffer_t *fb);
|
||||||
|
|
||||||
|
int32_t framebuffer_get_width(framebuffer_t *fb);
|
||||||
|
int32_t framebuffer_get_height(framebuffer_t *fb);
|
||||||
|
int32_t framebuffer_get_depth(framebuffer_t *fb);
|
||||||
|
|
||||||
|
// Force fb streaming to the IDE off.
|
||||||
|
void framebuffer_set_streaming(framebuffer_t *fb, bool enable);
|
||||||
|
bool framebuffer_get_streaming(framebuffer_t *fb);
|
||||||
|
|
||||||
|
// Encode jpeg data for transmission over a text channel.
|
||||||
|
void framebuffer_encode(framebuffer_t *fb, uint8_t *ptr, image_t *img);
|
||||||
|
int framebuffer_encoded_size(framebuffer_t *fb, image_t *img);
|
||||||
|
|
||||||
// Return the number of bytes in the current buffer.
|
// Return the number of bytes in the current buffer.
|
||||||
uint32_t framebuffer_get_buffer_size();
|
uint32_t framebuffer_get_buffer_size(framebuffer_t *fb);
|
||||||
|
|
||||||
// Return the state of a buffer.
|
// Return the state of a buffer.
|
||||||
vbuffer_t *framebuffer_get_buffer(int32_t index);
|
vbuffer_t *framebuffer_get_buffer(framebuffer_t *fb, int32_t index);
|
||||||
|
|
||||||
// Initializes an image from the frame buffer.
|
// Initializes an image from the frame buffer.
|
||||||
void framebuffer_init_image(image_t *img);
|
void framebuffer_init_image(framebuffer_t *fb, image_t *img);
|
||||||
|
|
||||||
// Sets the frame buffer from an image.
|
// Sets the frame buffer from an image.
|
||||||
void framebuffer_init_from_image(image_t *img);
|
void framebuffer_init_from_image(framebuffer_t *fb, image_t *img);
|
||||||
|
|
||||||
// Compress src image to the JPEG buffer if src is mutable, otherwise copy src to the JPEG buffer
|
// Compress src image to the JPEG buffer if src is mutable, otherwise copy src to the JPEG buffer
|
||||||
// if the src is JPEG and fits in the JPEG buffer, or encode and stream src image to the IDE if not.
|
// if the src is JPEG and fits in the JPEG buffer, or encode and stream src image to the IDE if not.
|
||||||
void framebuffer_update_jpeg_buffer();
|
void framebuffer_update_jpeg_buffer(framebuffer_t *fb);
|
||||||
|
|
||||||
// Clear the framebuffer FIFO. If fifo_flush is true, reset and discard all framebuffers,
|
// Clear the framebuffer FIFO. If fifo_flush is true, reset and discard all framebuffers,
|
||||||
// otherwise, retain the last frame in the fifo.
|
// otherwise, retain the last frame in the fifo.
|
||||||
void framebuffer_flush_buffers(bool fifo_flush);
|
void framebuffer_flush_buffers(framebuffer_t *fb, bool fifo_flush);
|
||||||
|
|
||||||
// Set the number of virtual buffers in the frame buffer.
|
// Set the number of virtual buffers in the frame buffer.
|
||||||
// If n_buffers = -1 the number of virtual buffers will be set to 3 each if possible.
|
// If n_buffers = -1 the number of virtual buffers will be set to 3 each if possible.
|
||||||
// If n_buffers = 1 the whole framebuffer is used. In this case, `frame_size` is ignored.
|
// If n_buffers = 1 the whole framebuffer is used. In this case, `frame_size` is ignored.
|
||||||
int framebuffer_set_buffers(int32_t n_buffers);
|
int framebuffer_set_buffers(framebuffer_t *fb, int32_t n_buffers);
|
||||||
|
|
||||||
// Call when done with the current vbuffer to mark it as free.
|
// Call when done with the current vbuffer to mark it as free.
|
||||||
void framebuffer_free_current_buffer();
|
void framebuffer_free_current_buffer(framebuffer_t *fb);
|
||||||
|
|
||||||
// Call to do any heavy setup before frame capture.
|
// Call to do any heavy setup before frame capture.
|
||||||
void framebuffer_setup_buffers();
|
void framebuffer_setup_buffers(framebuffer_t *fb);
|
||||||
|
|
||||||
// Sets the current frame buffer to the latest virtual frame buffer.
|
// Sets the current frame buffer to the latest virtual frame buffer.
|
||||||
// Returns the buffer if it is ready or NULL if not...
|
// Returns the buffer if it is ready or NULL if not...
|
||||||
// Pass FB_PEEK to get the next buffer but not take it.
|
// Pass FB_PEEK to get the next buffer but not take it.
|
||||||
vbuffer_t *framebuffer_get_head(framebuffer_flags_t flags);
|
vbuffer_t *framebuffer_get_head(framebuffer_t *fb, framebuffer_flags_t flags);
|
||||||
|
|
||||||
// Return the next vbuffer to store image data to or NULL if none.
|
// Return the next vbuffer to store image data to or NULL if none.
|
||||||
// Pass FB_PEEK to get the next buffer but not commit it.
|
// Pass FB_PEEK to get the next buffer but not commit it.
|
||||||
vbuffer_t *framebuffer_get_tail(framebuffer_flags_t flags);
|
vbuffer_t *framebuffer_get_tail(framebuffer_t *fb, framebuffer_flags_t flags);
|
||||||
|
|
||||||
// Returns a pointer to the end of the framebuffer(s).
|
// Returns a pointer to the end of the framebuffer(s).
|
||||||
char *framebuffer_get_buffers_end();
|
char *framebuffer_get_buffers_end(framebuffer_t *fb);
|
||||||
|
|
||||||
// Use these macros to get a pointer to main or JPEG framebuffer.
|
// Use this macro to get a pointer to the JPEG buffer.
|
||||||
#define MAIN_FB() (framebuffer)
|
#define JPEG_FB() (jpegbuffer)
|
||||||
#define JPEG_FB() (jpeg_framebuffer)
|
|
||||||
|
|
||||||
#endif /* __FRAMEBUFFER_H__ */
|
#endif /* __FRAMEBUFFER_H__ */
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user