mirror of
https://github.com/betaflight/betaflight.git
synced 2025-07-23 08:15:30 +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:
parent
de768751b4
commit
5f5ee33718
15 changed files with 305 additions and 49 deletions
|
@ -28,14 +28,31 @@
|
|||
|
||||
Next add the element to the osdElementDisplayOrder array defined in this file.
|
||||
If the element needs special runtime conditional processing then it should be added
|
||||
to the osdAnalyzeActiveElements() function instead.
|
||||
to the osdAddActiveElements() function instead.
|
||||
|
||||
Create the function to "draw" the element. It should be named like "osdElementSomething()"
|
||||
where the "Something" describes the element.
|
||||
Create the function to "draw" the element.
|
||||
------------------------------------------
|
||||
It should be named like "osdElementSomething()" where the "Something" describes
|
||||
the element. The drawing function should only render the dynamic portions of the
|
||||
element. If the element has static (unchanging) portions then those should be
|
||||
rendered in the background function. The exception to this is elements that are
|
||||
expected to blink (have a warning associated). In this case the entire element
|
||||
must be handled in the main draw function and you can't use the background capability.
|
||||
|
||||
Add the mapping from the element ID added in the first step to the function
|
||||
created in the third step to the osdElementDrawFunction array.
|
||||
|
||||
Create the function to draw the element's static (background) portion.
|
||||
---------------------------------------------------------------------
|
||||
If an element has static (unchanging) portions then create a function to draw only those
|
||||
parts. It should be named like "osdBackgroundSomething()" where the "Something" matches
|
||||
the related element function.
|
||||
|
||||
Add the mapping for the element ID to the background drawing function to the
|
||||
osdElementBackgroundFunction array.
|
||||
|
||||
Accelerometer reqirement:
|
||||
-------------------------
|
||||
If the new element utilizes the accelerometer, add it to the osdElementsNeedAccelerometer() function.
|
||||
|
||||
Finally add a CLI parameter for the new element in cli/settings.c.
|
||||
|
@ -152,6 +169,7 @@ static const char compassBar[] = {
|
|||
|
||||
static unsigned activeOsdElementCount = 0;
|
||||
static uint8_t activeOsdElementArray[OSD_ITEM_COUNT];
|
||||
static bool backgroundLayerSupported = false;
|
||||
|
||||
// Blink control
|
||||
static bool blinkState = true;
|
||||
|
@ -578,7 +596,7 @@ static void osdElementCoreTemperature(osdElementParms_t *element)
|
|||
}
|
||||
#endif // USE_ADC_INTERNAL
|
||||
|
||||
static void osdElementCraftName(osdElementParms_t *element)
|
||||
static void osdBackgroundCraftName(osdElementParms_t *element)
|
||||
{
|
||||
if (strlen(pilotConfig()->name) == 0) {
|
||||
strcpy(element->buff, "CRAFT_NAME");
|
||||
|
@ -639,7 +657,7 @@ static void osdElementCrashFlipArrow(osdElementParms_t *element)
|
|||
}
|
||||
#endif // USE_ACC
|
||||
|
||||
static void osdElementCrosshairs(osdElementParms_t *element)
|
||||
static void osdBackgroundCrosshairs(osdElementParms_t *element)
|
||||
{
|
||||
element->buff[0] = SYM_AH_CENTER_LINE;
|
||||
element->buff[1] = SYM_AH_CENTER;
|
||||
|
@ -665,7 +683,7 @@ static void osdElementDisarmed(osdElementParms_t *element)
|
|||
}
|
||||
}
|
||||
|
||||
static void osdElementDisplayName(osdElementParms_t *element)
|
||||
static void osdBackgroundDisplayName(osdElementParms_t *element)
|
||||
{
|
||||
if (strlen(pilotConfig()->displayName) == 0) {
|
||||
strcpy(element->buff, "DISPLAY_NAME");
|
||||
|
@ -862,7 +880,7 @@ static void osdElementGpsSpeed(osdElementParms_t *element)
|
|||
}
|
||||
#endif // USE_GPS
|
||||
|
||||
static void osdElementHorizonSidebars(osdElementParms_t *element)
|
||||
static void osdBackgroundHorizonSidebars(osdElementParms_t *element)
|
||||
{
|
||||
// Draw AH sides
|
||||
const int8_t hudwidth = AH_SIDEBAR_WIDTH_POS;
|
||||
|
@ -1078,7 +1096,7 @@ static void osdElementRssiDbm(osdElementParms_t *element)
|
|||
#endif // USE_RX_RSSI_DBM
|
||||
|
||||
#ifdef USE_OSD_STICK_OVERLAY
|
||||
static void osdElementStickOverlay(osdElementParms_t *element)
|
||||
static void osdBackgroundStickOverlay(osdElementParms_t *element)
|
||||
{
|
||||
const uint8_t xpos = element->elemPosX;
|
||||
const uint8_t ypos = element->elemPosY;
|
||||
|
@ -1097,6 +1115,14 @@ static void osdElementStickOverlay(osdElementParms_t *element)
|
|||
}
|
||||
}
|
||||
|
||||
element->drawElement = false; // element already drawn
|
||||
}
|
||||
|
||||
static void osdElementStickOverlay(osdElementParms_t *element)
|
||||
{
|
||||
const uint8_t xpos = element->elemPosX;
|
||||
const uint8_t ypos = element->elemPosY;
|
||||
|
||||
// Now draw the cursor
|
||||
rc_alias_e vertical_channel, horizontal_channel;
|
||||
|
||||
|
@ -1410,7 +1436,7 @@ static void osdElementWarnings(osdElementParms_t *element)
|
|||
// Elements positioned later in the list will overlay the earlier
|
||||
// ones if their character positions overlap
|
||||
// Elements that need special runtime conditional processing should be added
|
||||
// to osdAnalyzeActiveElements()
|
||||
// to osdAddActiveElements()
|
||||
|
||||
static const uint8_t osdElementDisplayOrder[] = {
|
||||
OSD_MAIN_BATT_VOLTAGE,
|
||||
|
@ -1487,15 +1513,15 @@ static const uint8_t osdElementDisplayOrder[] = {
|
|||
const osdElementDrawFn osdElementDrawFunction[OSD_ITEM_COUNT] = {
|
||||
[OSD_RSSI_VALUE] = osdElementRssi,
|
||||
[OSD_MAIN_BATT_VOLTAGE] = osdElementMainBatteryVoltage,
|
||||
[OSD_CROSSHAIRS] = osdElementCrosshairs,
|
||||
[OSD_CROSSHAIRS] = NULL, // only has background
|
||||
#ifdef USE_ACC
|
||||
[OSD_ARTIFICIAL_HORIZON] = osdElementArtificialHorizon,
|
||||
#endif
|
||||
[OSD_HORIZON_SIDEBARS] = osdElementHorizonSidebars,
|
||||
[OSD_HORIZON_SIDEBARS] = NULL, // only has background
|
||||
[OSD_ITEM_TIMER_1] = osdElementTimer,
|
||||
[OSD_ITEM_TIMER_2] = osdElementTimer,
|
||||
[OSD_FLYMODE] = osdElementFlymode,
|
||||
[OSD_CRAFT_NAME] = osdElementCraftName,
|
||||
[OSD_CRAFT_NAME] = NULL, // only has background
|
||||
[OSD_THROTTLE_POS] = osdElementThrottlePosition,
|
||||
#ifdef USE_VTX_COMMON
|
||||
[OSD_VTX_CHANNEL] = osdElementVtxChannel,
|
||||
|
@ -1571,7 +1597,7 @@ const osdElementDrawFn osdElementDrawFunction[OSD_ITEM_COUNT] = {
|
|||
[OSD_STICK_OVERLAY_LEFT] = osdElementStickOverlay,
|
||||
[OSD_STICK_OVERLAY_RIGHT] = osdElementStickOverlay,
|
||||
#endif
|
||||
[OSD_DISPLAY_NAME] = osdElementDisplayName,
|
||||
[OSD_DISPLAY_NAME] = NULL, // only has background
|
||||
#if defined(USE_DSHOT_TELEMETRY) || defined(USE_ESC_SENSOR)
|
||||
[OSD_ESC_RPM_FREQ] = osdElementEscRpmFreq,
|
||||
#endif
|
||||
|
@ -1588,6 +1614,20 @@ const osdElementDrawFn osdElementDrawFunction[OSD_ITEM_COUNT] = {
|
|||
[OSD_RC_CHANNELS] = osdElementRcChannels,
|
||||
};
|
||||
|
||||
// Define the mapping between the OSD element id and the function to draw its background (static part)
|
||||
// Only necessary to define the entries that actually have a background function
|
||||
|
||||
const osdElementDrawFn osdElementBackgroundFunction[OSD_ITEM_COUNT] = {
|
||||
[OSD_CROSSHAIRS] = osdBackgroundCrosshairs,
|
||||
[OSD_HORIZON_SIDEBARS] = osdBackgroundHorizonSidebars,
|
||||
[OSD_CRAFT_NAME] = osdBackgroundCraftName,
|
||||
#ifdef USE_OSD_STICK_OVERLAY
|
||||
[OSD_STICK_OVERLAY_LEFT] = osdBackgroundStickOverlay,
|
||||
[OSD_STICK_OVERLAY_RIGHT] = osdBackgroundStickOverlay,
|
||||
#endif
|
||||
[OSD_DISPLAY_NAME] = osdBackgroundDisplayName,
|
||||
};
|
||||
|
||||
static void osdAddActiveElement(osd_items_e element)
|
||||
{
|
||||
if (VISIBLE(osdConfig()->item_pos[element])) {
|
||||
|
@ -1598,7 +1638,7 @@ static void osdAddActiveElement(osd_items_e element)
|
|||
// Examine the elements and build a list of only the active (enabled)
|
||||
// ones to speed up rendering.
|
||||
|
||||
void osdAnalyzeActiveElements(void)
|
||||
void osdAddActiveElements(void)
|
||||
{
|
||||
activeOsdElementCount = 0;
|
||||
|
||||
|
@ -1638,10 +1678,14 @@ void osdAnalyzeActiveElements(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
static bool osdDrawSingleElement(displayPort_t *osdDisplayPort, uint8_t item)
|
||||
static void osdDrawSingleElement(displayPort_t *osdDisplayPort, uint8_t item)
|
||||
{
|
||||
if (!osdElementDrawFunction[item]) {
|
||||
// Element has no drawing function
|
||||
return;
|
||||
}
|
||||
if (BLINK(item)) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t elemPosX = OSD_X(osdConfig()->item_pos[item]);
|
||||
|
@ -1661,8 +1705,32 @@ static bool osdDrawSingleElement(displayPort_t *osdDisplayPort, uint8_t item)
|
|||
if (element.drawElement) {
|
||||
displayWrite(osdDisplayPort, elemPosX, elemPosY, buff);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
static void osdDrawSingleElementBackground(displayPort_t *osdDisplayPort, uint8_t item)
|
||||
{
|
||||
if (!osdElementBackgroundFunction[item]) {
|
||||
// Element has no background drawing function
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t elemPosX = OSD_X(osdConfig()->item_pos[item]);
|
||||
uint8_t elemPosY = OSD_Y(osdConfig()->item_pos[item]);
|
||||
char buff[OSD_ELEMENT_BUFFER_LENGTH] = "";
|
||||
|
||||
osdElementParms_t element;
|
||||
element.item = item;
|
||||
element.elemPosX = elemPosX;
|
||||
element.elemPosY = elemPosY;
|
||||
element.buff = (char *)&buff;
|
||||
element.osdDisplayPort = osdDisplayPort;
|
||||
element.drawElement = true;
|
||||
|
||||
// Call the element background drawing function
|
||||
osdElementBackgroundFunction[item](&element);
|
||||
if (element.drawElement) {
|
||||
displayWrite(osdDisplayPort, elemPosX, elemPosY, buff);
|
||||
}
|
||||
}
|
||||
|
||||
void osdDrawActiveElements(displayPort_t *osdDisplayPort, timeUs_t currentTimeUs)
|
||||
|
@ -1681,10 +1749,33 @@ void osdDrawActiveElements(displayPort_t *osdDisplayPort, timeUs_t currentTimeUs
|
|||
blinkState = (currentTimeUs / 200000) % 2;
|
||||
|
||||
for (unsigned i = 0; i < activeOsdElementCount; i++) {
|
||||
if (!backgroundLayerSupported) {
|
||||
// If the background layer isn't supported then we
|
||||
// have to draw the element's static layer as well.
|
||||
osdDrawSingleElementBackground(osdDisplayPort, activeOsdElementArray[i]);
|
||||
}
|
||||
osdDrawSingleElement(osdDisplayPort, activeOsdElementArray[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void osdDrawActiveElementsBackground(displayPort_t *osdDisplayPort)
|
||||
{
|
||||
if (backgroundLayerSupported) {
|
||||
displayLayerSelect(osdDisplayPort, DISPLAYPORT_LAYER_BACKGROUND);
|
||||
displayClearScreen(osdDisplayPort);
|
||||
for (unsigned i = 0; i < activeOsdElementCount; i++) {
|
||||
osdDrawSingleElementBackground(osdDisplayPort, activeOsdElementArray[i]);
|
||||
}
|
||||
displayLayerSelect(osdDisplayPort, DISPLAYPORT_LAYER_FOREGROUND);
|
||||
}
|
||||
}
|
||||
|
||||
void osdElementsInit(bool backgroundLayerFlag)
|
||||
{
|
||||
backgroundLayerSupported = backgroundLayerFlag;
|
||||
activeOsdElementCount = 0;
|
||||
}
|
||||
|
||||
void osdResetAlarms(void)
|
||||
{
|
||||
memset(blinkBits, 0, sizeof(blinkBits));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue