Merge pull request #2376 from openmv/framebuffer_vbuffer_fix

imlib: Fix automatic vbuffer count.
This commit is contained in:
Ibrahim Abdelkader 2024-08-17 18:39:26 +03:00 committed by GitHub
commit 51f84b70ab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 72 additions and 86 deletions

View File

@ -622,11 +622,11 @@ __weak int sensor_set_pixformat(pixformat_t pixformat) {
// Set pixel format
sensor.pixformat = pixformat;
// Skip the first frame.
// Reset pixel format to skip the first frame.
MAIN_FB()->pixfmt = PIXFORMAT_INVALID;
// Pickout a good buffer count for the user.
framebuffer_auto_adjust_buffers();
// Auto-adjust the number of frame buffers.
sensor_set_framebuffers(-1);
// Reconfigure the hardware if needed.
return sensor_config(SENSOR_CONFIG_PIXFORMAT);
@ -660,17 +660,20 @@ __weak int sensor_set_framesize(framesize_t framesize) {
// Set framebuffer size
sensor.framesize = framesize;
// Skip the first frame.
MAIN_FB()->pixfmt = PIXFORMAT_INVALID;
// Set MAIN FB x offset, y offset, width, height, backup width, and backup height.
// Set x and y offsets.
MAIN_FB()->x = 0;
MAIN_FB()->y = 0;
MAIN_FB()->w = MAIN_FB()->u = resolution[framesize][0];
MAIN_FB()->h = MAIN_FB()->v = resolution[framesize][1];
// Set width and height.
MAIN_FB()->w = resolution[framesize][0];
MAIN_FB()->h = resolution[framesize][1];
// Set backup width and height.
MAIN_FB()->u = resolution[framesize][0];
MAIN_FB()->v = resolution[framesize][1];
// Reset pixel format to skip the first frame.
MAIN_FB()->pixfmt = PIXFORMAT_INVALID;
// Pickout a good buffer count for the user.
framebuffer_auto_adjust_buffers();
// Auto-adjust the number of frame buffers.
sensor_set_framebuffers(-1);
// Reconfigure the hardware if needed.
return sensor_config(SENSOR_CONFIG_FRAMESIZE);
@ -731,14 +734,14 @@ __weak uint32_t sensor_get_src_bpp() {
return 1;
}
switch (sensor.pixformat) {
case PIXFORMAT_GRAYSCALE:
return sensor.hw_flags.gs_bpp;
case PIXFORMAT_RGB565:
case PIXFORMAT_YUV422:
return 2;
case PIXFORMAT_BAYER:
case PIXFORMAT_JPEG:
return 1;
case PIXFORMAT_RGB565:
case PIXFORMAT_YUV422:
return 2;
case PIXFORMAT_GRAYSCALE:
return sensor.hw_flags.gs_bpp;
default:
return 0;
}
@ -774,16 +777,20 @@ __weak int sensor_set_windowing(int x, int y, int w, int h) {
// Flush previous frame.
framebuffer_update_jpeg_buffer();
// Skip the first frame.
MAIN_FB()->pixfmt = PIXFORMAT_INVALID;
// Set x and y offsets.
MAIN_FB()->x = x;
MAIN_FB()->y = y;
MAIN_FB()->w = MAIN_FB()->u = w;
MAIN_FB()->h = MAIN_FB()->v = h;
// Set width and height.
MAIN_FB()->w = w;
MAIN_FB()->h = h;
// Set backup width and height.
MAIN_FB()->u = w;
MAIN_FB()->v = h;
// Reset pixel format to skip the first frame.
MAIN_FB()->pixfmt = PIXFORMAT_INVALID;
// Pickout a good buffer count for the user.
framebuffer_auto_adjust_buffers();
// Auto-adjust the number of frame buffers.
sensor_set_framebuffers(-1);
// Reconfigure the hardware if needed.
return sensor_config(SENSOR_CONFIG_WINDOWING);
@ -1114,6 +1121,22 @@ __weak int sensor_set_framebuffers(int count) {
// Flush previous frame.
framebuffer_update_jpeg_buffer();
if (sensor.pixformat == PIXFORMAT_INVALID) {
return SENSOR_ERROR_INVALID_PIXFORMAT;
}
if (sensor.framesize == FRAMESIZE_INVALID) {
return SENSOR_ERROR_INVALID_FRAMESIZE;
}
uint32_t bpp = IM_MAX(sensor_get_src_bpp(), sensor_get_dst_bpp());
#if OMV_CSI_HW_CROP_ENABLE
// If hardware cropping is supported, use window size.
MAIN_FB()->frame_size = MAIN_FB()->u * MAIN_FB()->v * bpp;
#else
// Otherwise, use the real frame size.
MAIN_FB()->frame_size = resolution[sensor.framesize][0] * resolution[sensor.framesize][1] * bpp;
#endif
return framebuffer_set_buffers(count);
}
@ -1279,8 +1302,8 @@ __weak int sensor_auto_crop_framebuffer() {
MAIN_FB()->y -= 1;
}
// Pickout a good buffer count for the user.
framebuffer_auto_adjust_buffers();
// Auto-adjust the number of frame buffers.
sensor_set_framebuffers(-1);
return 0;
}

View File

@ -262,45 +262,28 @@ int32_t framebuffer_get_depth() {
return framebuffer->bpp;
}
// Returns the number of bytes the frame buffer could be at the current moment it time.
static uint32_t framebuffer_raw_buffer_size() {
uint32_t size = (uint32_t) (fb_alloc_stack_pointer() - ((char *) framebuffer->data));
// We don't want to give all of the frame buffer RAM to the frame buffer. So, we will limit
// the maximum amount of RAM we return.
uint32_t raw_buf_size = (&_fb_memory_end - &_fb_memory_start - sizeof(framebuffer_t));
return IM_MIN(size, raw_buf_size);
// 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);
return IM_MIN(fb_total_size, fb_avail_size);
}
uint32_t framebuffer_get_buffer_size() {
uint32_t size;
if (framebuffer->n_buffers == 1) {
// With only 1 vbuffer it's fine to allow the frame buffer size to change given fb_alloc().
size = framebuffer_raw_buffer_size();
// With only 1 vbuffer the frame buffer size can change given fb_alloc().
size = framebuffer_max_buffer_size();
} else {
// Whatever the raw size was when the number of buffers were set is locked in.
size = framebuffer->raw_buffer_size;
size = framebuffer->buff_size;
}
// Remove the size of the state header plus alignment padding.
size -= sizeof(vbuffer_t);
#if (OMV_CSI_HW_CROP_ENABLE == 1)
// If the frame size is set, the memory for each buffer can be reduced,
// freeing up space for fb_alloc(). Note that this can only be done if
// the camera interface supports hardware cropping, i.e., the actual
// frame size will match the specified window size.
if ((framebuffer->n_buffers != 1) && framebuffer->u && framebuffer->v) {
// Typically a framebuffer will not need more than u*v*2 bytes.
uint32_t size_guess = framebuffer->u * framebuffer->v * 2;
// Add in extra bytes to prevent round down from shrinking buffer too small.
size_guess += FRAMEBUFFER_ALIGNMENT - 1;
// Limit the frame buffer size.
size = IM_MIN(size, size_guess);
}
#endif
// Needs to be a multiple of FRAMEBUFFER_ALIGNMENT for DMA transfers...
// Needs to be a multiple of FRAMEBUFFER_ALIGNMENT for DMA transfers.
return FB_ALIGN_SIZE_ROUND_DOWN(size);
}
@ -314,7 +297,7 @@ vbuffer_t *framebuffer_get_buffer(int32_t index) {
void framebuffer_flush_buffers(bool fifo_flush) {
if (fifo_flush) {
// Drop all frame buffers.
for (int32_t i = 0; i < framebuffer->n_buffers; i++) {
for (uint32_t i = 0; i < framebuffer->n_buffers; i++) {
memset(framebuffer_get_buffer(i), 0, sizeof(vbuffer_t));
}
}
@ -326,24 +309,21 @@ void framebuffer_flush_buffers(bool fifo_flush) {
}
int framebuffer_set_buffers(int32_t n_buffers) {
uint32_t total_size = framebuffer_raw_buffer_size();
uint32_t size = total_size / 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));
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);
// Error out if frame buffers are smaller than this...
if (size < (sizeof(vbuffer_t) + FRAMEBUFFER_ALIGNMENT)) {
if (vbuff_count == 0 || vbuff_size < sizeof(vbuffer_t)) {
return -1;
}
// Invalidate frame.
framebuffer->head = 0;
framebuffer->buff_size = vbuff_size;
framebuffer->n_buffers = vbuff_count;
framebuffer->pixfmt = PIXFORMAT_INVALID;
// Cache the maximum size we can allocate for the frame buffer when vbuffers are greater than 1.
framebuffer->raw_buffer_size = size;
framebuffer->n_buffers = n_buffers;
framebuffer->head = 0;
framebuffer_flush_buffers(true);
return 0;
}
@ -360,23 +340,6 @@ static uint32_t framebuffer_total_buffer_size() {
}
}
void framebuffer_auto_adjust_buffers() {
// Keep same buffer count in video fifo mode but resize buffer sizes.
if (framebuffer->n_buffers > 3) {
framebuffer_set_buffers(framebuffer->n_buffers);
return;
}
for (int i = 3; i > 0; i--) {
framebuffer_set_buffers(i);
// Find a buffering size automatically that doesn't use more than half.
if (fb_avail() >= framebuffer_total_buffer_size()) {
return;
}
}
}
void framebuffer_free_current_buffer() {
vbuffer_t *buffer = framebuffer_get_buffer(framebuffer->head);

View File

@ -28,8 +28,9 @@ typedef struct framebuffer {
int32_t u, v;
PIXFORMAT_STRUCT;
int32_t streaming_enabled;
uint32_t raw_buffer_size;
int32_t n_buffers;
uint32_t buff_size;
uint32_t n_buffers;
uint32_t frame_size;
int32_t head;
volatile int32_t tail;
bool check_head;
@ -106,12 +107,11 @@ void framebuffer_update_jpeg_buffer();
// otherwise, retain the last frame in the fifo.
void framebuffer_flush_buffers(bool fifo_flush);
// Controls 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 whole framebuffer is used. In this case, `frame_size` is ignored.
int framebuffer_set_buffers(int32_t n_buffers);
// Automatically finds the best buffering size given RAM.
void framebuffer_auto_adjust_buffers();
// Call when done with the current vbuffer to mark it as free.
void framebuffer_free_current_buffer();