arch(draw): add parallel rendering architecture

BREAKING CHANGE

This is a huge update which introduces parallel rendering. lv_conf.h needs to be updated too.
This commit is contained in:
Gabor Kiss-Vamosi
2023-07-05 13:05:19 +02:00
parent 08870996d1
commit f753265a79
637 changed files with 34425 additions and 35325 deletions

384
src/osal/lv_freertos.c Normal file
View File

@@ -0,0 +1,384 @@
/**
* @file lv_freertos.c
*
*/
/**
* Copyright 2023 NXP
*
* SPDX-License-Identifier: MIT
*/
/*********************
* INCLUDES
*********************/
#include "lv_os.h"
#if LV_USE_OS == LV_OS_FREERTOS
#include "atomic.h"
#include "../misc/lv_log.h"
/*********************
* DEFINES
*********************/
#define ulMAX_COUNT 10U
#ifndef pcTASK_NAME
#define pcTASK_NAME "lvglDraw"
#endif
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void prvRunThread(void * pxArg);
static void prvInitializeMutex(lv_mutex_t * pxMutex);
static void prvInitializeCond(lv_thread_sync_t * pxCond);
static void prvTestAndDecrement(lv_thread_sync_t * pxCond,
uint32_t ulLocalWaitingThreads);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_res_t lv_thread_init(lv_thread_t * pxThread, lv_thread_prio_t xSchedPriority,
void (*pvStartRoutine)(void *), size_t usStackSize,
void * xAttr)
{
pxThread->xTaskArg = xAttr;
pxThread->pvStartRoutine = (void * (*)(void *))pvStartRoutine;
BaseType_t xTaskCreateStatus = xTaskCreate(
prvRunThread,
pcTASK_NAME,
(uint16_t)usStackSize,
(void *)pxThread,
tskIDLE_PRIORITY + xSchedPriority,
&pxThread->xTaskHandle);
/* Ensure that the FreeRTOS task was successfully created. */
if(xTaskCreateStatus != pdPASS) {
LV_LOG_ERROR("xTaskCreate failed!");
return LV_RES_INV;
}
return LV_RES_OK;
}
lv_res_t lv_thread_delete(lv_thread_t * pxThread)
{
vTaskDelete(pxThread->xTaskHandle);
return LV_RES_OK;
}
lv_res_t lv_mutex_init(lv_mutex_t * pxMutex)
{
pxMutex->xMutex = xSemaphoreCreateMutex();
/* Ensure that the FreeRTOS mutex was successfully created. */
if(pxMutex->xMutex == NULL) {
LV_LOG_ERROR("xSemaphoreCreateMutex failed!");
return LV_RES_INV;
}
pxMutex->xIsInitialized = pdTRUE;
return LV_RES_OK;
}
lv_res_t lv_mutex_lock(lv_mutex_t * pxMutex)
{
/* If mutex in uninitialized, perform initialization. */
prvInitializeMutex(pxMutex);
BaseType_t xMutexTakeStatus = xSemaphoreTake(pxMutex->xMutex, portMAX_DELAY);
if(xMutexTakeStatus != pdTRUE) {
LV_LOG_ERROR("xSemaphoreTake failed!");
return LV_RES_INV;
}
return LV_RES_OK;
}
lv_res_t lv_mutex_lock_isr(lv_mutex_t * pxMutex)
{
//xSemaphoreTakeFromISR();
}
lv_res_t lv_mutex_unlock(lv_mutex_t * pxMutex)
{
/* If mutex in uninitialized, perform initialization. */
prvInitializeMutex(pxMutex);
BaseType_t xMutexGiveStatus = xSemaphoreGive(pxMutex->xMutex);
if(xMutexGiveStatus != pdTRUE) {
LV_LOG_ERROR("xSemaphoreGive failed!");
return LV_RES_INV;
}
return LV_RES_OK;
}
lv_res_t lv_mutex_delete(lv_mutex_t * pxMutex)
{
vSemaphoreDelete(pxMutex->xMutex);
pxMutex->xIsInitialized = pdFALSE;
return LV_RES_OK;
}
lv_res_t lv_thread_sync_init(lv_thread_sync_t * pxCond)
{
pxCond->xCondWaitSemaphore = xSemaphoreCreateCounting(ulMAX_COUNT, 0U);
/* Ensure that the FreeRTOS semaphore was successfully created. */
if(pxCond->xCondWaitSemaphore == NULL) {
LV_LOG_ERROR("xSemaphoreCreateCounting failed!");
return LV_RES_INV;
}
pxCond->xSyncMutex = xSemaphoreCreateMutex();
/* Ensure that the FreeRTOS mutex was successfully created. */
if(pxCond->xSyncMutex == NULL) {
LV_LOG_ERROR("xSemaphoreCreateMutex failed!");
return LV_RES_INV;
}
pxCond->ulWaitingThreads = 0;
pxCond->xSyncSignal = pdFALSE;
pxCond->xIsInitialized = pdTRUE;
return LV_RES_OK;
}
lv_res_t lv_thread_sync_wait(lv_thread_sync_t * pxCond)
{
lv_res_t lvRes = LV_RES_OK;
uint32_t ulLocalWaitingThreads;
/* If the cond is uninitialized, perform initialization. */
prvInitializeCond(pxCond);
/* Acquire the mutex. */
xSemaphoreTake(pxCond->xSyncMutex, portMAX_DELAY);
while(!pxCond->xSyncSignal) {
/* Increase the counter of threads blocking on condition variable, then
* release the mutex. */
/* Atomically increments thread waiting by 1, and
* stores number of threads waiting before increment. */
ulLocalWaitingThreads = Atomic_Increment_u32(&pxCond->ulWaitingThreads);
BaseType_t xMutexStatus = xSemaphoreGive(pxCond->xSyncMutex);
/* Wait on the condition variable. */
if(xMutexStatus == pdTRUE) {
BaseType_t xCondWaitStatus = xSemaphoreTake(
pxCond->xCondWaitSemaphore,
portMAX_DELAY);
/* Relock the mutex. */
xSemaphoreTake(pxCond->xSyncMutex, portMAX_DELAY);
if(xCondWaitStatus != pdTRUE) {
LV_LOG_ERROR("xSemaphoreTake(xCondWaitSemaphore) failed!");
lvRes = LV_RES_INV;
/* Atomically decrements thread waiting by 1.
* If iLocalWaitingThreads is updated by other thread(s) in between,
* this implementation guarantees to decrement by 1 based on the
* value currently in pxCond->ulWaitingThreads. */
prvTestAndDecrement(pxCond, ulLocalWaitingThreads + 1);
}
}
else {
LV_LOG_ERROR("xSemaphoreGive(xSyncMutex) failed!");
lvRes = LV_RES_INV;
/* Atomically decrements thread waiting by 1.
* If iLocalWaitingThreads is updated by other thread(s) in between,
* this implementation guarantees to decrement by 1 based on the
* value currently in pxCond->ulWaitingThreads. */
prvTestAndDecrement(pxCond, ulLocalWaitingThreads + 1);
}
}
pxCond->xSyncSignal = pdFALSE;
/* Release the mutex. */
xSemaphoreGive(pxCond->xSyncMutex);
return lvRes;
}
lv_res_t lv_thread_sync_signal(lv_thread_sync_t * pxCond)
{
/* If the cond is uninitialized, perform initialization. */
prvInitializeCond(pxCond);
/* Acquire the mutex. */
xSemaphoreTake(pxCond->xSyncMutex, portMAX_DELAY);
pxCond->xSyncSignal = pdTRUE;
/* Local copy of number of threads waiting. */
uint32_t ulLocalWaitingThreads = pxCond->ulWaitingThreads;
/* Test local copy of threads waiting is larger than zero. */
while(ulLocalWaitingThreads > 0) {
/* Atomically check whether the copy in memory has changed.
* If not, set the copy of threads waiting in memory to zero. */
if(ATOMIC_COMPARE_AND_SWAP_SUCCESS == Atomic_CompareAndSwap_u32(
&pxCond->ulWaitingThreads,
0,
ulLocalWaitingThreads)) {
/* Unblock all. */
for(int i = 0; i < ulLocalWaitingThreads; i++) {
xSemaphoreGive(pxCond->xCondWaitSemaphore);
}
break;
}
/* Local copy is out dated. Reload from memory and retry. */
ulLocalWaitingThreads = pxCond->ulWaitingThreads;
}
/* Release the mutex. */
xSemaphoreGive(pxCond->xSyncMutex);
return LV_RES_OK;
}
lv_res_t lv_thread_sync_delete(lv_thread_sync_t * pxCond)
{
/* Cleanup all resources used by the cond. */
vSemaphoreDelete(pxCond->xCondWaitSemaphore);
vSemaphoreDelete(pxCond->xSyncMutex);
pxCond->ulWaitingThreads = 0;
pxCond->xSyncSignal = pdFALSE;
pxCond->xIsInitialized = pdFALSE;
return LV_RES_OK;
}
/**********************
* STATIC FUNCTIONS
**********************/
static void prvRunThread(void * pxArg)
{
lv_thread_t * pxThread = (lv_thread_t *)pxArg;
/* Run the thread routine. */
pxThread->xReturn = pxThread->pvStartRoutine((void *)pxThread->xTaskArg);
vTaskDelete(NULL);
}
static void prvInitializeMutex(lv_mutex_t * pxMutex)
{
/* Check if the mutex needs to be initialized. */
if(pxMutex->xIsInitialized == pdFALSE) {
/* Mutex initialization must be in a critical section to prevent two threads
* from initializing it at the same time. */
taskENTER_CRITICAL();
/* Check again that the mutex is still uninitialized, i.e. it wasn't
* initialized while this function was waiting to enter the critical
* section. */
if(pxMutex->xIsInitialized == pdFALSE) {
pxMutex->xMutex = xSemaphoreCreateMutex();
/* Ensure that the FreeRTOS mutex was successfully created. */
if(pxMutex->xMutex == NULL) {
LV_LOG_ERROR("xSemaphoreCreateMutex failed!");
}
else {
/* Mutex successfully created. */
pxMutex->xIsInitialized = pdTRUE;
}
}
/* Exit the critical section. */
taskEXIT_CRITICAL();
}
}
static void prvInitializeCond(lv_thread_sync_t * pxCond)
{
BaseType_t xSemCreateStatus = pdTRUE;
/* Check if the condition variable needs to be initialized. */
if(pxCond->xIsInitialized == pdFALSE) {
/* Cond initialization must be in a critical section to prevent two
* threads from initializing it at the same time. */
taskENTER_CRITICAL();
pxCond->xCondWaitSemaphore = xSemaphoreCreateCounting(ulMAX_COUNT, 0U);
/* Ensure that the FreeRTOS semapahore was successfully created. */
if(pxCond->xCondWaitSemaphore == NULL) {
LV_LOG_ERROR("xSemaphoreCreateCounting failed!");
xSemCreateStatus = pdFALSE;
}
pxCond->xSyncMutex = xSemaphoreCreateMutex();
/* Ensure that the FreeRTOS mutex was successfully created. */
if(pxCond->xSyncMutex == NULL) {
LV_LOG_ERROR("xSemaphoreCreateMutex failed!");
xSemCreateStatus = pdFALSE;
}
if(xSemCreateStatus != pdFALSE) {
/* Condition variable successfully created. */
pxCond->ulWaitingThreads = 0;
pxCond->xSyncSignal = pdFALSE;
pxCond->xIsInitialized = pdTRUE;
}
/* Exit the critical section. */
taskEXIT_CRITICAL();
}
}
static void prvTestAndDecrement(lv_thread_sync_t * pxCond,
uint32_t ulLocalWaitingThreads)
{
/* Test local copy of threads waiting is larger than zero. */
while(ulLocalWaitingThreads > 0) {
/* Atomically check whether the copy in memory has changed.
* If not, decrease the copy of threads waiting in memory. */
if(ATOMIC_COMPARE_AND_SWAP_SUCCESS == Atomic_CompareAndSwap_u32(
&pxCond->ulWaitingThreads,
ulLocalWaitingThreads - 1,
ulLocalWaitingThreads)) {
/* Signal one succeeded. Break. */
break;
}
/* Local copy may be out dated. Reload from memory and retry. */
ulLocalWaitingThreads = pxCond->ulWaitingThreads;
}
}
#endif /*LV_USE_OS == LV_OS_FREERTOS*/