1
0
Fork 0
mirror of https://github.com/betaflight/betaflight.git synced 2025-07-19 14:25:20 +03:00

Add OSD background support for the static portions of display elements

Significantly reduces the time the OSD task spends drawing elements that are completely or mostly static. The larger the element the more time savings are realized. Currently implemented support for:
- Crosshairs
- Artificial Horizon Sidebars
- Craft name
- Display name
- Stick overlay

Since the static portions are only rendered once, the static elements add no processing time to the OSD task. As an example, enabling the above elements prior to these changes results in a total rendering time of 47us. After the enhancements they take only 6us (basically the rendering phase minimum overhead). So effectively 41us are removed from the OSD task.

Opens the possibility to add large mostly static elements with no additional overhead. An example would be a camera framing element that might draw a "box" around most of the screen. Previously this would add significant processing overhead to the OSD task, but now it will have no impact.
This commit is contained in:
Bruce Luckcuck 2019-10-02 17:47:10 -04:00
parent de768751b4
commit 5f5ee33718
15 changed files with 305 additions and 49 deletions

View file

@ -181,6 +181,15 @@
#define __spiBusTransactionEnd(busdev) {IOHi((busdev)->busdev_u.spi.csnPin);spiSetDivisor((busdev)->busdev_u.spi.instance, MAX7456_RESTORE_CLK);}
#endif
#define MAX7456_SUPPORTED_LAYER_COUNT (DISPLAYPORT_LAYER_BACKGROUND + 1)
typedef struct max7456Layer_s {
uint8_t buffer[VIDEO_BUFFER_CHARS_PAL];
} max7456Layer_t;
static max7456Layer_t displayLayers[MAX7456_SUPPORTED_LAYER_COUNT];
static displayPortLayer_e activeLayer = DISPLAYPORT_LAYER_FOREGROUND;
busDevice_t max7456BusDevice;
busDevice_t *busdev = &max7456BusDevice;
@ -188,11 +197,10 @@ static uint16_t max7456SpiClock = MAX7456_SPI_CLK;
uint16_t maxScreenSize = VIDEO_BUFFER_CHARS_PAL;
// We write everything in screenBuffer and then compare
// screenBuffer with shadowBuffer to upgrade only changed chars.
// We write everything to the active layer and then compare
// it with shadowBuffer to update only changed chars.
// This solution is faster then redrawing entire screen.
static uint8_t screenBuffer[VIDEO_BUFFER_CHARS_PAL+40]; // For faster writes we use memcpy so we need some space to don't overwrite buffer
static uint8_t shadowBuffer[VIDEO_BUFFER_CHARS_PAL];
//Max chars to update in one idle
@ -222,6 +230,16 @@ static uint8_t previousInvertRegister = INVALID_PREVIOUS_REGISTER_STATE;
static void max7456DrawScreenSlow(void);
static uint8_t *getLayerBuffer(displayPortLayer_e layer)
{
return displayLayers[layer].buffer;
}
static uint8_t *getActiveLayerBuffer(void)
{
return getLayerBuffer(activeLayer);
}
static uint8_t max7456Send(uint8_t add, uint8_t data)
{
spiTransferByte(busdev->busdev_u.spi.instance, add);
@ -349,11 +367,21 @@ uint8_t max7456GetRowsCount(void)
return (videoSignalReg & VIDEO_MODE_PAL) ? VIDEO_LINES_PAL : VIDEO_LINES_NTSC;
}
// When clearing the shadow buffer we fill with 0 so that the characters will
// be flagged as changed when compared to the 0x20 used in the layer buffers.
static void max7456ClearShadowBuffer(void)
{
memset(shadowBuffer, 0, maxScreenSize);
}
// Buffer is filled with the whitespace character (0x20)
static void max7456ClearLayer(displayPortLayer_e layer)
{
memset(getLayerBuffer(layer), 0x20, VIDEO_BUFFER_CHARS_PAL);
}
void max7456ReInit(void)
{
uint8_t srdata = 0;
@ -422,6 +450,11 @@ void max7456PreInit(const max7456Config_t *max7456Config)
bool max7456Init(const max7456Config_t *max7456Config, const vcdProfile_t *pVcdProfile, bool cpuOverclock)
{
// initialize all layers
for (unsigned i = 0; i < MAX7456_SUPPORTED_LAYER_COUNT; i++) {
max7456ClearLayer(i);
}
max7456HardwareReset();
if (!max7456Config->csTag || !max7456Config->spiDevice) {
@ -568,33 +601,58 @@ void max7456Brightness(uint8_t black, uint8_t white)
}
}
//just fill with spaces with some tricks
void max7456ClearScreen(void)
{
memset(screenBuffer, 0x20, VIDEO_BUFFER_CHARS_PAL);
}
uint8_t* max7456GetScreenBuffer(void)
{
return screenBuffer;
max7456ClearLayer(activeLayer);
}
void max7456WriteChar(uint8_t x, uint8_t y, uint8_t c)
{
uint8_t *buffer = getActiveLayerBuffer();
if (x < CHARS_PER_LINE && y < VIDEO_LINES_PAL) {
screenBuffer[y * CHARS_PER_LINE + x] = c;
buffer[y * CHARS_PER_LINE + x] = c;
}
}
void max7456Write(uint8_t x, uint8_t y, const char *buff)
{
if (y < VIDEO_LINES_PAL) {
uint8_t *buffer = getActiveLayerBuffer();
for (int i = 0; buff[i] && x + i < CHARS_PER_LINE; i++) {
screenBuffer[y * CHARS_PER_LINE + x + i] = buff[i];
buffer[y * CHARS_PER_LINE + x + i] = buff[i];
}
}
}
bool max7456LayerSupported(displayPortLayer_e layer)
{
if (layer == DISPLAYPORT_LAYER_FOREGROUND || layer == DISPLAYPORT_LAYER_BACKGROUND) {
return true;
} else {
return false;
}
}
bool max7456LayerSelect(displayPortLayer_e layer)
{
if (max7456LayerSupported(layer)) {
activeLayer = layer;
return true;
} else {
return false;
}
}
bool max7456LayerCopy(displayPortLayer_e destLayer, displayPortLayer_e sourceLayer)
{
if ((sourceLayer != destLayer) && max7456LayerSupported(sourceLayer) && max7456LayerSupported(destLayer)) {
memcpy(getLayerBuffer(destLayer), getLayerBuffer(sourceLayer), VIDEO_BUFFER_CHARS_PAL);
return true;
} else {
return false;
}
}
bool max7456DmaInProgress(void)
{
#ifdef MAX7456_DMA_CHANNEL_TX
@ -607,7 +665,7 @@ bool max7456DmaInProgress(void)
bool max7456BuffersSynced(void)
{
for (int i = 0; i < maxScreenSize; i++) {
if (screenBuffer[i] != shadowBuffer[i]) {
if (displayLayers[DISPLAYPORT_LAYER_FOREGROUND].buffer[i] != shadowBuffer[i]) {
return false;
}
}
@ -679,16 +737,18 @@ void max7456DrawScreen(void)
max7456ReInitIfRequired(false);
uint8_t *buffer = getActiveLayerBuffer();
int buff_len = 0;
for (int k = 0; k < MAX_CHARS2UPDATE; k++) {
if (screenBuffer[pos] != shadowBuffer[pos]) {
if (buffer[pos] != shadowBuffer[pos]) {
spiBuff[buff_len++] = MAX7456ADD_DMAH;
spiBuff[buff_len++] = pos >> 8;
spiBuff[buff_len++] = MAX7456ADD_DMAL;
spiBuff[buff_len++] = pos & 0xff;
spiBuff[buff_len++] = MAX7456ADD_DMDI;
spiBuff[buff_len++] = screenBuffer[pos];
shadowBuffer[pos] = screenBuffer[pos];
spiBuff[buff_len++] = buffer[pos];
shadowBuffer[pos] = buffer[pos];
}
if (++pos >= maxScreenSize) {
@ -712,23 +772,24 @@ void max7456DrawScreen(void)
static void max7456DrawScreenSlow(void)
{
bool escapeCharFound;
uint8_t *buffer = getActiveLayerBuffer();
__spiBusTransactionBegin(busdev);
// Enable auto-increment mode and update every character in the screenBuffer.
// Enable auto-increment mode and update every character in the active buffer.
// The "escape" character 0xFF must be skipped as it causes the MAX7456 to exit auto-increment mode.
max7456Send(MAX7456ADD_DMAH, 0);
max7456Send(MAX7456ADD_DMAL, 0);
max7456Send(MAX7456ADD_DMM, displayMemoryModeReg | 1);
for (int xx = 0; xx < maxScreenSize; xx++) {
if (screenBuffer[xx] == END_STRING) {
if (buffer[xx] == END_STRING) {
escapeCharFound = true;
max7456Send(MAX7456ADD_DMDI, ' '); // replace the 0xFF character with a blank in the first pass to avoid terminating auto-increment
} else {
max7456Send(MAX7456ADD_DMDI, screenBuffer[xx]);
max7456Send(MAX7456ADD_DMDI, buffer[xx]);
}
shadowBuffer[xx] = screenBuffer[xx];
shadowBuffer[xx] = buffer[xx];
}
max7456Send(MAX7456ADD_DMDI, END_STRING);
@ -738,7 +799,7 @@ static void max7456DrawScreenSlow(void)
// to update them with direct addressing
if (escapeCharFound) {
for (int xx = 0; xx < maxScreenSize; xx++) {
if (screenBuffer[xx] == END_STRING) {
if (buffer[xx] == END_STRING) {
max7456Send(MAX7456ADD_DMAH, xx >> 8);
max7456Send(MAX7456ADD_DMAL, xx & 0xFF);
max7456Send(MAX7456ADD_DMDI, END_STRING);