ports/all: Refactor frame buffer line copying code.

This commit is contained in:
iabdalkader 2024-02-02 15:33:23 +02:00
parent 27161405b4
commit 345b80358d
4 changed files with 98 additions and 142 deletions

View File

@ -14,18 +14,6 @@
#include "omv_i2c.h"
#include "imlib.h"
#define copy_transposed_line(dstp, srcp) \
for (int i = MAIN_FB()->u, h = MAIN_FB()->v; i; i--) { \
*dstp = *srcp++; \
dstp += h; \
}
#define copy_transposed_line_rev16(dstp, srcp) \
for (int i = MAIN_FB()->u, h = MAIN_FB()->v; i; i--) { \
*dstp = __REV16(*srcp++); \
dstp += h; \
}
#define OV2640_SLV_ADDR (0x60)
#define OV5640_SLV_ADDR (0x78)
#define OV7725_SLV_ADDR (0x42)
@ -484,6 +472,10 @@ int sensor_check_framebuffer_size();
// Auto-crop frame buffer until it fits in RAM (may switch pixel format to BAYER).
int sensor_auto_crop_framebuffer();
// Copy a single line buffer to its destination. The copying process is
// DMA-accelerated, if available, and falls back to slow software if not.
int sensor_copy_line(void *dma, uint8_t *src, uint8_t *dst);
// Default snapshot function.
int sensor_snapshot(sensor_t *sensor, image_t *image, uint32_t flags);

View File

@ -30,6 +30,7 @@
#include "frogeye2020.h"
#include "gc2145.h"
#include "framebuffer.h"
#include "unaligned_memcpy.h"
#include "omv_boardconfig.h"
#include "omv_gpio.h"
#include "omv_i2c.h"
@ -1249,6 +1250,85 @@ __weak int sensor_auto_crop_framebuffer() {
return 0;
}
#define copy_transposed_line(dstp, srcp) \
for (int i = MAIN_FB()->u, h = MAIN_FB()->v; i; i--) { \
*dstp = *srcp++; \
dstp += h; \
}
#define copy_transposed_line_rev16(dstp, srcp) \
for (int i = MAIN_FB()->u, h = MAIN_FB()->v; i; i--) { \
*dstp = __REV16(*srcp++); \
dstp += h; \
}
__weak int sensor_copy_line(void *dma, uint8_t *src, uint8_t *dst) {
uint16_t *src16 = (uint16_t *) src;
uint16_t *dst16 = (uint16_t *) dst;
#if OMA_ENABLE_DMA_MEMCPY
extern int sensor_dma_memcpy(void *dma, void *dst, void *src, int bpp, bool transposed);
#endif
switch (sensor.pixformat) {
case PIXFORMAT_BAYER:
#if OMA_ENABLE_DMA_MEMCPY
sensor_dma_memcpy(dma, dst, src, sizeof(uint8_t), sensor.transpose);
#else
if (!sensor.transpose) {
unaligned_memcpy(dst, src, MAIN_FB()->u);
} else {
copy_transposed_line(dst, src);
}
#endif
break;
case PIXFORMAT_GRAYSCALE:
#if OMA_ENABLE_DMA_MEMCPY
sensor_dma_memcpy(dma, dst, src, sizeof(uint8_t), sensor.transpose);
#else
if (sensor.hw_flags.gs_bpp == 1) {
// 1BPP GRAYSCALE.
if (!sensor.transpose) {
unaligned_memcpy(dst, src, MAIN_FB()->u);
} else {
copy_transposed_line(dst, src);
}
} else {
// Extract Y channel from YUV.
if (!sensor.transpose) {
unaligned_2_to_1_memcpy(dst, src16, MAIN_FB()->u);
} else {
copy_transposed_line(dst, src16);
}
}
#endif
break;
case PIXFORMAT_RGB565:
case PIXFORMAT_YUV422:
#if OMA_ENABLE_DMA_MEMCPY
sensor_dma_memcpy(dma, dst16, src16, sizeof(uint16_t), sensor.transpose);
#else
if ((sensor.pixformat == PIXFORMAT_RGB565 && sensor.hw_flags.rgb_swap)
|| (sensor.pixformat == PIXFORMAT_YUV422 && sensor.hw_flags.yuv_swap)) {
if (!sensor.transpose) {
unaligned_memcpy_rev16(dst16, src16, MAIN_FB()->u);
} else {
copy_transposed_line_rev16(dst16, src16);
}
} else {
if (!sensor.transpose) {
unaligned_memcpy(dst16, src16, MAIN_FB()->u * sizeof(uint16_t));
} else {
copy_transposed_line(dst16, src16);
}
}
#endif
break;
default:
break;
}
return 0;
}
__weak int sensor_snapshot(sensor_t *sensor, image_t *image, uint32_t flags) {
return -1;
}

