From c122c9dfc2df17f3da0426213160012544f149f6 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Mon, 21 Apr 2025 17:56:08 +0200 Subject: [PATCH] imlib: Refactor framebuffer API to accept a context. Updated all framebuffer functions to take a framebuffer_t argument. Signed-off-by: iabdalkader --- lib/imlib/framebuffer.c | 550 ++++++++++++++++++++-------------------- lib/imlib/framebuffer.h | 65 +++-- 2 files changed, 310 insertions(+), 305 deletions(-) diff --git a/lib/imlib/framebuffer.c b/lib/imlib/framebuffer.c index 76b8a8548..f0869a6e9 100644 --- a/lib/imlib/framebuffer.c +++ b/lib/imlib/framebuffer.c @@ -33,27 +33,216 @@ #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)) -extern char _fb_memory_start; -extern char _fb_memory_end; -framebuffer_t *framebuffer = (framebuffer_t *) &_fb_memory_start; +extern char _fb_memory_start[]; +extern char _fb_memory_end[]; +static framebuffer_t *framebuffer = (framebuffer_t *) &_fb_memory_start; extern char _jpeg_memory_start; 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) { - framebuffer->streaming_enabled = enable; +void framebuffer_init0() { + // 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() { - return framebuffer->streaming_enabled; +void framebuffer_init_image(framebuffer_t *fb, image_t *img) { + 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) { - return (((img->size * 8) + 5) / 6) + 2; +void framebuffer_init_from_image(framebuffer_t *fb, image_t *img) { + 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; 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; } -void framebuffer_init0() { - // Save fb_enabled flag state - 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; +int framebuffer_encoded_size(framebuffer_t *fb, image_t *img) { + return (((img->size * 8) + 5) / 6) + 2; } // Returns the current frame buffer size, factoring in the space taken by fb_alloc. -static uint32_t framebuffer_max_buffer_size() { - uint32_t fb_total_size = FB_ALIGN_SIZE_ROUND_DOWN(&_fb_memory_end - (char *) framebuffer->data); - uint32_t fb_avail_size = FB_ALIGN_SIZE_ROUND_DOWN(fb_alloc_stack_pointer() - (char *) framebuffer->data); +static uint32_t framebuffer_max_buffer_size(framebuffer_t *fb) { + 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 *) fb->data); 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; - if (framebuffer->n_buffers == 1) { + if (fb->n_buffers == 1) { // 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 { // 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. @@ -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 // padding and then the pixel array starting at the next 32-byte offset. -vbuffer_t *framebuffer_get_buffer(int32_t index) { - uint32_t offset = (sizeof(vbuffer_t) + framebuffer_get_buffer_size()) * index; - return (vbuffer_t *) (framebuffer->data + offset); +vbuffer_t *framebuffer_get_buffer(framebuffer_t *fb, int32_t index) { + uint32_t fbsize = framebuffer_get_buffer_size(fb); + 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) { // Drop all frame buffers. - for (uint32_t i = 0; i < framebuffer->n_buffers; i++) { - memset(framebuffer_get_buffer(i), 0, sizeof(vbuffer_t)); + for (uint32_t i = 0; i < fb->n_buffers; i++) { + 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 // position of the current frame for the rest of the code. - framebuffer->tail = framebuffer->head; - framebuffer->check_head = true; - framebuffer->sampled_head = 0; + fb->tail = fb->head; + fb->check_head = true; + fb->sampled_head = 0; } -int framebuffer_set_buffers(int32_t n_buffers) { - uint32_t avail_size = FB_ALIGN_SIZE_ROUND_DOWN(framebuffer_max_buffer_size()); - uint32_t frame_size = FB_ALIGN_SIZE_ROUND_UP(framebuffer->frame_size + sizeof(vbuffer_t)); +int framebuffer_set_buffers(framebuffer_t *fb, int32_t n_buffers) { + uint32_t avail_size = FB_ALIGN_SIZE_ROUND_DOWN(framebuffer_max_buffer_size(fb)); + 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_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; } - framebuffer->head = 0; - framebuffer->buff_size = vbuff_size; - framebuffer->n_buffers = vbuff_count; - framebuffer->pixfmt = PIXFORMAT_INVALID; + fb->head = 0; + fb->buff_size = vbuff_size; + fb->n_buffers = vbuff_count; + fb->pixfmt = PIXFORMAT_INVALID; - framebuffer_flush_buffers(true); + framebuffer_flush_buffers(fb, true); return 0; } // Returns the real size of bytes in the frame buffer. -static uint32_t framebuffer_total_buffer_size() { - if (framebuffer->n_buffers == 1) { +static uint32_t framebuffer_total_buffer_size(framebuffer_t *fb) { + if (fb->n_buffers == 1) { // Allow fb_alloc to use frame buffer space up until the image size. image_t img; - framebuffer_init_image(&img); + framebuffer_init_image(fb, &img); return sizeof(vbuffer_t) + FB_ALIGN_SIZE_ROUND_UP(image_size(&img)); } else { - // 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; + // fb_alloc may only use up to the size of all the virtual buffers. + uint32_t fbsize = framebuffer_get_buffer_size(fb); + return (sizeof(vbuffer_t) + fbsize) * fb->n_buffers; } } -void framebuffer_free_current_buffer() { - vbuffer_t *buffer = framebuffer_get_buffer(framebuffer->head); +void framebuffer_free_current_buffer(framebuffer_t *fb) { + vbuffer_t *buffer = framebuffer_get_buffer(fb, fb->head); #ifdef __DCACHE_PRESENT // 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 // Invalidate frame. - framebuffer->pixfmt = PIXFORMAT_INVALID; + fb->pixfmt = PIXFORMAT_INVALID; // Allow frame to be updated in single buffer mode... - if (framebuffer->n_buffers == 1) { + if (fb->n_buffers == 1) { buffer->waiting_for_data = true; } } -void framebuffer_setup_buffers() { +void framebuffer_setup_buffers(framebuffer_t *fb) { #ifdef __DCACHE_PRESENT - for (int32_t i = 0; i < framebuffer->n_buffers; i++) { - if (i != framebuffer->head) { - vbuffer_t *buffer = framebuffer_get_buffer(i); + for (int32_t i = 0; i < fb->n_buffers; i++) { + if (i != fb->head) { + vbuffer_t *buffer = framebuffer_get_buffer(fb, i); // 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 } -vbuffer_t *framebuffer_get_head(framebuffer_flags_t flags) { - int32_t new_head = (framebuffer->head + 1) % framebuffer->n_buffers; +vbuffer_t *framebuffer_get_head(framebuffer_t *fb, framebuffer_flags_t flags) { + int32_t new_head = (fb->head + 1) % fb->n_buffers; // Single Buffer Mode. - if (framebuffer->n_buffers == 1) { - if (framebuffer_get_buffer(framebuffer->head)->waiting_for_data) { + if (fb->n_buffers == 1) { + if (framebuffer_get_buffer(fb, fb->head)->waiting_for_data) { return NULL; } // Double Buffer Mode. - } else if (framebuffer->n_buffers == 2) { - if (framebuffer->head == framebuffer->tail) { + } else if (fb->n_buffers == 2) { + if (fb->head == fb->tail) { return NULL; } // Triple Buffer Mode. - } else if (framebuffer->n_buffers == 3) { - int32_t sampled_tail = framebuffer->tail; - if (framebuffer->head == sampled_tail) { + } else if (fb->n_buffers == 3) { + int32_t sampled_tail = fb->tail; + if (fb->head == sampled_tail) { return NULL; } else { new_head = sampled_tail; } // Video FIFO Mode. } else { - if (framebuffer->head == framebuffer->tail) { + if (fb->head == fb->tail) { return NULL; } } 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 if (flags & FB_INVALIDATE) { // 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 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. - if (framebuffer->check_head) { - framebuffer->check_head = false; - framebuffer->sampled_head = framebuffer->head; + if (fb->check_head) { + fb->check_head = false; + 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. - if (framebuffer->n_buffers == 1) { - if (!framebuffer_get_buffer(new_tail)->waiting_for_data) { + if (fb->n_buffers == 1) { + if (!framebuffer_get_buffer(fb, new_tail)->waiting_for_data) { // Setup to check head again. - framebuffer->check_head = true; + fb->check_head = true; return NULL; } // Double Buffer Mode. - } else if (framebuffer->n_buffers == 2) { - if (new_tail == framebuffer->sampled_head) { + } else if (fb->n_buffers == 2) { + if (new_tail == fb->sampled_head) { // Setup to check head again. - framebuffer->check_head = true; + fb->check_head = true; return NULL; } // 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 // (which may instantly update to be equal to tail) is. - if (new_tail == framebuffer->sampled_head) { - new_tail = (new_tail + 1) % framebuffer->n_buffers; + if (new_tail == fb->sampled_head) { + new_tail = (new_tail + 1) % fb->n_buffers; } // Video FIFO Mode. } else { - if (new_tail == framebuffer->sampled_head) { + if (new_tail == fb->sampled_head) { // Setup to check head again. - framebuffer->check_head = true; + fb->check_head = true; 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. if (buffer->reset_state) { @@ -481,18 +487,18 @@ vbuffer_t *framebuffer_get_tail(framebuffer_flags_t flags) { buffer->reset_state = true; // Mark the frame buffer ready in single buffer mode. - if (framebuffer->n_buffers == 1) { + if (fb->n_buffers == 1) { buffer->waiting_for_data = false; } - framebuffer->tail = new_tail; + fb->tail = new_tail; // Setup to check head again. - framebuffer->check_head = true; + fb->check_head = true; } return buffer; } -char *framebuffer_get_buffers_end() { - return (char *) (framebuffer->data + framebuffer_total_buffer_size()); +char *framebuffer_get_buffers_end(framebuffer_t *fb) { + return (char *) (fb->data + framebuffer_total_buffer_size(fb)); } diff --git a/lib/imlib/framebuffer.h b/lib/imlib/framebuffer.h index d919ce91c..117f0b7a9 100644 --- a/lib/imlib/framebuffer.h +++ b/lib/imlib/framebuffer.h @@ -53,8 +53,6 @@ typedef struct framebuffer { OMV_ATTR_ALIGNED(uint8_t data[], FRAMEBUFFER_ALIGNMENT); } framebuffer_t; -extern framebuffer_t *framebuffer; - typedef enum { FB_NO_FLAGS = (0 << 0), 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); } jpegbuffer_t; -extern jpegbuffer_t *jpeg_framebuffer; - -// 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); +extern jpegbuffer_t *jpegbuffer; void framebuffer_init0(); -int32_t framebuffer_get_x(); -int32_t framebuffer_get_y(); -int32_t framebuffer_get_u(); -int32_t framebuffer_get_v(); +framebuffer_t *framebuffer_get(size_t id); -int32_t framebuffer_get_width(); -int32_t framebuffer_get_height(); -int32_t framebuffer_get_depth(); +int32_t framebuffer_get_x(framebuffer_t *fb); +int32_t framebuffer_get_y(framebuffer_t *fb); +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. -uint32_t framebuffer_get_buffer_size(); +uint32_t framebuffer_get_buffer_size(framebuffer_t *fb); // 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. -void framebuffer_init_image(image_t *img); +void framebuffer_init_image(framebuffer_t *fb, image_t *img); // 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 // 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, // 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. // 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. -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. -void framebuffer_free_current_buffer(); +void framebuffer_free_current_buffer(framebuffer_t *fb); // 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. // Returns the buffer if it is ready or NULL if not... // 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. // 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). -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. -#define MAIN_FB() (framebuffer) -#define JPEG_FB() (jpeg_framebuffer) +// Use this macro to get a pointer to the JPEG buffer. +#define JPEG_FB() (jpegbuffer) #endif /* __FRAMEBUFFER_H__ */