mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
imlib: Fix automatic vbuffer count.
Before this patch, a 1.5MB framebuffer used a single vbuffer for VGA and smaller resolutions, causing the sensor driver to restart with every snapshot. With this patch, a 1.5MB frame buffer uses 2 vbuffers for VGA/RGB and 3 vbuffers for VGA/grayscale **by default**. In the case of 2 vbuffers, it should leave the rest for `fb_alloc`, so `fb_alloc` still gets some extra space, but only if there's any left. `set_buffers` now replaces `auto_adjust`. Passing `-1` to `set_buffers` will attempt to use 3 vbuffers, each with a size of `frame_size` if they fit; otherwise, the maximum possible buffers will be used. Passing `1` will use the whole framebuffer. In this case, `frame_size` is ignored. Additionally, `set_buffers` is now more efficient with buffer sizes. For example, if the source is 1bpp (Bayer) and the destination is 1bpp (grayscale or Bayer), the vbuffer size will be `w*h`, instead of assuming that everything is 2bpp, which allows for more vbuffers.
This commit is contained in:
parent
0533891c01
commit
7b36e4ef67
@ -622,11 +622,11 @@ __weak int sensor_set_pixformat(pixformat_t pixformat) {
|
|||||||
// Set pixel format
|
// Set pixel format
|
||||||
sensor.pixformat = pixformat;
|
sensor.pixformat = pixformat;
|
||||||
|
|
||||||
// Skip the first frame.
|
// Reset pixel format to skip the first frame.
|
||||||
MAIN_FB()->pixfmt = PIXFORMAT_INVALID;
|
MAIN_FB()->pixfmt = PIXFORMAT_INVALID;
|
||||||
|
|
||||||
// Pickout a good buffer count for the user.
|
// Auto-adjust the number of frame buffers.
|
||||||
framebuffer_auto_adjust_buffers();
|
sensor_set_framebuffers(-1);
|
||||||
|
|
||||||
// Reconfigure the hardware if needed.
|
// Reconfigure the hardware if needed.
|
||||||
return sensor_config(SENSOR_CONFIG_PIXFORMAT);
|
return sensor_config(SENSOR_CONFIG_PIXFORMAT);
|
||||||
@ -660,17 +660,20 @@ __weak int sensor_set_framesize(framesize_t framesize) {
|
|||||||
// Set framebuffer size
|
// Set framebuffer size
|
||||||
sensor.framesize = framesize;
|
sensor.framesize = framesize;
|
||||||
|
|
||||||
// Skip the first frame.
|
// Set x and y offsets.
|
||||||
MAIN_FB()->pixfmt = PIXFORMAT_INVALID;
|
|
||||||
|
|
||||||
// Set MAIN FB x offset, y offset, width, height, backup width, and backup height.
|
|
||||||
MAIN_FB()->x = 0;
|
MAIN_FB()->x = 0;
|
||||||
MAIN_FB()->y = 0;
|
MAIN_FB()->y = 0;
|
||||||
MAIN_FB()->w = MAIN_FB()->u = resolution[framesize][0];
|
// Set width and height.
|
||||||
MAIN_FB()->h = MAIN_FB()->v = resolution[framesize][1];
|
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.
|
// Auto-adjust the number of frame buffers.
|
||||||
framebuffer_auto_adjust_buffers();
|
sensor_set_framebuffers(-1);
|
||||||
|
|
||||||
// Reconfigure the hardware if needed.
|
// Reconfigure the hardware if needed.
|
||||||
return sensor_config(SENSOR_CONFIG_FRAMESIZE);
|
return sensor_config(SENSOR_CONFIG_FRAMESIZE);
|
||||||
@ -731,14 +734,14 @@ __weak uint32_t sensor_get_src_bpp() {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
switch (sensor.pixformat) {
|
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_BAYER:
|
||||||
case PIXFORMAT_JPEG:
|
case PIXFORMAT_JPEG:
|
||||||
return 1;
|
return 1;
|
||||||
|
case PIXFORMAT_RGB565:
|
||||||
|
case PIXFORMAT_YUV422:
|
||||||
|
return 2;
|
||||||
|
case PIXFORMAT_GRAYSCALE:
|
||||||
|
return sensor.hw_flags.gs_bpp;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -774,16 +777,20 @@ __weak int sensor_set_windowing(int x, int y, int w, int h) {
|
|||||||
// Flush previous frame.
|
// Flush previous frame.
|
||||||
framebuffer_update_jpeg_buffer();
|
framebuffer_update_jpeg_buffer();
|
||||||
|
|
||||||
// Skip the first frame.
|
// Set x and y offsets.
|
||||||
MAIN_FB()->pixfmt = PIXFORMAT_INVALID;
|
|
||||||
|
|
||||||
MAIN_FB()->x = x;
|
MAIN_FB()->x = x;
|
||||||
MAIN_FB()->y = y;
|
MAIN_FB()->y = y;
|
||||||
MAIN_FB()->w = MAIN_FB()->u = w;
|
// Set width and height.
|
||||||
MAIN_FB()->h = MAIN_FB()->v = h;
|
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.
|
// Auto-adjust the number of frame buffers.
|
||||||
framebuffer_auto_adjust_buffers();
|
sensor_set_framebuffers(-1);
|
||||||
|
|
||||||
// Reconfigure the hardware if needed.
|
// Reconfigure the hardware if needed.
|
||||||
return sensor_config(SENSOR_CONFIG_WINDOWING);
|
return sensor_config(SENSOR_CONFIG_WINDOWING);
|
||||||
@ -1114,6 +1121,22 @@ __weak int sensor_set_framebuffers(int count) {
|
|||||||
// Flush previous frame.
|
// Flush previous frame.
|
||||||
framebuffer_update_jpeg_buffer();
|
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);
|
return framebuffer_set_buffers(count);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1279,8 +1302,8 @@ __weak int sensor_auto_crop_framebuffer() {
|
|||||||
MAIN_FB()->y -= 1;
|
MAIN_FB()->y -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pickout a good buffer count for the user.
|
// Auto-adjust the number of frame buffers.
|
||||||
framebuffer_auto_adjust_buffers();
|
sensor_set_framebuffers(-1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -262,45 +262,28 @@ int32_t framebuffer_get_depth() {
|
|||||||
return framebuffer->bpp;
|
return framebuffer->bpp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the number of bytes the frame buffer could be at the current moment it time.
|
// Returns the current frame buffer size, factoring in the space taken by fb_alloc.
|
||||||
static uint32_t framebuffer_raw_buffer_size() {
|
static uint32_t framebuffer_max_buffer_size() {
|
||||||
uint32_t size = (uint32_t) (fb_alloc_stack_pointer() - ((char *) framebuffer->data));
|
uint32_t fb_total_size = FB_ALIGN_SIZE_ROUND_DOWN(&_fb_memory_end - (char *) framebuffer->data);
|
||||||
// We don't want to give all of the frame buffer RAM to the frame buffer. So, we will limit
|
uint32_t fb_avail_size = FB_ALIGN_SIZE_ROUND_DOWN(fb_alloc_stack_pointer() - (char *) framebuffer->data);
|
||||||
// the maximum amount of RAM we return.
|
return IM_MIN(fb_total_size, fb_avail_size);
|
||||||
uint32_t raw_buf_size = (&_fb_memory_end - &_fb_memory_start - sizeof(framebuffer_t));
|
|
||||||
return IM_MIN(size, raw_buf_size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t framebuffer_get_buffer_size() {
|
uint32_t framebuffer_get_buffer_size() {
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
|
|
||||||
if (framebuffer->n_buffers == 1) {
|
if (framebuffer->n_buffers == 1) {
|
||||||
// With only 1 vbuffer it's fine to allow the frame buffer size to change given fb_alloc().
|
// With only 1 vbuffer the frame buffer size can change given fb_alloc().
|
||||||
size = framebuffer_raw_buffer_size();
|
size = framebuffer_max_buffer_size();
|
||||||
} 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->raw_buffer_size;
|
size = framebuffer->buff_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the size of the state header plus alignment padding.
|
// Remove the size of the state header plus alignment padding.
|
||||||
size -= sizeof(vbuffer_t);
|
size -= sizeof(vbuffer_t);
|
||||||
|
|
||||||
#if (OMV_CSI_HW_CROP_ENABLE == 1)
|
// Needs to be a multiple of FRAMEBUFFER_ALIGNMENT for DMA transfers.
|
||||||
// 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...
|
|
||||||
return FB_ALIGN_SIZE_ROUND_DOWN(size);
|
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) {
|
void framebuffer_flush_buffers(bool fifo_flush) {
|
||||||
if (fifo_flush) {
|
if (fifo_flush) {
|
||||||
// Drop all frame buffers.
|
// 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));
|
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) {
|
int framebuffer_set_buffers(int32_t n_buffers) {
|
||||||
uint32_t total_size = framebuffer_raw_buffer_size();
|
uint32_t avail_size = FB_ALIGN_SIZE_ROUND_DOWN(framebuffer_max_buffer_size());
|
||||||
uint32_t size = total_size / n_buffers;
|
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 (vbuff_count == 0 || vbuff_size < sizeof(vbuffer_t)) {
|
||||||
if (size < (sizeof(vbuffer_t) + FRAMEBUFFER_ALIGNMENT)) {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invalidate frame.
|
framebuffer->head = 0;
|
||||||
|
framebuffer->buff_size = vbuff_size;
|
||||||
|
framebuffer->n_buffers = vbuff_count;
|
||||||
framebuffer->pixfmt = PIXFORMAT_INVALID;
|
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);
|
framebuffer_flush_buffers(true);
|
||||||
|
|
||||||
return 0;
|
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() {
|
void framebuffer_free_current_buffer() {
|
||||||
vbuffer_t *buffer = framebuffer_get_buffer(framebuffer->head);
|
vbuffer_t *buffer = framebuffer_get_buffer(framebuffer->head);
|
||||||
|
|
||||||
|
|||||||
@ -28,8 +28,9 @@ typedef struct framebuffer {
|
|||||||
int32_t u, v;
|
int32_t u, v;
|
||||||
PIXFORMAT_STRUCT;
|
PIXFORMAT_STRUCT;
|
||||||
int32_t streaming_enabled;
|
int32_t streaming_enabled;
|
||||||
uint32_t raw_buffer_size;
|
uint32_t buff_size;
|
||||||
int32_t n_buffers;
|
uint32_t n_buffers;
|
||||||
|
uint32_t frame_size;
|
||||||
int32_t head;
|
int32_t head;
|
||||||
volatile int32_t tail;
|
volatile int32_t tail;
|
||||||
bool check_head;
|
bool check_head;
|
||||||
@ -106,12 +107,11 @@ void framebuffer_update_jpeg_buffer();
|
|||||||
// 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(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);
|
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.
|
// Call when done with the current vbuffer to mark it as free.
|
||||||
void framebuffer_free_current_buffer();
|
void framebuffer_free_current_buffer();
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user