View File

@ -272,68 +272,8 @@ void sensor_line_callback(uint32_t addr) {
dst += MAIN_FB()->u * bytes_per_pixel * (buffer->offset - MAIN_FB()->y);
}
// Implement per line, per pixel cropping, and image transposing (for image rotation) in
// in software using the CPU to transfer the image from the line buffers to the frame buffer.
uint16_t *src16 = (uint16_t *) src;
uint16_t *dst16 = (uint16_t *) dst;
switch (sensor.pixformat) {
case PIXFORMAT_BAYER:
#if (OMV_ENABLE_SENSOR_EDMA == 1)
edma_memcpy(buffer, dst, src, sizeof(uint8_t), sensor.transpose);
#else
if (!sensor.transpose) {
unaligned_memcpy(dst, src, MAIN_FB()->u);
} else {
copy_transposed_line(dst, src);
}
#endif
break;
case PIXFORMAT_GRAYSCALE:
#if (OMV_ENABLE_SENSOR_EDMA == 1)
edma_memcpy(buffer, dst, src, sizeof(uint8_t), sensor.transpose);
#else
if (sensor.hw_flags.gs_bpp == 1) {
// 1BPP GRAYSCALE.
if (!sensor.transpose) {
unaligned_memcpy(dst, src, MAIN_FB()->u);
} else {
copy_transposed_line(dst, src);
}
} else {
// Extract Y channel from YUV.
if (!sensor.transpose) {
unaligned_2_to_1_memcpy(dst, src16, MAIN_FB()->u);
} else {
copy_transposed_line(dst, src16);
}
}
#endif
break;
case PIXFORMAT_RGB565:
case PIXFORMAT_YUV422:
#if (OMV_ENABLE_SENSOR_EDMA == 1)
edma_memcpy(buffer, dst16, src16, sizeof(uint16_t), sensor.transpose);
#else
if ((sensor.pixformat == PIXFORMAT_RGB565 && sensor.hw_flags.rgb_swap)
|| (sensor.pixformat == PIXFORMAT_YUV422 && sensor.hw_flags.yuv_swap)) {
if (!sensor.transpose) {
unaligned_memcpy_rev16(dst16, src16, MAIN_FB()->u);
} else {
copy_transposed_line_rev16(dst16, src16);
}
} else {
if (!sensor.transpose) {
unaligned_memcpy(dst16, src16, MAIN_FB()->u * sizeof(uint16_t));
} else {
copy_transposed_line(dst16, src16);
}
}
#endif
break;
default:
break;
}
// Copy line to frame buffer.
sensor_copy_line(NULL, src, dst);
}
if (++buffer->offset == resolution[sensor.framesize][1]) {

View File

@ -418,16 +418,13 @@ void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi) {
}
#if defined(OMV_MDMA_CHANNEL_DCMI_0)
static void mdma_memcpy(vbuffer_t *buffer, void *dst, void *src, int bpp, bool transposed) {
// We're using two handles to give each channel the maximum amount of time possible to do the line
// transfer. In most situations only one channel will be running at a time. However, if SDRAM is
// backedup we don't have to disable the channel if it is flushing trailing data to SDRAM.
MDMA_HandleTypeDef *handle = (buffer->offset % 2) ? &DCMI_MDMA_Handle1 : &DCMI_MDMA_Handle0;
int sensor_dma_memcpy(void *dma, void *dst, void *src, int bpp, bool transposed) {
MDMA_HandleTypeDef *handle = dma;
// Drop the frame if MDMA is not keeping up as the image will be corrupt.
if (handle->Instance->CCR & MDMA_CCR_EN) {
sensor.drop_frame = true;
return;
return 0;
}
// If MDMA is still running from a previous transfer HAL_MDMA_Start() will disable that transfer
@ -439,6 +436,7 @@ static void mdma_memcpy(vbuffer_t *buffer, void *dst, void *src, int bpp, bool t
(uint32_t) dst,
transposed ? bpp : (MAIN_FB()->u * bpp),
transposed ? MAIN_FB()->u : 1);
return 0;
}
#endif
@ -564,68 +562,14 @@ void DCMI_DMAConvCpltUser(uint32_t addr) {
dst += bytes_per_pixel * buffer->offset++;
}
// Implement per line, per pixel cropping, and image transposing (for image rotation) in
// in software using the CPU to transfer the image from the line buffers to the frame buffer.
uint16_t *src16 = (uint16_t *) src;
uint16_t *dst16 = (uint16_t *) dst;
switch (sensor.pixformat) {
case PIXFORMAT_BAYER:
#if defined(OMV_MDMA_CHANNEL_DCMI_0)
mdma_memcpy(buffer, dst, src, sizeof(uint8_t), sensor.transpose);
#else
if (!sensor.transpose) {
unaligned_memcpy(dst, src, MAIN_FB()->u);
} else {
copy_transposed_line(dst, src);
}
#endif
break;
case PIXFORMAT_GRAYSCALE:
#if defined(OMV_MDMA_CHANNEL_DCMI_0)
mdma_memcpy(buffer, dst, src, sizeof(uint8_t), sensor.transpose);
#else
if (sensor.hw_flags.gs_bpp == 1) {
// 1BPP GRAYSCALE.
if (!sensor.transpose) {
unaligned_memcpy(dst, src, MAIN_FB()->u);
} else {
copy_transposed_line(dst, src);
}
} else {
// Extract Y channel from YUV.
if (!sensor.transpose) {
unaligned_2_to_1_memcpy(dst, src16, MAIN_FB()->u);
} else {
copy_transposed_line(dst, src16);
}
}
#endif
break;
case PIXFORMAT_RGB565:
case PIXFORMAT_YUV422:
#if defined(OMV_MDMA_CHANNEL_DCMI_0)
mdma_memcpy(buffer, dst16, src16, sizeof(uint16_t), sensor.transpose);
#else
if ((sensor.pixformat == PIXFORMAT_RGB565 && sensor.hw_flags.rgb_swap)
|| (sensor.pixformat == PIXFORMAT_YUV422 && sensor.hw_flags.yuv_swap)) {
if (!sensor.transpose) {
unaligned_memcpy_rev16(dst16, src16, MAIN_FB()->u);
} else {
copy_transposed_line_rev16(dst16, src16);
}
} else {
if (!sensor.transpose) {
unaligned_memcpy(dst16, src16, MAIN_FB()->u * sizeof(uint16_t));
} else {
copy_transposed_line(dst16, src16);
}
}
#endif
break;
default:
break;
}
#if defined(OMV_MDMA_CHANNEL_DCMI_0)
// We're using two handles to give each channel the maximum amount of time possible to do the line
// transfer. In most situations only one channel will be running at a time. However, if SDRAM is
// backedup we don't have to disable the channel if it is flushing trailing data to SDRAM.
sensor_copy_line((buffer->offset % 2) ? &DCMI_MDMA_Handle1 : &DCMI_MDMA_Handle0, src, dst);
#else
sensor_copy_line(NULL, src, dst);
#endif
}
#if defined(OMV_MDMA_CHANNEL_DCMI_0)