perf: Enable 512KB LVGL image cache on PSRAM and move modified lvgl to local components
This commit is contained in:
@@ -0,0 +1,472 @@
|
||||
/**
|
||||
* @file lv_draw_dma2d.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_dma2d_private.h"
|
||||
#if LV_USE_DRAW_DMA2D
|
||||
|
||||
#include "../sw/lv_draw_sw.h"
|
||||
#include "../../misc/lv_area_private.h"
|
||||
|
||||
#if !LV_DRAW_DMA2D_ASYNC && LV_USE_DRAW_DMA2D_INTERRUPT
|
||||
#warning LV_USE_DRAW_DMA2D_INTERRUPT is 1 but has no effect because LV_USE_OS is LV_OS_NONE
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#define DRAW_UNIT_ID_DMA2D 5
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static int32_t evaluate_cb(lv_draw_unit_t * draw_unit, lv_draw_task_t * task);
|
||||
static int32_t dispatch_cb(lv_draw_unit_t * draw_unit, lv_layer_t * layer);
|
||||
static int32_t delete_cb(lv_draw_unit_t * draw_unit);
|
||||
#if LV_DRAW_DMA2D_ASYNC
|
||||
static void thread_cb(void * arg);
|
||||
#endif
|
||||
#if !LV_DRAW_DMA2D_ASYNC
|
||||
static bool check_transfer_completion(void);
|
||||
#endif
|
||||
static void post_transfer_tasks(lv_draw_dma2d_unit_t * u);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
#if LV_DRAW_DMA2D_ASYNC
|
||||
static lv_draw_dma2d_unit_t * g_unit;
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_dma2d_init(void)
|
||||
{
|
||||
lv_draw_dma2d_unit_t * draw_dma2d_unit = lv_draw_create_unit(sizeof(lv_draw_dma2d_unit_t));
|
||||
draw_dma2d_unit->base_unit.evaluate_cb = evaluate_cb;
|
||||
draw_dma2d_unit->base_unit.dispatch_cb = dispatch_cb;
|
||||
draw_dma2d_unit->base_unit.delete_cb = delete_cb;
|
||||
draw_dma2d_unit->base_unit.name = "DMA2D";
|
||||
|
||||
#if LV_DRAW_DMA2D_ASYNC
|
||||
g_unit = draw_dma2d_unit;
|
||||
|
||||
lv_result_t res = lv_thread_init(&draw_dma2d_unit->thread, "dma2d", LV_DRAW_THREAD_PRIO, thread_cb, 2 * 1024,
|
||||
draw_dma2d_unit);
|
||||
LV_ASSERT(res == LV_RESULT_OK);
|
||||
#endif
|
||||
|
||||
/* enable the DMA2D clock */
|
||||
#if defined(STM32F4) || defined(STM32F7) || defined(STM32U5)
|
||||
RCC->AHB1ENR |= RCC_AHB1ENR_DMA2DEN;
|
||||
#elif defined(STM32H7)
|
||||
RCC->AHB3ENR |= RCC_AHB3ENR_DMA2DEN;
|
||||
#elif defined(STM32H7RS)
|
||||
RCC->AHB5ENR |= RCC_AHB5ENR_DMA2DEN;
|
||||
#else
|
||||
#warning "LVGL can't enable the clock for DMA2D"
|
||||
#endif
|
||||
|
||||
/* disable dead time */
|
||||
DMA2D->AMTCR = 0;
|
||||
|
||||
/* enable the interrupt */
|
||||
NVIC_EnableIRQ(DMA2D_IRQn);
|
||||
}
|
||||
|
||||
void lv_draw_dma2d_deinit(void)
|
||||
{
|
||||
/* disable the interrupt */
|
||||
NVIC_DisableIRQ(DMA2D_IRQn);
|
||||
|
||||
/* disable the DMA2D clock */
|
||||
#if defined(STM32F4) || defined(STM32F7) || defined(STM32U5) || defined(STM32L4)
|
||||
RCC->AHB1ENR &= ~RCC_AHB1ENR_DMA2DEN;
|
||||
#elif defined(STM32H7)
|
||||
RCC->AHB3ENR &= ~RCC_AHB3ENR_DMA2DEN;
|
||||
#elif defined(STM32H7RS)
|
||||
RCC->AHB5ENR &= ~RCC_AHB5ENR_DMA2DEN;
|
||||
#endif
|
||||
|
||||
#if LV_DRAW_DMA2D_ASYNC
|
||||
lv_result_t res = lv_thread_delete(&g_unit->thread);
|
||||
LV_ASSERT(res == LV_RESULT_OK);
|
||||
|
||||
res = lv_thread_sync_delete(&g_unit->interrupt_signal);
|
||||
LV_ASSERT(res == LV_RESULT_OK);
|
||||
|
||||
g_unit = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if LV_USE_DRAW_DMA2D_INTERRUPT
|
||||
void lv_draw_dma2d_transfer_complete_interrupt_handler(void)
|
||||
{
|
||||
#if LV_DRAW_DMA2D_ASYNC
|
||||
lv_thread_sync_signal_isr(&g_unit->interrupt_signal);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
lv_draw_dma2d_output_cf_t lv_draw_dma2d_cf_to_dma2d_output_cf(lv_color_format_t cf)
|
||||
{
|
||||
switch(cf) {
|
||||
case LV_COLOR_FORMAT_ARGB8888:
|
||||
case LV_COLOR_FORMAT_XRGB8888:
|
||||
return LV_DRAW_DMA2D_OUTPUT_CF_ARGB8888;
|
||||
case LV_COLOR_FORMAT_RGB888:
|
||||
return LV_DRAW_DMA2D_OUTPUT_CF_RGB888;
|
||||
case LV_COLOR_FORMAT_RGB565:
|
||||
return LV_DRAW_DMA2D_OUTPUT_CF_RGB565;
|
||||
case LV_COLOR_FORMAT_ARGB1555:
|
||||
return LV_DRAW_DMA2D_OUTPUT_CF_ARGB1555;
|
||||
default:
|
||||
LV_ASSERT_MSG(false, "unsupported output color format");
|
||||
}
|
||||
return LV_DRAW_DMA2D_OUTPUT_CF_RGB565;
|
||||
}
|
||||
|
||||
uint32_t lv_draw_dma2d_color_to_dma2d_color(lv_draw_dma2d_output_cf_t cf, lv_color_t color)
|
||||
{
|
||||
switch(cf) {
|
||||
case LV_DRAW_DMA2D_OUTPUT_CF_ARGB8888:
|
||||
case LV_DRAW_DMA2D_OUTPUT_CF_RGB888:
|
||||
return lv_color_to_u32(color);
|
||||
case LV_DRAW_DMA2D_OUTPUT_CF_RGB565:
|
||||
return lv_color_to_u16(color);
|
||||
default:
|
||||
LV_ASSERT_MSG(false, "unsupported output color format");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void lv_draw_dma2d_configure_and_start_transfer(const lv_draw_dma2d_configuration_t * conf)
|
||||
{
|
||||
/* number of lines register */
|
||||
DMA2D->NLR = (conf->w << DMA2D_NLR_PL_Pos) | (conf->h << DMA2D_NLR_NL_Pos);
|
||||
|
||||
/* output */
|
||||
|
||||
/* output memory address register */
|
||||
DMA2D->OMAR = (uint32_t)(uintptr_t) conf->output_address;
|
||||
/* output offset register */
|
||||
DMA2D->OOR = conf->output_offset;
|
||||
/* output pixel format converter control register */
|
||||
DMA2D->OPFCCR = ((uint32_t) conf->output_cf) << DMA2D_OPFCCR_CM_Pos;
|
||||
|
||||
/* Fill color. Only for mode LV_DRAW_DMA2D_MODE_REGISTER_TO_MEMORY */
|
||||
DMA2D->OCOLR = conf->reg_to_mem_mode_color;
|
||||
|
||||
/* foreground */
|
||||
|
||||
/* foreground memory address register */
|
||||
DMA2D->FGMAR = (uint32_t)(uintptr_t) conf->fg_address;
|
||||
/* foreground offset register */
|
||||
DMA2D->FGOR = conf->fg_offset;
|
||||
/* foreground color. only for mem-to-mem with blending and fixed-color foreground */
|
||||
DMA2D->FGCOLR = conf->fg_color;
|
||||
/* foreground pixel format converter control register */
|
||||
DMA2D->FGPFCCR = (((uint32_t) conf->fg_cf) << DMA2D_FGPFCCR_CM_Pos)
|
||||
| (conf->fg_alpha << DMA2D_FGPFCCR_ALPHA_Pos)
|
||||
| (conf->fg_alpha_mode << DMA2D_FGPFCCR_AM_Pos);
|
||||
|
||||
/* background */
|
||||
|
||||
DMA2D->BGMAR = (uint32_t)(uintptr_t) conf->bg_address;
|
||||
DMA2D->BGOR = conf->bg_offset;
|
||||
DMA2D->BGCOLR = conf->bg_color;
|
||||
DMA2D->BGPFCCR = (((uint32_t) conf->bg_cf) << DMA2D_BGPFCCR_CM_Pos)
|
||||
| (conf->bg_alpha << DMA2D_BGPFCCR_ALPHA_Pos)
|
||||
| (conf->bg_alpha_mode << DMA2D_BGPFCCR_AM_Pos);
|
||||
|
||||
/* ensure the DMA2D register values are observed before the start transfer bit is set */
|
||||
__DSB();
|
||||
|
||||
/* start the transfer (also set mode and enable transfer complete interrupt) */
|
||||
DMA2D->CR = DMA2D_CR_START | (((uint32_t) conf->mode) << DMA2D_CR_MODE_Pos)
|
||||
#if LV_USE_DRAW_DMA2D_INTERRUPT
|
||||
| DMA2D_CR_TCIE
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
#if LV_DRAW_DMA2D_CACHE
|
||||
void lv_draw_dma2d_invalidate_cache(const lv_draw_dma2d_cache_area_t * mem_area)
|
||||
{
|
||||
if((SCB->CCR & SCB_CCR_DC_Msk) == 0) return; /* data cache is disabled */
|
||||
|
||||
uint32_t rows_remaining = mem_area->height;
|
||||
uint32_t row_addr = (uint32_t)(uintptr_t) mem_area->first_byte;
|
||||
uint32_t row_end_addr = 0;
|
||||
|
||||
__DSB();
|
||||
|
||||
while(rows_remaining) {
|
||||
uint32_t addr = row_addr & ~(__SCB_DCACHE_LINE_SIZE - 1U);
|
||||
uint32_t cache_lines = ((((row_addr + mem_area->width_bytes - 1) & ~(__SCB_DCACHE_LINE_SIZE - 1U)) - addr) /
|
||||
__SCB_DCACHE_LINE_SIZE) + 1;
|
||||
|
||||
if(addr == row_end_addr) {
|
||||
addr += __SCB_DCACHE_LINE_SIZE;
|
||||
cache_lines--;
|
||||
}
|
||||
|
||||
while(cache_lines) {
|
||||
SCB->DCIMVAC = addr;
|
||||
addr += __SCB_DCACHE_LINE_SIZE;
|
||||
cache_lines--;
|
||||
}
|
||||
|
||||
row_end_addr = addr - __SCB_DCACHE_LINE_SIZE;
|
||||
row_addr += mem_area->stride;
|
||||
rows_remaining--;
|
||||
};
|
||||
|
||||
__DSB();
|
||||
__ISB();
|
||||
}
|
||||
|
||||
void lv_draw_dma2d_clean_cache(const lv_draw_dma2d_cache_area_t * mem_area)
|
||||
{
|
||||
if((SCB->CCR & SCB_CCR_DC_Msk) == 0) return; /* data cache is disabled */
|
||||
|
||||
uint32_t rows_remaining = mem_area->height;
|
||||
uint32_t row_addr = (uint32_t)(uintptr_t) mem_area->first_byte;
|
||||
uint32_t row_end_addr = 0;
|
||||
|
||||
__DSB();
|
||||
|
||||
while(rows_remaining) {
|
||||
uint32_t addr = row_addr & ~(__SCB_DCACHE_LINE_SIZE - 1U);
|
||||
uint32_t cache_lines = ((((row_addr + mem_area->width_bytes - 1) & ~(__SCB_DCACHE_LINE_SIZE - 1U)) - addr) /
|
||||
__SCB_DCACHE_LINE_SIZE) + 1;
|
||||
|
||||
if(addr == row_end_addr) {
|
||||
addr += __SCB_DCACHE_LINE_SIZE;
|
||||
cache_lines--;
|
||||
}
|
||||
|
||||
while(cache_lines) {
|
||||
SCB->DCCMVAC = addr;
|
||||
addr += __SCB_DCACHE_LINE_SIZE;
|
||||
cache_lines--;
|
||||
}
|
||||
|
||||
row_end_addr = addr - __SCB_DCACHE_LINE_SIZE;
|
||||
row_addr += mem_area->stride;
|
||||
rows_remaining--;
|
||||
};
|
||||
|
||||
__DSB();
|
||||
__ISB();
|
||||
}
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static int32_t evaluate_cb(lv_draw_unit_t * draw_unit, lv_draw_task_t * task)
|
||||
{
|
||||
switch(task->type) {
|
||||
case LV_DRAW_TASK_TYPE_FILL: {
|
||||
lv_draw_fill_dsc_t * dsc = task->draw_dsc;
|
||||
if(!(dsc->radius == 0
|
||||
&& dsc->grad.dir == LV_GRAD_DIR_NONE
|
||||
&& (dsc->base.layer->color_format == LV_COLOR_FORMAT_ARGB8888
|
||||
|| dsc->base.layer->color_format == LV_COLOR_FORMAT_XRGB8888
|
||||
|| dsc->base.layer->color_format == LV_COLOR_FORMAT_RGB888
|
||||
|| dsc->base.layer->color_format == LV_COLOR_FORMAT_RGB565))) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_IMAGE: {
|
||||
lv_draw_image_dsc_t * dsc = task->draw_dsc;
|
||||
if(!(dsc->header.cf < LV_COLOR_FORMAT_PROPRIETARY_START
|
||||
&& dsc->clip_radius == 0
|
||||
&& dsc->bitmap_mask_src == NULL
|
||||
&& dsc->sup == NULL
|
||||
&& dsc->tile == 0
|
||||
&& dsc->blend_mode == LV_BLEND_MODE_NORMAL
|
||||
&& dsc->recolor_opa <= LV_OPA_MIN
|
||||
&& dsc->skew_y == 0
|
||||
&& dsc->skew_x == 0
|
||||
&& dsc->scale_x == 256
|
||||
&& dsc->scale_y == 256
|
||||
&& dsc->rotation == 0
|
||||
&& lv_image_src_get_type(dsc->src) == LV_IMAGE_SRC_VARIABLE
|
||||
&& (dsc->header.cf == LV_COLOR_FORMAT_ARGB8888
|
||||
|| dsc->header.cf == LV_COLOR_FORMAT_XRGB8888
|
||||
|| dsc->header.cf == LV_COLOR_FORMAT_RGB888
|
||||
|| dsc->header.cf == LV_COLOR_FORMAT_RGB565
|
||||
|| dsc->header.cf == LV_COLOR_FORMAT_ARGB1555)
|
||||
&& (dsc->base.layer->color_format == LV_COLOR_FORMAT_ARGB8888
|
||||
|| dsc->base.layer->color_format == LV_COLOR_FORMAT_XRGB8888
|
||||
|| dsc->base.layer->color_format == LV_COLOR_FORMAT_RGB888
|
||||
|| dsc->base.layer->color_format == LV_COLOR_FORMAT_RGB565))) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
task->preferred_draw_unit_id = DRAW_UNIT_ID_DMA2D;
|
||||
task->preference_score = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t dispatch_cb(lv_draw_unit_t * draw_unit, lv_layer_t * layer)
|
||||
{
|
||||
lv_draw_dma2d_unit_t * draw_dma2d_unit = (lv_draw_dma2d_unit_t *) draw_unit;
|
||||
|
||||
if(draw_dma2d_unit->task_act) {
|
||||
#if LV_DRAW_DMA2D_ASYNC
|
||||
/*Return immediately if it's busy with draw task*/
|
||||
return 0;
|
||||
#else
|
||||
if(!check_transfer_completion()) {
|
||||
return LV_DRAW_UNIT_IDLE;
|
||||
}
|
||||
post_transfer_tasks(draw_dma2d_unit);
|
||||
#endif
|
||||
}
|
||||
|
||||
lv_draw_task_t * t = lv_draw_get_available_task(layer, NULL, DRAW_UNIT_ID_DMA2D);
|
||||
if(t == NULL) {
|
||||
return LV_DRAW_UNIT_IDLE;
|
||||
}
|
||||
|
||||
void * buf = lv_draw_layer_alloc_buf(layer);
|
||||
if(buf == NULL) {
|
||||
return LV_DRAW_UNIT_IDLE;
|
||||
}
|
||||
|
||||
t->state = LV_DRAW_TASK_STATE_IN_PROGRESS;
|
||||
t->draw_unit = draw_unit;
|
||||
draw_dma2d_unit->task_act = t;
|
||||
|
||||
if(t->type == LV_DRAW_TASK_TYPE_FILL) {
|
||||
lv_draw_fill_dsc_t * dsc = t->draw_dsc;
|
||||
const lv_area_t * coords = &t->area;
|
||||
lv_area_t clipped_coords;
|
||||
if(!lv_area_intersect(&clipped_coords, coords, &t->clip_area)) {
|
||||
return LV_DRAW_UNIT_IDLE;
|
||||
}
|
||||
|
||||
void * dest = lv_draw_layer_go_to_xy(layer,
|
||||
clipped_coords.x1 - layer->buf_area.x1,
|
||||
clipped_coords.y1 - layer->buf_area.y1);
|
||||
|
||||
if(dsc->opa >= LV_OPA_MAX) {
|
||||
lv_draw_dma2d_opaque_fill(t,
|
||||
dest,
|
||||
lv_area_get_width(&clipped_coords),
|
||||
lv_area_get_height(&clipped_coords),
|
||||
lv_draw_buf_width_to_stride(lv_area_get_width(&layer->buf_area), dsc->base.layer->color_format));
|
||||
}
|
||||
else {
|
||||
lv_draw_dma2d_fill(t,
|
||||
dest,
|
||||
lv_area_get_width(&clipped_coords),
|
||||
lv_area_get_height(&clipped_coords),
|
||||
lv_draw_buf_width_to_stride(lv_area_get_width(&layer->buf_area), dsc->base.layer->color_format));
|
||||
}
|
||||
}
|
||||
else if(t->type == LV_DRAW_TASK_TYPE_IMAGE) {
|
||||
lv_draw_image_dsc_t * dsc = t->draw_dsc;
|
||||
const lv_area_t * coords = &t->area;
|
||||
lv_area_t clipped_coords;
|
||||
if(!lv_area_intersect(&clipped_coords, coords, &t->clip_area)) {
|
||||
return LV_DRAW_UNIT_IDLE;
|
||||
}
|
||||
|
||||
void * dest = lv_draw_layer_go_to_xy(layer,
|
||||
clipped_coords.x1 - layer->buf_area.x1,
|
||||
clipped_coords.y1 - layer->buf_area.y1);
|
||||
|
||||
if(dsc->opa >= LV_OPA_MAX) {
|
||||
lv_draw_dma2d_opaque_image(
|
||||
t,
|
||||
dest,
|
||||
&clipped_coords,
|
||||
lv_draw_buf_width_to_stride(lv_area_get_width(&layer->buf_area), dsc->base.layer->color_format));
|
||||
}
|
||||
else {
|
||||
lv_draw_dma2d_image(
|
||||
t,
|
||||
dest,
|
||||
&clipped_coords,
|
||||
lv_draw_buf_width_to_stride(lv_area_get_width(&layer->buf_area), dsc->base.layer->color_format));
|
||||
}
|
||||
}
|
||||
|
||||
#if !LV_DRAW_DMA2D_ASYNC
|
||||
lv_draw_dispatch_request();
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int32_t delete_cb(lv_draw_unit_t * draw_unit)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if LV_DRAW_DMA2D_ASYNC
|
||||
static void thread_cb(void * arg)
|
||||
{
|
||||
lv_draw_dma2d_unit_t * u = arg;
|
||||
|
||||
lv_thread_sync_init(&u->interrupt_signal);
|
||||
|
||||
while(1) {
|
||||
|
||||
do {
|
||||
lv_thread_sync_wait(&u->interrupt_signal);
|
||||
} while(u->task_act != NULL);
|
||||
|
||||
post_transfer_tasks(u);
|
||||
lv_draw_dispatch_request();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !LV_DRAW_DMA2D_ASYNC
|
||||
static bool check_transfer_completion(void)
|
||||
{
|
||||
return !(DMA2D->CR & DMA2D_CR_START);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void post_transfer_tasks(lv_draw_dma2d_unit_t * u)
|
||||
{
|
||||
#if LV_DRAW_DMA2D_CACHE
|
||||
lv_draw_dma2d_invalidate_cache(&u->writing_area);
|
||||
#endif
|
||||
u->task_act->state = LV_DRAW_TASK_STATE_READY;
|
||||
u->task_act = NULL;
|
||||
}
|
||||
|
||||
#endif /*LV_USE_DRAW_DMA2D*/
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* @file lv_draw_dma2d.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_DMA2D_H
|
||||
#define LV_DRAW_DMA2D_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../lv_conf_internal.h"
|
||||
#if LV_USE_DRAW_DMA2D
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
void lv_draw_dma2d_init(void);
|
||||
void lv_draw_dma2d_deinit(void);
|
||||
|
||||
#if LV_USE_DRAW_DMA2D_INTERRUPT
|
||||
void lv_draw_dma2d_transfer_complete_interrupt_handler(void);
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_DRAW_DMA2D*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_DMA2D_H*/
|
||||
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
* @file lv_draw_dma2d_fill.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_dma2d_private.h"
|
||||
#if LV_USE_DRAW_DMA2D
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_dma2d_opaque_fill(lv_draw_task_t * t, void * first_pixel, int32_t w, int32_t h, int32_t stride)
|
||||
{
|
||||
lv_draw_fill_dsc_t * dsc = t->draw_dsc;
|
||||
lv_color_format_t cf = dsc->base.layer->color_format;
|
||||
|
||||
lv_draw_dma2d_output_cf_t output_cf = lv_draw_dma2d_cf_to_dma2d_output_cf(cf);
|
||||
uint32_t cf_size = LV_COLOR_FORMAT_GET_SIZE(cf);
|
||||
uint32_t reg_to_mem_color = lv_draw_dma2d_color_to_dma2d_color(output_cf, dsc->color);
|
||||
|
||||
#if LV_DRAW_DMA2D_CACHE
|
||||
lv_draw_dma2d_cache_area_t cache_area = {
|
||||
.first_byte = first_pixel,
|
||||
.width_bytes = w * cf_size,
|
||||
.height = h,
|
||||
.stride = stride
|
||||
};
|
||||
lv_draw_dma2d_unit_t * u = (lv_draw_dma2d_unit_t *) t->draw_unit;
|
||||
lv_memcpy(&u->writing_area, &cache_area, sizeof(lv_draw_dma2d_cache_area_t));
|
||||
#endif
|
||||
|
||||
lv_draw_dma2d_configuration_t conf = {
|
||||
.mode = LV_DRAW_DMA2D_MODE_REGISTER_TO_MEMORY,
|
||||
.w = w,
|
||||
.h = h,
|
||||
|
||||
.output_address = first_pixel,
|
||||
.output_offset = (stride / cf_size) - w,
|
||||
.output_cf = output_cf,
|
||||
|
||||
.reg_to_mem_mode_color = reg_to_mem_color
|
||||
};
|
||||
lv_draw_dma2d_configure_and_start_transfer(&conf);
|
||||
}
|
||||
|
||||
void lv_draw_dma2d_fill(lv_draw_task_t * t, void * first_pixel, int32_t w, int32_t h, int32_t stride)
|
||||
{
|
||||
lv_draw_fill_dsc_t * dsc = t->draw_dsc;
|
||||
lv_color_t color = dsc->color;
|
||||
lv_color_format_t cf = dsc->base.layer->color_format;
|
||||
lv_opa_t opa = dsc->opa;
|
||||
|
||||
lv_draw_dma2d_output_cf_t output_cf = lv_draw_dma2d_cf_to_dma2d_output_cf(cf);
|
||||
uint32_t cf_size = LV_COLOR_FORMAT_GET_SIZE(cf);
|
||||
|
||||
#if LV_DRAW_DMA2D_CACHE
|
||||
lv_draw_dma2d_cache_area_t cache_area = {
|
||||
.first_byte = first_pixel,
|
||||
.width_bytes = w * cf_size,
|
||||
.height = h,
|
||||
.stride = stride
|
||||
};
|
||||
lv_draw_dma2d_unit_t * u = (lv_draw_dma2d_unit_t *) t->draw_unit;
|
||||
lv_memcpy(&u->writing_area, &cache_area, sizeof(lv_draw_dma2d_cache_area_t));
|
||||
|
||||
/* make sure the background area DMA2D is blending is up-to-date in main memory */
|
||||
lv_draw_dma2d_clean_cache(&cache_area);
|
||||
#endif
|
||||
|
||||
uint32_t output_offset = (stride / cf_size) - w;
|
||||
lv_draw_dma2d_configuration_t conf = {
|
||||
.mode = LV_DRAW_DMA2D_MODE_MEMORY_TO_MEMORY_WITH_BLENDING_AND_FIXED_COLOR_FG,
|
||||
.w = w,
|
||||
.h = h,
|
||||
|
||||
.output_address = first_pixel,
|
||||
.output_offset = output_offset,
|
||||
.output_cf = output_cf,
|
||||
|
||||
.fg_color = lv_color_to_u32(color),
|
||||
.fg_alpha_mode = LV_DRAW_DMA2D_ALPHA_MODE_REPLACE_ALPHA_CHANNEL,
|
||||
.fg_alpha = opa,
|
||||
|
||||
.bg_address = first_pixel,
|
||||
.bg_offset = output_offset,
|
||||
.bg_cf = (lv_draw_dma2d_fgbg_cf_t) output_cf
|
||||
};
|
||||
|
||||
/* Background alpha channel should be treated as 0xFF if the cf is XRGB */
|
||||
if(cf == LV_COLOR_FORMAT_XRGB8888) {
|
||||
conf.bg_alpha_mode = LV_DRAW_DMA2D_ALPHA_MODE_REPLACE_ALPHA_CHANNEL;
|
||||
conf.bg_alpha = 0xff;
|
||||
}
|
||||
|
||||
lv_draw_dma2d_configure_and_start_transfer(&conf);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_DRAW_DMA2D*/
|
||||
@@ -0,0 +1,210 @@
|
||||
/**
|
||||
* @file lv_draw_dma2d_image.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_dma2d_private.h"
|
||||
#if LV_USE_DRAW_DMA2D
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_dma2d_opaque_image(lv_draw_task_t * t, void * dest_first_pixel, lv_area_t * clipped_coords,
|
||||
int32_t dest_stride)
|
||||
{
|
||||
int32_t w = lv_area_get_width(clipped_coords);
|
||||
int32_t h = lv_area_get_height(clipped_coords);
|
||||
|
||||
lv_draw_image_dsc_t * dsc = t->draw_dsc;
|
||||
lv_color_format_t output_cf = dsc->base.layer->color_format;
|
||||
lv_color_format_t image_cf = dsc->header.cf;
|
||||
|
||||
lv_draw_dma2d_output_cf_t output_cf_dma2d = lv_draw_dma2d_cf_to_dma2d_output_cf(output_cf);
|
||||
uint32_t output_cf_size = LV_COLOR_FORMAT_GET_SIZE(output_cf);
|
||||
|
||||
lv_draw_dma2d_fgbg_cf_t image_cf_dma2d = (lv_draw_dma2d_fgbg_cf_t) lv_draw_dma2d_cf_to_dma2d_output_cf(image_cf);
|
||||
uint32_t image_cf_size = LV_COLOR_FORMAT_GET_SIZE(image_cf);
|
||||
|
||||
const lv_image_dsc_t * img_dsc = dsc->src;
|
||||
uint32_t image_stride = img_dsc->header.stride;
|
||||
if(image_stride == 0) image_stride = image_cf_size * img_dsc->header.w;
|
||||
|
||||
#if LV_DRAW_DMA2D_CACHE
|
||||
lv_draw_dma2d_cache_area_t dest_area = {
|
||||
.first_byte = dest_first_pixel,
|
||||
.width_bytes = w * output_cf_size,
|
||||
.height = h,
|
||||
.stride = dest_stride
|
||||
};
|
||||
lv_draw_dma2d_unit_t * u = (lv_draw_dma2d_unit_t *) t->draw_unit;
|
||||
lv_memcpy(&u->writing_area, &dest_area, sizeof(lv_draw_dma2d_cache_area_t));
|
||||
if(lv_color_format_has_alpha(image_cf)) {
|
||||
/* make sure the background area DMA2D is blending is up-to-date in main memory */
|
||||
lv_draw_dma2d_clean_cache(&dest_area);
|
||||
}
|
||||
#endif
|
||||
|
||||
const void * image_first_byte = img_dsc->data
|
||||
+ (image_stride * (clipped_coords->y1 - dsc->image_area.y1))
|
||||
+ (image_cf_size * (clipped_coords->x1 - dsc->image_area.x1));
|
||||
|
||||
#if LV_DRAW_DMA2D_CACHE
|
||||
lv_draw_dma2d_cache_area_t src_area = {
|
||||
.first_byte = image_first_byte,
|
||||
.width_bytes = w * image_cf_size,
|
||||
.height = h,
|
||||
.stride = image_stride
|
||||
};
|
||||
/* make sure the image area is up-to-date in main memory for DMA2D */
|
||||
lv_draw_dma2d_clean_cache(&src_area);
|
||||
#endif
|
||||
|
||||
uint32_t output_offset = (dest_stride / output_cf_size) - w;
|
||||
lv_draw_dma2d_configuration_t conf = {
|
||||
.mode = LV_DRAW_DMA2D_MODE_MEMORY_TO_MEMORY_WITH_PFC,
|
||||
.w = w,
|
||||
.h = h,
|
||||
|
||||
.output_address = dest_first_pixel,
|
||||
.output_offset = output_offset,
|
||||
.output_cf = output_cf_dma2d,
|
||||
|
||||
.fg_address = image_first_byte,
|
||||
.fg_offset = (image_stride / image_cf_size) - w,
|
||||
.fg_cf = image_cf_dma2d
|
||||
};
|
||||
|
||||
/* only process the background if the image might be transparent */
|
||||
if(lv_color_format_has_alpha(image_cf)) {
|
||||
conf.mode = LV_DRAW_DMA2D_MODE_MEMORY_TO_MEMORY_WITH_BLENDING;
|
||||
|
||||
conf.bg_address = dest_first_pixel;
|
||||
conf.bg_offset = output_offset;
|
||||
conf.bg_cf = output_cf_dma2d;
|
||||
}
|
||||
|
||||
/* Alpha channel should be treated as 0xFF if the cf is XRGB */
|
||||
if(image_cf == LV_COLOR_FORMAT_XRGB8888) {
|
||||
conf.fg_alpha_mode = LV_DRAW_DMA2D_ALPHA_MODE_REPLACE_ALPHA_CHANNEL;
|
||||
conf.fg_alpha = 0xff;
|
||||
}
|
||||
if(output_cf == LV_COLOR_FORMAT_XRGB8888) {
|
||||
conf.bg_alpha_mode = LV_DRAW_DMA2D_ALPHA_MODE_REPLACE_ALPHA_CHANNEL;
|
||||
conf.bg_alpha = 0xff;
|
||||
}
|
||||
|
||||
lv_draw_dma2d_configure_and_start_transfer(&conf);
|
||||
}
|
||||
|
||||
void lv_draw_dma2d_image(lv_draw_task_t * t, void * dest_first_pixel, lv_area_t * clipped_coords,
|
||||
int32_t dest_stride)
|
||||
{
|
||||
int32_t w = lv_area_get_width(clipped_coords);
|
||||
int32_t h = lv_area_get_height(clipped_coords);
|
||||
|
||||
lv_draw_image_dsc_t * dsc = t->draw_dsc;
|
||||
lv_color_format_t output_cf = dsc->base.layer->color_format;
|
||||
lv_color_format_t image_cf = dsc->header.cf;
|
||||
lv_opa_t opa = dsc->opa;
|
||||
|
||||
lv_draw_dma2d_output_cf_t output_cf_dma2d = lv_draw_dma2d_cf_to_dma2d_output_cf(output_cf);
|
||||
uint32_t output_cf_size = LV_COLOR_FORMAT_GET_SIZE(output_cf);
|
||||
|
||||
lv_draw_dma2d_fgbg_cf_t image_cf_dma2d = (lv_draw_dma2d_fgbg_cf_t) lv_draw_dma2d_cf_to_dma2d_output_cf(image_cf);
|
||||
uint32_t image_cf_size = LV_COLOR_FORMAT_GET_SIZE(image_cf);
|
||||
|
||||
const lv_image_dsc_t * img_dsc = dsc->src;
|
||||
uint32_t image_stride = img_dsc->header.stride;
|
||||
if(image_stride == 0) image_stride = image_cf_size * img_dsc->header.w;
|
||||
|
||||
#if LV_DRAW_DMA2D_CACHE
|
||||
lv_draw_dma2d_cache_area_t dest_area = {
|
||||
.first_byte = dest_first_pixel,
|
||||
.width_bytes = w * output_cf_size,
|
||||
.height = h,
|
||||
.stride = dest_stride
|
||||
};
|
||||
lv_draw_dma2d_unit_t * u = (lv_draw_dma2d_unit_t *) t->draw_unit;
|
||||
lv_memcpy(&u->writing_area, &dest_area, sizeof(lv_draw_dma2d_cache_area_t));
|
||||
/* make sure the background area DMA2D is blending is up-to-date in main memory */
|
||||
lv_draw_dma2d_clean_cache(&dest_area);
|
||||
#endif
|
||||
|
||||
const void * image_first_byte = img_dsc->data
|
||||
+ (image_stride * (clipped_coords->y1 - dsc->image_area.y1))
|
||||
+ (image_cf_size * (clipped_coords->x1 - dsc->image_area.x1));
|
||||
|
||||
#if LV_DRAW_DMA2D_CACHE
|
||||
lv_draw_dma2d_cache_area_t src_area = {
|
||||
.first_byte = image_first_byte,
|
||||
.width_bytes = w * image_cf_size,
|
||||
.height = h,
|
||||
.stride = image_stride
|
||||
};
|
||||
/* make sure the image area is up-to-date in main memory for DMA2D */
|
||||
lv_draw_dma2d_clean_cache(&src_area);
|
||||
#endif
|
||||
|
||||
uint32_t output_offset = (dest_stride / output_cf_size) - w;
|
||||
lv_draw_dma2d_configuration_t conf = {
|
||||
.mode = LV_DRAW_DMA2D_MODE_MEMORY_TO_MEMORY_WITH_BLENDING,
|
||||
.w = w,
|
||||
.h = h,
|
||||
|
||||
.output_address = dest_first_pixel,
|
||||
.output_offset = output_offset,
|
||||
.output_cf = output_cf_dma2d,
|
||||
|
||||
.fg_address = image_first_byte,
|
||||
.fg_offset = (image_stride / image_cf_size) - w,
|
||||
.fg_cf = image_cf_dma2d,
|
||||
.fg_alpha_mode = LV_DRAW_DMA2D_ALPHA_MODE_MULTIPLY_IMAGE_ALPHA_CHANNEL,
|
||||
.fg_alpha = opa,
|
||||
|
||||
.bg_address = dest_first_pixel,
|
||||
.bg_offset = output_offset,
|
||||
.bg_cf = output_cf_dma2d,
|
||||
};
|
||||
|
||||
/* Alpha channel should be treated as 0xFF if the cf is XRGB */
|
||||
if(image_cf == LV_COLOR_FORMAT_XRGB8888) {
|
||||
conf.fg_alpha_mode = LV_DRAW_DMA2D_ALPHA_MODE_REPLACE_ALPHA_CHANNEL;
|
||||
}
|
||||
if(output_cf == LV_COLOR_FORMAT_XRGB8888) {
|
||||
conf.bg_alpha_mode = LV_DRAW_DMA2D_ALPHA_MODE_REPLACE_ALPHA_CHANNEL;
|
||||
conf.bg_alpha = 0xff;
|
||||
}
|
||||
|
||||
lv_draw_dma2d_configure_and_start_transfer(&conf);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_DRAW_DMA2D*/
|
||||
@@ -0,0 +1,156 @@
|
||||
/**
|
||||
* @file lv_draw_dma2d_private.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_DMA2D_PRIVATE_H
|
||||
#define LV_DRAW_DMA2D_PRIVATE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_dma2d.h"
|
||||
#if LV_USE_DRAW_DMA2D
|
||||
|
||||
#include "../lv_draw_private.h"
|
||||
#include "../sw/lv_draw_sw.h"
|
||||
#include LV_DRAW_DMA2D_HAL_INCLUDE
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#if LV_USE_DRAW_DMA2D_INTERRUPT && LV_USE_OS
|
||||
#define LV_DRAW_DMA2D_ASYNC 1
|
||||
#else
|
||||
#define LV_DRAW_DMA2D_ASYNC 0
|
||||
#endif
|
||||
|
||||
#if defined(__CORTEX_M) && (__CORTEX_M == 7)
|
||||
#define LV_DRAW_DMA2D_CACHE 1
|
||||
#else
|
||||
#define LV_DRAW_DMA2D_CACHE 0
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef enum {
|
||||
LV_DRAW_DMA2D_OUTPUT_CF_ARGB8888 = 0,
|
||||
LV_DRAW_DMA2D_OUTPUT_CF_RGB888,
|
||||
LV_DRAW_DMA2D_OUTPUT_CF_RGB565,
|
||||
LV_DRAW_DMA2D_OUTPUT_CF_ARGB1555,
|
||||
LV_DRAW_DMA2D_OUTPUT_CF_ARGB4444
|
||||
} lv_draw_dma2d_output_cf_t;
|
||||
|
||||
typedef enum {
|
||||
LV_DRAW_DMA2D_FGBG_CF_ARGB8888 = 0,
|
||||
LV_DRAW_DMA2D_FGBG_CF_RGB888,
|
||||
LV_DRAW_DMA2D_FGBG_CF_RGB565,
|
||||
LV_DRAW_DMA2D_FGBG_CF_ARGB1555,
|
||||
LV_DRAW_DMA2D_FGBG_CF_ARGB4444,
|
||||
LV_DRAW_DMA2D_FGBG_CF_L8,
|
||||
LV_DRAW_DMA2D_FGBG_CF_AL44,
|
||||
LV_DRAW_DMA2D_FGBG_CF_AL88,
|
||||
LV_DRAW_DMA2D_FGBG_CF_L4,
|
||||
LV_DRAW_DMA2D_FGBG_CF_A8,
|
||||
LV_DRAW_DMA2D_FGBG_CF_A4,
|
||||
LV_DRAW_DMA2D_FGBG_CF_YCBCR
|
||||
} lv_draw_dma2d_fgbg_cf_t;
|
||||
|
||||
typedef enum {
|
||||
LV_DRAW_DMA2D_MODE_MEMORY_TO_MEMORY = 0,
|
||||
LV_DRAW_DMA2D_MODE_MEMORY_TO_MEMORY_WITH_PFC,
|
||||
LV_DRAW_DMA2D_MODE_MEMORY_TO_MEMORY_WITH_BLENDING,
|
||||
LV_DRAW_DMA2D_MODE_REGISTER_TO_MEMORY,
|
||||
LV_DRAW_DMA2D_MODE_MEMORY_TO_MEMORY_WITH_BLENDING_AND_FIXED_COLOR_FG,
|
||||
LV_DRAW_DMA2D_MODE_MEMORY_TO_MEMORY_WITH_BLENDING_AND_FIXED_COLOR_BG
|
||||
} lv_draw_dma2d_mode_t;
|
||||
|
||||
typedef enum {
|
||||
LV_DRAW_DMA2D_ALPHA_MODE_NO_MODIFY_IMAGE_ALPHA_CHANNEL = 0,
|
||||
LV_DRAW_DMA2D_ALPHA_MODE_REPLACE_ALPHA_CHANNEL,
|
||||
LV_DRAW_DMA2D_ALPHA_MODE_MULTIPLY_IMAGE_ALPHA_CHANNEL
|
||||
} lv_draw_dma2d_alpha_mode_t;
|
||||
|
||||
typedef struct {
|
||||
lv_draw_dma2d_mode_t mode;
|
||||
uint32_t w;
|
||||
uint32_t h;
|
||||
|
||||
void * output_address;
|
||||
uint32_t output_offset;
|
||||
lv_draw_dma2d_output_cf_t output_cf;
|
||||
|
||||
uint32_t reg_to_mem_mode_color;
|
||||
|
||||
const void * fg_address;
|
||||
uint32_t fg_offset;
|
||||
lv_draw_dma2d_fgbg_cf_t fg_cf;
|
||||
uint32_t fg_color;
|
||||
uint32_t fg_alpha_mode;
|
||||
uint32_t fg_alpha;
|
||||
|
||||
const void * bg_address;
|
||||
uint32_t bg_offset;
|
||||
lv_draw_dma2d_fgbg_cf_t bg_cf;
|
||||
uint32_t bg_color;
|
||||
uint32_t bg_alpha_mode;
|
||||
uint32_t bg_alpha;
|
||||
|
||||
} lv_draw_dma2d_configuration_t;
|
||||
|
||||
typedef struct {
|
||||
const void * first_byte;
|
||||
uint32_t width_bytes;
|
||||
uint32_t height;
|
||||
uint32_t stride;
|
||||
} lv_draw_dma2d_cache_area_t;
|
||||
|
||||
typedef struct {
|
||||
lv_draw_unit_t base_unit;
|
||||
lv_draw_task_t * volatile task_act;
|
||||
#if LV_DRAW_DMA2D_CACHE
|
||||
lv_draw_dma2d_cache_area_t writing_area;
|
||||
#endif
|
||||
#if LV_DRAW_DMA2D_ASYNC
|
||||
lv_thread_t thread;
|
||||
lv_thread_sync_t interrupt_signal;
|
||||
#endif
|
||||
} lv_draw_dma2d_unit_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
void lv_draw_dma2d_opaque_fill(lv_draw_task_t * t, void * first_pixel, int32_t w, int32_t h, int32_t stride);
|
||||
void lv_draw_dma2d_fill(lv_draw_task_t * t, void * first_pixel, int32_t w, int32_t h, int32_t stride);
|
||||
void lv_draw_dma2d_opaque_image(lv_draw_task_t * t, void * dest_first_pixel, lv_area_t * clipped_coords,
|
||||
int32_t dest_stride);
|
||||
void lv_draw_dma2d_image(lv_draw_task_t * t, void * dest_first_pixel, lv_area_t * clipped_coords,
|
||||
int32_t dest_stride);
|
||||
lv_draw_dma2d_output_cf_t lv_draw_dma2d_cf_to_dma2d_output_cf(lv_color_format_t cf);
|
||||
uint32_t lv_draw_dma2d_color_to_dma2d_color(lv_draw_dma2d_output_cf_t cf, lv_color_t color);
|
||||
void lv_draw_dma2d_configure_and_start_transfer(const lv_draw_dma2d_configuration_t * conf);
|
||||
#if LV_DRAW_DMA2D_CACHE
|
||||
void lv_draw_dma2d_invalidate_cache(const lv_draw_dma2d_cache_area_t * mem_area);
|
||||
void lv_draw_dma2d_clean_cache(const lv_draw_dma2d_cache_area_t * mem_area);
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_DRAW_DMA2D*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_DMA2D_PRIVATE_H*/
|
||||
@@ -0,0 +1,683 @@
|
||||
/**
|
||||
* @file lv_draw.c
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Modified by NXP in 2024
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../misc/lv_area_private.h"
|
||||
#include "../misc/lv_assert.h"
|
||||
#include "lv_draw_private.h"
|
||||
#include "lv_draw_mask_private.h"
|
||||
#include "lv_draw_vector_private.h"
|
||||
#include "lv_draw_3d.h"
|
||||
#include "sw/lv_draw_sw.h"
|
||||
#include "../display/lv_display_private.h"
|
||||
#include "../core/lv_global.h"
|
||||
#include "../core/lv_refr_private.h"
|
||||
#include "../stdlib/lv_string.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define _draw_info LV_GLOBAL_DEFAULT()->draw_info
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static bool is_independent(lv_layer_t * layer, lv_draw_task_t * t_check);
|
||||
static void cleanup_task(lv_draw_task_t * t, lv_display_t * disp);
|
||||
static inline size_t get_draw_dsc_size(lv_draw_task_type_t type);
|
||||
static lv_draw_task_t * get_first_available_task(lv_layer_t * layer);
|
||||
|
||||
#if LV_LOG_LEVEL <= LV_LOG_LEVEL_INFO
|
||||
static inline uint32_t get_layer_size_kb(uint32_t size_byte)
|
||||
{
|
||||
return (size_byte + 1023) >> 10;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_init(void)
|
||||
{
|
||||
#if LV_USE_OS
|
||||
lv_thread_sync_init(&_draw_info.sync);
|
||||
#endif
|
||||
}
|
||||
|
||||
void lv_draw_deinit(void)
|
||||
{
|
||||
#if LV_USE_OS
|
||||
lv_thread_sync_delete(&_draw_info.sync);
|
||||
#endif
|
||||
|
||||
lv_draw_unit_t * u = _draw_info.unit_head;
|
||||
while(u) {
|
||||
lv_draw_unit_t * cur_unit = u;
|
||||
u = u->next;
|
||||
|
||||
if(cur_unit->delete_cb) cur_unit->delete_cb(cur_unit);
|
||||
lv_free(cur_unit);
|
||||
}
|
||||
_draw_info.unit_head = NULL;
|
||||
}
|
||||
|
||||
void * lv_draw_create_unit(size_t size)
|
||||
{
|
||||
lv_draw_unit_t * new_unit = lv_malloc_zeroed(size);
|
||||
LV_ASSERT_MALLOC(new_unit);
|
||||
new_unit->next = _draw_info.unit_head;
|
||||
|
||||
_draw_info.unit_head = new_unit;
|
||||
_draw_info.unit_cnt++;
|
||||
|
||||
new_unit->idx = _draw_info.unit_cnt;
|
||||
|
||||
return new_unit;
|
||||
}
|
||||
|
||||
lv_draw_task_t * lv_draw_add_task(lv_layer_t * layer, const lv_area_t * coords, lv_draw_task_type_t type)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
size_t dsc_size = get_draw_dsc_size(type);
|
||||
LV_ASSERT_FORMAT_MSG(dsc_size > 0, "Draw task size is 0 for type %d", type);
|
||||
lv_draw_task_t * new_task = lv_malloc_zeroed(LV_ALIGN_UP(sizeof(lv_draw_task_t), 8) + dsc_size);
|
||||
LV_ASSERT_MALLOC(new_task);
|
||||
new_task->area = *coords;
|
||||
new_task->_real_area = *coords;
|
||||
new_task->target_layer = layer;
|
||||
new_task->clip_area = layer->_clip_area;
|
||||
#if LV_DRAW_TRANSFORM_USE_MATRIX
|
||||
new_task->matrix = layer->matrix;
|
||||
#endif
|
||||
new_task->type = type;
|
||||
new_task->draw_dsc = (uint8_t *)new_task + LV_ALIGN_UP(sizeof(lv_draw_task_t), 8);
|
||||
new_task->state = LV_DRAW_TASK_STATE_QUEUED;
|
||||
|
||||
/*Find the tail*/
|
||||
if(layer->draw_task_head == NULL) {
|
||||
layer->draw_task_head = new_task;
|
||||
}
|
||||
else {
|
||||
lv_draw_task_t * tail = layer->draw_task_head;
|
||||
while(tail->next) tail = tail->next;
|
||||
|
||||
tail->next = new_task;
|
||||
}
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
return new_task;
|
||||
}
|
||||
|
||||
void lv_draw_finalize_task_creation(lv_layer_t * layer, lv_draw_task_t * t)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
lv_draw_dsc_base_t * base_dsc = t->draw_dsc;
|
||||
base_dsc->layer = layer;
|
||||
|
||||
lv_draw_global_info_t * info = &_draw_info;
|
||||
|
||||
/*Send LV_EVENT_DRAW_TASK_ADDED and dispatch only on the "main" draw_task
|
||||
*and not on the draw tasks added in the event.
|
||||
*Sending LV_EVENT_DRAW_TASK_ADDED events might cause recursive event sends and besides
|
||||
*dispatching might remove the "main" draw task while it's still being used in the event*/
|
||||
|
||||
if(info->task_running == false) {
|
||||
if(base_dsc->obj && lv_obj_has_flag(base_dsc->obj, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS)) {
|
||||
info->task_running = true;
|
||||
lv_obj_send_event(base_dsc->obj, LV_EVENT_DRAW_TASK_ADDED, t);
|
||||
info->task_running = false;
|
||||
}
|
||||
|
||||
/*Let the draw units set their preference score*/
|
||||
t->preference_score = 100;
|
||||
t->preferred_draw_unit_id = 0;
|
||||
lv_draw_unit_t * u = info->unit_head;
|
||||
while(u) {
|
||||
if(u->evaluate_cb) {
|
||||
LV_PROFILER_DRAW_BEGIN_TAG("evaluate_cb");
|
||||
LV_PROFILER_DRAW_BEGIN_TAG(u->name);
|
||||
u->evaluate_cb(u, t);
|
||||
LV_PROFILER_DRAW_END_TAG(u->name);
|
||||
LV_PROFILER_DRAW_END_TAG("evaluate_cb");
|
||||
}
|
||||
u = u->next;
|
||||
}
|
||||
if(t->preferred_draw_unit_id == LV_DRAW_UNIT_NONE) {
|
||||
LV_LOG_WARN("the draw task was not taken by any units");
|
||||
t->state = LV_DRAW_TASK_STATE_READY;
|
||||
}
|
||||
else {
|
||||
lv_draw_dispatch();
|
||||
}
|
||||
}
|
||||
else {
|
||||
/*Let the draw units set their preference score*/
|
||||
t->preference_score = 100;
|
||||
t->preferred_draw_unit_id = 0;
|
||||
lv_draw_unit_t * u = info->unit_head;
|
||||
while(u) {
|
||||
if(u->evaluate_cb) {
|
||||
LV_PROFILER_DRAW_BEGIN_TAG("evaluate_cb");
|
||||
LV_PROFILER_DRAW_BEGIN_TAG(u->name);
|
||||
u->evaluate_cb(u, t);
|
||||
LV_PROFILER_DRAW_END_TAG(u->name);
|
||||
LV_PROFILER_DRAW_END_TAG("evaluate_cb");
|
||||
}
|
||||
u = u->next;
|
||||
}
|
||||
}
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
void lv_draw_wait_for_finish(void)
|
||||
{
|
||||
#if LV_USE_OS
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
lv_draw_unit_t * u = _draw_info.unit_head;
|
||||
while(u) {
|
||||
if(u->wait_for_finish_cb) {
|
||||
LV_PROFILER_DRAW_BEGIN_TAG("wait_for_finish_cb");
|
||||
LV_PROFILER_DRAW_BEGIN_TAG(u->name);
|
||||
u->wait_for_finish_cb(u);
|
||||
LV_PROFILER_DRAW_END_TAG(u->name);
|
||||
LV_PROFILER_DRAW_END_TAG("wait_for_finish_cb");
|
||||
}
|
||||
u = u->next;
|
||||
}
|
||||
LV_PROFILER_DRAW_END;
|
||||
#endif
|
||||
}
|
||||
|
||||
void lv_draw_dispatch(void)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
bool task_dispatched = false;
|
||||
lv_display_t * disp = lv_display_get_next(NULL);
|
||||
while(disp) {
|
||||
lv_layer_t * layer = disp->layer_head;
|
||||
while(layer) {
|
||||
if(lv_draw_dispatch_layer(disp, layer))
|
||||
task_dispatched = true;
|
||||
layer = layer->next;
|
||||
}
|
||||
if(!task_dispatched) {
|
||||
lv_draw_wait_for_finish();
|
||||
lv_draw_dispatch_request();
|
||||
}
|
||||
disp = lv_display_get_next(disp);
|
||||
}
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
bool lv_draw_dispatch_layer(lv_display_t * disp, lv_layer_t * layer)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
/*Remove the finished tasks first*/
|
||||
lv_draw_task_t * t_prev = NULL;
|
||||
lv_draw_task_t * t = layer->draw_task_head;
|
||||
lv_draw_task_t * t_next;
|
||||
bool remove_task = false;
|
||||
while(t) {
|
||||
t_next = t->next;
|
||||
if(t->state == LV_DRAW_TASK_STATE_READY) {
|
||||
cleanup_task(t, disp);
|
||||
remove_task = true;
|
||||
if(t_prev != NULL)
|
||||
t_prev->next = t_next;
|
||||
else
|
||||
layer->draw_task_head = t_next;
|
||||
}
|
||||
else {
|
||||
t_prev = t;
|
||||
}
|
||||
t = t_next;
|
||||
}
|
||||
|
||||
bool task_dispatched = false;
|
||||
|
||||
/*This layer is ready, enable blending its buffer*/
|
||||
if(layer->parent && layer->all_tasks_added && layer->draw_task_head == NULL) {
|
||||
/*Find a draw task with TYPE_LAYER in the layer where the src is this layer*/
|
||||
lv_draw_task_t * t_src = layer->parent->draw_task_head;
|
||||
while(t_src) {
|
||||
if(t_src->type == LV_DRAW_TASK_TYPE_LAYER && t_src->state == LV_DRAW_TASK_STATE_WAITING) {
|
||||
lv_draw_image_dsc_t * draw_dsc = t_src->draw_dsc;
|
||||
if(draw_dsc->src == layer) {
|
||||
t_src->state = LV_DRAW_TASK_STATE_QUEUED;
|
||||
lv_draw_dispatch_request();
|
||||
break;
|
||||
}
|
||||
}
|
||||
t_src = t_src->next;
|
||||
}
|
||||
}
|
||||
/*Assign draw tasks to the draw_units*/
|
||||
else if(remove_task || layer->draw_task_head) {
|
||||
/*Find a draw unit which is not busy and can take at least one task*/
|
||||
/*Let all draw units to pick draw tasks*/
|
||||
lv_draw_unit_t * u = _draw_info.unit_head;
|
||||
while(u) {
|
||||
LV_PROFILER_DRAW_BEGIN_TAG("dispatch_cb");
|
||||
LV_PROFILER_DRAW_BEGIN_TAG(u->name);
|
||||
int32_t taken_cnt = u->dispatch_cb(u, layer);
|
||||
LV_PROFILER_DRAW_END_TAG(u->name);
|
||||
LV_PROFILER_DRAW_END_TAG("dispatch_cb");
|
||||
if(taken_cnt != LV_DRAW_UNIT_IDLE) task_dispatched = true;
|
||||
u = u->next;
|
||||
}
|
||||
}
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
return task_dispatched;
|
||||
}
|
||||
|
||||
void lv_draw_dispatch_wait_for_request(void)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
#if LV_USE_OS
|
||||
lv_thread_sync_wait(&_draw_info.sync);
|
||||
#else
|
||||
while(!_draw_info.dispatch_req);
|
||||
_draw_info.dispatch_req = 0;
|
||||
#endif
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
void lv_draw_dispatch_request(void)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
#if LV_USE_OS
|
||||
lv_thread_sync_signal(&_draw_info.sync);
|
||||
#else
|
||||
_draw_info.dispatch_req = 1;
|
||||
#endif
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
uint32_t lv_draw_get_unit_count(void)
|
||||
{
|
||||
return _draw_info.unit_cnt;
|
||||
}
|
||||
|
||||
lv_draw_task_t * lv_draw_get_available_task(lv_layer_t * layer, lv_draw_task_t * t_prev, uint8_t draw_unit_id)
|
||||
{
|
||||
if(_draw_info.unit_cnt == 1) {
|
||||
return get_first_available_task(layer);
|
||||
}
|
||||
else {
|
||||
return lv_draw_get_next_available_task(layer, t_prev, draw_unit_id);
|
||||
}
|
||||
}
|
||||
|
||||
lv_draw_task_t * lv_draw_get_next_available_task(lv_layer_t * layer, lv_draw_task_t * t_prev, uint8_t draw_unit_id)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
|
||||
/*If the first task is screen sized, there cannot be independent areas*/
|
||||
if(layer->draw_task_head) {
|
||||
int32_t hor_res = lv_display_get_horizontal_resolution(lv_refr_get_disp_refreshing());
|
||||
int32_t ver_res = lv_display_get_vertical_resolution(lv_refr_get_disp_refreshing());
|
||||
lv_draw_task_t * t = layer->draw_task_head;
|
||||
if(t->state != LV_DRAW_TASK_STATE_QUEUED &&
|
||||
t->area.x1 <= 0 && t->area.x2 >= hor_res - 1 &&
|
||||
t->area.y1 <= 0 && t->area.y2 >= ver_res - 1) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
lv_draw_task_t * t = t_prev ? t_prev->next : layer->draw_task_head;
|
||||
while(t) {
|
||||
/*Find a queued and independent task*/
|
||||
if(t->state == LV_DRAW_TASK_STATE_QUEUED &&
|
||||
(t->preferred_draw_unit_id == LV_DRAW_UNIT_NONE || t->preferred_draw_unit_id == draw_unit_id) &&
|
||||
is_independent(layer, t)) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return t;
|
||||
}
|
||||
t = t->next;
|
||||
}
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint32_t lv_draw_get_dependent_count(lv_draw_task_t * t_check)
|
||||
{
|
||||
if(t_check == NULL) return 0;
|
||||
if(t_check->next == NULL) return 0;
|
||||
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
uint32_t cnt = 0;
|
||||
|
||||
lv_draw_task_t * t = t_check->next;
|
||||
while(t) {
|
||||
if((t->state == LV_DRAW_TASK_STATE_QUEUED || t->state == LV_DRAW_TASK_STATE_WAITING) &&
|
||||
lv_area_is_on(&t_check->area, &t->area)) {
|
||||
cnt++;
|
||||
}
|
||||
|
||||
t = t->next;
|
||||
}
|
||||
LV_PROFILER_DRAW_END;
|
||||
return cnt;
|
||||
}
|
||||
|
||||
void lv_layer_init(lv_layer_t * layer)
|
||||
{
|
||||
LV_ASSERT_NULL(layer);
|
||||
lv_memzero(layer, sizeof(lv_layer_t));
|
||||
lv_layer_reset(layer);
|
||||
}
|
||||
|
||||
void lv_layer_reset(lv_layer_t * layer)
|
||||
{
|
||||
LV_ASSERT_NULL(layer);
|
||||
#if LV_DRAW_TRANSFORM_USE_MATRIX
|
||||
lv_matrix_identity(&layer->matrix);
|
||||
#endif
|
||||
layer->opa = LV_OPA_COVER;
|
||||
layer->recolor = lv_color32_make(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
lv_layer_t * lv_draw_layer_create(lv_layer_t * parent_layer, lv_color_format_t color_format, const lv_area_t * area)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
lv_layer_t * new_layer = lv_malloc_zeroed(sizeof(lv_layer_t));
|
||||
LV_ASSERT_MALLOC(new_layer);
|
||||
if(new_layer == NULL) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lv_draw_layer_init(new_layer, parent_layer, color_format, area);
|
||||
|
||||
/*Inherits transparency from parent*/
|
||||
if(parent_layer) {
|
||||
new_layer->opa = parent_layer->opa;
|
||||
new_layer->recolor = parent_layer->recolor;
|
||||
}
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
return new_layer;
|
||||
}
|
||||
|
||||
void lv_draw_layer_init(lv_layer_t * layer, lv_layer_t * parent_layer, lv_color_format_t color_format,
|
||||
const lv_area_t * area)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
lv_layer_init(layer);
|
||||
lv_display_t * disp = lv_refr_get_disp_refreshing();
|
||||
|
||||
layer->parent = parent_layer;
|
||||
layer->_clip_area = *area;
|
||||
layer->buf_area = *area;
|
||||
layer->phy_clip_area = *area;
|
||||
layer->color_format = color_format;
|
||||
|
||||
if(disp->layer_init) disp->layer_init(disp, layer);
|
||||
|
||||
if(disp->layer_head) {
|
||||
lv_layer_t * tail = disp->layer_head;
|
||||
while(tail->next) tail = tail->next;
|
||||
tail->next = layer;
|
||||
}
|
||||
else {
|
||||
disp->layer_head = layer;
|
||||
}
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
void * lv_draw_layer_alloc_buf(lv_layer_t * layer)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
/*If the buffer of the layer is already allocated return it*/
|
||||
if(layer->draw_buf != NULL) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return layer->draw_buf->data;
|
||||
}
|
||||
|
||||
/*If the buffer of the layer is not allocated yet, allocate it now*/
|
||||
int32_t w = lv_area_get_width(&layer->buf_area);
|
||||
int32_t h = lv_area_get_height(&layer->buf_area);
|
||||
uint32_t layer_size_byte = h * lv_draw_buf_width_to_stride(w, layer->color_format);
|
||||
|
||||
#if LV_DRAW_LAYER_MAX_MEMORY > 0
|
||||
/* Do not allocate the layer if the sum of allocated layer sizes
|
||||
* will exceed `LV_DRAW_LAYER_MAX_MEMORY` */
|
||||
if((_draw_info.used_memory_for_layers + layer_size_byte) > LV_DRAW_LAYER_MAX_MEMORY) {
|
||||
LV_LOG_WARN("LV_DRAW_LAYER_MAX_MEMORY was reached when allocating the layer.");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
layer->draw_buf = lv_draw_buf_create(w, h, layer->color_format, 0);
|
||||
|
||||
if(layer->draw_buf == NULL) {
|
||||
LV_LOG_WARN("Allocating layer buffer failed. Try later");
|
||||
LV_PROFILER_DRAW_END;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_draw_info.used_memory_for_layers += layer_size_byte;
|
||||
LV_LOG_INFO("Layer memory used: %" LV_PRIu32 " kB", get_layer_size_kb(_draw_info.used_memory_for_layers));
|
||||
|
||||
if(lv_color_format_has_alpha(layer->color_format)) {
|
||||
lv_draw_buf_clear(layer->draw_buf, NULL);
|
||||
}
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
return layer->draw_buf->data;
|
||||
}
|
||||
|
||||
void * lv_draw_layer_go_to_xy(lv_layer_t * layer, int32_t x, int32_t y)
|
||||
{
|
||||
return lv_draw_buf_goto_xy(layer->draw_buf, x, y);
|
||||
}
|
||||
|
||||
lv_draw_task_type_t lv_draw_task_get_type(const lv_draw_task_t * t)
|
||||
{
|
||||
return t->type;
|
||||
}
|
||||
|
||||
void * lv_draw_task_get_draw_dsc(const lv_draw_task_t * t)
|
||||
{
|
||||
return t->draw_dsc;
|
||||
}
|
||||
|
||||
void lv_draw_task_get_area(const lv_draw_task_t * t, lv_area_t * area)
|
||||
{
|
||||
*area = t->area;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Check if there are older draw task overlapping the area of `t_check`
|
||||
* @param layer the draw ctx to search in
|
||||
* @param t_check check this task if it overlaps with the older ones
|
||||
* @return true: `t_check` is not overlapping with older tasks so it's independent
|
||||
*/
|
||||
static bool is_independent(lv_layer_t * layer, lv_draw_task_t * t_check)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
lv_draw_task_t * t = layer->draw_task_head;
|
||||
|
||||
/*If t_check is outside of the older tasks then it's independent*/
|
||||
while(t && t != t_check) {
|
||||
if(t->state != LV_DRAW_TASK_STATE_READY) {
|
||||
lv_area_t a;
|
||||
if(lv_area_intersect(&a, &t->_real_area, &t_check->_real_area)) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
t = t->next;
|
||||
}
|
||||
LV_PROFILER_DRAW_END;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size of the draw descriptor of a draw task
|
||||
* @param type type of the draw task
|
||||
* @return size of the draw descriptor in bytes
|
||||
*/
|
||||
static inline size_t get_draw_dsc_size(lv_draw_task_type_t type)
|
||||
{
|
||||
switch(type) {
|
||||
case LV_DRAW_TASK_TYPE_NONE:
|
||||
return 0;
|
||||
case LV_DRAW_TASK_TYPE_FILL:
|
||||
return sizeof(lv_draw_fill_dsc_t);
|
||||
case LV_DRAW_TASK_TYPE_BORDER:
|
||||
return sizeof(lv_draw_border_dsc_t);
|
||||
case LV_DRAW_TASK_TYPE_BOX_SHADOW:
|
||||
return sizeof(lv_draw_box_shadow_dsc_t);
|
||||
case LV_DRAW_TASK_TYPE_LETTER:
|
||||
return sizeof(lv_draw_letter_dsc_t);
|
||||
case LV_DRAW_TASK_TYPE_LABEL:
|
||||
return sizeof(lv_draw_label_dsc_t);
|
||||
case LV_DRAW_TASK_TYPE_IMAGE:
|
||||
return sizeof(lv_draw_image_dsc_t);
|
||||
case LV_DRAW_TASK_TYPE_LAYER:
|
||||
return sizeof(lv_draw_image_dsc_t);
|
||||
case LV_DRAW_TASK_TYPE_LINE:
|
||||
return sizeof(lv_draw_line_dsc_t);
|
||||
case LV_DRAW_TASK_TYPE_ARC:
|
||||
return sizeof(lv_draw_arc_dsc_t);
|
||||
case LV_DRAW_TASK_TYPE_TRIANGLE:
|
||||
return sizeof(lv_draw_triangle_dsc_t);
|
||||
case LV_DRAW_TASK_TYPE_MASK_RECTANGLE:
|
||||
return sizeof(lv_draw_mask_rect_dsc_t);
|
||||
|
||||
/* no struct match for LV_DRAW_TASK_TYPE_MASK_BITMAP, set it to zero now */
|
||||
case LV_DRAW_TASK_TYPE_MASK_BITMAP:
|
||||
return 0;
|
||||
#if LV_USE_VECTOR_GRAPHIC
|
||||
case LV_DRAW_TASK_TYPE_VECTOR:
|
||||
return sizeof(lv_draw_vector_task_dsc_t);
|
||||
#endif
|
||||
#if LV_USE_3DTEXTURE
|
||||
case LV_DRAW_TASK_TYPE_3D:
|
||||
return sizeof(lv_draw_3d_dsc_t);
|
||||
#endif
|
||||
/* Note that default is not added here because when adding new draw task type,
|
||||
* if forget to add case, the compiler will automatically report a warning.
|
||||
*/
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean-up resources allocated by a finished task
|
||||
* @param t pointer to a draw task
|
||||
* @param disp pointer to a display on which the task was drawn
|
||||
*/
|
||||
static void cleanup_task(lv_draw_task_t * t, lv_display_t * disp)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
/*If it was layer drawing free the layer too*/
|
||||
if(t->type == LV_DRAW_TASK_TYPE_LAYER) {
|
||||
lv_draw_image_dsc_t * draw_image_dsc = t->draw_dsc;
|
||||
lv_layer_t * layer_drawn = (lv_layer_t *)draw_image_dsc->src;
|
||||
|
||||
if(layer_drawn->draw_buf) {
|
||||
int32_t h = lv_area_get_height(&layer_drawn->buf_area);
|
||||
uint32_t layer_size_byte = h * layer_drawn->draw_buf->header.stride;
|
||||
|
||||
if(_draw_info.used_memory_for_layers >= layer_size_byte) {
|
||||
_draw_info.used_memory_for_layers -= layer_size_byte;
|
||||
}
|
||||
else {
|
||||
_draw_info.used_memory_for_layers = 0;
|
||||
LV_LOG_WARN("More layers were freed than allocated");
|
||||
}
|
||||
LV_LOG_INFO("Layer memory used: %" LV_PRIu32 " kB", get_layer_size_kb(_draw_info.used_memory_for_layers));
|
||||
lv_draw_buf_destroy(layer_drawn->draw_buf);
|
||||
layer_drawn->draw_buf = NULL;
|
||||
}
|
||||
|
||||
/*Remove the layer from the display's*/
|
||||
if(disp) {
|
||||
lv_layer_t * l2 = disp->layer_head;
|
||||
while(l2) {
|
||||
if(l2->next == layer_drawn) {
|
||||
l2->next = layer_drawn->next;
|
||||
break;
|
||||
}
|
||||
l2 = l2->next;
|
||||
}
|
||||
|
||||
if(disp->layer_deinit) {
|
||||
LV_PROFILER_DRAW_BEGIN_TAG("layer_deinit");
|
||||
disp->layer_deinit(disp, layer_drawn);
|
||||
LV_PROFILER_DRAW_END_TAG("layer_deinit");
|
||||
}
|
||||
lv_free(layer_drawn);
|
||||
}
|
||||
}
|
||||
lv_draw_label_dsc_t * draw_label_dsc = lv_draw_task_get_label_dsc(t);
|
||||
if(draw_label_dsc && draw_label_dsc->text_local) {
|
||||
lv_free((void *)draw_label_dsc->text);
|
||||
draw_label_dsc->text = NULL;
|
||||
}
|
||||
|
||||
lv_free(t);
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
static lv_draw_task_t * get_first_available_task(lv_layer_t * layer)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
/* If there is only 1 draw unit the task can be consumed linearly as
|
||||
* they are added in the correct order. However, it can happen that
|
||||
* there is a `LV_DRAW_TASK_TYPE_LAYER` which can be blended only when
|
||||
* all its tasks are ready. As other areas might be on top of that
|
||||
* layer-to-blend don't skip it. Instead stop there, so that the
|
||||
* draw tasks of that layer can be consumed and can be finished.
|
||||
* After that this layer-to-blenf will have `LV_DRAW_TASK_STATE_QUEUED`
|
||||
* so it can be blended normally.*/
|
||||
lv_draw_task_t * t = layer->draw_task_head;
|
||||
while(t) {
|
||||
/*Not queued yet, leave this layer while the first task is queued*/
|
||||
if(t->state != LV_DRAW_TASK_STATE_QUEUED) {
|
||||
t = NULL;
|
||||
break;
|
||||
}
|
||||
/*It's a supported and queued task, process it*/
|
||||
else {
|
||||
break;
|
||||
}
|
||||
t = t->next;
|
||||
}
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
return t;
|
||||
}
|
||||
@@ -0,0 +1,332 @@
|
||||
/**
|
||||
* @file lv_draw.h
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Modified by NXP in 2024
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_H
|
||||
#define LV_DRAW_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../lv_conf_internal.h"
|
||||
|
||||
#include "../misc/lv_types.h"
|
||||
#include "../misc/lv_style.h"
|
||||
#include "../misc/lv_text.h"
|
||||
#include "../misc/lv_profiler.h"
|
||||
#include "../misc/lv_matrix.h"
|
||||
#include "lv_image_decoder.h"
|
||||
#include "lv_draw_buf.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_DRAW_UNIT_NONE 0
|
||||
#define LV_DRAW_UNIT_IDLE -1 /**< The draw unit is idle, new dispatching might be requested to try again */
|
||||
|
||||
#if LV_DRAW_TRANSFORM_USE_MATRIX
|
||||
#if !LV_USE_MATRIX
|
||||
#error "LV_DRAW_TRANSFORM_USE_MATRIX requires LV_USE_MATRIX = 1"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef enum {
|
||||
LV_DRAW_TASK_TYPE_NONE = 0,
|
||||
LV_DRAW_TASK_TYPE_FILL,
|
||||
LV_DRAW_TASK_TYPE_BORDER,
|
||||
LV_DRAW_TASK_TYPE_BOX_SHADOW,
|
||||
LV_DRAW_TASK_TYPE_LETTER,
|
||||
LV_DRAW_TASK_TYPE_LABEL,
|
||||
LV_DRAW_TASK_TYPE_IMAGE,
|
||||
LV_DRAW_TASK_TYPE_LAYER,
|
||||
LV_DRAW_TASK_TYPE_LINE,
|
||||
LV_DRAW_TASK_TYPE_ARC,
|
||||
LV_DRAW_TASK_TYPE_TRIANGLE,
|
||||
LV_DRAW_TASK_TYPE_MASK_RECTANGLE,
|
||||
LV_DRAW_TASK_TYPE_MASK_BITMAP,
|
||||
#if LV_USE_VECTOR_GRAPHIC
|
||||
LV_DRAW_TASK_TYPE_VECTOR,
|
||||
#endif
|
||||
#if LV_USE_3DTEXTURE
|
||||
LV_DRAW_TASK_TYPE_3D,
|
||||
#endif
|
||||
} lv_draw_task_type_t;
|
||||
|
||||
typedef enum {
|
||||
LV_DRAW_TASK_STATE_WAITING, /*Waiting for something to be finished. E.g. rendering a layer*/
|
||||
LV_DRAW_TASK_STATE_QUEUED,
|
||||
LV_DRAW_TASK_STATE_IN_PROGRESS,
|
||||
LV_DRAW_TASK_STATE_READY,
|
||||
} lv_draw_task_state_t;
|
||||
|
||||
struct _lv_layer_t {
|
||||
|
||||
/** Target draw buffer of the layer*/
|
||||
lv_draw_buf_t * draw_buf;
|
||||
|
||||
/** The absolute coordinates of the buffer */
|
||||
lv_area_t buf_area;
|
||||
|
||||
/** The color format of the layer. LV_COLOR_FORMAT_... */
|
||||
lv_color_format_t color_format;
|
||||
|
||||
/**
|
||||
* NEVER USE IT DRAW UNITS. USED INTERNALLY DURING DRAW TASK CREATION.
|
||||
* The current clip area with absolute coordinates, always the same or smaller than `buf_area`
|
||||
* Can be set before new draw tasks are added to indicate the clip area of the draw tasks.
|
||||
* Therefore `lv_draw_add_task()` always saves it in the new draw task to know the clip area when the draw task was added.
|
||||
* During drawing the draw units also sees the saved clip_area and should use it during drawing.
|
||||
* During drawing the layer's clip area shouldn't be used as it might be already changed for other draw tasks.
|
||||
*/
|
||||
lv_area_t _clip_area;
|
||||
|
||||
/**
|
||||
* The physical clipping area relative to the display.
|
||||
*/
|
||||
lv_area_t phy_clip_area;
|
||||
|
||||
#if LV_DRAW_TRANSFORM_USE_MATRIX
|
||||
/** Transform matrix to be applied when rendering the layer */
|
||||
lv_matrix_t matrix;
|
||||
#endif
|
||||
|
||||
/** Opacity of the layer */
|
||||
lv_opa_t opa;
|
||||
|
||||
/*Recolor of the layer*/
|
||||
lv_color32_t recolor;
|
||||
|
||||
/** Partial y offset */
|
||||
int32_t partial_y_offset;
|
||||
|
||||
/** Linked list of draw tasks */
|
||||
lv_draw_task_t * draw_task_head;
|
||||
|
||||
lv_layer_t * parent;
|
||||
lv_layer_t * next;
|
||||
bool all_tasks_added;
|
||||
void * user_data;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
/**The widget for which draw descriptor was created */
|
||||
lv_obj_t * obj;
|
||||
|
||||
/**The widget part for which draw descriptor was created */
|
||||
lv_part_t part;
|
||||
|
||||
/**A widget type specific ID (e.g. table row index). See the docs of the given widget.*/
|
||||
uint32_t id1;
|
||||
|
||||
/**A widget type specific ID (e.g. table column index). See the docs of the given widget.*/
|
||||
uint32_t id2;
|
||||
|
||||
/**The target layer */
|
||||
lv_layer_t * layer;
|
||||
|
||||
/**Size of the specific draw descriptor into which this base descriptor is embedded*/
|
||||
size_t dsc_size;
|
||||
|
||||
/**Any custom user data*/
|
||||
void * user_data;
|
||||
} lv_draw_dsc_base_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Used internally to initialize the drawing module
|
||||
*/
|
||||
void lv_draw_init(void);
|
||||
|
||||
/**
|
||||
* Deinitialize the drawing module
|
||||
*/
|
||||
void lv_draw_deinit(void);
|
||||
|
||||
/**
|
||||
* Allocate a new draw unit with the given size and appends it to the list of draw units
|
||||
* @param size the size to allocate. E.g. `sizeof(my_draw_unit_t)`,
|
||||
* where the first element of `my_draw_unit_t` is `lv_draw_unit_t`.
|
||||
*/
|
||||
void * lv_draw_create_unit(size_t size);
|
||||
|
||||
/**
|
||||
* Add an empty draw task to the draw task list of a layer.
|
||||
* @param layer pointer to a layer
|
||||
* @param coords the coordinates of the draw task
|
||||
* @return the created draw task which needs to be
|
||||
* further configured e.g. by added a draw descriptor
|
||||
*/
|
||||
lv_draw_task_t * lv_draw_add_task(lv_layer_t * layer, const lv_area_t * coords, lv_draw_task_type_t type);
|
||||
|
||||
/**
|
||||
* Needs to be called when a draw task is created and configured.
|
||||
* It will send an event about the new draw task to the widget
|
||||
* and assign it to a draw unit.
|
||||
* @param layer pointer to a layer
|
||||
* @param t pointer to a draw task
|
||||
*/
|
||||
void lv_draw_finalize_task_creation(lv_layer_t * layer, lv_draw_task_t * t);
|
||||
|
||||
/**
|
||||
* Try dispatching draw tasks to draw units
|
||||
*/
|
||||
void lv_draw_dispatch(void);
|
||||
|
||||
/**
|
||||
* Used internally to try dispatching draw tasks of a specific layer
|
||||
* @param disp pointer to a display on which the dispatching was requested
|
||||
* @param layer pointer to a layer
|
||||
* @return at least one draw task is being rendered (maybe it was taken earlier)
|
||||
*/
|
||||
bool lv_draw_dispatch_layer(lv_display_t * disp, lv_layer_t * layer);
|
||||
|
||||
/**
|
||||
* Wait for a new dispatch request.
|
||||
* It's blocking if `LV_USE_OS == 0` else it yields
|
||||
*/
|
||||
void lv_draw_dispatch_wait_for_request(void);
|
||||
|
||||
/**
|
||||
* Wait for draw finish in case of asynchronous task execution.
|
||||
* If `LV_USE_OS == 0` it just return.
|
||||
*/
|
||||
void lv_draw_wait_for_finish(void);
|
||||
|
||||
/**
|
||||
* When a draw unit finished a draw task it needs to request dispatching
|
||||
* to let LVGL assign a new draw task to it
|
||||
*/
|
||||
void lv_draw_dispatch_request(void);
|
||||
|
||||
/**
|
||||
* Get the total number of draw units.
|
||||
*/
|
||||
uint32_t lv_draw_get_unit_count(void);
|
||||
|
||||
/**
|
||||
* If there is only one draw unit check the first draw task if it's available.
|
||||
* If there are multiple draw units call `lv_draw_get_next_available_task` to find a task.
|
||||
* @param layer the draw layer to search in
|
||||
* @param t_prev continue searching from this task
|
||||
* @param draw_unit_id check the task where `preferred_draw_unit_id` equals this value or `LV_DRAW_UNIT_NONE`
|
||||
* @return an available draw task or NULL if there is not any
|
||||
*/
|
||||
lv_draw_task_t * lv_draw_get_available_task(lv_layer_t * layer, lv_draw_task_t * t_prev, uint8_t draw_unit_id);
|
||||
|
||||
/**
|
||||
* Find and available draw task
|
||||
* @param layer the draw layer to search in
|
||||
* @param t_prev continue searching from this task
|
||||
* @param draw_unit_id check the task where `preferred_draw_unit_id` equals this value or `LV_DRAW_UNIT_NONE`
|
||||
* @return an available draw task or NULL if there is not any
|
||||
*/
|
||||
lv_draw_task_t * lv_draw_get_next_available_task(lv_layer_t * layer, lv_draw_task_t * t_prev, uint8_t draw_unit_id);
|
||||
|
||||
/**
|
||||
* Tell how many draw task are waiting to be drawn on the area of `t_check`.
|
||||
* It can be used to determine if a GPU shall combine many draw tasks into one or not.
|
||||
* If a lot of tasks are waiting for the current ones it makes sense to draw them one-by-one
|
||||
* to not block the dependent tasks' rendering
|
||||
* @param t_check the task whose dependent tasks shall be counted
|
||||
* @return number of tasks depending on `t_check`
|
||||
*/
|
||||
uint32_t lv_draw_get_dependent_count(lv_draw_task_t * t_check);
|
||||
|
||||
/**
|
||||
* Initialize a layer
|
||||
* @param layer pointer to a layer to initialize
|
||||
*/
|
||||
void lv_layer_init(lv_layer_t * layer);
|
||||
|
||||
/**
|
||||
* Reset the layer to a drawable state
|
||||
* @param layer pointer to a layer to reset
|
||||
*/
|
||||
void lv_layer_reset(lv_layer_t * layer);
|
||||
|
||||
/**
|
||||
* Create (allocate) a new layer on a parent layer
|
||||
* @param parent_layer the parent layer to which the layer will be merged when it's rendered
|
||||
* @param color_format the color format of the layer
|
||||
* @param area the areas of the layer (absolute coordinates)
|
||||
* @return the new target_layer or NULL on error
|
||||
*/
|
||||
lv_layer_t * lv_draw_layer_create(lv_layer_t * parent_layer, lv_color_format_t color_format, const lv_area_t * area);
|
||||
|
||||
/**
|
||||
* Initialize a layer which is allocated by the user
|
||||
* @param layer pointer the layer to initialize (its lifetime needs to be managed by the user)
|
||||
* @param parent_layer the parent layer to which the layer will be merged when it's rendered
|
||||
* @param color_format the color format of the layer
|
||||
* @param area the areas of the layer (absolute coordinates)
|
||||
* @return the new target_layer or NULL on error
|
||||
*/
|
||||
void lv_draw_layer_init(lv_layer_t * layer, lv_layer_t * parent_layer, lv_color_format_t color_format,
|
||||
const lv_area_t * area);
|
||||
|
||||
/**
|
||||
* Try to allocate a buffer for the layer.
|
||||
* @param layer pointer to a layer
|
||||
* @return pointer to the allocated aligned buffer or NULL on failure
|
||||
*/
|
||||
void * lv_draw_layer_alloc_buf(lv_layer_t * layer);
|
||||
|
||||
/**
|
||||
* Got to a pixel at X and Y coordinate on a layer
|
||||
* @param layer pointer to a layer
|
||||
* @param x the target X coordinate
|
||||
* @param y the target X coordinate
|
||||
* @return `buf` offset to point to the given X and Y coordinate
|
||||
*/
|
||||
void * lv_draw_layer_go_to_xy(lv_layer_t * layer, int32_t x, int32_t y);
|
||||
|
||||
/**
|
||||
* Get the type of a draw task
|
||||
* @param t the draw task to get the type of
|
||||
* @return the draw task type
|
||||
*/
|
||||
lv_draw_task_type_t lv_draw_task_get_type(const lv_draw_task_t * t);
|
||||
|
||||
/**
|
||||
* Get the draw descriptor of a draw task
|
||||
* @param t the draw task to get the draw descriptor of
|
||||
* @return a void pointer to the draw descriptor
|
||||
*/
|
||||
void * lv_draw_task_get_draw_dsc(const lv_draw_task_t * t);
|
||||
|
||||
/**
|
||||
* Get the draw area of a draw task
|
||||
* @param t the draw task to get the draw area of
|
||||
* @param area the destination where the draw area will be stored
|
||||
*/
|
||||
void lv_draw_task_get_area(const lv_draw_task_t * t, lv_area_t * area);
|
||||
|
||||
/**********************
|
||||
* GLOBAL VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_H*/
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* @file lv_draw_3d.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_3d.h"
|
||||
#if LV_USE_3DTEXTURE
|
||||
|
||||
#include "lv_draw_private.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_3d_dsc_init(lv_draw_3d_dsc_t * dsc)
|
||||
{
|
||||
lv_memzero(dsc, sizeof(lv_draw_3d_dsc_t));
|
||||
dsc->base.dsc_size = sizeof(lv_draw_3d_dsc_t);
|
||||
dsc->tex_id = LV_3DTEXTURE_ID_NULL;
|
||||
dsc->opa = LV_OPA_COVER;
|
||||
}
|
||||
|
||||
lv_draw_3d_dsc_t * lv_draw_task_get_3d_dsc(lv_draw_task_t * task)
|
||||
{
|
||||
return task->type == LV_DRAW_TASK_TYPE_3D ? (lv_draw_3d_dsc_t *)task->draw_dsc : NULL;
|
||||
}
|
||||
|
||||
void lv_draw_3d(lv_layer_t * layer, const lv_draw_3d_dsc_t * dsc, const lv_area_t * coords)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
|
||||
lv_draw_task_t * t = lv_draw_add_task(layer, coords, LV_DRAW_TASK_TYPE_3D);
|
||||
|
||||
lv_memcpy(t->draw_dsc, dsc, sizeof(*dsc));
|
||||
|
||||
lv_draw_finalize_task_creation(layer, t);
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_3DTEXTURE*/
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* @file lv_draw_3d.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_3D_H
|
||||
#define LV_DRAW_3D_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../lv_conf_internal.h"
|
||||
#if LV_USE_3DTEXTURE
|
||||
|
||||
#include "lv_draw.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct {
|
||||
lv_draw_dsc_base_t base;
|
||||
lv_3dtexture_id_t tex_id;
|
||||
lv_opa_t opa;
|
||||
} lv_draw_3d_dsc_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize a 3D draw descriptor
|
||||
* @param dsc pointer to a draw descriptor
|
||||
*/
|
||||
void lv_draw_3d_dsc_init(lv_draw_3d_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Try to get a 3D draw descriptor from a draw task.
|
||||
* @param task draw task
|
||||
* @return the task's draw descriptor or NULL if the task is not of type LV_DRAW_TASK_TYPE_3D
|
||||
*/
|
||||
lv_draw_3d_dsc_t * lv_draw_task_get_3d_dsc(lv_draw_task_t * task);
|
||||
|
||||
/**
|
||||
* Create a 3D draw task
|
||||
* @param layer pointer to a layer
|
||||
* @param dsc pointer to an initialized `lv_draw_3d_dsc_t` variable
|
||||
*/
|
||||
void lv_draw_3d(lv_layer_t * layer, const lv_draw_3d_dsc_t * dsc, const lv_area_t * coords);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_3DTEXTURE*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_3D_H*/
|
||||
@@ -0,0 +1,172 @@
|
||||
/**
|
||||
* @file lv_draw_arc.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_private.h"
|
||||
#include "../core/lv_obj.h"
|
||||
#include "lv_draw_arc.h"
|
||||
#include "../core/lv_obj_event.h"
|
||||
#include "../stdlib/lv_string.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_arc_dsc_init(lv_draw_arc_dsc_t * dsc)
|
||||
{
|
||||
lv_memzero(dsc, sizeof(lv_draw_arc_dsc_t));
|
||||
dsc->width = 1;
|
||||
dsc->opa = LV_OPA_COVER;
|
||||
dsc->color = lv_color_black();
|
||||
dsc->base.dsc_size = sizeof(lv_draw_arc_dsc_t);
|
||||
}
|
||||
|
||||
lv_draw_arc_dsc_t * lv_draw_task_get_arc_dsc(lv_draw_task_t * task)
|
||||
{
|
||||
return task->type == LV_DRAW_TASK_TYPE_ARC ? (lv_draw_arc_dsc_t *)task->draw_dsc : NULL;
|
||||
}
|
||||
|
||||
void lv_draw_arc(lv_layer_t * layer, const lv_draw_arc_dsc_t * dsc)
|
||||
{
|
||||
if(dsc->opa <= LV_OPA_MIN) return;
|
||||
if(dsc->width == 0) return;
|
||||
if(dsc->start_angle == dsc->end_angle) return;
|
||||
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
lv_area_t a;
|
||||
a.x1 = dsc->center.x - dsc->radius;
|
||||
a.y1 = dsc->center.y - dsc->radius;
|
||||
a.x2 = dsc->center.x + dsc->radius - 1;
|
||||
a.y2 = dsc->center.y + dsc->radius - 1;
|
||||
lv_draw_task_t * t = lv_draw_add_task(layer, &a, LV_DRAW_TASK_TYPE_ARC);
|
||||
|
||||
lv_memcpy(t->draw_dsc, dsc, sizeof(*dsc));
|
||||
|
||||
lv_draw_finalize_task_creation(layer, t);
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
void lv_draw_arc_get_area(int32_t x, int32_t y, uint16_t radius, lv_value_precise_t start_angle,
|
||||
lv_value_precise_t end_angle,
|
||||
int32_t w, bool rounded, lv_area_t * area)
|
||||
{
|
||||
int32_t rout = radius;
|
||||
int32_t start_angle_int = (int32_t) start_angle;
|
||||
int32_t end_angle_int = (int32_t) end_angle;
|
||||
|
||||
/*Special case: full arc invalidation */
|
||||
if(end_angle_int == start_angle_int + 360) {
|
||||
area->x1 = x - rout;
|
||||
area->y1 = y - rout;
|
||||
area->x2 = x + rout;
|
||||
area->y2 = y + rout;
|
||||
return;
|
||||
}
|
||||
|
||||
if(start_angle_int > 360) start_angle_int -= 360;
|
||||
if(end_angle_int > 360) end_angle_int -= 360;
|
||||
|
||||
int32_t rin = radius - w;
|
||||
int32_t extra_area = rounded ? w / 2 + 1 : 0;
|
||||
uint8_t start_quarter = start_angle_int / 90;
|
||||
uint8_t end_quarter = end_angle_int / 90;
|
||||
|
||||
/*360 deg still counts as quarter 3 (360 / 90 would be 4)*/
|
||||
if(start_quarter == 4) start_quarter = 3;
|
||||
if(end_quarter == 4) end_quarter = 3;
|
||||
|
||||
if(start_quarter == end_quarter && start_angle_int <= end_angle_int) {
|
||||
if(start_quarter == 0) {
|
||||
area->y1 = y + ((lv_trigo_sin(start_angle_int) * rin) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
area->x2 = x + ((lv_trigo_sin(start_angle_int + 90) * rout) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
|
||||
area->y2 = y + ((lv_trigo_sin(end_angle_int) * rout) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
area->x1 = x + ((lv_trigo_sin(end_angle_int + 90) * rin) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
}
|
||||
else if(start_quarter == 1) {
|
||||
area->y2 = y + ((lv_trigo_sin(start_angle_int) * rout) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
area->x2 = x + ((lv_trigo_sin(start_angle_int + 90) * rin) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
|
||||
area->y1 = y + ((lv_trigo_sin(end_angle_int) * rin) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
area->x1 = x + ((lv_trigo_sin(end_angle_int + 90) * rout) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
}
|
||||
else if(start_quarter == 2) {
|
||||
area->x1 = x + ((lv_trigo_sin(start_angle_int + 90) * rout) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
area->y2 = y + ((lv_trigo_sin(start_angle_int) * rin) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
|
||||
area->y1 = y + ((lv_trigo_sin(end_angle_int) * rout) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
area->x2 = x + ((lv_trigo_sin(end_angle_int + 90) * rin) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
}
|
||||
else if(start_quarter == 3) {
|
||||
area->x1 = x + ((lv_trigo_sin(start_angle_int + 90) * rin) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
area->y1 = y + ((lv_trigo_sin(start_angle_int) * rout) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
|
||||
area->x2 = x + ((lv_trigo_sin(end_angle_int + 90) * rout) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
area->y2 = y + ((lv_trigo_sin(end_angle_int) * rin) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
}
|
||||
}
|
||||
else if(start_quarter == 0 && end_quarter == 1) {
|
||||
area->x1 = x + ((lv_trigo_sin(end_angle_int + 90) * rout) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
area->y1 = y + ((LV_MIN(lv_trigo_sin(end_angle_int),
|
||||
lv_trigo_sin(start_angle_int)) * rin) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
area->x2 = x + ((lv_trigo_sin(start_angle_int + 90) * rout) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
area->y2 = y + rout + extra_area;
|
||||
}
|
||||
else if(start_quarter == 1 && end_quarter == 2) {
|
||||
area->x1 = x - rout - extra_area;
|
||||
area->y1 = y + ((lv_trigo_sin(end_angle_int) * rout) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
area->x2 = x + ((LV_MAX(lv_trigo_sin(start_angle_int + 90),
|
||||
lv_trigo_sin(end_angle_int + 90)) * rin) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
area->y2 = y + ((lv_trigo_sin(start_angle_int) * rout) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
}
|
||||
else if(start_quarter == 2 && end_quarter == 3) {
|
||||
area->x1 = x + ((lv_trigo_sin(start_angle_int + 90) * rout) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
area->y1 = y - rout - extra_area;
|
||||
area->x2 = x + ((lv_trigo_sin(end_angle_int + 90) * rout) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
area->y2 = y + (LV_MAX(lv_trigo_sin(end_angle_int) * rin,
|
||||
lv_trigo_sin(start_angle_int) * rin) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
}
|
||||
else if(start_quarter == 3 && end_quarter == 0) {
|
||||
area->x1 = x + ((LV_MIN(lv_trigo_sin(end_angle_int + 90),
|
||||
lv_trigo_sin(start_angle_int + 90)) * rin) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
area->y1 = y + ((lv_trigo_sin(start_angle_int) * rout) >> LV_TRIGO_SHIFT) - extra_area;
|
||||
area->x2 = x + rout + extra_area;
|
||||
area->y2 = y + ((lv_trigo_sin(end_angle_int) * rout) >> LV_TRIGO_SHIFT) + extra_area;
|
||||
|
||||
}
|
||||
else {
|
||||
area->x1 = x - rout;
|
||||
area->y1 = y - rout;
|
||||
area->x2 = x + rout;
|
||||
area->y2 = y + rout;
|
||||
}
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* @file lv_draw_arc.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_ARC_H
|
||||
#define LV_DRAW_ARC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../lv_conf_internal.h"
|
||||
#include "../misc/lv_color.h"
|
||||
#include "../misc/lv_area.h"
|
||||
#include "../misc/lv_style.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct {
|
||||
lv_draw_dsc_base_t base;
|
||||
|
||||
/**The color of the arc*/
|
||||
lv_color_t color;
|
||||
|
||||
/**The width (thickness) of the arc */
|
||||
int32_t width;
|
||||
|
||||
/**The start angle in 1 degree units (if `LV_USE_FLOAT` is enabled a float number can be also used)
|
||||
* 0° is the 3 o'clock position, 90° is the 6 o'clock, etc. */
|
||||
lv_value_precise_t start_angle;
|
||||
|
||||
/**The end angle, similarly to start_angle. */
|
||||
lv_value_precise_t end_angle;
|
||||
|
||||
/**The center point of the arc. */
|
||||
lv_point_t center;
|
||||
|
||||
/**The outer radius of the arc*/
|
||||
uint16_t radius;
|
||||
|
||||
/**An image source to be used instead of `color`. `NULL` if unused*/
|
||||
const void * img_src;
|
||||
|
||||
/**Opacity of the arc in 0...255 range.
|
||||
* LV_OPA_TRANSP, LV_OPA_10, LV_OPA_20, .. LV_OPA_COVER can be used as well*/
|
||||
lv_opa_t opa;
|
||||
|
||||
/**1: Make the arc ends rounded*/
|
||||
uint8_t rounded : 1;
|
||||
} lv_draw_arc_dsc_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize an arc draw descriptor.
|
||||
* @param dsc pointer to a draw descriptor
|
||||
*/
|
||||
void lv_draw_arc_dsc_init(lv_draw_arc_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Try to get an arc draw descriptor from a draw task.
|
||||
* @param task draw task
|
||||
* @return the task's draw descriptor or NULL if the task is not of type LV_DRAW_TASK_TYPE_ARC
|
||||
*/
|
||||
lv_draw_arc_dsc_t * lv_draw_task_get_arc_dsc(lv_draw_task_t * task);
|
||||
|
||||
/**
|
||||
* Create an arc draw task.
|
||||
* @param layer pointer to a layer
|
||||
* @param dsc pointer to an initialized draw descriptor variable
|
||||
*/
|
||||
void lv_draw_arc(lv_layer_t * layer, const lv_draw_arc_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Get an area the should be invalidated when the arcs angle changed between start_angle and end_ange
|
||||
* @param x the x coordinate of the center of the arc
|
||||
* @param y the y coordinate of the center of the arc
|
||||
* @param radius the radius of the arc
|
||||
* @param start_angle the start angle of the arc (0 deg on the bottom, 90 deg on the right)
|
||||
* @param end_angle the end angle of the arc
|
||||
* @param w width of the arc
|
||||
* @param rounded true: the arc is rounded
|
||||
* @param area store the area to invalidate here
|
||||
*/
|
||||
void lv_draw_arc_get_area(int32_t x, int32_t y, uint16_t radius, lv_value_precise_t start_angle,
|
||||
lv_value_precise_t end_angle,
|
||||
int32_t w, bool rounded, lv_area_t * area);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_ARC_H*/
|
||||
@@ -0,0 +1,725 @@
|
||||
/**
|
||||
* @file lv_draw_buf.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_buf_private.h"
|
||||
#include "../misc/lv_types.h"
|
||||
#include "../stdlib/lv_string.h"
|
||||
#include "../core/lv_global.h"
|
||||
#include "../misc/lv_math.h"
|
||||
#include "../misc/lv_area_private.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define default_handlers LV_GLOBAL_DEFAULT()->draw_buf_handlers
|
||||
#define font_draw_buf_handlers LV_GLOBAL_DEFAULT()->font_draw_buf_handlers
|
||||
#define image_cache_draw_buf_handlers LV_GLOBAL_DEFAULT()->image_cache_draw_buf_handlers
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static void * buf_malloc(size_t size, lv_color_format_t color_format);
|
||||
static void buf_free(void * buf);
|
||||
static void * buf_align(void * buf, lv_color_format_t color_format);
|
||||
static void * draw_buf_malloc(const lv_draw_buf_handlers_t * handler, size_t size_bytes,
|
||||
lv_color_format_t color_format);
|
||||
static void draw_buf_free(const lv_draw_buf_handlers_t * handler, void * buf);
|
||||
static uint32_t width_to_stride(uint32_t w, lv_color_format_t color_format);
|
||||
static uint32_t _calculate_draw_buf_size(uint32_t w, uint32_t h, lv_color_format_t cf, uint32_t stride);
|
||||
static void draw_buf_get_full_area(const lv_draw_buf_t * draw_buf, lv_area_t * full_area);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_buf_init_handlers(void)
|
||||
{
|
||||
lv_draw_buf_init_with_default_handlers(&default_handlers);
|
||||
lv_draw_buf_init_with_default_handlers(&font_draw_buf_handlers);
|
||||
lv_draw_buf_init_with_default_handlers(&image_cache_draw_buf_handlers);
|
||||
}
|
||||
|
||||
void lv_draw_buf_init_with_default_handlers(lv_draw_buf_handlers_t * handlers)
|
||||
{
|
||||
lv_draw_buf_handlers_init(handlers, buf_malloc, buf_free, buf_align, NULL, NULL, width_to_stride);
|
||||
}
|
||||
|
||||
void lv_draw_buf_handlers_init(lv_draw_buf_handlers_t * handlers,
|
||||
lv_draw_buf_malloc_cb buf_malloc_cb,
|
||||
lv_draw_buf_free_cb buf_free_cb,
|
||||
lv_draw_buf_align_cb align_pointer_cb,
|
||||
lv_draw_buf_cache_operation_cb invalidate_cache_cb,
|
||||
lv_draw_buf_cache_operation_cb flush_cache_cb,
|
||||
lv_draw_buf_width_to_stride_cb width_to_stride_cb)
|
||||
{
|
||||
lv_memzero(handlers, sizeof(lv_draw_buf_handlers_t));
|
||||
handlers->buf_malloc_cb = buf_malloc_cb;
|
||||
handlers->buf_free_cb = buf_free_cb;
|
||||
handlers->align_pointer_cb = align_pointer_cb;
|
||||
handlers->invalidate_cache_cb = invalidate_cache_cb;
|
||||
handlers->flush_cache_cb = flush_cache_cb;
|
||||
handlers->width_to_stride_cb = width_to_stride_cb;
|
||||
}
|
||||
|
||||
lv_draw_buf_handlers_t * lv_draw_buf_get_handlers(void)
|
||||
{
|
||||
return &default_handlers;
|
||||
}
|
||||
|
||||
lv_draw_buf_handlers_t * lv_draw_buf_get_font_handlers(void)
|
||||
{
|
||||
return &font_draw_buf_handlers;
|
||||
}
|
||||
|
||||
lv_draw_buf_handlers_t * lv_draw_buf_get_image_handlers(void)
|
||||
{
|
||||
return &image_cache_draw_buf_handlers;
|
||||
}
|
||||
|
||||
uint32_t lv_draw_buf_width_to_stride(uint32_t w, lv_color_format_t color_format)
|
||||
{
|
||||
return lv_draw_buf_width_to_stride_ex(&default_handlers, w, color_format);
|
||||
}
|
||||
|
||||
uint32_t lv_draw_buf_width_to_stride_ex(const lv_draw_buf_handlers_t * handlers, uint32_t w,
|
||||
lv_color_format_t color_format)
|
||||
{
|
||||
if(handlers->width_to_stride_cb) return handlers->width_to_stride_cb(w, color_format);
|
||||
else return 0;
|
||||
}
|
||||
|
||||
void * lv_draw_buf_align(void * data, lv_color_format_t color_format)
|
||||
{
|
||||
return lv_draw_buf_align_ex(&default_handlers, data, color_format);
|
||||
}
|
||||
|
||||
void * lv_draw_buf_align_ex(const lv_draw_buf_handlers_t * handlers, void * data, lv_color_format_t color_format)
|
||||
{
|
||||
if(handlers->align_pointer_cb) return handlers->align_pointer_cb(data, color_format);
|
||||
else return NULL;
|
||||
}
|
||||
|
||||
void lv_draw_buf_invalidate_cache(const lv_draw_buf_t * draw_buf, const lv_area_t * area)
|
||||
{
|
||||
LV_ASSERT_NULL(draw_buf);
|
||||
LV_ASSERT_NULL(draw_buf->handlers);
|
||||
|
||||
const lv_draw_buf_handlers_t * handlers = draw_buf->handlers;
|
||||
if(!handlers->invalidate_cache_cb) {
|
||||
return;
|
||||
}
|
||||
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
|
||||
lv_area_t full;
|
||||
if(area == NULL) {
|
||||
draw_buf_get_full_area(draw_buf, &full);
|
||||
area = &full;
|
||||
}
|
||||
|
||||
handlers->invalidate_cache_cb(draw_buf, area);
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
void lv_draw_buf_flush_cache(const lv_draw_buf_t * draw_buf, const lv_area_t * area)
|
||||
{
|
||||
LV_ASSERT_NULL(draw_buf);
|
||||
LV_ASSERT_NULL(draw_buf->handlers);
|
||||
|
||||
const lv_draw_buf_handlers_t * handlers = draw_buf->handlers;
|
||||
if(!handlers->flush_cache_cb) {
|
||||
return;
|
||||
}
|
||||
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
|
||||
lv_area_t full;
|
||||
if(area == NULL) {
|
||||
draw_buf_get_full_area(draw_buf, &full);
|
||||
area = &full;
|
||||
}
|
||||
|
||||
handlers->flush_cache_cb(draw_buf, area);
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
void lv_draw_buf_clear(lv_draw_buf_t * draw_buf, const lv_area_t * a)
|
||||
{
|
||||
LV_ASSERT_NULL(draw_buf);
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
|
||||
const lv_image_header_t * header = &draw_buf->header;
|
||||
uint32_t stride = header->stride;
|
||||
|
||||
if(a == NULL) {
|
||||
uint8_t * buf = lv_draw_buf_goto_xy(draw_buf, 0, 0);
|
||||
lv_memzero(buf, header->h * stride);
|
||||
lv_draw_buf_flush_cache(draw_buf, a);
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
|
||||
lv_area_t a_draw_buf;
|
||||
a_draw_buf.x1 = 0;
|
||||
a_draw_buf.y1 = 0;
|
||||
a_draw_buf.x2 = draw_buf->header.w - 1;
|
||||
a_draw_buf.y2 = draw_buf->header.h - 1;
|
||||
|
||||
lv_area_t a_clipped;
|
||||
if(!lv_area_intersect(&a_clipped, a, &a_draw_buf)) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
|
||||
if(lv_area_get_width(&a_clipped) <= 0) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
|
||||
if(lv_area_get_height(&a_clipped) <= 0) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t * buf = lv_draw_buf_goto_xy(draw_buf, a_clipped.x1, a_clipped.y1);
|
||||
uint8_t bpp = lv_color_format_get_bpp(header->cf);
|
||||
uint32_t line_length = (lv_area_get_width(&a_clipped) * bpp + 7) >> 3;
|
||||
int32_t y;
|
||||
for(y = a_clipped.y1; y <= a_clipped.y2; y++) {
|
||||
lv_memzero(buf, line_length);
|
||||
buf += stride;
|
||||
}
|
||||
lv_draw_buf_flush_cache(draw_buf, a);
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
void lv_draw_buf_copy(lv_draw_buf_t * dest, const lv_area_t * dest_area,
|
||||
const lv_draw_buf_t * src, const lv_area_t * src_area)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
uint8_t * dest_bufc;
|
||||
uint8_t * src_bufc;
|
||||
int32_t line_width;
|
||||
|
||||
/*Source and dest color format must be same. Color conversion is not supported yet.*/
|
||||
LV_ASSERT_FORMAT_MSG(dest->header.cf == src->header.cf, "Color format mismatch: %d != %d",
|
||||
dest->header.cf, src->header.cf);
|
||||
|
||||
if(dest_area == NULL) line_width = dest->header.w;
|
||||
else line_width = lv_area_get_width(dest_area);
|
||||
|
||||
/* For indexed image, copy the palette if we are copying full image area*/
|
||||
if(dest_area == NULL || src_area == NULL) {
|
||||
if(LV_COLOR_FORMAT_IS_INDEXED(dest->header.cf)) {
|
||||
lv_memcpy(dest->data, src->data, LV_COLOR_INDEXED_PALETTE_SIZE(dest->header.cf) * sizeof(lv_color32_t));
|
||||
}
|
||||
}
|
||||
|
||||
/*Check source and dest area have same width*/
|
||||
if((src_area == NULL && line_width != src->header.w) || \
|
||||
(src_area != NULL && line_width != lv_area_get_width(src_area))) {
|
||||
LV_ASSERT_MSG(0, "Source and destination areas have different width");
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
|
||||
if(src_area) src_bufc = lv_draw_buf_goto_xy(src, src_area->x1, src_area->y1);
|
||||
else src_bufc = lv_draw_buf_goto_xy(src, 0, 0);
|
||||
|
||||
if(dest_area) dest_bufc = lv_draw_buf_goto_xy(dest, dest_area->x1, dest_area->y1);
|
||||
else dest_bufc = lv_draw_buf_goto_xy(dest, 0, 0);
|
||||
|
||||
int32_t start_y, end_y;
|
||||
if(dest_area) {
|
||||
start_y = dest_area->y1;
|
||||
end_y = dest_area->y2;
|
||||
}
|
||||
else {
|
||||
start_y = 0;
|
||||
end_y = dest->header.h - 1;
|
||||
}
|
||||
|
||||
uint32_t dest_stride = dest->header.stride;
|
||||
uint32_t src_stride = src->header.stride;
|
||||
uint32_t line_bytes = (line_width * lv_color_format_get_bpp(dest->header.cf) + 7) >> 3;
|
||||
|
||||
for(; start_y <= end_y; start_y++) {
|
||||
lv_memcpy(dest_bufc, src_bufc, line_bytes);
|
||||
dest_bufc += dest_stride;
|
||||
src_bufc += src_stride;
|
||||
}
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
lv_result_t lv_draw_buf_init(lv_draw_buf_t * draw_buf, uint32_t w, uint32_t h, lv_color_format_t cf, uint32_t stride,
|
||||
void * data, uint32_t data_size)
|
||||
{
|
||||
LV_ASSERT_NULL(draw_buf);
|
||||
if(draw_buf == NULL) return LV_RESULT_INVALID;
|
||||
|
||||
lv_memzero(draw_buf, sizeof(lv_draw_buf_t));
|
||||
if(stride == 0) stride = lv_draw_buf_width_to_stride(w, cf);
|
||||
if(stride * h > data_size) {
|
||||
LV_LOG_WARN("Data size too small, required: %" LV_PRId32 ", provided: %" LV_PRId32, stride * h,
|
||||
data_size);
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
|
||||
lv_image_header_t * header = &draw_buf->header;
|
||||
header->w = w;
|
||||
header->h = h;
|
||||
header->cf = cf;
|
||||
header->stride = stride;
|
||||
header->flags = 0;
|
||||
header->magic = LV_IMAGE_HEADER_MAGIC;
|
||||
|
||||
draw_buf->data = data;
|
||||
draw_buf->unaligned_data = data;
|
||||
draw_buf->handlers = &default_handlers;
|
||||
draw_buf->data_size = data_size;
|
||||
if(lv_draw_buf_align(data, cf) != draw_buf->unaligned_data) {
|
||||
LV_LOG_WARN("Data is not aligned, ignored");
|
||||
}
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
|
||||
lv_draw_buf_t * lv_draw_buf_create(uint32_t w, uint32_t h, lv_color_format_t cf, uint32_t stride)
|
||||
{
|
||||
return lv_draw_buf_create_ex(&default_handlers, w, h, cf, stride);
|
||||
}
|
||||
|
||||
lv_draw_buf_t * lv_draw_buf_create_ex(const lv_draw_buf_handlers_t * handlers, uint32_t w, uint32_t h,
|
||||
lv_color_format_t cf, uint32_t stride)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
lv_draw_buf_t * draw_buf = lv_malloc_zeroed(sizeof(lv_draw_buf_t));
|
||||
LV_ASSERT_MALLOC(draw_buf);
|
||||
if(draw_buf == NULL) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return NULL;
|
||||
}
|
||||
if(stride == 0) stride = lv_draw_buf_width_to_stride(w, cf);
|
||||
|
||||
uint32_t size = _calculate_draw_buf_size(w, h, cf, stride);
|
||||
|
||||
void * buf = draw_buf_malloc(handlers, size, cf);
|
||||
/*Do not assert here as LVGL or the app might just want to try creating a draw_buf*/
|
||||
if(buf == NULL) {
|
||||
LV_LOG_WARN("No memory: %"LV_PRIu32"x%"LV_PRIu32", cf: %d, stride: %"LV_PRIu32", %"LV_PRIu32"Byte, ",
|
||||
w, h, cf, stride, size);
|
||||
lv_free(draw_buf);
|
||||
LV_PROFILER_DRAW_END;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
draw_buf->header.w = w;
|
||||
draw_buf->header.h = h;
|
||||
draw_buf->header.cf = cf;
|
||||
draw_buf->header.flags = LV_IMAGE_FLAGS_MODIFIABLE | LV_IMAGE_FLAGS_ALLOCATED;
|
||||
draw_buf->header.stride = stride;
|
||||
draw_buf->header.magic = LV_IMAGE_HEADER_MAGIC;
|
||||
draw_buf->data = lv_draw_buf_align(buf, cf);
|
||||
draw_buf->unaligned_data = buf;
|
||||
draw_buf->data_size = size;
|
||||
draw_buf->handlers = handlers;
|
||||
LV_PROFILER_DRAW_END;
|
||||
return draw_buf;
|
||||
}
|
||||
|
||||
lv_draw_buf_t * lv_draw_buf_dup(const lv_draw_buf_t * draw_buf)
|
||||
{
|
||||
return lv_draw_buf_dup_ex(&default_handlers, draw_buf);
|
||||
}
|
||||
|
||||
lv_draw_buf_t * lv_draw_buf_dup_ex(const lv_draw_buf_handlers_t * handlers, const lv_draw_buf_t * draw_buf)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
const lv_image_header_t * header = &draw_buf->header;
|
||||
lv_draw_buf_t * new_buf = lv_draw_buf_create_ex(handlers, header->w, header->h, header->cf, header->stride);
|
||||
if(new_buf == NULL) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
new_buf->header.flags = draw_buf->header.flags;
|
||||
new_buf->header.flags |= LV_IMAGE_FLAGS_MODIFIABLE | LV_IMAGE_FLAGS_ALLOCATED;
|
||||
|
||||
/*Choose the smaller size to copy*/
|
||||
uint32_t size = LV_MIN(draw_buf->data_size, new_buf->data_size);
|
||||
|
||||
/*Copy image data*/
|
||||
lv_memcpy(new_buf->data, draw_buf->data, size);
|
||||
LV_PROFILER_DRAW_END;
|
||||
return new_buf;
|
||||
}
|
||||
|
||||
lv_draw_buf_t * lv_draw_buf_reshape(lv_draw_buf_t * draw_buf, lv_color_format_t cf, uint32_t w, uint32_t h,
|
||||
uint32_t stride)
|
||||
{
|
||||
if(draw_buf == NULL) return NULL;
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
|
||||
/*If color format is unknown, keep using the original color format.*/
|
||||
if(cf == LV_COLOR_FORMAT_UNKNOWN) cf = draw_buf->header.cf;
|
||||
if(stride == 0) stride = lv_draw_buf_width_to_stride(w, cf);
|
||||
|
||||
uint32_t size = _calculate_draw_buf_size(w, h, cf, stride);
|
||||
|
||||
if(size > draw_buf->data_size) {
|
||||
LV_LOG_TRACE("Draw buf too small for new shape");
|
||||
LV_PROFILER_DRAW_END;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
draw_buf->header.cf = cf;
|
||||
draw_buf->header.w = w;
|
||||
draw_buf->header.h = h;
|
||||
draw_buf->header.stride = stride;
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
return draw_buf;
|
||||
}
|
||||
|
||||
void lv_draw_buf_destroy(lv_draw_buf_t * draw_buf)
|
||||
{
|
||||
LV_ASSERT_NULL(draw_buf);
|
||||
if(draw_buf == NULL) return;
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
|
||||
if(draw_buf->header.flags & LV_IMAGE_FLAGS_ALLOCATED) {
|
||||
LV_ASSERT_NULL(draw_buf->handlers);
|
||||
|
||||
const lv_draw_buf_handlers_t * handlers = draw_buf->handlers;
|
||||
draw_buf_free(handlers, draw_buf->unaligned_data);
|
||||
lv_free(draw_buf);
|
||||
}
|
||||
else {
|
||||
LV_LOG_ERROR("draw buffer is not allocated, ignored");
|
||||
}
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
void * lv_draw_buf_goto_xy(const lv_draw_buf_t * buf, uint32_t x, uint32_t y)
|
||||
{
|
||||
LV_ASSERT_NULL(buf);
|
||||
if(buf == NULL) return NULL;
|
||||
|
||||
uint8_t * data = buf->data;
|
||||
|
||||
/*Skip palette*/
|
||||
data += LV_COLOR_INDEXED_PALETTE_SIZE(buf->header.cf) * sizeof(lv_color32_t);
|
||||
data += buf->header.stride * y;
|
||||
|
||||
if(x == 0) return data;
|
||||
|
||||
return data + x * lv_color_format_get_bpp(buf->header.cf) / 8;
|
||||
}
|
||||
|
||||
lv_result_t lv_draw_buf_adjust_stride(lv_draw_buf_t * src, uint32_t stride)
|
||||
{
|
||||
LV_ASSERT_NULL(src);
|
||||
LV_ASSERT_NULL(src->data);
|
||||
if(src == NULL) return LV_RESULT_INVALID;
|
||||
if(src->data == NULL) return LV_RESULT_INVALID;
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
|
||||
const lv_image_header_t * header = &src->header;
|
||||
uint32_t w = header->w;
|
||||
uint32_t h = header->h;
|
||||
|
||||
if(!lv_draw_buf_has_flag(src, LV_IMAGE_FLAGS_MODIFIABLE)) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
|
||||
/*Use global stride*/
|
||||
if(stride == 0) stride = lv_draw_buf_width_to_stride(w, header->cf);
|
||||
|
||||
/*Check if stride already match*/
|
||||
if(header->stride == stride) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
|
||||
/*Calculate the minimal stride allowed from bpp*/
|
||||
uint32_t bpp = lv_color_format_get_bpp(header->cf);
|
||||
uint32_t min_stride = (w * bpp + 7) >> 3;
|
||||
if(stride < min_stride) {
|
||||
LV_LOG_WARN("New stride is too small. min: %" LV_PRId32, min_stride);
|
||||
LV_PROFILER_DRAW_END;
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
|
||||
/*Check if buffer has enough space. */
|
||||
uint32_t new_size = _calculate_draw_buf_size(w, h, header->cf, stride);
|
||||
if(new_size > src->data_size) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
|
||||
uint32_t offset = LV_COLOR_INDEXED_PALETTE_SIZE(header->cf) * 4;
|
||||
|
||||
if(stride > header->stride) {
|
||||
/*Copy from the last line to the first*/
|
||||
uint8_t * src_data = src->data + offset + header->stride * (h - 1);
|
||||
uint8_t * dst_data = src->data + offset + stride * (h - 1);
|
||||
for(uint32_t y = 0; y < h; y++) {
|
||||
lv_memmove(dst_data, src_data, min_stride);
|
||||
src_data -= header->stride;
|
||||
dst_data -= stride;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/*Copy from the first line to the last*/
|
||||
uint8_t * src_data = src->data + offset;
|
||||
uint8_t * dst_data = src->data + offset;
|
||||
for(uint32_t y = 0; y < h; y++) {
|
||||
lv_memmove(dst_data, src_data, min_stride);
|
||||
src_data += header->stride;
|
||||
dst_data += stride;
|
||||
}
|
||||
}
|
||||
|
||||
src->header.stride = stride;
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
|
||||
lv_result_t lv_draw_buf_premultiply(lv_draw_buf_t * draw_buf)
|
||||
{
|
||||
LV_ASSERT_NULL(draw_buf);
|
||||
if(draw_buf == NULL) return LV_RESULT_INVALID;
|
||||
|
||||
if(draw_buf->header.flags & LV_IMAGE_FLAGS_PREMULTIPLIED) return LV_RESULT_INVALID;
|
||||
if((draw_buf->header.flags & LV_IMAGE_FLAGS_MODIFIABLE) == 0) {
|
||||
LV_LOG_WARN("draw buf is not modifiable: 0x%04x", draw_buf->header.flags);
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
|
||||
/*Premultiply color with alpha, do case by case by judging color format*/
|
||||
lv_color_format_t cf = draw_buf->header.cf;
|
||||
if(LV_COLOR_FORMAT_IS_INDEXED(cf)) {
|
||||
int size = LV_COLOR_INDEXED_PALETTE_SIZE(cf);
|
||||
lv_color32_t * palette = (lv_color32_t *)draw_buf->data;
|
||||
for(int i = 0; i < size; i++) {
|
||||
lv_color_premultiply(&palette[i]);
|
||||
}
|
||||
}
|
||||
else if(cf == LV_COLOR_FORMAT_ARGB8888) {
|
||||
uint32_t h = draw_buf->header.h;
|
||||
uint32_t w = draw_buf->header.w;
|
||||
uint32_t stride = draw_buf->header.stride;
|
||||
uint8_t * line = (uint8_t *)draw_buf->data;
|
||||
for(uint32_t y = 0; y < h; y++) {
|
||||
lv_color32_t * pixel = (lv_color32_t *)line;
|
||||
for(uint32_t x = 0; x < w; x++) {
|
||||
lv_color_premultiply(pixel);
|
||||
pixel++;
|
||||
}
|
||||
line += stride;
|
||||
}
|
||||
}
|
||||
else if(cf == LV_COLOR_FORMAT_RGB565A8) {
|
||||
uint32_t h = draw_buf->header.h;
|
||||
uint32_t w = draw_buf->header.w;
|
||||
uint32_t stride = draw_buf->header.stride;
|
||||
uint32_t alpha_stride = stride / 2;
|
||||
uint8_t * line = (uint8_t *)draw_buf->data;
|
||||
lv_opa_t * alpha = (lv_opa_t *)(line + stride * h);
|
||||
for(uint32_t y = 0; y < h; y++) {
|
||||
lv_color16_t * pixel = (lv_color16_t *)line;
|
||||
for(uint32_t x = 0; x < w; x++) {
|
||||
lv_color16_premultiply(pixel, alpha[x]);
|
||||
pixel++;
|
||||
}
|
||||
line += stride;
|
||||
alpha += alpha_stride;
|
||||
}
|
||||
}
|
||||
else if(cf == LV_COLOR_FORMAT_ARGB8565) {
|
||||
uint32_t h = draw_buf->header.h;
|
||||
uint32_t w = draw_buf->header.w;
|
||||
uint32_t stride = draw_buf->header.stride;
|
||||
uint8_t * line = (uint8_t *)draw_buf->data;
|
||||
for(uint32_t y = 0; y < h; y++) {
|
||||
uint8_t * pixel = line;
|
||||
for(uint32_t x = 0; x < w; x++) {
|
||||
uint8_t alpha = pixel[2];
|
||||
lv_color16_premultiply((lv_color16_t *)pixel, alpha);
|
||||
pixel += 3;
|
||||
}
|
||||
line += stride;
|
||||
}
|
||||
}
|
||||
else if(LV_COLOR_FORMAT_IS_ALPHA_ONLY(cf)) {
|
||||
/*Pass*/
|
||||
}
|
||||
else {
|
||||
LV_LOG_WARN("draw buf has no alpha, cf: %d", cf);
|
||||
}
|
||||
|
||||
draw_buf->header.flags |= LV_IMAGE_FLAGS_PREMULTIPLIED;
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
|
||||
void lv_draw_buf_set_palette(lv_draw_buf_t * draw_buf, uint8_t index, lv_color32_t color)
|
||||
{
|
||||
LV_ASSERT_NULL(draw_buf);
|
||||
if(draw_buf == NULL) return;
|
||||
|
||||
if(!LV_COLOR_FORMAT_IS_INDEXED(draw_buf->header.cf)) {
|
||||
LV_LOG_WARN("Not indexed color format");
|
||||
return;
|
||||
}
|
||||
|
||||
lv_color32_t * palette = (lv_color32_t *)draw_buf->data;
|
||||
palette[index] = color;
|
||||
}
|
||||
|
||||
bool lv_draw_buf_has_flag(const lv_draw_buf_t * draw_buf, lv_image_flags_t flag)
|
||||
{
|
||||
return draw_buf->header.flags & flag;
|
||||
}
|
||||
|
||||
void lv_draw_buf_set_flag(lv_draw_buf_t * draw_buf, lv_image_flags_t flag)
|
||||
{
|
||||
draw_buf->header.flags |= flag;
|
||||
}
|
||||
|
||||
void lv_draw_buf_clear_flag(lv_draw_buf_t * draw_buf, lv_image_flags_t flag)
|
||||
{
|
||||
draw_buf->header.flags &= ~flag;
|
||||
}
|
||||
|
||||
lv_result_t lv_draw_buf_from_image(lv_draw_buf_t * buf, const lv_image_dsc_t * img)
|
||||
{
|
||||
const lv_result_t res = lv_draw_buf_init(buf, img->header.w, img->header.h, img->header.cf, img->header.stride,
|
||||
(void *)img->data, img->data_size);
|
||||
if(res != LV_RESULT_OK) {
|
||||
return res;
|
||||
}
|
||||
|
||||
buf->header.flags = img->header.flags;
|
||||
return res;
|
||||
}
|
||||
|
||||
void lv_draw_buf_to_image(const lv_draw_buf_t * buf, lv_image_dsc_t * img)
|
||||
{
|
||||
lv_memcpy((void *)img, buf, sizeof(lv_image_dsc_t));
|
||||
}
|
||||
|
||||
void lv_image_buf_set_palette(lv_image_dsc_t * dsc, uint8_t id, lv_color32_t c)
|
||||
{
|
||||
LV_LOG_WARN("Deprecated API, use lv_draw_buf_set_palette instead.");
|
||||
lv_draw_buf_set_palette((lv_draw_buf_t *)dsc, id, c);
|
||||
}
|
||||
|
||||
void lv_image_buf_free(lv_image_dsc_t * dsc)
|
||||
{
|
||||
LV_LOG_WARN("Deprecated API, use lv_draw_buf_destroy instead.");
|
||||
if(dsc != NULL) {
|
||||
if(dsc->data != NULL)
|
||||
lv_free((void *)dsc->data);
|
||||
|
||||
lv_free((void *)dsc);
|
||||
}
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void * buf_malloc(size_t size_bytes, lv_color_format_t color_format)
|
||||
{
|
||||
LV_UNUSED(color_format);
|
||||
|
||||
/*Allocate larger memory to be sure it can be aligned as needed*/
|
||||
size_bytes += LV_DRAW_BUF_ALIGN - 1;
|
||||
return lv_malloc(size_bytes);
|
||||
}
|
||||
|
||||
static void buf_free(void * buf)
|
||||
{
|
||||
lv_free(buf);
|
||||
}
|
||||
|
||||
static void * buf_align(void * buf, lv_color_format_t color_format)
|
||||
{
|
||||
LV_UNUSED(color_format);
|
||||
|
||||
uint8_t * buf_u8 = buf;
|
||||
if(buf_u8) {
|
||||
buf_u8 = (uint8_t *)LV_ROUND_UP((lv_uintptr_t)buf_u8, LV_DRAW_BUF_ALIGN);
|
||||
}
|
||||
return buf_u8;
|
||||
}
|
||||
|
||||
static uint32_t width_to_stride(uint32_t w, lv_color_format_t color_format)
|
||||
{
|
||||
uint32_t width_byte;
|
||||
width_byte = w * lv_color_format_get_bpp(color_format);
|
||||
width_byte = (width_byte + 7) >> 3; /*Round up*/
|
||||
|
||||
return LV_ROUND_UP(width_byte, LV_DRAW_BUF_STRIDE_ALIGN);
|
||||
}
|
||||
|
||||
static void * draw_buf_malloc(const lv_draw_buf_handlers_t * handlers, size_t size_bytes,
|
||||
lv_color_format_t color_format)
|
||||
{
|
||||
if(handlers->buf_malloc_cb) return handlers->buf_malloc_cb(size_bytes, color_format);
|
||||
else return NULL;
|
||||
}
|
||||
|
||||
static void draw_buf_free(const lv_draw_buf_handlers_t * handlers, void * buf)
|
||||
{
|
||||
if(handlers->buf_free_cb)
|
||||
handlers->buf_free_cb(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* For given width, height, color format, and stride, calculate the size needed for a new draw buffer.
|
||||
*/
|
||||
static uint32_t _calculate_draw_buf_size(uint32_t w, uint32_t h, lv_color_format_t cf, uint32_t stride)
|
||||
{
|
||||
uint32_t size;
|
||||
|
||||
if(stride == 0) stride = lv_draw_buf_width_to_stride(w, cf);
|
||||
|
||||
size = stride * h;
|
||||
if(cf == LV_COLOR_FORMAT_RGB565A8) {
|
||||
size += (stride / 2) * h; /*A8 mask*/
|
||||
}
|
||||
else if(LV_COLOR_FORMAT_IS_INDEXED(cf)) {
|
||||
/*@todo we have to include palette right before image data*/
|
||||
size += LV_COLOR_INDEXED_PALETTE_SIZE(cf) * 4;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static void draw_buf_get_full_area(const lv_draw_buf_t * draw_buf, lv_area_t * full_area)
|
||||
{
|
||||
const lv_image_header_t * header = &draw_buf->header;
|
||||
lv_area_set(full_area, 0, 0, header->w - 1, header->h - 1);
|
||||
}
|
||||
@@ -0,0 +1,356 @@
|
||||
/**
|
||||
* @file lv_draw_buf.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_BUF_H
|
||||
#define LV_DRAW_BUF_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../misc/lv_types.h"
|
||||
#include "../misc/lv_area.h"
|
||||
#include "../misc/lv_color.h"
|
||||
#include "../stdlib/lv_string.h"
|
||||
#include "lv_image_dsc.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/** Use this value to let LVGL calculate stride automatically */
|
||||
#define LV_STRIDE_AUTO 0
|
||||
LV_EXPORT_CONST_INT(LV_STRIDE_AUTO);
|
||||
|
||||
/**
|
||||
* Stride alignment for draw buffers.
|
||||
* It may vary between different color formats and hardware.
|
||||
* Refine it to suit your needs.
|
||||
*/
|
||||
|
||||
#define LV_DRAW_BUF_STRIDE(w, cf) \
|
||||
LV_ROUND_UP(((w) * LV_COLOR_FORMAT_GET_BPP(cf) + 7) / 8, LV_DRAW_BUF_STRIDE_ALIGN)
|
||||
|
||||
/** Allocate a slightly larger buffer, so we can adjust the start address to meet alignment */
|
||||
#define LV_DRAW_BUF_SIZE(w, h, cf) \
|
||||
(LV_DRAW_BUF_STRIDE(w, cf) * (h) + LV_DRAW_BUF_ALIGN + \
|
||||
LV_COLOR_INDEXED_PALETTE_SIZE(cf) * sizeof(lv_color32_t))
|
||||
|
||||
/**
|
||||
* Define a static draw buffer with the given width, height, and color format.
|
||||
* Stride alignment is set to LV_DRAW_BUF_STRIDE_ALIGN.
|
||||
*
|
||||
* For platform that needs special buffer alignment, call LV_DRAW_BUF_INIT_STATIC.
|
||||
*/
|
||||
#define LV_DRAW_BUF_DEFINE_STATIC(name, _w, _h, _cf) \
|
||||
static LV_ATTRIBUTE_MEM_ALIGN uint8_t buf_##name[LV_DRAW_BUF_SIZE(_w, _h, _cf)]; \
|
||||
static lv_draw_buf_t name = { \
|
||||
.header = { \
|
||||
.magic = LV_IMAGE_HEADER_MAGIC, \
|
||||
.cf = (_cf), \
|
||||
.flags = LV_IMAGE_FLAGS_MODIFIABLE, \
|
||||
.w = (_w), \
|
||||
.h = (_h), \
|
||||
.stride = LV_DRAW_BUF_STRIDE(_w, _cf), \
|
||||
.reserved_2 = 0, \
|
||||
}, \
|
||||
.data_size = sizeof(buf_##name), \
|
||||
.data = buf_##name, \
|
||||
.unaligned_data = buf_##name, \
|
||||
}
|
||||
|
||||
#define LV_DRAW_BUF_INIT_STATIC(name) \
|
||||
do { \
|
||||
lv_image_header_t * header = &name.header; \
|
||||
lv_draw_buf_init(&name, header->w, header->h, (lv_color_format_t)header->cf, header->stride, buf_##name, sizeof(buf_##name)); \
|
||||
lv_draw_buf_set_flag(&name, LV_IMAGE_FLAGS_MODIFIABLE); \
|
||||
} while(0)
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef void * (*lv_draw_buf_malloc_cb)(size_t size, lv_color_format_t color_format);
|
||||
|
||||
typedef void (*lv_draw_buf_free_cb)(void * draw_buf);
|
||||
|
||||
typedef void * (*lv_draw_buf_align_cb)(void * buf, lv_color_format_t color_format);
|
||||
|
||||
typedef void (*lv_draw_buf_cache_operation_cb)(const lv_draw_buf_t * draw_buf, const lv_area_t * area);
|
||||
|
||||
typedef uint32_t (*lv_draw_buf_width_to_stride_cb)(uint32_t w, lv_color_format_t color_format);
|
||||
|
||||
struct _lv_draw_buf_t {
|
||||
lv_image_header_t header;
|
||||
uint32_t data_size; /**< Total buf size in bytes */
|
||||
uint8_t * data;
|
||||
void * unaligned_data; /**< Unaligned address of `data`, used internally by lvgl */
|
||||
const lv_draw_buf_handlers_t * handlers; /**< draw buffer alloc/free ops. */
|
||||
};
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize the draw buffer with the default handlers.
|
||||
*
|
||||
* @param handlers the draw buffer handlers to set
|
||||
*/
|
||||
void lv_draw_buf_init_with_default_handlers(lv_draw_buf_handlers_t * handlers);
|
||||
|
||||
/**
|
||||
* Initialize the draw buffer with given handlers.
|
||||
*
|
||||
* @param handlers the draw buffer handlers to set
|
||||
* @param buf_malloc_cb the callback to allocate memory for the buffer
|
||||
* @param buf_free_cb the callback to free memory of the buffer
|
||||
* @param align_pointer_cb the callback to align the buffer
|
||||
* @param invalidate_cache_cb the callback to invalidate the cache of the buffer
|
||||
* @param flush_cache_cb the callback to flush buffer
|
||||
* @param width_to_stride_cb the callback to calculate the stride based on the width and color format
|
||||
*/
|
||||
void lv_draw_buf_handlers_init(lv_draw_buf_handlers_t * handlers,
|
||||
lv_draw_buf_malloc_cb buf_malloc_cb,
|
||||
lv_draw_buf_free_cb buf_free_cb,
|
||||
lv_draw_buf_align_cb align_pointer_cb,
|
||||
lv_draw_buf_cache_operation_cb invalidate_cache_cb,
|
||||
lv_draw_buf_cache_operation_cb flush_cache_cb,
|
||||
lv_draw_buf_width_to_stride_cb width_to_stride_cb);
|
||||
|
||||
/**
|
||||
* Get the struct which holds the callbacks for draw buf management.
|
||||
* Custom callback can be set on the returned value
|
||||
* @return pointer to the struct of handlers
|
||||
*/
|
||||
lv_draw_buf_handlers_t * lv_draw_buf_get_handlers(void);
|
||||
lv_draw_buf_handlers_t * lv_draw_buf_get_font_handlers(void);
|
||||
lv_draw_buf_handlers_t * lv_draw_buf_get_image_handlers(void);
|
||||
|
||||
|
||||
/**
|
||||
* Align the address of a buffer. The buffer needs to be large enough for the real data after alignment
|
||||
* @param buf the data to align
|
||||
* @param color_format the color format of the buffer
|
||||
* @return the aligned buffer
|
||||
*/
|
||||
void * lv_draw_buf_align(void * buf, lv_color_format_t color_format);
|
||||
|
||||
/**
|
||||
* Align the address of a buffer with custom draw buffer handlers.
|
||||
* The buffer needs to be large enough for the real data after alignment
|
||||
* @param handlers the draw buffer handlers
|
||||
* @param buf the data to align
|
||||
* @param color_format the color format of the buffer
|
||||
* @return the aligned buffer
|
||||
*/
|
||||
void * lv_draw_buf_align_ex(const lv_draw_buf_handlers_t * handlers, void * buf, lv_color_format_t color_format);
|
||||
|
||||
/**
|
||||
* Invalidate the cache of the buffer
|
||||
* @param draw_buf the draw buffer needs to be invalidated
|
||||
* @param area the area to invalidate in the buffer,
|
||||
* use NULL to invalidate the whole draw buffer address range
|
||||
*/
|
||||
void lv_draw_buf_invalidate_cache(const lv_draw_buf_t * draw_buf, const lv_area_t * area);
|
||||
|
||||
/**
|
||||
* Flush the cache of the buffer
|
||||
* @param draw_buf the draw buffer needs to be flushed
|
||||
* @param area the area to flush in the buffer,
|
||||
* use NULL to flush the whole draw buffer address range
|
||||
*/
|
||||
void lv_draw_buf_flush_cache(const lv_draw_buf_t * draw_buf, const lv_area_t * area);
|
||||
|
||||
/**
|
||||
* Calculate the stride in bytes based on a width and color format
|
||||
* @param w the width in pixels
|
||||
* @param color_format the color format
|
||||
* @return the stride in bytes
|
||||
*/
|
||||
uint32_t lv_draw_buf_width_to_stride(uint32_t w, lv_color_format_t color_format);
|
||||
|
||||
/**
|
||||
* Calculate the stride in bytes based on a width and color format
|
||||
* @param handlers the draw buffer handlers
|
||||
* @param w the width in pixels
|
||||
* @param color_format the color format
|
||||
* @return the stride in bytes
|
||||
*/
|
||||
uint32_t lv_draw_buf_width_to_stride_ex(const lv_draw_buf_handlers_t * handlers, uint32_t w,
|
||||
lv_color_format_t color_format);
|
||||
|
||||
/**
|
||||
* Clear an area on the buffer
|
||||
* @param draw_buf pointer to draw buffer
|
||||
* @param a the area to clear, or NULL to clear the whole buffer
|
||||
*/
|
||||
void lv_draw_buf_clear(lv_draw_buf_t * draw_buf, const lv_area_t * a);
|
||||
|
||||
/**
|
||||
* Copy an area from a buffer to another
|
||||
* @param dest pointer to the destination draw buffer
|
||||
* @param dest_area the area to copy from the destination buffer, if NULL, use the whole buffer
|
||||
* @param src pointer to the source draw buffer
|
||||
* @param src_area the area to copy from the destination buffer, if NULL, use the whole buffer
|
||||
* @note `dest_area` and `src_area` should have the same width and height
|
||||
* @note `dest` and `src` should have same color format. Color converting is not supported fow now.
|
||||
*/
|
||||
void lv_draw_buf_copy(lv_draw_buf_t * dest, const lv_area_t * dest_area,
|
||||
const lv_draw_buf_t * src, const lv_area_t * src_area);
|
||||
|
||||
/**
|
||||
* Note: Eventually, lv_draw_buf_malloc/free will be kept as private.
|
||||
* For now, we use `create` to distinguish with malloc.
|
||||
*
|
||||
* Create an draw buf by allocating struct for `lv_draw_buf_t` and allocating a buffer for it
|
||||
* that meets specified requirements.
|
||||
*
|
||||
* @param w the buffer width in pixels
|
||||
* @param h the buffer height in pixels
|
||||
* @param cf the color format for image
|
||||
* @param stride the stride in bytes for image. Use 0 for automatic calculation based on
|
||||
* w, cf, and global stride alignment configuration.
|
||||
*/
|
||||
lv_draw_buf_t * lv_draw_buf_create(uint32_t w, uint32_t h, lv_color_format_t cf, uint32_t stride);
|
||||
|
||||
/**
|
||||
* Note: Eventually, lv_draw_buf_malloc/free will be kept as private.
|
||||
* For now, we use `create` to distinguish with malloc.
|
||||
*
|
||||
* Create an draw buf by allocating struct for `lv_draw_buf_t` and allocating a buffer for it
|
||||
* that meets specified requirements.
|
||||
*
|
||||
* @param handlers the draw buffer handlers
|
||||
* @param w the buffer width in pixels
|
||||
* @param h the buffer height in pixels
|
||||
* @param cf the color format for image
|
||||
* @param stride the stride in bytes for image. Use 0 for automatic calculation based on
|
||||
* w, cf, and global stride alignment configuration.
|
||||
*/
|
||||
lv_draw_buf_t * lv_draw_buf_create_ex(const lv_draw_buf_handlers_t * handlers, uint32_t w, uint32_t h,
|
||||
lv_color_format_t cf, uint32_t stride);
|
||||
|
||||
/**
|
||||
* Duplicate a draw buf with same image size, stride and color format. Copy the image data too.
|
||||
* @param draw_buf the draw buf to duplicate
|
||||
* @return the duplicated draw buf on success, NULL if failed
|
||||
*/
|
||||
lv_draw_buf_t * lv_draw_buf_dup(const lv_draw_buf_t * draw_buf);
|
||||
|
||||
/**
|
||||
* Duplicate a draw buf with same image size, stride and color format. Copy the image data too.
|
||||
* @param handlers the draw buffer handlers
|
||||
* @param draw_buf the draw buf to duplicate
|
||||
* @return the duplicated draw buf on success, NULL if failed
|
||||
*/
|
||||
lv_draw_buf_t * lv_draw_buf_dup_ex(const lv_draw_buf_handlers_t * handlers, const lv_draw_buf_t * draw_buf);
|
||||
|
||||
/**
|
||||
* Initialize a draw buf with the given buffer and parameters. Clear draw buffer flag to zero.
|
||||
* @param draw_buf the draw buf to initialize
|
||||
* @param w the buffer width in pixels
|
||||
* @param h the buffer height in pixels
|
||||
* @param cf the color format
|
||||
* @param stride the stride in bytes. Use 0 for automatic calculation
|
||||
* @param data the buffer used for drawing. Unaligned `data` will be aligned internally
|
||||
* @param data_size the size of the buffer in bytes
|
||||
* @return return LV_RESULT_OK on success, LV_RESULT_INVALID otherwise
|
||||
*/
|
||||
lv_result_t lv_draw_buf_init(lv_draw_buf_t * draw_buf, uint32_t w, uint32_t h, lv_color_format_t cf, uint32_t stride,
|
||||
void * data, uint32_t data_size);
|
||||
|
||||
/**
|
||||
* Keep using the existing memory, reshape the draw buffer to the given width and height.
|
||||
* Return NULL if data_size is smaller than the required size.
|
||||
* @param draw_buf pointer to a draw buffer
|
||||
* @param cf the new color format, use 0 or LV_COLOR_FORMAT_UNKNOWN to keep using the original color format.
|
||||
* @param w the new width in pixels
|
||||
* @param h the new height in pixels
|
||||
* @param stride the stride in bytes for image. Use 0 for automatic calculation.
|
||||
*/
|
||||
lv_draw_buf_t * lv_draw_buf_reshape(lv_draw_buf_t * draw_buf, lv_color_format_t cf, uint32_t w, uint32_t h,
|
||||
uint32_t stride);
|
||||
|
||||
/**
|
||||
* Destroy a draw buf by freeing the actual buffer if it's marked as LV_IMAGE_FLAGS_ALLOCATED in header.
|
||||
* Then free the lv_draw_buf_t struct.
|
||||
*
|
||||
* @param draw_buf the draw buffer to destroy
|
||||
*/
|
||||
void lv_draw_buf_destroy(lv_draw_buf_t * draw_buf);
|
||||
|
||||
/**
|
||||
* Return pointer to the buffer at the given coordinates
|
||||
*/
|
||||
void * lv_draw_buf_goto_xy(const lv_draw_buf_t * buf, uint32_t x, uint32_t y);
|
||||
|
||||
/**
|
||||
* Adjust the stride of a draw buf in place.
|
||||
* @param src pointer to a draw buffer
|
||||
* @param stride the new stride in bytes for image. Use LV_STRIDE_AUTO for automatic calculation.
|
||||
* @return LV_RESULT_OK: success or LV_RESULT_INVALID: failed
|
||||
*/
|
||||
lv_result_t lv_draw_buf_adjust_stride(lv_draw_buf_t * src, uint32_t stride);
|
||||
|
||||
/**
|
||||
* Premultiply draw buffer color with alpha channel.
|
||||
* If it's already premultiplied, return directly.
|
||||
* Only color formats with alpha channel will be processed.
|
||||
*
|
||||
* @return LV_RESULT_OK: premultiply success
|
||||
*/
|
||||
lv_result_t lv_draw_buf_premultiply(lv_draw_buf_t * draw_buf);
|
||||
|
||||
bool lv_draw_buf_has_flag(const lv_draw_buf_t * draw_buf, lv_image_flags_t flag);
|
||||
|
||||
void lv_draw_buf_set_flag(lv_draw_buf_t * draw_buf, lv_image_flags_t flag);
|
||||
|
||||
void lv_draw_buf_clear_flag(lv_draw_buf_t * draw_buf, lv_image_flags_t flag);
|
||||
|
||||
/**
|
||||
* As of now, draw buf share same definition as `lv_image_dsc_t`.
|
||||
* And is interchangeable with `lv_image_dsc_t`.
|
||||
*/
|
||||
|
||||
lv_result_t lv_draw_buf_from_image(lv_draw_buf_t * buf, const lv_image_dsc_t * img);
|
||||
|
||||
void lv_draw_buf_to_image(const lv_draw_buf_t * buf, lv_image_dsc_t * img);
|
||||
|
||||
/**
|
||||
* Set the palette color of an indexed image. Valid only for `LV_COLOR_FORMAT_I1/2/4/8`
|
||||
* @param draw_buf pointer to an image descriptor
|
||||
* @param index the palette color to set:
|
||||
* - for `LV_COLOR_FORMAT_I1`: 0..1
|
||||
* - for `LV_COLOR_FORMAT_I2`: 0..3
|
||||
* - for `LV_COLOR_FORMAT_I4`: 0..15
|
||||
* - for `LV_COLOR_FORMAT_I8`: 0..255
|
||||
* @param color the color to set in lv_color32_t format
|
||||
*/
|
||||
void lv_draw_buf_set_palette(lv_draw_buf_t * draw_buf, uint8_t index, lv_color32_t color);
|
||||
|
||||
/**
|
||||
* @deprecated Use lv_draw_buf_set_palette instead.
|
||||
*/
|
||||
void lv_image_buf_set_palette(lv_image_dsc_t * dsc, uint8_t id, lv_color32_t c);
|
||||
|
||||
/**
|
||||
* @deprecated Use lv_draw_buffer_create/destroy instead.
|
||||
* Free the data pointer and dsc struct of an image.
|
||||
*/
|
||||
void lv_image_buf_free(lv_image_dsc_t * dsc);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_BUF_H*/
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* @file lv_draw_buf_private.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_BUF_PRIVATE_H
|
||||
#define LV_DRAW_BUF_PRIVATE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_buf.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
struct _lv_draw_buf_handlers_t {
|
||||
lv_draw_buf_malloc_cb buf_malloc_cb;
|
||||
lv_draw_buf_free_cb buf_free_cb;
|
||||
lv_draw_buf_align_cb align_pointer_cb;
|
||||
lv_draw_buf_cache_operation_cb invalidate_cache_cb;
|
||||
lv_draw_buf_cache_operation_cb flush_cache_cb;
|
||||
lv_draw_buf_width_to_stride_cb width_to_stride_cb;
|
||||
};
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Called internally to initialize the draw_buf_handlers in lv_global
|
||||
*/
|
||||
void lv_draw_buf_init_handlers(void);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_BUF_PRIVATE_H*/
|
||||
@@ -0,0 +1,376 @@
|
||||
/**
|
||||
* @file lv_draw_img.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_image_private.h"
|
||||
#include "../misc/lv_area_private.h"
|
||||
#include "lv_image_decoder_private.h"
|
||||
#include "lv_draw_private.h"
|
||||
#include "../display/lv_display.h"
|
||||
#include "../misc/lv_log.h"
|
||||
#include "../misc/lv_math.h"
|
||||
#include "../core/lv_refr.h"
|
||||
#include "../core/lv_obj_private.h"
|
||||
#include "../stdlib/lv_mem.h"
|
||||
#include "../stdlib/lv_string.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static void img_decode_and_draw(lv_draw_task_t * t, const lv_draw_image_dsc_t * draw_dsc,
|
||||
lv_image_decoder_dsc_t * decoder_dsc, lv_area_t * relative_decoded_area,
|
||||
const lv_area_t * img_area, const lv_area_t * clipped_img_area,
|
||||
lv_draw_image_core_cb draw_core_cb);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_image_dsc_init(lv_draw_image_dsc_t * dsc)
|
||||
{
|
||||
lv_memzero(dsc, sizeof(lv_draw_image_dsc_t));
|
||||
dsc->recolor = lv_color_black();
|
||||
dsc->opa = LV_OPA_COVER;
|
||||
dsc->scale_x = LV_SCALE_NONE;
|
||||
dsc->scale_y = LV_SCALE_NONE;
|
||||
dsc->antialias = LV_COLOR_DEPTH > 8 ? 1 : 0;
|
||||
dsc->image_area.x2 = LV_COORD_MIN; /*Indicate invalid area by default by setting a negative size*/
|
||||
dsc->base.dsc_size = sizeof(lv_draw_image_dsc_t);
|
||||
}
|
||||
|
||||
lv_draw_image_dsc_t * lv_draw_task_get_image_dsc(lv_draw_task_t * task)
|
||||
{
|
||||
return task->type == LV_DRAW_TASK_TYPE_IMAGE ? (lv_draw_image_dsc_t *)task->draw_dsc : NULL;
|
||||
}
|
||||
|
||||
void lv_draw_layer(lv_layer_t * layer, const lv_draw_image_dsc_t * dsc, const lv_area_t * coords)
|
||||
{
|
||||
if(dsc->scale_x <= 0 || dsc->scale_y <= 0) {
|
||||
/* NOT draw if scale is negative or zero */
|
||||
return;
|
||||
}
|
||||
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
|
||||
lv_draw_task_t * t = lv_draw_add_task(layer, coords, LV_DRAW_TASK_TYPE_LAYER);
|
||||
lv_draw_image_dsc_t * new_image_dsc = t->draw_dsc;
|
||||
lv_memcpy(new_image_dsc, dsc, sizeof(*dsc));
|
||||
t->state = LV_DRAW_TASK_STATE_WAITING;
|
||||
|
||||
lv_image_buf_get_transformed_area(&t->_real_area, lv_area_get_width(coords), lv_area_get_height(coords),
|
||||
dsc->rotation, dsc->scale_x, dsc->scale_y, &dsc->pivot);
|
||||
lv_area_move(&t->_real_area, coords->x1, coords->y1);
|
||||
|
||||
/*If the image_area is not set assume that it's the same as the rendering area */
|
||||
if(new_image_dsc->image_area.x2 == LV_COORD_MIN) {
|
||||
new_image_dsc->image_area = *coords;
|
||||
}
|
||||
|
||||
lv_layer_t * layer_to_draw = (lv_layer_t *)dsc->src;
|
||||
layer_to_draw->all_tasks_added = true;
|
||||
|
||||
lv_draw_finalize_task_creation(layer, t);
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
void lv_draw_image(lv_layer_t * layer, const lv_draw_image_dsc_t * dsc, const lv_area_t * image_coords)
|
||||
{
|
||||
if(dsc->src == NULL) {
|
||||
LV_LOG_WARN("Image draw: src is NULL");
|
||||
return;
|
||||
}
|
||||
if(dsc->opa <= LV_OPA_MIN) return;
|
||||
|
||||
if(dsc->scale_x <= 0 || dsc->scale_y <= 0) {
|
||||
/* NOT draw if scale is negative or zero */
|
||||
return;
|
||||
}
|
||||
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
|
||||
lv_draw_image_dsc_t new_image_dsc;
|
||||
lv_memcpy(&new_image_dsc, dsc, sizeof(*dsc));
|
||||
lv_result_t res = lv_image_decoder_get_info(new_image_dsc.src, &new_image_dsc.header);
|
||||
if(res != LV_RESULT_OK) {
|
||||
LV_LOG_WARN("Couldn't get info about the image");
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
|
||||
/*If the image_area is not set assume that it's the same as the rendering area */
|
||||
if(new_image_dsc.image_area.x2 == LV_COORD_MIN) {
|
||||
new_image_dsc.image_area = *image_coords;
|
||||
}
|
||||
|
||||
/*Typical case, draw the image as bitmap*/
|
||||
if(!(new_image_dsc.header.flags & LV_IMAGE_FLAGS_CUSTOM_DRAW)) {
|
||||
lv_draw_task_t * t = lv_draw_add_task(layer, image_coords, LV_DRAW_TASK_TYPE_IMAGE);
|
||||
lv_memcpy(t->draw_dsc, &new_image_dsc, sizeof(lv_draw_image_dsc_t));
|
||||
|
||||
lv_image_buf_get_transformed_area(&t->_real_area, lv_area_get_width(image_coords), lv_area_get_height(image_coords),
|
||||
dsc->rotation, dsc->scale_x, dsc->scale_y, &dsc->pivot);
|
||||
lv_area_move(&t->_real_area, image_coords->x1, image_coords->y1);
|
||||
|
||||
lv_draw_finalize_task_creation(layer, t);
|
||||
}
|
||||
/*Use a custom draw callback*/
|
||||
else {
|
||||
|
||||
lv_image_decoder_dsc_t decoder_dsc;
|
||||
res = lv_image_decoder_open(&decoder_dsc, new_image_dsc.src, NULL);
|
||||
if(res != LV_RESULT_OK) {
|
||||
LV_LOG_ERROR("Failed to open image");
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
|
||||
if(decoder_dsc.decoder && decoder_dsc.decoder->custom_draw_cb) {
|
||||
lv_area_t draw_area = layer->buf_area;
|
||||
lv_area_t coords_area = *image_coords;
|
||||
|
||||
lv_area_t obj_area = dsc->base.obj->coords;
|
||||
if(layer->parent) { /* child layer */
|
||||
if(lv_area_intersect(&coords_area, &coords_area, &obj_area)) {
|
||||
int32_t xpos = image_coords->x1 - draw_area.x1;
|
||||
int32_t ypos = image_coords->y1 - draw_area.y1;
|
||||
|
||||
lv_area_move(&coords_area, -(image_coords->x1 - xpos), -(image_coords->y1 - ypos));
|
||||
layer->_clip_area = coords_area;
|
||||
decoder_dsc.decoder->custom_draw_cb(layer, &decoder_dsc, &coords_area, &new_image_dsc, &coords_area);
|
||||
}
|
||||
}
|
||||
else {
|
||||
lv_area_t clip_area = draw_area;
|
||||
if(lv_area_intersect(&clip_area, &clip_area, &coords_area)) {
|
||||
|
||||
lv_image_buf_get_transformed_area(&coords_area, lv_area_get_width(image_coords), lv_area_get_height(image_coords),
|
||||
dsc->rotation, dsc->scale_x, dsc->scale_y, &dsc->pivot);
|
||||
lv_area_move(&coords_area, image_coords->x1, image_coords->y1);
|
||||
|
||||
lv_image_buf_get_transformed_area(&clip_area, lv_area_get_width(image_coords), lv_area_get_height(image_coords),
|
||||
dsc->rotation, dsc->scale_x, dsc->scale_y, &dsc->pivot);
|
||||
lv_area_move(&clip_area, image_coords->x1, image_coords->y1);
|
||||
|
||||
if(lv_area_intersect(&clip_area, &clip_area, &obj_area)) {
|
||||
decoder_dsc.decoder->custom_draw_cb(layer, &decoder_dsc, &coords_area, &new_image_dsc, &clip_area);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
lv_image_src_t lv_image_src_get_type(const void * src)
|
||||
{
|
||||
if(src == NULL) return LV_IMAGE_SRC_UNKNOWN;
|
||||
const uint8_t * u8_p = src;
|
||||
|
||||
/*The first byte shows the type of the image source*/
|
||||
if(u8_p[0] >= 0x20 && u8_p[0] <= 0x7F) {
|
||||
return LV_IMAGE_SRC_FILE; /*If it's an ASCII character then it's file name*/
|
||||
}
|
||||
else if(u8_p[0] >= 0x80) {
|
||||
return LV_IMAGE_SRC_SYMBOL; /*Symbols begins after 0x7F*/
|
||||
}
|
||||
else {
|
||||
return LV_IMAGE_SRC_VARIABLE; /*`lv_image_dsc_t` is draw to the first byte < 0x20*/
|
||||
}
|
||||
}
|
||||
|
||||
void lv_draw_image_normal_helper(lv_draw_task_t * t, const lv_draw_image_dsc_t * draw_dsc,
|
||||
const lv_area_t * coords, lv_draw_image_core_cb draw_core_cb)
|
||||
{
|
||||
if(draw_core_cb == NULL) {
|
||||
LV_LOG_WARN("draw_core_cb is NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
lv_area_t draw_area;
|
||||
lv_area_copy(&draw_area, coords);
|
||||
if(draw_dsc->rotation || draw_dsc->scale_x != LV_SCALE_NONE || draw_dsc->scale_y != LV_SCALE_NONE) {
|
||||
int32_t w = lv_area_get_width(coords);
|
||||
int32_t h = lv_area_get_height(coords);
|
||||
|
||||
lv_image_buf_get_transformed_area(&draw_area, w, h, draw_dsc->rotation, draw_dsc->scale_x, draw_dsc->scale_y,
|
||||
&draw_dsc->pivot);
|
||||
|
||||
draw_area.x1 += coords->x1;
|
||||
draw_area.y1 += coords->y1;
|
||||
draw_area.x2 += coords->x1;
|
||||
draw_area.y2 += coords->y1;
|
||||
}
|
||||
|
||||
lv_area_t clipped_img_area;
|
||||
if(!lv_area_intersect(&clipped_img_area, &draw_area, &t->clip_area)) {
|
||||
return;
|
||||
}
|
||||
|
||||
lv_image_decoder_dsc_t decoder_dsc;
|
||||
lv_result_t res = lv_image_decoder_open(&decoder_dsc, draw_dsc->src, NULL);
|
||||
if(res != LV_RESULT_OK) {
|
||||
LV_LOG_ERROR("Failed to open image");
|
||||
return;
|
||||
}
|
||||
|
||||
img_decode_and_draw(t, draw_dsc, &decoder_dsc, NULL, coords, &clipped_img_area, draw_core_cb);
|
||||
|
||||
lv_image_decoder_close(&decoder_dsc);
|
||||
}
|
||||
|
||||
void lv_draw_image_tiled_helper(lv_draw_task_t * t, const lv_draw_image_dsc_t * draw_dsc,
|
||||
const lv_area_t * coords, lv_draw_image_core_cb draw_core_cb)
|
||||
{
|
||||
if(draw_core_cb == NULL) {
|
||||
LV_LOG_WARN("draw_core_cb is NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
lv_image_decoder_dsc_t decoder_dsc;
|
||||
lv_result_t res = lv_image_decoder_open(&decoder_dsc, draw_dsc->src, NULL);
|
||||
if(res != LV_RESULT_OK) {
|
||||
LV_LOG_ERROR("Failed to open image");
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t img_w = draw_dsc->header.w;
|
||||
int32_t img_h = draw_dsc->header.h;
|
||||
|
||||
lv_area_t tile_area;
|
||||
if(lv_area_get_width(&draw_dsc->image_area) >= 0) {
|
||||
tile_area = draw_dsc->image_area;
|
||||
}
|
||||
else {
|
||||
tile_area = *coords;
|
||||
}
|
||||
lv_area_set_width(&tile_area, img_w);
|
||||
lv_area_set_height(&tile_area, img_h);
|
||||
|
||||
int32_t tile_x_start = tile_area.x1;
|
||||
|
||||
lv_area_t relative_decoded_area = {
|
||||
.x1 = LV_COORD_MIN,
|
||||
.y1 = LV_COORD_MIN,
|
||||
.x2 = LV_COORD_MIN,
|
||||
.y2 = LV_COORD_MIN,
|
||||
};
|
||||
|
||||
while(tile_area.y1 <= coords->y2) {
|
||||
while(tile_area.x1 <= coords->x2) {
|
||||
|
||||
lv_area_t clipped_img_area;
|
||||
if(lv_area_intersect(&clipped_img_area, &tile_area, coords)) {
|
||||
img_decode_and_draw(t, draw_dsc, &decoder_dsc, &relative_decoded_area, &tile_area, &clipped_img_area,
|
||||
draw_core_cb);
|
||||
}
|
||||
|
||||
tile_area.x1 += img_w;
|
||||
tile_area.x2 += img_w;
|
||||
}
|
||||
|
||||
tile_area.y1 += img_h;
|
||||
tile_area.y2 += img_h;
|
||||
tile_area.x1 = tile_x_start;
|
||||
tile_area.x2 = tile_x_start + img_w - 1;
|
||||
}
|
||||
|
||||
lv_image_decoder_close(&decoder_dsc);
|
||||
}
|
||||
|
||||
void lv_image_buf_get_transformed_area(lv_area_t * res, int32_t w, int32_t h, int32_t angle,
|
||||
uint16_t scale_x, uint16_t scale_y, const lv_point_t * pivot)
|
||||
{
|
||||
if(angle == 0 && scale_x == LV_SCALE_NONE && scale_y == LV_SCALE_NONE) {
|
||||
res->x1 = 0;
|
||||
res->y1 = 0;
|
||||
res->x2 = w - 1;
|
||||
res->y2 = h - 1;
|
||||
return;
|
||||
}
|
||||
|
||||
lv_point_t p[4] = {
|
||||
{0, 0},
|
||||
{w, 0},
|
||||
{0, h},
|
||||
{w, h},
|
||||
};
|
||||
lv_point_transform(&p[0], angle, scale_x, scale_y, pivot, true);
|
||||
lv_point_transform(&p[1], angle, scale_x, scale_y, pivot, true);
|
||||
lv_point_transform(&p[2], angle, scale_x, scale_y, pivot, true);
|
||||
lv_point_transform(&p[3], angle, scale_x, scale_y, pivot, true);
|
||||
res->x1 = LV_MIN4(p[0].x, p[1].x, p[2].x, p[3].x);
|
||||
res->x2 = LV_MAX4(p[0].x, p[1].x, p[2].x, p[3].x) - 1;
|
||||
res->y1 = LV_MIN4(p[0].y, p[1].y, p[2].y, p[3].y);
|
||||
res->y2 = LV_MAX4(p[0].y, p[1].y, p[2].y, p[3].y) - 1;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void img_decode_and_draw(lv_draw_task_t * t, const lv_draw_image_dsc_t * draw_dsc,
|
||||
lv_image_decoder_dsc_t * decoder_dsc, lv_area_t * relative_decoded_area,
|
||||
const lv_area_t * img_area, const lv_area_t * clipped_img_area,
|
||||
lv_draw_image_core_cb draw_core_cb)
|
||||
{
|
||||
lv_draw_image_sup_t sup;
|
||||
sup.alpha_color = draw_dsc->recolor;
|
||||
sup.palette = decoder_dsc->palette;
|
||||
sup.palette_size = decoder_dsc->palette_size;
|
||||
|
||||
/*The whole image is available, just draw it*/
|
||||
if(decoder_dsc->decoded && (relative_decoded_area == NULL || relative_decoded_area->x1 == LV_COORD_MIN)) {
|
||||
draw_core_cb(t, draw_dsc, decoder_dsc, &sup, img_area, clipped_img_area);
|
||||
}
|
||||
/*Draw in smaller pieces*/
|
||||
else {
|
||||
lv_area_t relative_full_area_to_decode = *clipped_img_area;
|
||||
lv_area_move(&relative_full_area_to_decode, -img_area->x1, -img_area->y1);
|
||||
lv_area_t tmp;
|
||||
if(relative_decoded_area == NULL) relative_decoded_area = &tmp;
|
||||
relative_decoded_area->x1 = LV_COORD_MIN;
|
||||
relative_decoded_area->y1 = LV_COORD_MIN;
|
||||
relative_decoded_area->x2 = LV_COORD_MIN;
|
||||
relative_decoded_area->y2 = LV_COORD_MIN;
|
||||
lv_result_t res = LV_RESULT_OK;
|
||||
|
||||
while(res == LV_RESULT_OK) {
|
||||
res = lv_image_decoder_get_area(decoder_dsc, &relative_full_area_to_decode, relative_decoded_area);
|
||||
|
||||
lv_area_t absolute_decoded_area = *relative_decoded_area;
|
||||
lv_area_move(&absolute_decoded_area, img_area->x1, img_area->y1);
|
||||
if(res == LV_RESULT_OK) {
|
||||
/*Limit draw area to the current decoded area and draw the image*/
|
||||
lv_area_t clipped_img_area_sub;
|
||||
if(lv_area_intersect(&clipped_img_area_sub, clipped_img_area, &absolute_decoded_area)) {
|
||||
draw_core_cb(t, draw_dsc, decoder_dsc, &sup,
|
||||
&absolute_decoded_area, &clipped_img_area_sub);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
/**
|
||||
* @file lv_draw_image.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_IMAGE_H
|
||||
#define LV_DRAW_IMAGE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw.h"
|
||||
#include "lv_image_decoder.h"
|
||||
#include "lv_draw_buf.h"
|
||||
#include "../misc/lv_style.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
struct _lv_draw_image_dsc_t {
|
||||
lv_draw_dsc_base_t base;
|
||||
|
||||
/**The image source: pointer to `lv_image_dsc_t` or a path to a file*/
|
||||
const void * src;
|
||||
|
||||
/**The header of the image. Initialized internally in `lv_draw_image` */
|
||||
lv_image_header_t header;
|
||||
|
||||
/**Clip the corner of the image with this radius. Use `LV_RADIUS_CIRCLE` for max. radius */
|
||||
int32_t clip_radius;
|
||||
|
||||
/**The rotation of the image in 0.1 degree unit. E.g. 234 means 23.4° */
|
||||
int32_t rotation;
|
||||
|
||||
/**Horizontal scale (zoom) of the image.
|
||||
* 256 (LV_SCALE_NONE): means no zoom, 512 double size, 128 half size.*/
|
||||
int32_t scale_x;
|
||||
|
||||
/**Same as `scale_y` but vertically*/
|
||||
int32_t scale_y;
|
||||
|
||||
/**Parallelogram like transformation of the image horizontally in 0.1 degree unit. E.g. 456 means 45.6°.*/
|
||||
int32_t skew_x;
|
||||
|
||||
/**Same as `skew_x` but vertically*/
|
||||
int32_t skew_y;
|
||||
|
||||
/**The pivot point of transformation (scale and rotation).
|
||||
* 0;0 is the top left corner of the image. Can be outside of the image too.*/
|
||||
lv_point_t pivot;
|
||||
|
||||
/**Mix this color to the images. In case of `LV_COLOR_FORMAT_A8` it will be the color of the visible pixels*/
|
||||
lv_color_t recolor;
|
||||
|
||||
/**The intensity of recoloring. 0 means, no recolor, 255 means full cover (transparent pixels remain transparent)*/
|
||||
lv_opa_t recolor_opa;
|
||||
|
||||
/**Opacity in 0...255 range.
|
||||
* LV_OPA_TRANSP, LV_OPA_10, LV_OPA_20, .. LV_OPA_COVER can be used as well*/
|
||||
lv_opa_t opa;
|
||||
|
||||
/**Describes how to blend the pixels of the image to the background.
|
||||
* See `lv_blend_mode_t` for more details.
|
||||
*/
|
||||
lv_blend_mode_t blend_mode : 4;
|
||||
|
||||
/**1: perform the transformation with anti-alaising */
|
||||
uint16_t antialias : 1;
|
||||
|
||||
/**If the image is smaller than the `image_area` field of `lv_draw_image_dsc_t`
|
||||
* tile the image (repeat is both horizontally and vertically) to fill the
|
||||
* `image_area` area*/
|
||||
uint16_t tile : 1;
|
||||
|
||||
/**Used internally to store some information about the palette or the color of A8 images*/
|
||||
lv_draw_image_sup_t * sup;
|
||||
|
||||
/** Used to indicate the entire original, non-clipped area where the image is to be drawn.
|
||||
* This is important for:
|
||||
* 1. Layer rendering, where it might happen that only a smaller area of the layer is rendered and e.g.
|
||||
* `clip_radius` needs to know what the original image was.
|
||||
* 2. Tiled images, where the target draw area is larger than the image to be tiled.
|
||||
*/
|
||||
lv_area_t image_area;
|
||||
|
||||
/**Pointer to an A8 or L8 image descriptor to mask the image with.
|
||||
* The mask is always center aligned. */
|
||||
const lv_image_dsc_t * bitmap_mask_src;
|
||||
};
|
||||
|
||||
/**
|
||||
* PErform the actual rendering of a decoded image
|
||||
* @param t pointer to a draw task
|
||||
* @param draw_dsc the draw descriptor of the image
|
||||
* @param decoder_dsc pointer to the decoded image's descriptor
|
||||
* @param sup supplementary data
|
||||
* @param img_coords the absolute coordinates of the image
|
||||
* @param clipped_img_area the absolute clip coordinates
|
||||
*/
|
||||
typedef void (*lv_draw_image_core_cb)(lv_draw_task_t * t, const lv_draw_image_dsc_t * draw_dsc,
|
||||
const lv_image_decoder_dsc_t * decoder_dsc, lv_draw_image_sup_t * sup,
|
||||
const lv_area_t * img_coords, const lv_area_t * clipped_img_area);
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize an image draw descriptor.
|
||||
* @param dsc pointer to a draw descriptor
|
||||
*/
|
||||
void lv_draw_image_dsc_init(lv_draw_image_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Try to get an image draw descriptor from a draw task.
|
||||
* @param task draw task
|
||||
* @return the task's draw descriptor or NULL if the task is not of type LV_DRAW_TASK_TYPE_IMAGE
|
||||
*/
|
||||
lv_draw_image_dsc_t * lv_draw_task_get_image_dsc(lv_draw_task_t * task);
|
||||
|
||||
/**
|
||||
* Create an image draw task
|
||||
* @param layer pointer to a layer
|
||||
* @param dsc pointer to an initialized draw descriptor
|
||||
* @param coords the coordinates of the image
|
||||
* @note `coords` can be small than the real image area
|
||||
* (if only a part of the image is rendered)
|
||||
* or can be larger (in case of tiled images). .
|
||||
*/
|
||||
void lv_draw_image(lv_layer_t * layer, const lv_draw_image_dsc_t * dsc, const lv_area_t * coords);
|
||||
|
||||
/**
|
||||
* Create a draw task to blend a layer to another layer
|
||||
* @param layer pointer to a layer
|
||||
* @param dsc pointer to an initialized draw descriptor. `src` must be set to the layer to blend
|
||||
* @param coords the coordinates of the layer.
|
||||
* @note `coords` can be small than the total widget area from which the layer is created
|
||||
* (if only a part of the widget was rendered to a layer)
|
||||
*/
|
||||
void lv_draw_layer(lv_layer_t * layer, const lv_draw_image_dsc_t * dsc, const lv_area_t * coords);
|
||||
|
||||
/**
|
||||
* Get the type of an image source
|
||||
* @param src pointer to an image source:
|
||||
* - pointer to an 'lv_image_t' variable (image stored internally and compiled into the code)
|
||||
* - a path to a file (e.g. "S:/folder/image.bin")
|
||||
* - or a symbol (e.g. LV_SYMBOL_CLOSE)
|
||||
* @return type of the image source LV_IMAGE_SRC_VARIABLE/FILE/SYMBOL/UNKNOWN
|
||||
*/
|
||||
lv_image_src_t lv_image_src_get_type(const void * src);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_IMAGE_H*/
|
||||
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* @file lv_draw_image_private.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_IMAGE_PRIVATE_H
|
||||
#define LV_DRAW_IMAGE_PRIVATE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_image.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
struct _lv_draw_image_sup_t {
|
||||
lv_color_t alpha_color;
|
||||
const lv_color32_t * palette;
|
||||
uint32_t palette_size : 9;
|
||||
};
|
||||
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Can be used by draw units to handle the decoding and
|
||||
* prepare everything for the actual image rendering
|
||||
* @param t pointer to a draw task
|
||||
* @param draw_dsc the draw descriptor of the image
|
||||
* @param coords the absolute coordinates of the image
|
||||
* @param draw_core_cb a callback to perform the actual rendering
|
||||
*/
|
||||
void lv_draw_image_normal_helper(lv_draw_task_t * t, const lv_draw_image_dsc_t * draw_dsc,
|
||||
const lv_area_t * coords, lv_draw_image_core_cb draw_core_cb);
|
||||
|
||||
/**
|
||||
* Can be used by draw units for TILED images to handle the decoding and
|
||||
* prepare everything for the actual image rendering
|
||||
* @param t pointer to a draw task
|
||||
* @param draw_dsc the draw descriptor of the image
|
||||
* @param coords the absolute coordinates of the image
|
||||
* @param draw_core_cb a callback to perform the actual rendering
|
||||
*/
|
||||
void lv_draw_image_tiled_helper(lv_draw_task_t * t, const lv_draw_image_dsc_t * draw_dsc,
|
||||
const lv_area_t * coords, lv_draw_image_core_cb draw_core_cb);
|
||||
|
||||
/**
|
||||
* Get the area of a rectangle if its rotated and scaled
|
||||
* @param res store the coordinates here
|
||||
* @param w width of the rectangle to transform
|
||||
* @param h height of the rectangle to transform
|
||||
* @param angle angle of rotation
|
||||
* @param scale_x zoom in x direction, (256 no zoom)
|
||||
* @param scale_y zoom in y direction, (256 no zoom)
|
||||
* @param pivot x,y pivot coordinates of rotation
|
||||
*/
|
||||
void lv_image_buf_get_transformed_area(lv_area_t * res, int32_t w, int32_t h, int32_t angle,
|
||||
uint16_t scale_x, uint16_t scale_y, const lv_point_t * pivot);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_IMAGE_PRIVATE_H*/
|
||||
@@ -0,0 +1,636 @@
|
||||
/**
|
||||
* @file lv_draw_label.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_label_private.h"
|
||||
#include "lv_draw_private.h"
|
||||
#include "../misc/lv_area_private.h"
|
||||
#include "lv_draw_vector_private.h"
|
||||
#include "lv_draw_rect_private.h"
|
||||
#include "../core/lv_obj.h"
|
||||
#include "../misc/lv_math.h"
|
||||
#include "../core/lv_obj_event.h"
|
||||
#include "../misc/lv_bidi_private.h"
|
||||
#include "../misc/lv_text_private.h"
|
||||
#include "../misc/lv_assert.h"
|
||||
#include "../stdlib/lv_mem.h"
|
||||
#include "../stdlib/lv_string.h"
|
||||
#include "../core/lv_global.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LABEL_RECOLOR_PAR_LENGTH 6
|
||||
#define LV_LABEL_HINT_UPDATE_TH 1024 /*Update the "hint" if the label's y coordinates have changed more then this*/
|
||||
|
||||
#define font_draw_buf_handlers &(LV_GLOBAL_DEFAULT()->font_draw_buf_handlers)
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
enum {
|
||||
RECOLOR_CMD_STATE_WAIT_FOR_PARAMETER,
|
||||
RECOLOR_CMD_STATE_PARAMETER,
|
||||
RECOLOR_CMD_STATE_TEXT_INPUT,
|
||||
};
|
||||
typedef unsigned char cmd_state_t;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static uint8_t hex_char_to_num(char hex);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_letter_dsc_init(lv_draw_letter_dsc_t * dsc)
|
||||
{
|
||||
lv_memzero(dsc, sizeof(lv_draw_letter_dsc_t));
|
||||
dsc->opa = LV_OPA_COVER;
|
||||
dsc->color = lv_color_black();
|
||||
dsc->font = LV_FONT_DEFAULT;
|
||||
dsc->rotation = 0;
|
||||
dsc->scale_x = LV_SCALE_NONE;
|
||||
dsc->scale_y = LV_SCALE_NONE;
|
||||
dsc->base.dsc_size = sizeof(lv_draw_letter_dsc_t);
|
||||
}
|
||||
|
||||
void lv_draw_label_dsc_init(lv_draw_label_dsc_t * dsc)
|
||||
{
|
||||
lv_memzero(dsc, sizeof(lv_draw_label_dsc_t));
|
||||
dsc->opa = LV_OPA_COVER;
|
||||
dsc->color = lv_color_black();
|
||||
dsc->text_length = LV_TEXT_LEN_MAX;
|
||||
dsc->font = LV_FONT_DEFAULT;
|
||||
dsc->sel_start = LV_DRAW_LABEL_NO_TXT_SEL;
|
||||
dsc->sel_end = LV_DRAW_LABEL_NO_TXT_SEL;
|
||||
dsc->sel_color = lv_color_black();
|
||||
dsc->sel_bg_color = lv_palette_main(LV_PALETTE_BLUE);
|
||||
dsc->bidi_dir = LV_BASE_DIR_LTR;
|
||||
dsc->base.dsc_size = sizeof(lv_draw_label_dsc_t);
|
||||
}
|
||||
|
||||
lv_draw_label_dsc_t * lv_draw_task_get_label_dsc(lv_draw_task_t * task)
|
||||
{
|
||||
return task->type == LV_DRAW_TASK_TYPE_LABEL ? (lv_draw_label_dsc_t *)task->draw_dsc : NULL;
|
||||
}
|
||||
|
||||
void lv_draw_glyph_dsc_init(lv_draw_glyph_dsc_t * dsc)
|
||||
{
|
||||
lv_memzero(dsc, sizeof(lv_draw_glyph_dsc_t));
|
||||
}
|
||||
|
||||
void LV_ATTRIBUTE_FAST_MEM lv_draw_label(lv_layer_t * layer, const lv_draw_label_dsc_t * dsc,
|
||||
const lv_area_t * coords)
|
||||
{
|
||||
if(dsc->opa <= LV_OPA_MIN) return;
|
||||
if(dsc->text == NULL || dsc->text[0] == '\0') return;
|
||||
if(dsc->font == NULL) {
|
||||
LV_LOG_WARN("dsc->font == NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
lv_draw_task_t * t = lv_draw_add_task(layer, coords, LV_DRAW_TASK_TYPE_LABEL);
|
||||
|
||||
lv_memcpy(t->draw_dsc, dsc, sizeof(*dsc));
|
||||
|
||||
/*The text is stored in a local variable so malloc memory for it*/
|
||||
if(dsc->text_local) {
|
||||
lv_draw_label_dsc_t * new_dsc = t->draw_dsc;
|
||||
new_dsc->text = lv_strndup(dsc->text, dsc->text_length);
|
||||
LV_ASSERT_MALLOC(new_dsc->text);
|
||||
}
|
||||
|
||||
lv_draw_finalize_task_creation(layer, t);
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
void LV_ATTRIBUTE_FAST_MEM lv_draw_character(lv_layer_t * layer, lv_draw_label_dsc_t * dsc,
|
||||
const lv_point_t * point, uint32_t unicode_letter)
|
||||
{
|
||||
if(dsc->opa <= LV_OPA_MIN) return;
|
||||
if(dsc->font == NULL) {
|
||||
LV_LOG_WARN("dsc->font == NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
if(lv_text_is_marker(unicode_letter)) return;
|
||||
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
|
||||
lv_font_glyph_dsc_t g;
|
||||
lv_font_get_glyph_dsc(dsc->font, &g, unicode_letter, 0);
|
||||
|
||||
lv_area_t a;
|
||||
a.x1 = point->x;
|
||||
a.y1 = point->y;
|
||||
a.x2 = a.x1 + g.adv_w;
|
||||
a.y2 = a.y1 + lv_font_get_line_height(g.resolved_font ? g.resolved_font : dsc->font);
|
||||
|
||||
/*lv_draw_label needs UTF8 text so convert the Unicode character to an UTF8 string */
|
||||
uint32_t letter_buf[2];
|
||||
letter_buf[0] = lv_text_unicode_to_encoded(unicode_letter);
|
||||
letter_buf[1] = '\0';
|
||||
|
||||
const char * letter_buf_char = (const char *)letter_buf;
|
||||
|
||||
#if LV_BIG_ENDIAN_SYSTEM
|
||||
while(*letter_buf_char == 0) ++letter_buf_char;
|
||||
#endif
|
||||
|
||||
dsc->text = letter_buf_char;
|
||||
dsc->text_local = 1;
|
||||
|
||||
lv_draw_label(layer, dsc, &a);
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
void LV_ATTRIBUTE_FAST_MEM lv_draw_letter(lv_layer_t * layer, lv_draw_letter_dsc_t * dsc, const lv_point_t * point)
|
||||
{
|
||||
if(dsc->opa <= LV_OPA_MIN) return;
|
||||
if(dsc->font == NULL) {
|
||||
LV_LOG_WARN("dsc->font == NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
const lv_font_t * font = dsc->font;
|
||||
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
lv_font_glyph_dsc_t g;
|
||||
lv_font_get_glyph_dsc(font, &g, dsc->unicode, 0);
|
||||
|
||||
font = g.resolved_font ? g.resolved_font : dsc->font;
|
||||
|
||||
lv_area_t a;
|
||||
a.x1 = point->x;
|
||||
a.y1 = point->y;
|
||||
a.x2 = a.x1 + g.adv_w;
|
||||
a.y2 = a.y1 + lv_font_get_line_height(font);
|
||||
|
||||
dsc->pivot.x = g.adv_w / 2 ;
|
||||
dsc->pivot.y = font->line_height - font->base_line;
|
||||
|
||||
lv_draw_task_t * t = lv_draw_add_task(layer, &a, LV_DRAW_TASK_TYPE_LETTER);
|
||||
|
||||
lv_memcpy(t->draw_dsc, dsc, sizeof(*dsc));
|
||||
|
||||
lv_draw_finalize_task_creation(layer, t);
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
void lv_draw_label_iterate_characters(lv_draw_task_t * t, const lv_draw_label_dsc_t * dsc,
|
||||
const lv_area_t * coords,
|
||||
lv_draw_glyph_cb_t cb)
|
||||
{
|
||||
lv_draw_dsc_base_t * base_dsc = t->draw_dsc;
|
||||
const lv_font_t * font = dsc->font;
|
||||
int32_t w;
|
||||
|
||||
lv_area_t clipped_area;
|
||||
bool clip_ok = lv_area_intersect(&clipped_area, coords, &t->clip_area);
|
||||
if(!clip_ok) return;
|
||||
|
||||
lv_text_align_t align = dsc->align;
|
||||
lv_base_dir_t base_dir = dsc->bidi_dir;
|
||||
|
||||
lv_bidi_calculate_align(&align, &base_dir, dsc->text);
|
||||
|
||||
if((dsc->flag & LV_TEXT_FLAG_EXPAND) == 0) {
|
||||
/*Normally use the label's width as width*/
|
||||
w = lv_area_get_width(coords);
|
||||
}
|
||||
else {
|
||||
/*If EXPAND is enabled then not limit the text's width to the object's width*/
|
||||
if(base_dsc->obj && !lv_obj_has_flag(base_dsc->obj, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS)) {
|
||||
w = dsc->text_size.x;
|
||||
}
|
||||
else {
|
||||
lv_point_t p;
|
||||
lv_text_get_size(&p, dsc->text, dsc->font, dsc->letter_space, dsc->line_space, LV_COORD_MAX,
|
||||
dsc->flag);
|
||||
w = p.x;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t line_height_font = lv_font_get_line_height(font);
|
||||
int32_t line_height = line_height_font + dsc->line_space;
|
||||
|
||||
/*Init variables for the first line*/
|
||||
int32_t line_width = 0;
|
||||
lv_point_t pos;
|
||||
lv_point_set(&pos, coords->x1, coords->y1);
|
||||
|
||||
int32_t x_ofs = 0;
|
||||
int32_t y_ofs = 0;
|
||||
x_ofs = dsc->ofs_x;
|
||||
y_ofs = dsc->ofs_y;
|
||||
pos.y += y_ofs;
|
||||
|
||||
uint32_t line_start = 0;
|
||||
int32_t last_line_start = -1;
|
||||
|
||||
/*Check the hint to use the cached info*/
|
||||
if(dsc->hint && y_ofs == 0 && coords->y1 < 0) {
|
||||
/*If the label changed too much recalculate the hint.*/
|
||||
if(LV_ABS(dsc->hint->coord_y - coords->y1) > LV_LABEL_HINT_UPDATE_TH - 2 * line_height) {
|
||||
dsc->hint->line_start = -1;
|
||||
}
|
||||
last_line_start = dsc->hint->line_start;
|
||||
}
|
||||
|
||||
/*Use the hint if it's valid*/
|
||||
if(dsc->hint && last_line_start >= 0) {
|
||||
line_start = last_line_start;
|
||||
pos.y += dsc->hint->y;
|
||||
}
|
||||
|
||||
uint32_t remaining_len = dsc->text_length;
|
||||
|
||||
uint32_t line_end = line_start + lv_text_get_next_line(&dsc->text[line_start], remaining_len, font, dsc->letter_space,
|
||||
w, NULL, dsc->flag);
|
||||
|
||||
/*Go the first visible line*/
|
||||
while(pos.y + line_height_font < t->clip_area.y1) {
|
||||
/*Go to next line*/
|
||||
line_start = line_end;
|
||||
line_end += lv_text_get_next_line(&dsc->text[line_start], remaining_len, font, dsc->letter_space, w, NULL, dsc->flag);
|
||||
pos.y += line_height;
|
||||
|
||||
/*Save at the threshold coordinate*/
|
||||
if(dsc->hint && pos.y >= -LV_LABEL_HINT_UPDATE_TH && dsc->hint->line_start < 0) {
|
||||
dsc->hint->line_start = line_start;
|
||||
dsc->hint->y = pos.y - coords->y1;
|
||||
dsc->hint->coord_y = coords->y1;
|
||||
}
|
||||
|
||||
if(dsc->text[line_start] == '\0') return;
|
||||
}
|
||||
|
||||
/*Align to middle*/
|
||||
if(align == LV_TEXT_ALIGN_CENTER) {
|
||||
line_width = lv_text_get_width_with_flags(&dsc->text[line_start], line_end - line_start, font, dsc->letter_space,
|
||||
dsc->flag);
|
||||
|
||||
pos.x += (lv_area_get_width(coords) - line_width) / 2;
|
||||
|
||||
}
|
||||
/*Align to the right*/
|
||||
else if(align == LV_TEXT_ALIGN_RIGHT) {
|
||||
line_width = lv_text_get_width_with_flags(&dsc->text[line_start], line_end - line_start, font, dsc->letter_space,
|
||||
dsc->flag);
|
||||
pos.x += lv_area_get_width(coords) - line_width;
|
||||
}
|
||||
|
||||
uint32_t sel_start = dsc->sel_start;
|
||||
uint32_t sel_end = dsc->sel_end;
|
||||
if(sel_start > sel_end) {
|
||||
uint32_t tmp = sel_start;
|
||||
sel_start = sel_end;
|
||||
sel_end = tmp;
|
||||
}
|
||||
|
||||
lv_area_t bg_coords;
|
||||
lv_draw_glyph_dsc_t draw_letter_dsc;
|
||||
lv_draw_glyph_dsc_init(&draw_letter_dsc);
|
||||
draw_letter_dsc.opa = dsc->opa;
|
||||
draw_letter_dsc.bg_coords = &bg_coords;
|
||||
draw_letter_dsc.color = dsc->color;
|
||||
draw_letter_dsc.rotation = dsc->rotation;
|
||||
|
||||
/* Set letter outline stroke attributes */
|
||||
draw_letter_dsc.outline_stroke_width = dsc->outline_stroke_width;
|
||||
draw_letter_dsc.outline_stroke_opa = dsc->outline_stroke_opa;
|
||||
draw_letter_dsc.outline_stroke_color = dsc->outline_stroke_color;
|
||||
|
||||
lv_draw_fill_dsc_t fill_dsc;
|
||||
lv_draw_fill_dsc_init(&fill_dsc);
|
||||
fill_dsc.opa = dsc->opa;
|
||||
int32_t underline_width = font->underline_thickness ? font->underline_thickness : 1;
|
||||
int32_t line_start_x;
|
||||
uint32_t next_char_offset;
|
||||
uint32_t recolor_command_start_index = 0;
|
||||
int32_t letter_w;
|
||||
cmd_state_t recolor_cmd_state = RECOLOR_CMD_STATE_WAIT_FOR_PARAMETER;
|
||||
lv_color_t recolor = lv_color_black(); /* Holds the selected color inside the recolor command */
|
||||
uint8_t is_first_space_after_cmd = 0;
|
||||
|
||||
/*Write out all lines*/
|
||||
while(remaining_len && dsc->text[line_start] != '\0') {
|
||||
pos.x += x_ofs;
|
||||
line_start_x = pos.x;
|
||||
|
||||
/*Write all letter of a line*/
|
||||
recolor_cmd_state = RECOLOR_CMD_STATE_WAIT_FOR_PARAMETER;
|
||||
next_char_offset = 0;
|
||||
#if LV_USE_BIDI
|
||||
size_t bidi_size = line_end - line_start;
|
||||
char * bidi_txt = lv_malloc(bidi_size + 1);
|
||||
LV_ASSERT_MALLOC(bidi_txt);
|
||||
|
||||
/**
|
||||
* has_bided = 1: already executed lv_bidi_process_paragraph.
|
||||
* has_bided = 0: has not been executed lv_bidi_process_paragraph.*/
|
||||
if(dsc->has_bided) {
|
||||
lv_memcpy(bidi_txt, &dsc->text[line_start], bidi_size);
|
||||
}
|
||||
else {
|
||||
lv_bidi_process_paragraph(dsc->text + line_start, bidi_txt, bidi_size, base_dir, NULL, 0);
|
||||
}
|
||||
#else
|
||||
const char * bidi_txt = dsc->text + line_start;
|
||||
#endif
|
||||
|
||||
while(next_char_offset < remaining_len && next_char_offset < line_end - line_start) {
|
||||
uint32_t logical_char_pos = 0;
|
||||
|
||||
/* Check if the text selection is enabled */
|
||||
if(sel_start != LV_DRAW_LABEL_NO_TXT_SEL && sel_end != LV_DRAW_LABEL_NO_TXT_SEL) {
|
||||
#if LV_USE_BIDI
|
||||
if(dsc->has_bided) {
|
||||
logical_char_pos = lv_text_encoded_get_char_id(dsc->text, line_start + next_char_offset);
|
||||
}
|
||||
else {
|
||||
logical_char_pos = lv_text_encoded_get_char_id(dsc->text, line_start);
|
||||
uint32_t c_idx = lv_text_encoded_get_char_id(bidi_txt, next_char_offset);
|
||||
logical_char_pos += lv_bidi_get_logical_pos(bidi_txt, NULL, line_end - line_start, base_dir, c_idx, NULL);
|
||||
}
|
||||
#else
|
||||
logical_char_pos = lv_text_encoded_get_char_id(dsc->text, line_start + next_char_offset);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t letter;
|
||||
uint32_t letter_next;
|
||||
lv_text_encoded_letter_next_2(bidi_txt, &letter, &letter_next, &next_char_offset);
|
||||
|
||||
/* If recolor is enabled */
|
||||
if((dsc->flag & LV_TEXT_FLAG_RECOLOR) != 0) {
|
||||
|
||||
if(letter == (uint32_t)LV_TXT_COLOR_CMD[0]) {
|
||||
/* Handle the recolor command marker depending of the current recolor state */
|
||||
|
||||
if(recolor_cmd_state == RECOLOR_CMD_STATE_WAIT_FOR_PARAMETER) {
|
||||
recolor_command_start_index = next_char_offset;
|
||||
recolor_cmd_state = RECOLOR_CMD_STATE_PARAMETER;
|
||||
continue;
|
||||
}
|
||||
/*Other start char in parameter escaped cmd. char*/
|
||||
else if(recolor_cmd_state == RECOLOR_CMD_STATE_PARAMETER) {
|
||||
recolor_cmd_state = RECOLOR_CMD_STATE_WAIT_FOR_PARAMETER;
|
||||
}
|
||||
/* If letter is LV_TXT_COLOR_CMD and we were in the CMD_STATE_IN then the recolor close marked has been found */
|
||||
else if(recolor_cmd_state == RECOLOR_CMD_STATE_TEXT_INPUT) {
|
||||
recolor_cmd_state = RECOLOR_CMD_STATE_WAIT_FOR_PARAMETER;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find the first space (aka ' ') after the recolor command parameter, we need to skip rendering it */
|
||||
if((recolor_cmd_state == RECOLOR_CMD_STATE_PARAMETER) && (letter == ' ') && (is_first_space_after_cmd == 0)) {
|
||||
is_first_space_after_cmd = 1;
|
||||
}
|
||||
else {
|
||||
is_first_space_after_cmd = 0;
|
||||
}
|
||||
|
||||
/* Skip the color parameter and wait the space after it
|
||||
* Once we have reach the space ' ', then we will extract the color information
|
||||
* and store it into the recolor variable */
|
||||
if(recolor_cmd_state == RECOLOR_CMD_STATE_PARAMETER) {
|
||||
/* Not an space? Continue with the next character */
|
||||
if(letter != ' ') {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*Get the recolor parameter*/
|
||||
if((next_char_offset - recolor_command_start_index) == LABEL_RECOLOR_PAR_LENGTH + 1) {
|
||||
/* Temporary buffer to hold the recolor information */
|
||||
char buf[LABEL_RECOLOR_PAR_LENGTH + 1];
|
||||
lv_memcpy(buf, &bidi_txt[recolor_command_start_index], LABEL_RECOLOR_PAR_LENGTH);
|
||||
buf[LABEL_RECOLOR_PAR_LENGTH] = '\0';
|
||||
|
||||
uint8_t r, g, b;
|
||||
r = (hex_char_to_num(buf[0]) << 4) + hex_char_to_num(buf[1]);
|
||||
g = (hex_char_to_num(buf[2]) << 4) + hex_char_to_num(buf[3]);
|
||||
b = (hex_char_to_num(buf[4]) << 4) + hex_char_to_num(buf[5]);
|
||||
|
||||
recolor = lv_color_make(r, g, b);
|
||||
}
|
||||
else {
|
||||
recolor.red = dsc->color.red;
|
||||
recolor.blue = dsc->color.blue;
|
||||
recolor.green = dsc->color.green;
|
||||
}
|
||||
|
||||
/*After the parameter the text is in the command*/
|
||||
recolor_cmd_state = RECOLOR_CMD_STATE_TEXT_INPUT;
|
||||
}
|
||||
|
||||
/* Don't draw the first space after the recolor command */
|
||||
if(is_first_space_after_cmd) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we're in the CMD_STATE_IN state then we need to subtract the recolor command length */
|
||||
if(((dsc->flag & LV_TEXT_FLAG_RECOLOR) != 0) && (recolor_cmd_state == RECOLOR_CMD_STATE_TEXT_INPUT)) {
|
||||
logical_char_pos -= (LABEL_RECOLOR_PAR_LENGTH + 1);
|
||||
}
|
||||
|
||||
letter_w = lv_font_get_glyph_width(font, letter, letter_next);
|
||||
|
||||
/*Always set the bg_coordinates for placeholder drawing*/
|
||||
bg_coords.x1 = pos.x;
|
||||
bg_coords.y1 = pos.y;
|
||||
bg_coords.x2 = pos.x + letter_w - 1;
|
||||
bg_coords.y2 = pos.y + line_height - 1;
|
||||
|
||||
if(next_char_offset >= line_end - line_start) {
|
||||
if(dsc->decor & LV_TEXT_DECOR_UNDERLINE) {
|
||||
lv_area_t fill_area;
|
||||
fill_area.x1 = line_start_x;
|
||||
fill_area.x2 = pos.x + letter_w - 1;
|
||||
fill_area.y1 = pos.y + font->line_height - font->base_line - font->underline_position;
|
||||
fill_area.y2 = fill_area.y1 + underline_width - 1;
|
||||
|
||||
fill_dsc.color = dsc->color;
|
||||
cb(t, NULL, &fill_dsc, &fill_area);
|
||||
}
|
||||
if(dsc->decor & LV_TEXT_DECOR_STRIKETHROUGH) {
|
||||
lv_area_t fill_area;
|
||||
fill_area.x1 = line_start_x;
|
||||
fill_area.x2 = pos.x + letter_w - 1;
|
||||
fill_area.y1 = pos.y + (font->line_height - font->base_line) * 2 / 3 + font->underline_thickness / 2;
|
||||
fill_area.y2 = fill_area.y1 + underline_width - 1;
|
||||
|
||||
fill_dsc.color = dsc->color;
|
||||
cb(t, NULL, &fill_dsc, &fill_area);
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle text selection */
|
||||
if(sel_start != LV_DRAW_LABEL_NO_TXT_SEL && sel_end != LV_DRAW_LABEL_NO_TXT_SEL
|
||||
&& logical_char_pos >= sel_start && logical_char_pos < sel_end) {
|
||||
draw_letter_dsc.color = dsc->sel_color;
|
||||
fill_dsc.color = dsc->sel_bg_color;
|
||||
cb(t, NULL, &fill_dsc, &bg_coords);
|
||||
}
|
||||
else if(recolor_cmd_state == RECOLOR_CMD_STATE_TEXT_INPUT) {
|
||||
draw_letter_dsc.color = recolor;
|
||||
}
|
||||
else {
|
||||
draw_letter_dsc.color = dsc->color;
|
||||
}
|
||||
|
||||
lv_draw_unit_draw_letter(t, &draw_letter_dsc, &pos, font, letter, cb);
|
||||
|
||||
if(letter_w > 0) {
|
||||
pos.x += letter_w + dsc->letter_space;
|
||||
}
|
||||
}
|
||||
|
||||
#if LV_USE_BIDI
|
||||
lv_free(bidi_txt);
|
||||
bidi_txt = NULL;
|
||||
#endif
|
||||
/*Go to next line*/
|
||||
remaining_len -= line_end - line_start;
|
||||
line_start = line_end;
|
||||
if(remaining_len) {
|
||||
line_end += lv_text_get_next_line(&dsc->text[line_start], remaining_len, font, dsc->letter_space, w, NULL, dsc->flag);
|
||||
}
|
||||
|
||||
pos.x = coords->x1;
|
||||
/*Align to middle*/
|
||||
if(align == LV_TEXT_ALIGN_CENTER) {
|
||||
line_width =
|
||||
lv_text_get_width_with_flags(&dsc->text[line_start], line_end - line_start, font, dsc->letter_space, dsc->flag);
|
||||
|
||||
pos.x += (lv_area_get_width(coords) - line_width) / 2;
|
||||
}
|
||||
/*Align to the right*/
|
||||
else if(align == LV_TEXT_ALIGN_RIGHT) {
|
||||
line_width =
|
||||
lv_text_get_width_with_flags(&dsc->text[line_start], line_end - line_start, font, dsc->letter_space, dsc->flag);
|
||||
pos.x += lv_area_get_width(coords) - line_width;
|
||||
}
|
||||
|
||||
/*Go the next line position*/
|
||||
pos.y += line_height;
|
||||
|
||||
if(pos.y > t->clip_area.y2) break;
|
||||
}
|
||||
|
||||
if(draw_letter_dsc._draw_buf) lv_draw_buf_destroy(draw_letter_dsc._draw_buf);
|
||||
|
||||
LV_ASSERT_MEM_INTEGRITY();
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Convert a hexadecimal characters to a number (0..15)
|
||||
* @param hex Pointer to a hexadecimal character (0..9, A..F)
|
||||
* @return the numerical value of `hex` or 0 on error
|
||||
*/
|
||||
static uint8_t hex_char_to_num(char hex)
|
||||
{
|
||||
if(hex >= '0' && hex <= '9') return hex - '0';
|
||||
if(hex >= 'a') hex -= 'a' - 'A'; /*Convert to upper case*/
|
||||
return 'A' <= hex && hex <= 'F' ? hex - 'A' + 10 : 0;
|
||||
}
|
||||
|
||||
void lv_draw_unit_draw_letter(lv_draw_task_t * t, lv_draw_glyph_dsc_t * dsc, const lv_point_t * pos,
|
||||
const lv_font_t * font, uint32_t letter, lv_draw_glyph_cb_t cb)
|
||||
{
|
||||
lv_font_glyph_dsc_t g;
|
||||
|
||||
if(lv_text_is_marker(letter)) /*Markers are valid letters but should not be rendered.*/
|
||||
return;
|
||||
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
bool g_ret = lv_font_get_glyph_dsc(font, &g, letter, '\0');
|
||||
if(g_ret == false) {
|
||||
/*Add warning if the dsc is not found*/
|
||||
LV_LOG_WARN("lv_draw_letter: glyph dsc. not found for U+%" LV_PRIX32, letter);
|
||||
}
|
||||
|
||||
/*Don't draw anything if the character is empty. E.g. space*/
|
||||
if((g.box_h == 0) || (g.box_w == 0)) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
|
||||
lv_area_t letter_coords;
|
||||
letter_coords.x1 = pos->x + g.ofs_x;
|
||||
letter_coords.x2 = letter_coords.x1 + g.box_w - 1;
|
||||
letter_coords.y1 = pos->y + (font->line_height - font->base_line) - g.box_h - g.ofs_y;
|
||||
letter_coords.y2 = letter_coords.y1 + g.box_h - 1;
|
||||
lv_area_move(&letter_coords, -dsc->pivot.x, -dsc->pivot.y);
|
||||
|
||||
/*If the letter is completely out of mask don't draw it*/
|
||||
if(lv_area_is_out(&letter_coords, &t->clip_area, 0) &&
|
||||
dsc->bg_coords &&
|
||||
lv_area_is_out(dsc->bg_coords, &t->clip_area, 0)) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
|
||||
if(g.resolved_font) {
|
||||
lv_draw_buf_t * draw_buf = NULL;
|
||||
if(LV_FONT_GLYPH_FORMAT_NONE < g.format && g.format < LV_FONT_GLYPH_FORMAT_IMAGE) {
|
||||
/*Only check draw buf for bitmap glyph*/
|
||||
draw_buf = lv_draw_buf_reshape(dsc->_draw_buf, 0, g.box_w, g.box_h, LV_STRIDE_AUTO);
|
||||
if(draw_buf == NULL) {
|
||||
if(dsc->_draw_buf) lv_draw_buf_destroy(dsc->_draw_buf);
|
||||
|
||||
uint32_t h = LV_ROUND_UP(g.box_h, 32); /*Assume a larger size to avoid many reallocations*/
|
||||
draw_buf = lv_draw_buf_create_ex(font_draw_buf_handlers, g.box_w, h, LV_COLOR_FORMAT_A8, LV_STRIDE_AUTO);
|
||||
LV_ASSERT_MALLOC(draw_buf);
|
||||
draw_buf->header.h = g.box_h;
|
||||
dsc->_draw_buf = draw_buf;
|
||||
}
|
||||
}
|
||||
|
||||
dsc->format = g.format;
|
||||
|
||||
if(g.format == LV_FONT_GLYPH_FORMAT_VECTOR) {
|
||||
|
||||
/*Load the outline of the glyph, even if the function says bitmap*/
|
||||
g.outline_stroke_width = dsc->outline_stroke_width;
|
||||
dsc->glyph_data = (void *) lv_font_get_glyph_bitmap(&g, draw_buf);
|
||||
dsc->format = dsc->glyph_data ? g.format : LV_FONT_GLYPH_FORMAT_NONE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
dsc->format = LV_FONT_GLYPH_FORMAT_NONE;
|
||||
}
|
||||
|
||||
dsc->letter_coords = &letter_coords;
|
||||
dsc->g = &g;
|
||||
cb(t, dsc, NULL, NULL);
|
||||
|
||||
lv_font_glyph_release_draw_data(&g);
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
/**
|
||||
* @file lv_draw_label.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_LABEL_H
|
||||
#define LV_DRAW_LABEL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw.h"
|
||||
#include "lv_draw_rect.h"
|
||||
#include "../misc/lv_bidi.h"
|
||||
#include "../misc/lv_text.h"
|
||||
#include "../misc/lv_color.h"
|
||||
#include "../misc/lv_style.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_DRAW_LABEL_NO_TXT_SEL (0xFFFF)
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct {
|
||||
lv_draw_dsc_base_t base;
|
||||
|
||||
/**The text to draw*/
|
||||
const char * text;
|
||||
|
||||
/**The size of the text*/
|
||||
lv_point_t text_size;
|
||||
|
||||
/**The font to use. Fallback fonts are also handled.*/
|
||||
const lv_font_t * font;
|
||||
|
||||
/**Color of the text*/
|
||||
lv_color_t color;
|
||||
|
||||
/**Extra space between the lines*/
|
||||
int32_t line_space;
|
||||
|
||||
/**Extra space between the characters*/
|
||||
int32_t letter_space;
|
||||
|
||||
/**Offset the text with this value horizontally*/
|
||||
int32_t ofs_x;
|
||||
|
||||
/**Offset the text with this value vertically*/
|
||||
int32_t ofs_y;
|
||||
|
||||
/**Rotation of the letters in 0.1 degree unit*/
|
||||
int32_t rotation;
|
||||
|
||||
/**The first characters index for selection (not byte index). `LV_DRAW_LABEL_NO_TXT_SEL` for no selection*/
|
||||
uint32_t sel_start;
|
||||
|
||||
/**The last characters's index for selection (not byte index). `LV_DRAW_LABEL_NO_TXT_SEL` for no selection*/
|
||||
uint32_t sel_end;
|
||||
|
||||
/**Color of the selected characters*/
|
||||
lv_color_t sel_color;
|
||||
|
||||
/**Background color of the selected characters*/
|
||||
lv_color_t sel_bg_color;
|
||||
|
||||
/**The number of characters to render. 0: means render until reaching the `\0` termination.*/
|
||||
uint32_t text_length;
|
||||
|
||||
/**Opacity of the text in 0...255 range.
|
||||
* LV_OPA_TRANSP, LV_OPA_10, LV_OPA_20, .. LV_OPA_COVER can be used as well*/
|
||||
lv_opa_t opa;
|
||||
|
||||
/**The alignment of the text `LV_TEXT_ALIGN_LEFT/RIGHT/CENTER`*/
|
||||
lv_text_align_t align;
|
||||
|
||||
/**The base direction. Used when type setting Right-to-left (e.g. Arabic) texts*/
|
||||
lv_base_dir_t bidi_dir;
|
||||
|
||||
/**Text decoration, e.g. underline*/
|
||||
lv_text_decor_t decor : 3;
|
||||
|
||||
/**Some flags to control type setting*/
|
||||
lv_text_flag_t flag : 5;
|
||||
|
||||
/**1: malloc a buffer and copy `text` there.
|
||||
* 0: `text` will be valid during rendering.*/
|
||||
uint8_t text_local : 1;
|
||||
|
||||
/**Indicate that the text is constant and its pointer can be safely saved e.g. in a cache.*/
|
||||
uint8_t text_static : 1;
|
||||
|
||||
/**1: already executed lv_bidi_process_paragraph.
|
||||
* 0: has not been executed lv_bidi_process_paragraph.*/
|
||||
uint8_t has_bided : 1;
|
||||
|
||||
/**Pointer to an externally stored struct where some data can be cached to speed up rendering*/
|
||||
lv_draw_label_hint_t * hint;
|
||||
|
||||
/* Properties of the letter outlines */
|
||||
lv_opa_t outline_stroke_opa;
|
||||
lv_color_t outline_stroke_color;
|
||||
int32_t outline_stroke_width;
|
||||
|
||||
} lv_draw_label_dsc_t;
|
||||
|
||||
typedef struct {
|
||||
lv_draw_dsc_base_t base;
|
||||
|
||||
uint32_t unicode;
|
||||
const lv_font_t * font;
|
||||
lv_color_t color;
|
||||
|
||||
int32_t rotation;
|
||||
int32_t scale_x;
|
||||
int32_t scale_y;
|
||||
int32_t skew_x;
|
||||
int32_t skew_y;
|
||||
lv_point_t pivot;
|
||||
|
||||
lv_opa_t opa;
|
||||
lv_text_decor_t decor : 3;
|
||||
lv_blend_mode_t blend_mode : 3;
|
||||
|
||||
/* Properties of the letter outlines */
|
||||
lv_opa_t outline_stroke_opa;
|
||||
int32_t outline_stroke_width;
|
||||
lv_color_t outline_stroke_color;
|
||||
|
||||
} lv_draw_letter_dsc_t;
|
||||
|
||||
/**
|
||||
* Passed as a parameter to `lv_draw_label_iterate_characters` to
|
||||
* draw the characters one by one
|
||||
* @param t pointer to a draw task
|
||||
* @param dsc pointer to `lv_draw_glyph_dsc_t` to describe the character to draw
|
||||
* if NULL don't draw character
|
||||
* @param fill_dsc pointer to a fill descriptor to draw a background for the character or
|
||||
* underline or strike through
|
||||
* if NULL do not fill anything
|
||||
* @param fill_area the area to fill
|
||||
* if NULL do not fill anything
|
||||
*/
|
||||
typedef void(*lv_draw_glyph_cb_t)(lv_draw_task_t * t, lv_draw_glyph_dsc_t * dsc, lv_draw_fill_dsc_t * fill_dsc,
|
||||
const lv_area_t * fill_area);
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
void /* LV_ATTRIBUTE_FAST_MEM */ lv_draw_letter_dsc_init(lv_draw_letter_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Initialize a label draw descriptor
|
||||
* @param dsc pointer to a draw descriptor
|
||||
*/
|
||||
void /* LV_ATTRIBUTE_FAST_MEM */ lv_draw_label_dsc_init(lv_draw_label_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Try to get a label draw descriptor from a draw task.
|
||||
* @param task draw task
|
||||
* @return the task's draw descriptor or NULL if the task is not of type LV_DRAW_TASK_TYPE_LABEL
|
||||
*/
|
||||
lv_draw_label_dsc_t * lv_draw_task_get_label_dsc(lv_draw_task_t * task);
|
||||
|
||||
/**
|
||||
* Initialize a glyph draw descriptor.
|
||||
* Used internally.
|
||||
* @param dsc pointer to a draw descriptor
|
||||
*/
|
||||
void lv_draw_glyph_dsc_init(lv_draw_glyph_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Create a draw task to render a text
|
||||
* @param layer pointer to a layer
|
||||
* @param dsc pointer to draw descriptor
|
||||
* @param coords coordinates of the character
|
||||
*/
|
||||
void /* LV_ATTRIBUTE_FAST_MEM */ lv_draw_label(lv_layer_t * layer, const lv_draw_label_dsc_t * dsc,
|
||||
const lv_area_t * coords);
|
||||
|
||||
/**
|
||||
* Create a draw task to render a single character
|
||||
* @param layer pointer to a layer
|
||||
* @param dsc pointer to draw descriptor
|
||||
* @param point position of the label
|
||||
* @param unicode_letter the letter to draw
|
||||
*/
|
||||
void /* LV_ATTRIBUTE_FAST_MEM */ lv_draw_character(lv_layer_t * layer, lv_draw_label_dsc_t * dsc,
|
||||
const lv_point_t * point, uint32_t unicode_letter);
|
||||
|
||||
/**
|
||||
* Draw a single letter
|
||||
* @param layer pointer to a layer
|
||||
* @param dsc pointer to draw descriptor
|
||||
* @param point position of the label
|
||||
*/
|
||||
void /* LV_ATTRIBUTE_FAST_MEM */ lv_draw_letter(lv_layer_t * layer, lv_draw_letter_dsc_t * dsc,
|
||||
const lv_point_t * point);
|
||||
|
||||
/**
|
||||
* Should be used during rendering the characters to get the position and other
|
||||
* parameters of the characters
|
||||
* @param t pointer to a draw task
|
||||
* @param dsc pointer to draw descriptor
|
||||
* @param coords coordinates of the label
|
||||
* @param cb a callback to call to draw each glyphs one by one
|
||||
*/
|
||||
void lv_draw_label_iterate_characters(lv_draw_task_t * t, const lv_draw_label_dsc_t * dsc,
|
||||
const lv_area_t * coords, lv_draw_glyph_cb_t cb);
|
||||
|
||||
/**
|
||||
* @brief Draw a single letter using the provided draw unit, glyph descriptor, position, font, and callback.
|
||||
*
|
||||
* This function is responsible for rendering a single character from a text string,
|
||||
* applying the necessary styling described by the glyph descriptor (`dsc`). It handles
|
||||
* the retrieval of the glyph's description, checks its visibility within the clipping area,
|
||||
* and invokes the callback (`cb`) to render the glyph at the specified position (`pos`)
|
||||
* using the given font (`font`).
|
||||
*
|
||||
* @param t Pointer to the drawing task.
|
||||
* @param dsc Pointer to the descriptor containing styling for the glyph to be drawn.
|
||||
* @param pos Pointer to the point coordinates where the letter should be drawn.
|
||||
* @param font Pointer to the font containing the glyph.
|
||||
* @param letter The Unicode code point of the letter to be drawn.
|
||||
* @param cb Callback function to execute the actual rendering of the glyph.
|
||||
*/
|
||||
void lv_draw_unit_draw_letter(lv_draw_task_t * t, lv_draw_glyph_dsc_t * dsc, const lv_point_t * pos,
|
||||
const lv_font_t * font, uint32_t letter, lv_draw_glyph_cb_t cb);
|
||||
|
||||
/***********************
|
||||
* GLOBAL VARIABLES
|
||||
***********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_LABEL_H*/
|
||||
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* @file lv_draw_label_private.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_LABEL_PRIVATE_H
|
||||
#define LV_DRAW_LABEL_PRIVATE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_label.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/** Store some info to speed up drawing of very large texts
|
||||
* It takes a lot of time to get the first visible character because
|
||||
* all the previous characters needs to be checked to calculate the positions.
|
||||
* This structure stores an earlier (e.g. at -1000 px) coordinate and the index of that line.
|
||||
* Therefore the calculations can start from here.*/
|
||||
struct _lv_draw_label_hint_t {
|
||||
/** Index of the line at `y` coordinate*/
|
||||
int32_t line_start;
|
||||
|
||||
/** Give the `y` coordinate of the first letter at `line start` index. Relative to the label's coordinates*/
|
||||
int32_t y;
|
||||
|
||||
/** The 'y1' coordinate of the label when the hint was saved.
|
||||
* Used to invalidate the hint if the label has moved too much.*/
|
||||
int32_t coord_y;
|
||||
};
|
||||
|
||||
struct _lv_draw_glyph_dsc_t {
|
||||
/** Depends on `format` field, it could be image source or draw buf of bitmap or vector data. */
|
||||
const void * glyph_data;
|
||||
lv_font_glyph_format_t format;
|
||||
const lv_area_t * letter_coords;
|
||||
const lv_area_t * bg_coords;
|
||||
lv_font_glyph_dsc_t * g;
|
||||
lv_color_t color;
|
||||
lv_opa_t opa;
|
||||
lv_color_t outline_stroke_color;
|
||||
lv_opa_t outline_stroke_opa;
|
||||
int32_t outline_stroke_width;
|
||||
int32_t rotation;
|
||||
lv_point_t pivot; /**< Rotation pivot point associated with total glyph including line_height */
|
||||
lv_draw_buf_t * _draw_buf; /**< a shared draw buf for get_bitmap, do not use it directly, use glyph_data instead */
|
||||
};
|
||||
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_LABEL_PRIVATE_H*/
|
||||
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* @file lv_draw_line.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_private.h"
|
||||
#include "../core/lv_refr.h"
|
||||
#include "../misc/lv_math.h"
|
||||
#include "../misc/lv_types.h"
|
||||
#include "../stdlib/lv_string.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void LV_ATTRIBUTE_FAST_MEM lv_draw_line_dsc_init(lv_draw_line_dsc_t * dsc)
|
||||
{
|
||||
lv_memzero(dsc, sizeof(lv_draw_line_dsc_t));
|
||||
dsc->width = 1;
|
||||
dsc->opa = LV_OPA_COVER;
|
||||
dsc->color = lv_color_black();
|
||||
dsc->base.dsc_size = sizeof(lv_draw_line_dsc_t);
|
||||
}
|
||||
|
||||
lv_draw_line_dsc_t * lv_draw_task_get_line_dsc(lv_draw_task_t * task)
|
||||
{
|
||||
return task->type == LV_DRAW_TASK_TYPE_LINE ? (lv_draw_line_dsc_t *)task->draw_dsc : NULL;
|
||||
}
|
||||
|
||||
void LV_ATTRIBUTE_FAST_MEM lv_draw_line(lv_layer_t * layer, const lv_draw_line_dsc_t * dsc)
|
||||
{
|
||||
if(dsc->width == 0) return;
|
||||
if(dsc->opa <= LV_OPA_MIN) return;
|
||||
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
|
||||
lv_area_t a;
|
||||
a.x1 = (int32_t)LV_MIN(dsc->p1.x, dsc->p2.x) - dsc->width;
|
||||
a.x2 = (int32_t)LV_MAX(dsc->p1.x, dsc->p2.x) + dsc->width;
|
||||
a.y1 = (int32_t)LV_MIN(dsc->p1.y, dsc->p2.y) - dsc->width;
|
||||
a.y2 = (int32_t)LV_MAX(dsc->p1.y, dsc->p2.y) + dsc->width;
|
||||
|
||||
lv_draw_task_t * t = lv_draw_add_task(layer, &a, LV_DRAW_TASK_TYPE_LINE);
|
||||
|
||||
lv_memcpy(t->draw_dsc, dsc, sizeof(*dsc));
|
||||
|
||||
lv_draw_finalize_task_creation(layer, t);
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* @file lv_draw_line.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_LINE_H
|
||||
#define LV_DRAW_LINE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../lv_conf_internal.h"
|
||||
#include "../misc/lv_color.h"
|
||||
#include "../misc/lv_area.h"
|
||||
#include "../misc/lv_style.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
typedef struct {
|
||||
lv_draw_dsc_base_t base;
|
||||
|
||||
/**The first point of the line. If `LV_USE_FLOAT` is enabled float number can be also used*/
|
||||
lv_point_precise_t p1;
|
||||
|
||||
/**The second point of the line. If `LV_USE_FLOAT` is enabled float number can be also used*/
|
||||
lv_point_precise_t p2;
|
||||
|
||||
/**The color of the line*/
|
||||
lv_color_t color;
|
||||
|
||||
/**The width (thickness) of the line*/
|
||||
int32_t width;
|
||||
|
||||
/** The length of a dash (0: don't dash)*/
|
||||
int32_t dash_width;
|
||||
|
||||
/** The length of the gaps between dashes (0: don't dash)*/
|
||||
int32_t dash_gap;
|
||||
|
||||
/**Opacity of the line in 0...255 range.
|
||||
* LV_OPA_TRANSP, LV_OPA_10, LV_OPA_20, .. LV_OPA_COVER can be used as well*/
|
||||
lv_opa_t opa;
|
||||
|
||||
/**Make the line start rounded*/
|
||||
uint8_t round_start : 1;
|
||||
|
||||
/**Make the line end rounded*/
|
||||
uint8_t round_end : 1;
|
||||
|
||||
/**1: Do not bother with line ending (if it's not visible for any reason) */
|
||||
uint8_t raw_end : 1;
|
||||
} lv_draw_line_dsc_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize a line draw descriptor
|
||||
* @param dsc pointer to a draw descriptor
|
||||
*/
|
||||
void lv_draw_line_dsc_init(lv_draw_line_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Try to get a line draw descriptor from a draw task.
|
||||
* @param task draw task
|
||||
* @return the task's draw descriptor or NULL if the task is not of type LV_DRAW_TASK_TYPE_LINE
|
||||
*/
|
||||
lv_draw_line_dsc_t * lv_draw_task_get_line_dsc(lv_draw_task_t * task);
|
||||
|
||||
/**
|
||||
* Create a line draw task
|
||||
* @param layer pointer to a layer
|
||||
* @param dsc pointer to an initialized `lv_draw_line_dsc_t` variable
|
||||
*/
|
||||
void lv_draw_line(lv_layer_t * layer, const lv_draw_line_dsc_t * dsc);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_LINE_H*/
|
||||
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* @file lv_draw_mask.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_mask_private.h"
|
||||
#include "lv_draw_private.h"
|
||||
#include "../core/lv_refr.h"
|
||||
#include "../misc/lv_math.h"
|
||||
#include "../misc/lv_types.h"
|
||||
#include "../stdlib/lv_string.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void LV_ATTRIBUTE_FAST_MEM lv_draw_mask_rect_dsc_init(lv_draw_mask_rect_dsc_t * dsc)
|
||||
{
|
||||
lv_memzero(dsc, sizeof(lv_draw_mask_rect_dsc_t));
|
||||
}
|
||||
|
||||
lv_draw_mask_rect_dsc_t * lv_draw_task_get_mask_rect_dsc(lv_draw_task_t * task)
|
||||
{
|
||||
return task->type == LV_DRAW_TASK_TYPE_MASK_RECTANGLE ? (lv_draw_mask_rect_dsc_t *)task->draw_dsc : NULL;
|
||||
}
|
||||
|
||||
void LV_ATTRIBUTE_FAST_MEM lv_draw_mask_rect(lv_layer_t * layer, const lv_draw_mask_rect_dsc_t * dsc)
|
||||
{
|
||||
if(!lv_color_format_has_alpha(layer->color_format)) {
|
||||
LV_LOG_WARN("Only layers with alpha channel can be masked");
|
||||
return;
|
||||
}
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
|
||||
lv_draw_task_t * t = lv_draw_add_task(layer, &layer->buf_area, LV_DRAW_TASK_TYPE_MASK_RECTANGLE);
|
||||
|
||||
lv_memcpy(t->draw_dsc, dsc, sizeof(*dsc));
|
||||
|
||||
lv_draw_dsc_base_t * base_dsc = t->draw_dsc;
|
||||
base_dsc->layer = layer;
|
||||
|
||||
if(base_dsc->obj && lv_obj_has_flag(base_dsc->obj, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS)) {
|
||||
/*Disable sending LV_EVENT_DRAW_TASK_ADDED first to avoid triggering recursive
|
||||
*event calls due draw task adds in the event*/
|
||||
lv_obj_remove_flag(base_dsc->obj, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS);
|
||||
lv_obj_send_event(dsc->base.obj, LV_EVENT_DRAW_TASK_ADDED, t);
|
||||
lv_obj_add_flag(base_dsc->obj, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS);
|
||||
}
|
||||
|
||||
lv_draw_finalize_task_creation(layer, t);
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* @file lv_draw_mask.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_MASK_H
|
||||
#define LV_DRAW_MASK_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../misc/lv_color.h"
|
||||
#include "../misc/lv_area.h"
|
||||
#include "../misc/lv_style.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize a rectangle mask draw descriptor.
|
||||
* @param dsc pointer to a draw descriptor
|
||||
*/
|
||||
void /* LV_ATTRIBUTE_FAST_MEM */ lv_draw_mask_rect_dsc_init(lv_draw_mask_rect_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Try to get a rectangle mask draw descriptor from a draw task.
|
||||
* @param task draw task
|
||||
* @return the task's draw descriptor or NULL if the task is not of type LV_DRAW_TASK_TYPE_MASK_RECTANGLE
|
||||
*/
|
||||
lv_draw_mask_rect_dsc_t * lv_draw_task_get_mask_rect_dsc(lv_draw_task_t * task);
|
||||
|
||||
/**
|
||||
* Create a draw task to mask a rectangle from the buffer
|
||||
* @param layer pointer to a layer
|
||||
* @param dsc pointer to a draw descriptor
|
||||
*/
|
||||
void lv_draw_mask_rect(lv_layer_t * layer, const lv_draw_mask_rect_dsc_t * dsc);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_MASK_H*/
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* @file lv_draw_mask_private.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_MASK_PRIVATE_H
|
||||
#define LV_DRAW_MASK_PRIVATE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_mask.h"
|
||||
#include "lv_draw.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
struct _lv_draw_mask_rect_dsc_t {
|
||||
lv_draw_dsc_base_t base;
|
||||
|
||||
/**The area t mask.*/
|
||||
lv_area_t area;
|
||||
|
||||
/**The radius of masking*/
|
||||
int32_t radius;
|
||||
|
||||
/**0: clear the content out of the `area`.
|
||||
* 1: don't touch the area out of `area`*/
|
||||
uint32_t keep_outside : 1;
|
||||
};
|
||||
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_MASK_PRIVATE_H*/
|
||||
@@ -0,0 +1,201 @@
|
||||
/**
|
||||
* @file lv_draw_private.h
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Modified by NXP in 2024
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_PRIVATE_H
|
||||
#define LV_DRAW_PRIVATE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw.h"
|
||||
#include "../osal/lv_os.h"
|
||||
#include "../misc/cache/lv_cache.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
struct _lv_draw_task_t {
|
||||
lv_draw_task_t * next;
|
||||
|
||||
lv_draw_task_type_t type;
|
||||
|
||||
/**
|
||||
* The area where to draw
|
||||
*/
|
||||
lv_area_t area;
|
||||
|
||||
/**
|
||||
* The real draw area. E.g. for shadow, outline, or transformed images it's different from `area`
|
||||
*/
|
||||
lv_area_t _real_area;
|
||||
|
||||
/** The original area which is updated*/
|
||||
lv_area_t clip_area_original;
|
||||
|
||||
/**
|
||||
* The clip area of the layer is saved here when the draw task is created.
|
||||
* As the clip area of the layer can be changed as new draw tasks are added its current value needs to be saved.
|
||||
* Therefore during drawing the layer's clip area shouldn't be used as it might be already changed for other draw tasks.
|
||||
*/
|
||||
lv_area_t clip_area;
|
||||
lv_layer_t * target_layer;
|
||||
|
||||
#if LV_DRAW_TRANSFORM_USE_MATRIX
|
||||
/** Transform matrix to be applied when rendering the layer */
|
||||
lv_matrix_t matrix;
|
||||
#endif
|
||||
|
||||
/* Reference to the draw unit for debug or draw context purposes */
|
||||
lv_draw_unit_t * draw_unit;
|
||||
|
||||
volatile int state; /** int instead of lv_draw_task_state_t to be sure its atomic */
|
||||
|
||||
void * draw_dsc;
|
||||
|
||||
/**
|
||||
* The ID of the draw_unit which should take this task
|
||||
*/
|
||||
uint8_t preferred_draw_unit_id;
|
||||
|
||||
/**
|
||||
* Set to which extent `preferred_draw_unit_id` is good at this task.
|
||||
* 80: means 20% better (faster) than software rendering
|
||||
* 100: the default value
|
||||
* 110: means 10% worse (slower) than software rendering
|
||||
*/
|
||||
uint8_t preference_score;
|
||||
|
||||
};
|
||||
|
||||
struct _lv_draw_mask_t {
|
||||
void * user_data;
|
||||
};
|
||||
|
||||
struct _lv_draw_unit_t {
|
||||
lv_draw_unit_t * next;
|
||||
|
||||
/**
|
||||
* Name and ID of the draw unit, for debugging purposes only.
|
||||
*/
|
||||
const char * name;
|
||||
int32_t idx;
|
||||
|
||||
/**
|
||||
* Called to try to assign a draw task to itself.
|
||||
* `lv_draw_get_next_available_task` can be used to get an independent draw task.
|
||||
* A draw task should be assign only if the draw unit can draw it too
|
||||
* @param draw_unit pointer to the draw unit
|
||||
* @param layer pointer to a layer on which the draw task should be drawn
|
||||
* @return >=0: The number of taken draw task:
|
||||
* 0 means the task has not yet been completed.
|
||||
* 1 means a new task has been accepted.
|
||||
* -1: The draw unit wanted to work on a task but couldn't do that
|
||||
* due to some errors (e.g. out of memory).
|
||||
* It signals that LVGL should call the dispatcher later again
|
||||
* to let draw unit try to start the rendering again.
|
||||
*/
|
||||
int32_t (*dispatch_cb)(lv_draw_unit_t * draw_unit, lv_layer_t * layer);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param draw_unit
|
||||
* @param task
|
||||
* @return
|
||||
*/
|
||||
int32_t (*evaluate_cb)(lv_draw_unit_t * draw_unit, lv_draw_task_t * task);
|
||||
|
||||
/**
|
||||
* Called to signal the unit to complete all tasks in order to return their ready status.
|
||||
* This callback can be implemented in case of asynchronous task processing.
|
||||
* Below is an example to show the difference between synchronous and asynchronous:
|
||||
*
|
||||
* Synchronous:
|
||||
* LVGL thread DRAW thread HW
|
||||
*
|
||||
* task1 --> submit --> Receive task1
|
||||
* wait_for_finish()
|
||||
* <-- task1->state = READY <-- Complete task1
|
||||
* task2 --> submit --> Receive task2
|
||||
* wait_for_finish()
|
||||
* task2->state = READY <-- Complete task2
|
||||
* task3 --> submit --> Receive task3
|
||||
* wait_for_finish()
|
||||
* <-- task3->state = READY <-- Complete task3
|
||||
* task4 --> submit --> Receive task4
|
||||
* wait_for_finish()
|
||||
* <-- task4->state = READY <-- Complete task4
|
||||
* NO MORE TASKS
|
||||
*
|
||||
*
|
||||
* Asynchronous:
|
||||
* LVGL thread DRAW thread HW
|
||||
* is IDLE
|
||||
* task1 --> queue task1
|
||||
* submit --> Receive task1
|
||||
* task2 --> queue task2 is BUSY (with task1)
|
||||
* task3 --> queue task3 still BUSY (with task1)
|
||||
* task4 --> queue task4 becomes IDLE
|
||||
* <-- task1->state = READY <-- Complete task1
|
||||
* submit --> Receive task2, task3, task4
|
||||
* NO MORE TASKS
|
||||
* wait_for_finish_cb() wait_for_finish()
|
||||
* <-- Complete task2, task3, task4
|
||||
* <-- task2->state = READY <--
|
||||
* <-- task3->state = READY <--
|
||||
* <-- task4->state = READY <--
|
||||
*
|
||||
* @param draw_unit
|
||||
* @return
|
||||
*/
|
||||
int32_t (*wait_for_finish_cb)(lv_draw_unit_t * draw_unit);
|
||||
|
||||
/**
|
||||
* Called to delete draw unit.
|
||||
* @param draw_unit
|
||||
* @return
|
||||
*/
|
||||
int32_t (*delete_cb)(lv_draw_unit_t * draw_unit);
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
lv_draw_unit_t * unit_head;
|
||||
uint32_t unit_cnt;
|
||||
uint32_t used_memory_for_layers; /* measured as bytes */
|
||||
#if LV_USE_OS
|
||||
lv_thread_sync_t sync;
|
||||
#else
|
||||
volatile int dispatch_req;
|
||||
#endif
|
||||
lv_mutex_t circle_cache_mutex;
|
||||
bool task_running;
|
||||
} lv_draw_global_info_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_PRIVATE_H*/
|
||||
@@ -0,0 +1,337 @@
|
||||
/**
|
||||
* @file lv_draw_rect.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_rect_private.h"
|
||||
#include "lv_draw_private.h"
|
||||
#include "../core/lv_obj.h"
|
||||
#include "../misc/lv_assert.h"
|
||||
#include "../core/lv_obj_event.h"
|
||||
#include "../stdlib/lv_string.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void LV_ATTRIBUTE_FAST_MEM lv_draw_rect_dsc_init(lv_draw_rect_dsc_t * dsc)
|
||||
{
|
||||
lv_memzero(dsc, sizeof(lv_draw_rect_dsc_t));
|
||||
dsc->bg_color = lv_color_white();
|
||||
dsc->bg_grad.stops[0].color = lv_color_white();
|
||||
dsc->bg_grad.stops[1].color = lv_color_black();
|
||||
dsc->bg_grad.stops[1].frac = 0xFF;
|
||||
dsc->bg_grad.stops_count = 2;
|
||||
dsc->border_color = lv_color_black();
|
||||
dsc->shadow_color = lv_color_black();
|
||||
dsc->bg_image_symbol_font = LV_FONT_DEFAULT;
|
||||
dsc->bg_opa = LV_OPA_COVER;
|
||||
dsc->bg_image_opa = LV_OPA_COVER;
|
||||
dsc->outline_opa = LV_OPA_COVER;
|
||||
dsc->border_opa = LV_OPA_COVER;
|
||||
dsc->shadow_opa = LV_OPA_COVER;
|
||||
dsc->border_side = LV_BORDER_SIDE_FULL;
|
||||
}
|
||||
|
||||
void lv_draw_fill_dsc_init(lv_draw_fill_dsc_t * dsc)
|
||||
{
|
||||
lv_memzero(dsc, sizeof(*dsc));
|
||||
dsc->opa = LV_OPA_COVER;
|
||||
dsc->base.dsc_size = sizeof(lv_draw_fill_dsc_t);
|
||||
}
|
||||
|
||||
lv_draw_fill_dsc_t * lv_draw_task_get_fill_dsc(lv_draw_task_t * task)
|
||||
{
|
||||
return task->type == LV_DRAW_TASK_TYPE_FILL ? (lv_draw_fill_dsc_t *)task->draw_dsc : NULL;
|
||||
}
|
||||
|
||||
void lv_draw_fill(lv_layer_t * layer, const lv_draw_fill_dsc_t * dsc, const lv_area_t * coords)
|
||||
{
|
||||
if(dsc->opa <= LV_OPA_MIN) return;
|
||||
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
lv_draw_task_t * t = lv_draw_add_task(layer, coords, LV_DRAW_TASK_TYPE_FILL);
|
||||
|
||||
lv_memcpy(t->draw_dsc, dsc, sizeof(*dsc));
|
||||
|
||||
lv_draw_finalize_task_creation(layer, t);
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
void lv_draw_border_dsc_init(lv_draw_border_dsc_t * dsc)
|
||||
{
|
||||
lv_memzero(dsc, sizeof(*dsc));
|
||||
dsc->opa = LV_OPA_COVER;
|
||||
dsc->side = LV_BORDER_SIDE_FULL;
|
||||
dsc->base.dsc_size = sizeof(lv_draw_border_dsc_t);
|
||||
}
|
||||
|
||||
lv_draw_border_dsc_t * lv_draw_task_get_border_dsc(lv_draw_task_t * task)
|
||||
{
|
||||
return task->type == LV_DRAW_TASK_TYPE_BORDER ? (lv_draw_border_dsc_t *)task->draw_dsc : NULL;
|
||||
}
|
||||
|
||||
void lv_draw_border(lv_layer_t * layer, const lv_draw_border_dsc_t * dsc, const lv_area_t * coords)
|
||||
{
|
||||
if(dsc->opa <= LV_OPA_MIN) return;
|
||||
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
lv_draw_task_t * t = lv_draw_add_task(layer, coords, LV_DRAW_TASK_TYPE_BORDER);
|
||||
|
||||
lv_memcpy(t->draw_dsc, dsc, sizeof(*dsc));
|
||||
|
||||
lv_draw_finalize_task_creation(layer, t);
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
void lv_draw_box_shadow_dsc_init(lv_draw_box_shadow_dsc_t * dsc)
|
||||
{
|
||||
lv_memzero(dsc, sizeof(*dsc));
|
||||
dsc->opa = LV_OPA_COVER;
|
||||
dsc->base.dsc_size = sizeof(lv_draw_box_shadow_dsc_t);
|
||||
}
|
||||
|
||||
lv_draw_box_shadow_dsc_t * lv_draw_task_get_box_shadow_dsc(lv_draw_task_t * task)
|
||||
{
|
||||
return task->type == LV_DRAW_TASK_TYPE_BOX_SHADOW ? (lv_draw_box_shadow_dsc_t *)task->draw_dsc : NULL;
|
||||
}
|
||||
|
||||
void lv_draw_box_shadow(lv_layer_t * layer, const lv_draw_box_shadow_dsc_t * dsc, const lv_area_t * coords)
|
||||
{
|
||||
if(dsc->opa <= LV_OPA_MIN) return;
|
||||
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
lv_draw_task_t * t = lv_draw_add_task(layer, coords, LV_DRAW_TASK_TYPE_BOX_SHADOW);
|
||||
|
||||
lv_memcpy(t->draw_dsc, dsc, sizeof(*dsc));
|
||||
|
||||
lv_draw_finalize_task_creation(layer, t);
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
void lv_draw_rect(lv_layer_t * layer, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords)
|
||||
{
|
||||
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
bool has_shadow;
|
||||
bool has_fill;
|
||||
bool has_border;
|
||||
bool has_outline;
|
||||
bool has_bg_img;
|
||||
|
||||
if(dsc->shadow_width == 0 ||
|
||||
dsc->shadow_opa <= LV_OPA_MIN ||
|
||||
(dsc->shadow_width == 1 && dsc->shadow_spread <= 0 &&
|
||||
dsc->shadow_offset_x == 0 && dsc->shadow_offset_y == 0)) {
|
||||
has_shadow = false;
|
||||
}
|
||||
else {
|
||||
has_shadow = true;
|
||||
}
|
||||
|
||||
if(dsc->bg_opa <= LV_OPA_MIN) has_fill = false;
|
||||
else has_fill = true;
|
||||
|
||||
if(dsc->bg_image_opa <= LV_OPA_MIN || dsc->bg_image_src == NULL) has_bg_img = false;
|
||||
else has_bg_img = true;
|
||||
|
||||
if(dsc->border_opa <= LV_OPA_MIN
|
||||
|| dsc->border_width == 0
|
||||
|| dsc->border_post == true
|
||||
|| dsc->border_side == LV_BORDER_SIDE_NONE) has_border = false;
|
||||
else has_border = true;
|
||||
|
||||
if(dsc->outline_opa <= LV_OPA_MIN || dsc->outline_width == 0) has_outline = false;
|
||||
else has_outline = true;
|
||||
|
||||
bool bg_cover = true;
|
||||
if(dsc->bg_opa < LV_OPA_COVER) bg_cover = false;
|
||||
else if(dsc->bg_grad.dir != LV_GRAD_DIR_NONE) {
|
||||
uint32_t s;
|
||||
for(s = 0; s < dsc->bg_grad.stops_count; s++) {
|
||||
if(dsc->bg_grad.stops[s].opa != LV_OPA_COVER) {
|
||||
bg_cover = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lv_draw_task_t * t;
|
||||
|
||||
/*Shadow*/
|
||||
if(has_shadow) {
|
||||
/*Check whether the shadow is visible*/
|
||||
t = lv_draw_add_task(layer, coords, LV_DRAW_TASK_TYPE_BOX_SHADOW);
|
||||
lv_draw_box_shadow_dsc_t * shadow_dsc = t->draw_dsc;
|
||||
|
||||
lv_area_increase(&t->_real_area, dsc->shadow_spread, dsc->shadow_spread);
|
||||
lv_area_increase(&t->_real_area, dsc->shadow_width, dsc->shadow_width);
|
||||
lv_area_move(&t->_real_area, dsc->shadow_offset_x, dsc->shadow_offset_y);
|
||||
shadow_dsc->base = dsc->base;
|
||||
shadow_dsc->base.dsc_size = sizeof(lv_draw_box_shadow_dsc_t);
|
||||
shadow_dsc->radius = dsc->radius;
|
||||
shadow_dsc->color = dsc->shadow_color;
|
||||
shadow_dsc->width = dsc->shadow_width;
|
||||
shadow_dsc->spread = dsc->shadow_spread;
|
||||
shadow_dsc->opa = dsc->shadow_opa;
|
||||
shadow_dsc->ofs_x = dsc->shadow_offset_x;
|
||||
shadow_dsc->ofs_y = dsc->shadow_offset_y;
|
||||
shadow_dsc->bg_cover = bg_cover;
|
||||
lv_draw_finalize_task_creation(layer, t);
|
||||
}
|
||||
|
||||
/*Background*/
|
||||
if(has_fill) {
|
||||
lv_area_t bg_coords = *coords;
|
||||
/*If the border fully covers make the bg area 1px smaller to avoid artifacts on the corners*/
|
||||
if(dsc->border_width > 1 && dsc->border_opa >= LV_OPA_MAX && dsc->radius != 0) {
|
||||
bg_coords.x1 += (dsc->border_side & LV_BORDER_SIDE_LEFT) ? 1 : 0;
|
||||
bg_coords.y1 += (dsc->border_side & LV_BORDER_SIDE_TOP) ? 1 : 0;
|
||||
bg_coords.x2 -= (dsc->border_side & LV_BORDER_SIDE_RIGHT) ? 1 : 0;
|
||||
bg_coords.y2 -= (dsc->border_side & LV_BORDER_SIDE_BOTTOM) ? 1 : 0;
|
||||
}
|
||||
|
||||
t = lv_draw_add_task(layer, &bg_coords, LV_DRAW_TASK_TYPE_FILL);
|
||||
lv_draw_fill_dsc_t * bg_dsc = t->draw_dsc;
|
||||
|
||||
lv_draw_fill_dsc_init(bg_dsc);
|
||||
bg_dsc->base = dsc->base;
|
||||
bg_dsc->base.dsc_size = sizeof(lv_draw_fill_dsc_t);
|
||||
bg_dsc->radius = dsc->radius;
|
||||
bg_dsc->color = dsc->bg_color;
|
||||
bg_dsc->grad = dsc->bg_grad;
|
||||
bg_dsc->opa = dsc->bg_opa;
|
||||
|
||||
lv_draw_finalize_task_creation(layer, t);
|
||||
}
|
||||
|
||||
/*Background image*/
|
||||
if(has_bg_img) {
|
||||
lv_image_src_t src_type = lv_image_src_get_type(dsc->bg_image_src);
|
||||
lv_result_t res = LV_RESULT_OK;
|
||||
lv_image_header_t header;
|
||||
if(src_type == LV_IMAGE_SRC_VARIABLE || src_type == LV_IMAGE_SRC_FILE) {
|
||||
res = lv_image_decoder_get_info(dsc->bg_image_src, &header);
|
||||
}
|
||||
else {
|
||||
lv_memzero(&header, sizeof(header));
|
||||
|
||||
if(src_type == LV_IMAGE_SRC_UNKNOWN) {
|
||||
res = LV_RESULT_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
if(res == LV_RESULT_OK) {
|
||||
if(src_type == LV_IMAGE_SRC_VARIABLE || src_type == LV_IMAGE_SRC_FILE) {
|
||||
|
||||
if(dsc->bg_image_tiled) {
|
||||
t = lv_draw_add_task(layer, coords, LV_DRAW_TASK_TYPE_IMAGE);
|
||||
}
|
||||
else {
|
||||
lv_area_t a = {0, 0, header.w - 1, header.h - 1};
|
||||
lv_area_align(coords, &a, LV_ALIGN_CENTER, 0, 0);
|
||||
t = lv_draw_add_task(layer, &a, LV_DRAW_TASK_TYPE_IMAGE);
|
||||
}
|
||||
|
||||
lv_draw_image_dsc_t * bg_image_dsc = t->draw_dsc;
|
||||
|
||||
lv_draw_image_dsc_init(bg_image_dsc);
|
||||
bg_image_dsc->base = dsc->base;
|
||||
bg_image_dsc->base.dsc_size = sizeof(lv_draw_image_dsc_t);
|
||||
bg_image_dsc->src = dsc->bg_image_src;
|
||||
bg_image_dsc->opa = dsc->bg_image_opa;
|
||||
bg_image_dsc->recolor = dsc->bg_image_recolor;
|
||||
bg_image_dsc->recolor_opa = dsc->bg_image_recolor_opa;
|
||||
bg_image_dsc->tile = dsc->bg_image_tiled;
|
||||
bg_image_dsc->header = header;
|
||||
bg_image_dsc->clip_radius = dsc->radius;
|
||||
bg_image_dsc->image_area = *coords;
|
||||
lv_draw_finalize_task_creation(layer, t);
|
||||
}
|
||||
else {
|
||||
lv_point_t s;
|
||||
lv_text_get_size(&s, dsc->bg_image_src, dsc->bg_image_symbol_font, 0, 0, LV_COORD_MAX, LV_TEXT_FLAG_NONE);
|
||||
|
||||
lv_area_t a = {0, 0, s.x - 1, s.y - 1};
|
||||
lv_area_align(coords, &a, LV_ALIGN_CENTER, 0, 0);
|
||||
t = lv_draw_add_task(layer, &a, LV_DRAW_TASK_TYPE_LABEL);
|
||||
|
||||
lv_draw_label_dsc_t * bg_label_dsc = t->draw_dsc;
|
||||
|
||||
lv_draw_label_dsc_init(bg_label_dsc);
|
||||
bg_label_dsc->base = dsc->base;
|
||||
bg_label_dsc->base.dsc_size = sizeof(lv_draw_label_dsc_t);
|
||||
bg_label_dsc->color = dsc->bg_image_recolor;
|
||||
bg_label_dsc->font = dsc->bg_image_symbol_font;
|
||||
bg_label_dsc->text = dsc->bg_image_src;
|
||||
t->type = LV_DRAW_TASK_TYPE_LABEL;
|
||||
lv_draw_finalize_task_creation(layer, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*Border*/
|
||||
if(has_border) {
|
||||
t = lv_draw_add_task(layer, coords, LV_DRAW_TASK_TYPE_BORDER);
|
||||
lv_draw_border_dsc_t * border_dsc = t->draw_dsc;
|
||||
|
||||
border_dsc->base = dsc->base;
|
||||
border_dsc->base.dsc_size = sizeof(lv_draw_border_dsc_t);
|
||||
border_dsc->radius = dsc->radius;
|
||||
border_dsc->color = dsc->border_color;
|
||||
border_dsc->opa = dsc->border_opa;
|
||||
border_dsc->width = dsc->border_width;
|
||||
border_dsc->side = dsc->border_side;
|
||||
lv_draw_finalize_task_creation(layer, t);
|
||||
}
|
||||
|
||||
/*Outline*/
|
||||
if(has_outline) {
|
||||
lv_area_t outline_coords = *coords;
|
||||
lv_area_increase(&outline_coords, dsc->outline_width + dsc->outline_pad, dsc->outline_width + dsc->outline_pad);
|
||||
t = lv_draw_add_task(layer, &outline_coords, LV_DRAW_TASK_TYPE_BORDER);
|
||||
lv_draw_border_dsc_t * outline_dsc = t->draw_dsc;
|
||||
lv_area_increase(&t->_real_area, dsc->outline_width, dsc->outline_width);
|
||||
lv_area_increase(&t->_real_area, dsc->outline_pad, dsc->outline_pad);
|
||||
outline_dsc->base = dsc->base;
|
||||
outline_dsc->base.dsc_size = sizeof(lv_draw_border_dsc_t);
|
||||
outline_dsc->radius = dsc->radius == LV_RADIUS_CIRCLE ? LV_RADIUS_CIRCLE : dsc->radius + dsc->outline_width +
|
||||
dsc->outline_pad;
|
||||
outline_dsc->color = dsc->outline_color;
|
||||
outline_dsc->opa = dsc->outline_opa;
|
||||
outline_dsc->width = dsc->outline_width;
|
||||
outline_dsc->side = LV_BORDER_SIDE_FULL;
|
||||
lv_draw_finalize_task_creation(layer, t);
|
||||
}
|
||||
|
||||
LV_ASSERT_MEM_INTEGRITY();
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
@@ -0,0 +1,233 @@
|
||||
/**
|
||||
* @file lv_draw_rect.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_RECT_H
|
||||
#define LV_DRAW_RECT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw.h"
|
||||
#include "../misc/lv_color.h"
|
||||
#include "../misc/lv_area.h"
|
||||
#include "../misc/lv_style.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_RADIUS_CIRCLE 0x7FFF /**< A very big radius to always draw as circle*/
|
||||
LV_EXPORT_CONST_INT(LV_RADIUS_CIRCLE);
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct {
|
||||
lv_draw_dsc_base_t base;
|
||||
|
||||
int32_t radius;
|
||||
|
||||
/*Background*/
|
||||
lv_opa_t bg_opa;
|
||||
lv_color_t bg_color; /**< First element of a gradient is a color, so it maps well here*/
|
||||
lv_grad_dsc_t bg_grad;
|
||||
|
||||
/*Background img*/
|
||||
const void * bg_image_src;
|
||||
const void * bg_image_symbol_font;
|
||||
lv_color_t bg_image_recolor;
|
||||
lv_opa_t bg_image_opa;
|
||||
lv_opa_t bg_image_recolor_opa;
|
||||
uint8_t bg_image_tiled;
|
||||
|
||||
/*Border*/
|
||||
lv_color_t border_color;
|
||||
int32_t border_width;
|
||||
lv_opa_t border_opa;
|
||||
lv_border_side_t border_side : 5;
|
||||
uint8_t border_post : 1; /*The border will be drawn later*/
|
||||
|
||||
/*Outline*/
|
||||
lv_color_t outline_color;
|
||||
int32_t outline_width;
|
||||
int32_t outline_pad;
|
||||
lv_opa_t outline_opa;
|
||||
|
||||
/*Shadow*/
|
||||
lv_color_t shadow_color;
|
||||
int32_t shadow_width;
|
||||
int32_t shadow_offset_x;
|
||||
int32_t shadow_offset_y;
|
||||
int32_t shadow_spread;
|
||||
lv_opa_t shadow_opa;
|
||||
} lv_draw_rect_dsc_t;
|
||||
|
||||
typedef struct {
|
||||
lv_draw_dsc_base_t base;
|
||||
|
||||
/**Radius, LV_RADIUS_CIRCLE for max. radius */
|
||||
int32_t radius;
|
||||
|
||||
/**Opacity in 0...255 range.
|
||||
* LV_OPA_TRANSP, LV_OPA_10, LV_OPA_20, .. LV_OPA_COVER can be used as well*/
|
||||
lv_opa_t opa;
|
||||
|
||||
/**The color of the rectangle.
|
||||
* If the gradient is set (grad.dir!=LV_GRAD_DIR_NONE) it's ignored. */
|
||||
lv_color_t color;
|
||||
|
||||
/**Describe a gradient. If `grad.dir` is not `LV_GRAD_DIR_NONE` `color` will be ignored*/
|
||||
lv_grad_dsc_t grad;
|
||||
} lv_draw_fill_dsc_t;
|
||||
|
||||
typedef struct {
|
||||
lv_draw_dsc_base_t base;
|
||||
|
||||
/**Radius, LV_RADIUS_CIRCLE for max. radius */
|
||||
int32_t radius;
|
||||
|
||||
/**The color of the border. */
|
||||
lv_color_t color;
|
||||
|
||||
|
||||
/**The width of the border in pixels */
|
||||
int32_t width;
|
||||
|
||||
/**Opacity in 0...255 range.
|
||||
* LV_OPA_TRANSP, LV_OPA_10, LV_OPA_20, .. LV_OPA_COVER can be used as well*/
|
||||
lv_opa_t opa;
|
||||
|
||||
/**LV_BORDER_SIDE_NONE/LEFT/RIGHT/TOP/BOTTOM/FULL.
|
||||
* LV_BORDER_SIDE_INTERNAL is an information for upper layers
|
||||
* and shouldn't be used here. */
|
||||
lv_border_side_t side : 5;
|
||||
|
||||
} lv_draw_border_dsc_t;
|
||||
|
||||
typedef struct {
|
||||
lv_draw_dsc_base_t base;
|
||||
|
||||
/**Radius, LV_RADIUS_CIRCLE for max. radius */
|
||||
int32_t radius;
|
||||
|
||||
/**Color of the the shadow */
|
||||
lv_color_t color;
|
||||
|
||||
/**Width of the shadow. (radius of the blur)*/
|
||||
int32_t width;
|
||||
|
||||
/**Make the rectangle larger with this value in all directions. Can be negative too. */
|
||||
int32_t spread;
|
||||
|
||||
/**Offset the rectangle horizontally.*/
|
||||
int32_t ofs_x;
|
||||
|
||||
/**Offset the rectangle vertically.*/
|
||||
int32_t ofs_y;
|
||||
|
||||
/**Opacity in 0...255 range.
|
||||
* LV_OPA_TRANSP, LV_OPA_10, LV_OPA_20, .. LV_OPA_COVER can be used as well*/
|
||||
lv_opa_t opa;
|
||||
|
||||
/**Set `bg_cover` to 1 if the background will cover the shadow.
|
||||
* It's a hint to the renderer about it might skip some masking.*/
|
||||
uint8_t bg_cover : 1;
|
||||
} lv_draw_box_shadow_dsc_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize a rectangle draw descriptor.
|
||||
* @param dsc pointer to a draw descriptor
|
||||
*/
|
||||
void /* LV_ATTRIBUTE_FAST_MEM */ lv_draw_rect_dsc_init(lv_draw_rect_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Initialize a fill draw descriptor.
|
||||
* @param dsc pointer to a draw descriptor
|
||||
*/
|
||||
void lv_draw_fill_dsc_init(lv_draw_fill_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Try to get a fill draw descriptor from a draw task.
|
||||
* @param task draw task
|
||||
* @return the task's draw descriptor or NULL if the task is not of type LV_DRAW_TASK_TYPE_FILL
|
||||
*/
|
||||
lv_draw_fill_dsc_t * lv_draw_task_get_fill_dsc(lv_draw_task_t * task);
|
||||
|
||||
/**
|
||||
* Fill an area
|
||||
* @param layer pointer to a layer
|
||||
* @param dsc pointer to an initialized draw descriptor variable
|
||||
* @param coords the coordinates of the rectangle
|
||||
*/
|
||||
void lv_draw_fill(lv_layer_t * layer, const lv_draw_fill_dsc_t * dsc, const lv_area_t * coords);
|
||||
|
||||
/**
|
||||
* Initialize a border draw descriptor.
|
||||
* @param dsc pointer to a draw descriptor
|
||||
*/
|
||||
void lv_draw_border_dsc_init(lv_draw_border_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Try to get a border draw descriptor from a draw task.
|
||||
* @param task draw task
|
||||
* @return the task's draw descriptor or NULL if the task is not of type LV_DRAW_TASK_TYPE_BORDER
|
||||
*/
|
||||
lv_draw_border_dsc_t * lv_draw_task_get_border_dsc(lv_draw_task_t * task);
|
||||
|
||||
/**
|
||||
* Draw a border
|
||||
* @param layer pointer to a layer
|
||||
* @param dsc pointer to an initialized draw descriptor variable
|
||||
* @param coords the coordinates of the rectangle
|
||||
*/
|
||||
void lv_draw_border(lv_layer_t * layer, const lv_draw_border_dsc_t * dsc, const lv_area_t * coords);
|
||||
|
||||
/**
|
||||
* Initialize a box shadow draw descriptor.
|
||||
* @param dsc pointer to a draw descriptor
|
||||
*/
|
||||
void lv_draw_box_shadow_dsc_init(lv_draw_box_shadow_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Try to get a box shadow draw descriptor from a draw task.
|
||||
* @param task draw task
|
||||
* @return the task's draw descriptor or NULL if the task is not of type LV_DRAW_TASK_TYPE_BOX_SHADOW
|
||||
*/
|
||||
lv_draw_box_shadow_dsc_t * lv_draw_task_get_box_shadow_dsc(lv_draw_task_t * task);
|
||||
|
||||
/**
|
||||
* Draw a box shadow
|
||||
* @param layer pointer to a layer
|
||||
* @param dsc pointer to an initialized draw descriptor variable
|
||||
* @param coords the coordinates of the rectangle
|
||||
*/
|
||||
void lv_draw_box_shadow(lv_layer_t * layer, const lv_draw_box_shadow_dsc_t * dsc, const lv_area_t * coords);
|
||||
|
||||
/**
|
||||
* The rectangle is a wrapper for fill, border, bg. image and box shadow.
|
||||
* Internally fill, border, image and box shadow draw tasks will be created.
|
||||
* @param layer pointer to a layer
|
||||
* @param dsc pointer to an initialized draw descriptor variable
|
||||
* @param coords the coordinates of the rectangle
|
||||
*/
|
||||
void lv_draw_rect(lv_layer_t * layer, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_RECT_H*/
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* @file lv_draw_rect_private.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_RECT_PRIVATE_H
|
||||
#define LV_DRAW_RECT_PRIVATE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_rect.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_RECT_PRIVATE_H*/
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* @file lv_draw_triangle.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_triangle_private.h"
|
||||
#include "lv_draw_private.h"
|
||||
#include "../core/lv_obj.h"
|
||||
#include "../misc/lv_math.h"
|
||||
#include "../stdlib/lv_mem.h"
|
||||
#include "../stdlib/lv_string.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_triangle_dsc_init(lv_draw_triangle_dsc_t * dsc)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
lv_memzero(dsc, sizeof(lv_draw_triangle_dsc_t));
|
||||
dsc->color = lv_color_white();
|
||||
dsc->grad.stops[0].color = lv_color_white();
|
||||
dsc->grad.stops[1].color = lv_color_black();
|
||||
dsc->grad.stops[1].frac = 0xFF;
|
||||
dsc->grad.stops_count = 2;
|
||||
dsc->opa = LV_OPA_COVER;
|
||||
dsc->base.dsc_size = sizeof(lv_draw_triangle_dsc_t);
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
lv_draw_triangle_dsc_t * lv_draw_task_get_triangle_dsc(lv_draw_task_t * task)
|
||||
{
|
||||
return task->type == LV_DRAW_TASK_TYPE_TRIANGLE ? (lv_draw_triangle_dsc_t *)task->draw_dsc : NULL;
|
||||
}
|
||||
|
||||
void lv_draw_triangle(lv_layer_t * layer, const lv_draw_triangle_dsc_t * dsc)
|
||||
{
|
||||
if(dsc->opa <= LV_OPA_MIN) return;
|
||||
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
|
||||
lv_area_t a;
|
||||
a.x1 = (int32_t)LV_MIN3(dsc->p[0].x, dsc->p[1].x, dsc->p[2].x);
|
||||
a.y1 = (int32_t)LV_MIN3(dsc->p[0].y, dsc->p[1].y, dsc->p[2].y);
|
||||
a.x2 = (int32_t)LV_MAX3(dsc->p[0].x, dsc->p[1].x, dsc->p[2].x);
|
||||
a.y2 = (int32_t)LV_MAX3(dsc->p[0].y, dsc->p[1].y, dsc->p[2].y);
|
||||
|
||||
lv_draw_task_t * t = lv_draw_add_task(layer, &a, LV_DRAW_TASK_TYPE_TRIANGLE);
|
||||
|
||||
lv_memcpy(t->draw_dsc, dsc, sizeof(*dsc));
|
||||
|
||||
lv_draw_finalize_task_creation(layer, t);
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* @file lv_draw_triangle.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_TRIANGLE_H
|
||||
#define LV_DRAW_TRIANGLE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_rect.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
typedef struct {
|
||||
lv_draw_dsc_base_t base;
|
||||
|
||||
/**Points of the triangle. If `LV_USE_FLOAT` is enabled floats can be used here*/
|
||||
lv_point_precise_t p[3];
|
||||
|
||||
/**Color of the triangle*/
|
||||
lv_color_t color;
|
||||
|
||||
/**Opacity of the arc in 0...255 range.
|
||||
* LV_OPA_TRANSP, LV_OPA_10, LV_OPA_20, .. LV_OPA_COVER can be used as well*/
|
||||
lv_opa_t opa;
|
||||
|
||||
/**Describe a gradient. If `grad.dir` is not `LV_GRAD_DIR_NONE` `color` will be ignored*/
|
||||
lv_grad_dsc_t grad;
|
||||
|
||||
} lv_draw_triangle_dsc_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize a triangle draw descriptor
|
||||
* @param draw_dsc pointer to a draw descriptor
|
||||
*/
|
||||
void lv_draw_triangle_dsc_init(lv_draw_triangle_dsc_t * draw_dsc);
|
||||
|
||||
/**
|
||||
* Try to get a triangle draw descriptor from a draw task.
|
||||
* @param task draw task
|
||||
* @return the task's draw descriptor or NULL if the task is not of type LV_DRAW_TASK_TYPE_TRIANGLE
|
||||
*/
|
||||
lv_draw_triangle_dsc_t * lv_draw_task_get_triangle_dsc(lv_draw_task_t * task);
|
||||
|
||||
/**
|
||||
* Create a triangle draw task
|
||||
* @param layer pointer to a layer
|
||||
* @param draw_dsc pointer to an initialized `lv_draw_triangle_dsc_t` object
|
||||
*/
|
||||
void lv_draw_triangle(lv_layer_t * layer, const lv_draw_triangle_dsc_t * draw_dsc);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_TRIANGLE_H*/
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* @file lv_draw_triangle_private.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_TRIANGLE_PRIVATE_H
|
||||
#define LV_DRAW_TRIANGLE_PRIVATE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_triangle.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_TRIANGLE_PRIVATE_H*/
|
||||
@@ -0,0 +1,819 @@
|
||||
/**
|
||||
* @file lv_draw_vector.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_vector_private.h"
|
||||
#include "../misc/lv_area_private.h"
|
||||
#include "lv_draw_private.h"
|
||||
|
||||
#if LV_USE_VECTOR_GRAPHIC
|
||||
|
||||
#include "../misc/lv_ll.h"
|
||||
#include "../misc/lv_types.h"
|
||||
#include "../stdlib/lv_string.h"
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
|
||||
#define MATH_PI 3.14159265358979323846f
|
||||
#define MATH_HALF_PI 1.57079632679489661923f
|
||||
|
||||
#define DEG_TO_RAD 0.017453292519943295769236907684886f
|
||||
#define RAD_TO_DEG 57.295779513082320876798154814105f
|
||||
|
||||
#define MATH_RADIANS(deg) ((deg) * DEG_TO_RAD)
|
||||
#define MATH_DEGREES(rad) ((rad) * RAD_TO_DEG)
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.1415926f
|
||||
#endif
|
||||
|
||||
#define CHECK_AND_RESIZE_PATH_CONTAINER(P, N) \
|
||||
do { \
|
||||
if ((lv_array_size(&(P)->ops) + (N)) > lv_array_capacity(&(P)->ops)) { \
|
||||
lv_array_resize(&(P)->ops, ((P)->ops.capacity << 1)); \
|
||||
} \
|
||||
if ((lv_array_size(&(P)->points) + (N)) > lv_array_capacity(&(P)->points)) { \
|
||||
lv_array_resize(&(P)->points, ((P)->points.capacity << 1)); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct {
|
||||
lv_vector_path_t * path;
|
||||
lv_vector_draw_dsc_t dsc;
|
||||
} lv_vector_draw_task;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static void _copy_draw_dsc(lv_vector_draw_dsc_t * dst, const lv_vector_draw_dsc_t * src)
|
||||
{
|
||||
lv_memcpy(&(dst->fill_dsc), &(src->fill_dsc), sizeof(lv_vector_fill_dsc_t));
|
||||
|
||||
dst->stroke_dsc.style = src->stroke_dsc.style;
|
||||
dst->stroke_dsc.color = src->stroke_dsc.color;
|
||||
dst->stroke_dsc.opa = src->stroke_dsc.opa;
|
||||
dst->stroke_dsc.width = src->stroke_dsc.width;
|
||||
dst->stroke_dsc.cap = src->stroke_dsc.cap;
|
||||
dst->stroke_dsc.join = src->stroke_dsc.join;
|
||||
dst->stroke_dsc.miter_limit = src->stroke_dsc.miter_limit;
|
||||
lv_array_copy(&(dst->stroke_dsc.dash_pattern), &(src->stroke_dsc.dash_pattern));
|
||||
dst->stroke_dsc.gradient.style = src->stroke_dsc.gradient.style;
|
||||
dst->stroke_dsc.gradient.cx = src->stroke_dsc.gradient.cx;
|
||||
dst->stroke_dsc.gradient.cy = src->stroke_dsc.gradient.cy;
|
||||
dst->stroke_dsc.gradient.cr = src->stroke_dsc.gradient.cr;
|
||||
dst->stroke_dsc.gradient.spread = src->fill_dsc.gradient.spread;
|
||||
lv_memcpy(&(dst->stroke_dsc.gradient), &(src->stroke_dsc.gradient), sizeof(lv_vector_gradient_t));
|
||||
lv_memcpy(&(dst->stroke_dsc.matrix), &(src->stroke_dsc.matrix), sizeof(lv_matrix_t));
|
||||
|
||||
dst->blend_mode = src->blend_mode;
|
||||
lv_memcpy(&(dst->matrix), &(src->matrix), sizeof(lv_matrix_t));
|
||||
lv_area_copy(&(dst->scissor_area), &(src->scissor_area));
|
||||
}
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_matrix_transform_point(const lv_matrix_t * matrix, lv_fpoint_t * point)
|
||||
{
|
||||
float x = point->x;
|
||||
float y = point->y;
|
||||
|
||||
point->x = x * matrix->m[0][0] + y * matrix->m[1][0] + matrix->m[0][2];
|
||||
point->y = x * matrix->m[0][1] + y * matrix->m[1][1] + matrix->m[1][2];
|
||||
}
|
||||
|
||||
void lv_matrix_transform_path(const lv_matrix_t * matrix, lv_vector_path_t * path)
|
||||
{
|
||||
lv_fpoint_t * pt = lv_array_front(&path->points);
|
||||
uint32_t size = lv_array_size(&path->points);
|
||||
for(uint32_t i = 0; i < size; i++) {
|
||||
lv_matrix_transform_point(matrix, &pt[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* path functions */
|
||||
lv_vector_path_t * lv_vector_path_create(lv_vector_path_quality_t quality)
|
||||
{
|
||||
lv_vector_path_t * path = lv_malloc(sizeof(lv_vector_path_t));
|
||||
LV_ASSERT_MALLOC(path);
|
||||
lv_memzero(path, sizeof(lv_vector_path_t));
|
||||
path->quality = quality;
|
||||
lv_array_init(&path->ops, 8, sizeof(lv_vector_path_op_t));
|
||||
lv_array_init(&path->points, 8, sizeof(lv_fpoint_t));
|
||||
return path;
|
||||
}
|
||||
|
||||
void lv_vector_path_copy(lv_vector_path_t * target_path, const lv_vector_path_t * path)
|
||||
{
|
||||
target_path->quality = path->quality;
|
||||
lv_array_copy(&target_path->ops, &path->ops);
|
||||
lv_array_copy(&target_path->points, &path->points);
|
||||
}
|
||||
|
||||
void lv_vector_path_clear(lv_vector_path_t * path)
|
||||
{
|
||||
lv_array_clear(&path->ops);
|
||||
lv_array_clear(&path->points);
|
||||
}
|
||||
|
||||
void lv_vector_path_delete(lv_vector_path_t * path)
|
||||
{
|
||||
lv_array_deinit(&path->ops);
|
||||
lv_array_deinit(&path->points);
|
||||
lv_free(path);
|
||||
}
|
||||
|
||||
void lv_vector_path_move_to(lv_vector_path_t * path, const lv_fpoint_t * p)
|
||||
{
|
||||
CHECK_AND_RESIZE_PATH_CONTAINER(path, 1);
|
||||
|
||||
lv_vector_path_op_t op = LV_VECTOR_PATH_OP_MOVE_TO;
|
||||
lv_array_push_back(&path->ops, &op);
|
||||
lv_array_push_back(&path->points, p);
|
||||
}
|
||||
|
||||
void lv_vector_path_line_to(lv_vector_path_t * path, const lv_fpoint_t * p)
|
||||
{
|
||||
if(lv_array_is_empty(&path->ops)) {
|
||||
/*first op must be move_to*/
|
||||
return;
|
||||
}
|
||||
|
||||
CHECK_AND_RESIZE_PATH_CONTAINER(path, 1);
|
||||
|
||||
lv_vector_path_op_t op = LV_VECTOR_PATH_OP_LINE_TO;
|
||||
lv_array_push_back(&path->ops, &op);
|
||||
lv_array_push_back(&path->points, p);
|
||||
}
|
||||
|
||||
void lv_vector_path_quad_to(lv_vector_path_t * path, const lv_fpoint_t * p1, const lv_fpoint_t * p2)
|
||||
{
|
||||
if(lv_array_is_empty(&path->ops)) {
|
||||
/*first op must be move_to*/
|
||||
return;
|
||||
}
|
||||
|
||||
CHECK_AND_RESIZE_PATH_CONTAINER(path, 2);
|
||||
|
||||
lv_vector_path_op_t op = LV_VECTOR_PATH_OP_QUAD_TO;
|
||||
lv_array_push_back(&path->ops, &op);
|
||||
lv_array_push_back(&path->points, p1);
|
||||
lv_array_push_back(&path->points, p2);
|
||||
}
|
||||
|
||||
void lv_vector_path_cubic_to(lv_vector_path_t * path, const lv_fpoint_t * p1, const lv_fpoint_t * p2,
|
||||
const lv_fpoint_t * p3)
|
||||
{
|
||||
if(lv_array_is_empty(&path->ops)) {
|
||||
/*first op must be move_to*/
|
||||
return;
|
||||
}
|
||||
|
||||
CHECK_AND_RESIZE_PATH_CONTAINER(path, 3);
|
||||
|
||||
lv_vector_path_op_t op = LV_VECTOR_PATH_OP_CUBIC_TO;
|
||||
lv_array_push_back(&path->ops, &op);
|
||||
lv_array_push_back(&path->points, p1);
|
||||
lv_array_push_back(&path->points, p2);
|
||||
lv_array_push_back(&path->points, p3);
|
||||
}
|
||||
|
||||
void lv_vector_path_close(lv_vector_path_t * path)
|
||||
{
|
||||
if(lv_array_is_empty(&path->ops)) {
|
||||
/*first op must be move_to*/
|
||||
return;
|
||||
}
|
||||
|
||||
CHECK_AND_RESIZE_PATH_CONTAINER(path, 1);
|
||||
|
||||
lv_vector_path_op_t op = LV_VECTOR_PATH_OP_CLOSE;
|
||||
lv_array_push_back(&path->ops, &op);
|
||||
}
|
||||
|
||||
void lv_vector_path_get_bounding(const lv_vector_path_t * path, lv_area_t * area)
|
||||
{
|
||||
LV_ASSERT_NULL(path);
|
||||
LV_ASSERT_NULL(area);
|
||||
|
||||
uint32_t len = lv_array_size(&path->points);
|
||||
if(len == 0) {
|
||||
lv_memzero(area, sizeof(lv_area_t));
|
||||
return;
|
||||
}
|
||||
|
||||
lv_fpoint_t * p = lv_array_front(&path->points);
|
||||
float x1 = p[0].x;
|
||||
float x2 = p[0].x;
|
||||
float y1 = p[0].y;
|
||||
float y2 = p[0].y;
|
||||
|
||||
for(uint32_t i = 1; i < len; i++) {
|
||||
if(p[i].x < x1) x1 = p[i].x;
|
||||
if(p[i].y < y1) y1 = p[i].y;
|
||||
if(p[i].x > x2) x2 = p[i].x;
|
||||
if(p[i].y > y2) y2 = p[i].y;
|
||||
}
|
||||
|
||||
area->x1 = lroundf(x1);
|
||||
area->y1 = lroundf(y1);
|
||||
area->x2 = lroundf(x2);
|
||||
area->y2 = lroundf(y2);
|
||||
}
|
||||
|
||||
void lv_vector_path_append_rect(lv_vector_path_t * path, const lv_area_t * rect, float rx, float ry)
|
||||
{
|
||||
float x = rect->x1;
|
||||
float y = rect->y1;
|
||||
float w = (float)lv_area_get_width(rect);
|
||||
float h = (float)lv_area_get_height(rect);
|
||||
|
||||
float hw = w * 0.5f;
|
||||
float hh = h * 0.5f;
|
||||
|
||||
if(rx > hw) rx = hw;
|
||||
if(ry > hh) ry = hh;
|
||||
|
||||
if(rx == 0 && ry == 0) {
|
||||
lv_fpoint_t pt = {x, y};
|
||||
lv_vector_path_move_to(path, &pt);
|
||||
pt.x += w;
|
||||
lv_vector_path_line_to(path, &pt);
|
||||
pt.y += h;
|
||||
lv_vector_path_line_to(path, &pt);
|
||||
pt.x -= w;
|
||||
lv_vector_path_line_to(path, &pt);
|
||||
lv_vector_path_close(path);
|
||||
}
|
||||
else if(rx == hw && ry == hh) {
|
||||
lv_fpoint_t pt = {x + w * 0.5f, y + h * 0.5f};
|
||||
lv_vector_path_append_circle(path, &pt, rx, ry);
|
||||
}
|
||||
else {
|
||||
float hrx = rx * 0.5f;
|
||||
float hry = ry * 0.5f;
|
||||
lv_fpoint_t pt, pt2, pt3;
|
||||
|
||||
pt.x = x + rx;
|
||||
pt.y = y;
|
||||
lv_vector_path_move_to(path, &pt);
|
||||
|
||||
pt.x = x + w - rx;
|
||||
pt.y = y;
|
||||
lv_vector_path_line_to(path, &pt);
|
||||
|
||||
pt.x = x + w - rx + hrx;
|
||||
pt.y = y;
|
||||
pt2.x = x + w;
|
||||
pt2.y = y + ry - hry;
|
||||
pt3.x = x + w;
|
||||
pt3.y = y + ry;
|
||||
lv_vector_path_cubic_to(path, &pt, &pt2, &pt3);
|
||||
|
||||
pt.x = x + w;
|
||||
pt.y = y + h - ry;
|
||||
lv_vector_path_line_to(path, &pt);
|
||||
|
||||
pt.x = x + w;
|
||||
pt.y = y + h - ry + hry;
|
||||
pt2.x = x + w - rx + hrx;
|
||||
pt2.y = y + h;
|
||||
pt3.x = x + w - rx;
|
||||
pt3.y = y + h;
|
||||
lv_vector_path_cubic_to(path, &pt, &pt2, &pt3);
|
||||
|
||||
pt.x = x + rx;
|
||||
pt.y = y + h;
|
||||
lv_vector_path_line_to(path, &pt);
|
||||
|
||||
pt.x = x + rx - hrx;
|
||||
pt.y = y + h;
|
||||
pt2.x = x;
|
||||
pt2.y = y + h - ry + hry;
|
||||
pt3.x = x;
|
||||
pt3.y = y + h - ry;
|
||||
lv_vector_path_cubic_to(path, &pt, &pt2, &pt3);
|
||||
|
||||
pt.x = x;
|
||||
pt.y = y + ry;
|
||||
lv_vector_path_line_to(path, &pt);
|
||||
|
||||
pt.x = x;
|
||||
pt.y = y + ry - hry;
|
||||
pt2.x = x + rx - hrx;
|
||||
pt2.y = y;
|
||||
pt3.x = x + rx;
|
||||
pt3.y = y;
|
||||
lv_vector_path_cubic_to(path, &pt, &pt2, &pt3);
|
||||
lv_vector_path_close(path);
|
||||
}
|
||||
}
|
||||
|
||||
void lv_vector_path_append_circle(lv_vector_path_t * path, const lv_fpoint_t * c, float rx, float ry)
|
||||
{
|
||||
float krx = rx * 0.552284f;
|
||||
float kry = ry * 0.552284f;
|
||||
float cx = c->x;
|
||||
float cy = c->y;
|
||||
|
||||
lv_fpoint_t pt, pt2, pt3;
|
||||
pt.x = cx;
|
||||
pt.y = cy - ry;
|
||||
lv_vector_path_move_to(path, &pt);
|
||||
|
||||
pt.x = cx + krx;
|
||||
pt.y = cy - ry;
|
||||
pt2.x = cx + rx;
|
||||
pt2.y = cy - kry;
|
||||
pt3.x = cx + rx;
|
||||
pt3.y = cy;
|
||||
lv_vector_path_cubic_to(path, &pt, &pt2, &pt3);
|
||||
|
||||
pt.x = cx + rx;
|
||||
pt.y = cy + kry;
|
||||
pt2.x = cx + krx;
|
||||
pt2.y = cy + ry;
|
||||
pt3.x = cx;
|
||||
pt3.y = cy + ry;
|
||||
lv_vector_path_cubic_to(path, &pt, &pt2, &pt3);
|
||||
|
||||
pt.x = cx - krx;
|
||||
pt.y = cy + ry;
|
||||
pt2.x = cx - rx;
|
||||
pt2.y = cy + kry;
|
||||
pt3.x = cx - rx;
|
||||
pt3.y = cy;
|
||||
lv_vector_path_cubic_to(path, &pt, &pt2, &pt3);
|
||||
|
||||
pt.x = cx - rx;
|
||||
pt.y = cy - kry;
|
||||
pt2.x = cx - krx;
|
||||
pt2.y = cy - ry;
|
||||
pt3.x = cx;
|
||||
pt3.y = cy - ry;
|
||||
lv_vector_path_cubic_to(path, &pt, &pt2, &pt3);
|
||||
|
||||
lv_vector_path_close(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a arc to the path
|
||||
* @param path pointer to a path
|
||||
* @param c pointer to a `lv_fpoint_t` variable for center of the circle
|
||||
* @param radius the radius for arc
|
||||
* @param start_angle the start angle for arc
|
||||
* @param sweep the sweep angle for arc, could be negative
|
||||
* @param pie true: draw a pie, false: draw a arc
|
||||
*/
|
||||
void lv_vector_path_append_arc(lv_vector_path_t * path, const lv_fpoint_t * c, float radius, float start_angle,
|
||||
float sweep, bool pie)
|
||||
{
|
||||
float cx = c->x;
|
||||
float cy = c->y;
|
||||
|
||||
/* just circle */
|
||||
if(sweep >= 360.0f || sweep <= -360.0f) {
|
||||
lv_vector_path_append_circle(path, c, radius, radius);
|
||||
return;
|
||||
}
|
||||
|
||||
start_angle = MATH_RADIANS(start_angle);
|
||||
sweep = MATH_RADIANS(sweep);
|
||||
|
||||
int n_curves = (int)ceil(fabsf(sweep / MATH_HALF_PI));
|
||||
float sweep_sign = sweep < 0 ? -1.f : 1.f;
|
||||
float fract = fmodf(sweep, MATH_HALF_PI);
|
||||
fract = (fabsf(fract) < FLT_EPSILON) ? MATH_HALF_PI * sweep_sign : fract;
|
||||
|
||||
/* Start from here */
|
||||
lv_fpoint_t start = {
|
||||
.x = radius * cosf(start_angle),
|
||||
.y = radius * sinf(start_angle),
|
||||
};
|
||||
|
||||
if(pie) {
|
||||
lv_vector_path_move_to(path, &(lv_fpoint_t) {
|
||||
cx, cy
|
||||
});
|
||||
lv_vector_path_line_to(path, &(lv_fpoint_t) {
|
||||
start.x + cx, start.y + cy
|
||||
});
|
||||
}
|
||||
else {
|
||||
lv_vector_path_move_to(path, &(lv_fpoint_t) {
|
||||
start.x + cx, start.y + cy
|
||||
});
|
||||
}
|
||||
|
||||
for(int i = 0; i < n_curves; ++i) {
|
||||
float end_angle = start_angle + ((i != n_curves - 1) ? MATH_HALF_PI * sweep_sign : fract);
|
||||
float end_x = radius * cosf(end_angle);
|
||||
float end_y = radius * sinf(end_angle);
|
||||
|
||||
/* variables needed to calculate bezier control points */
|
||||
|
||||
/** get bezier control points using article:
|
||||
* (http://itc.ktu.lt/index.php/ITC/article/view/11812/6479)
|
||||
*/
|
||||
float ax = start.x;
|
||||
float ay = start.y;
|
||||
float bx = end_x;
|
||||
float by = end_y;
|
||||
float q1 = ax * ax + ay * ay;
|
||||
float q2 = ax * bx + ay * by + q1;
|
||||
float k2 = (4.0f / 3.0f) * ((sqrtf(2 * q1 * q2) - q2) / (ax * by - ay * bx));
|
||||
|
||||
/* Next start point is the current end point */
|
||||
start.x = end_x;
|
||||
start.y = end_y;
|
||||
|
||||
end_x += cx;
|
||||
end_y += cy;
|
||||
|
||||
lv_fpoint_t ctrl1 = {ax - k2 * ay + cx, ay + k2 * ax + cy};
|
||||
lv_fpoint_t ctrl2 = {bx + k2 * by + cx, by - k2 * bx + cy};
|
||||
lv_fpoint_t end = {end_x, end_y};
|
||||
lv_vector_path_cubic_to(path, &ctrl1, &ctrl2, &end);
|
||||
start_angle = end_angle;
|
||||
}
|
||||
|
||||
if(pie) {
|
||||
lv_vector_path_close(path);
|
||||
}
|
||||
}
|
||||
|
||||
void lv_vector_path_append_path(lv_vector_path_t * path, const lv_vector_path_t * subpath)
|
||||
{
|
||||
uint32_t ops_size = lv_array_size(&path->ops);
|
||||
uint32_t nops_size = lv_array_size(&subpath->ops);
|
||||
uint32_t point_size = lv_array_size(&path->points);
|
||||
uint32_t npoint_size = lv_array_size(&subpath->points);
|
||||
|
||||
lv_array_concat(&path->ops, &subpath->ops);
|
||||
path->ops.size = ops_size + nops_size;
|
||||
|
||||
lv_array_concat(&path->points, &subpath->points);
|
||||
path->points.size = point_size + npoint_size;
|
||||
}
|
||||
|
||||
/* draw dsc functions */
|
||||
|
||||
lv_vector_dsc_t * lv_vector_dsc_create(lv_layer_t * layer)
|
||||
{
|
||||
lv_vector_dsc_t * dsc = lv_malloc(sizeof(lv_vector_dsc_t));
|
||||
LV_ASSERT_MALLOC(dsc);
|
||||
lv_memzero(dsc, sizeof(lv_vector_dsc_t));
|
||||
|
||||
dsc->layer = layer;
|
||||
|
||||
lv_vector_fill_dsc_t * fill_dsc = &(dsc->current_dsc.fill_dsc);
|
||||
fill_dsc->style = LV_VECTOR_DRAW_STYLE_SOLID;
|
||||
fill_dsc->color = lv_color_to_32(lv_color_black(), 0xFF);
|
||||
fill_dsc->opa = LV_OPA_COVER;
|
||||
fill_dsc->fill_rule = LV_VECTOR_FILL_NONZERO;
|
||||
lv_matrix_identity(&(fill_dsc->matrix)); /*identity matrix*/
|
||||
|
||||
lv_vector_stroke_dsc_t * stroke_dsc = &(dsc->current_dsc.stroke_dsc);
|
||||
stroke_dsc->style = LV_VECTOR_DRAW_STYLE_SOLID;
|
||||
stroke_dsc->color = lv_color_to_32(lv_color_black(), 0xFF);
|
||||
stroke_dsc->opa = LV_OPA_0; /*default no stroke*/
|
||||
stroke_dsc->width = 1.0f;
|
||||
stroke_dsc->cap = LV_VECTOR_STROKE_CAP_BUTT;
|
||||
stroke_dsc->join = LV_VECTOR_STROKE_JOIN_MITER;
|
||||
stroke_dsc->miter_limit = 4.0f;
|
||||
lv_matrix_identity(&(stroke_dsc->matrix)); /*identity matrix*/
|
||||
|
||||
dsc->current_dsc.blend_mode = LV_VECTOR_BLEND_SRC_OVER;
|
||||
dsc->current_dsc.scissor_area = layer->_clip_area;
|
||||
lv_matrix_identity(&(dsc->current_dsc.matrix)); /*identity matrix*/
|
||||
dsc->tasks.task_list = NULL;
|
||||
return dsc;
|
||||
}
|
||||
|
||||
void lv_vector_dsc_delete(lv_vector_dsc_t * dsc)
|
||||
{
|
||||
if(dsc->tasks.task_list) {
|
||||
lv_ll_t * task_list = dsc->tasks.task_list;
|
||||
lv_vector_for_each_destroy_tasks(task_list, NULL, NULL);
|
||||
dsc->tasks.task_list = NULL;
|
||||
}
|
||||
lv_array_deinit(&(dsc->current_dsc.stroke_dsc.dash_pattern));
|
||||
lv_free(dsc);
|
||||
}
|
||||
|
||||
void lv_vector_dsc_set_blend_mode(lv_vector_dsc_t * dsc, lv_vector_blend_t blend)
|
||||
{
|
||||
dsc->current_dsc.blend_mode = blend;
|
||||
}
|
||||
|
||||
void lv_vector_dsc_set_transform(lv_vector_dsc_t * dsc, const lv_matrix_t * matrix)
|
||||
{
|
||||
lv_memcpy(&(dsc->current_dsc.matrix), matrix, sizeof(lv_matrix_t));
|
||||
}
|
||||
|
||||
void lv_vector_dsc_set_fill_color(lv_vector_dsc_t * dsc, lv_color_t color)
|
||||
{
|
||||
dsc->current_dsc.fill_dsc.style = LV_VECTOR_DRAW_STYLE_SOLID;
|
||||
dsc->current_dsc.fill_dsc.color = lv_color_to_32(color, 0xFF);
|
||||
}
|
||||
|
||||
void lv_vector_dsc_set_fill_color32(lv_vector_dsc_t * dsc, lv_color32_t color)
|
||||
{
|
||||
dsc->current_dsc.fill_dsc.style = LV_VECTOR_DRAW_STYLE_SOLID;
|
||||
dsc->current_dsc.fill_dsc.color = color;
|
||||
}
|
||||
|
||||
void lv_vector_dsc_set_fill_opa(lv_vector_dsc_t * dsc, lv_opa_t opa)
|
||||
{
|
||||
dsc->current_dsc.fill_dsc.opa = opa;
|
||||
}
|
||||
|
||||
void lv_vector_dsc_set_fill_rule(lv_vector_dsc_t * dsc, lv_vector_fill_t rule)
|
||||
{
|
||||
dsc->current_dsc.fill_dsc.fill_rule = rule;
|
||||
}
|
||||
|
||||
void lv_vector_dsc_set_fill_units(lv_vector_dsc_t * dsc, const lv_vector_fill_units_t units)
|
||||
{
|
||||
dsc->current_dsc.fill_dsc.fill_units = units;
|
||||
}
|
||||
|
||||
void lv_vector_dsc_set_fill_image(lv_vector_dsc_t * dsc, const lv_draw_image_dsc_t * img_dsc)
|
||||
{
|
||||
dsc->current_dsc.fill_dsc.style = LV_VECTOR_DRAW_STYLE_PATTERN;
|
||||
lv_memcpy(&(dsc->current_dsc.fill_dsc.img_dsc), img_dsc, sizeof(lv_draw_image_dsc_t));
|
||||
}
|
||||
|
||||
void lv_vector_dsc_set_fill_linear_gradient(lv_vector_dsc_t * dsc, float x1, float y1, float x2, float y2)
|
||||
{
|
||||
dsc->current_dsc.fill_dsc.style = LV_VECTOR_DRAW_STYLE_GRADIENT;
|
||||
dsc->current_dsc.fill_dsc.gradient.style = LV_VECTOR_GRADIENT_STYLE_LINEAR;
|
||||
dsc->current_dsc.fill_dsc.gradient.x1 = x1;
|
||||
dsc->current_dsc.fill_dsc.gradient.y1 = y1;
|
||||
dsc->current_dsc.fill_dsc.gradient.x2 = x2;
|
||||
dsc->current_dsc.fill_dsc.gradient.y2 = y2;
|
||||
}
|
||||
|
||||
void lv_vector_dsc_set_fill_radial_gradient(lv_vector_dsc_t * dsc, float cx, float cy, float radius)
|
||||
{
|
||||
dsc->current_dsc.fill_dsc.style = LV_VECTOR_DRAW_STYLE_GRADIENT;
|
||||
dsc->current_dsc.fill_dsc.gradient.style = LV_VECTOR_GRADIENT_STYLE_RADIAL;
|
||||
dsc->current_dsc.fill_dsc.gradient.cx = cx;
|
||||
dsc->current_dsc.fill_dsc.gradient.cy = cy;
|
||||
dsc->current_dsc.fill_dsc.gradient.cr = radius;
|
||||
}
|
||||
|
||||
void lv_vector_dsc_set_fill_gradient_spread(lv_vector_dsc_t * dsc, lv_vector_gradient_spread_t spread)
|
||||
{
|
||||
dsc->current_dsc.fill_dsc.gradient.spread = spread;
|
||||
}
|
||||
|
||||
void lv_vector_dsc_set_fill_gradient_color_stops(lv_vector_dsc_t * dsc, const lv_grad_stop_t * stops,
|
||||
uint16_t count)
|
||||
{
|
||||
if(count > LV_GRADIENT_MAX_STOPS) {
|
||||
LV_LOG_WARN("Gradient stops limited: %d, max: %d", count, LV_GRADIENT_MAX_STOPS);
|
||||
count = LV_GRADIENT_MAX_STOPS;
|
||||
}
|
||||
|
||||
lv_memcpy(&(dsc->current_dsc.fill_dsc.gradient.stops), stops, sizeof(lv_grad_stop_t) * count);
|
||||
dsc->current_dsc.fill_dsc.gradient.stops_count = count;
|
||||
}
|
||||
|
||||
void lv_vector_dsc_set_fill_transform(lv_vector_dsc_t * dsc, const lv_matrix_t * matrix)
|
||||
{
|
||||
lv_memcpy(&(dsc->current_dsc.fill_dsc.matrix), matrix, sizeof(lv_matrix_t));
|
||||
}
|
||||
|
||||
void lv_vector_dsc_set_stroke_transform(lv_vector_dsc_t * dsc, const lv_matrix_t * matrix)
|
||||
{
|
||||
lv_memcpy(&(dsc->current_dsc.stroke_dsc.matrix), matrix, sizeof(lv_matrix_t));
|
||||
}
|
||||
|
||||
void lv_vector_dsc_set_stroke_color32(lv_vector_dsc_t * dsc, lv_color32_t color)
|
||||
{
|
||||
dsc->current_dsc.stroke_dsc.style = LV_VECTOR_DRAW_STYLE_SOLID;
|
||||
dsc->current_dsc.stroke_dsc.color = color;
|
||||
}
|
||||
|
||||
void lv_vector_dsc_set_stroke_color(lv_vector_dsc_t * dsc, lv_color_t color)
|
||||
{
|
||||
dsc->current_dsc.stroke_dsc.style = LV_VECTOR_DRAW_STYLE_SOLID;
|
||||
dsc->current_dsc.stroke_dsc.color = lv_color_to_32(color, 0xFF);
|
||||
}
|
||||
|
||||
void lv_vector_dsc_set_stroke_opa(lv_vector_dsc_t * dsc, lv_opa_t opa)
|
||||
{
|
||||
dsc->current_dsc.stroke_dsc.opa = opa;
|
||||
}
|
||||
|
||||
void lv_vector_dsc_set_stroke_width(lv_vector_dsc_t * dsc, float width)
|
||||
{
|
||||
dsc->current_dsc.stroke_dsc.width = width;
|
||||
}
|
||||
|
||||
void lv_vector_dsc_set_stroke_dash(lv_vector_dsc_t * dsc, float * dash_pattern, uint16_t dash_count)
|
||||
{
|
||||
lv_array_t * dash_array = &(dsc->current_dsc.stroke_dsc.dash_pattern);
|
||||
if(dash_pattern) {
|
||||
lv_array_clear(dash_array);
|
||||
if(lv_array_capacity(dash_array) == 0) {
|
||||
lv_array_init(dash_array, dash_count, sizeof(float));
|
||||
}
|
||||
else {
|
||||
lv_array_resize(dash_array, dash_count);
|
||||
}
|
||||
for(uint16_t i = 0; i < dash_count; i++) {
|
||||
lv_array_push_back(dash_array, &dash_pattern[i]);
|
||||
}
|
||||
}
|
||||
else { /*clear dash*/
|
||||
lv_array_clear(dash_array);
|
||||
}
|
||||
}
|
||||
|
||||
void lv_vector_dsc_set_stroke_cap(lv_vector_dsc_t * dsc, lv_vector_stroke_cap_t cap)
|
||||
{
|
||||
dsc->current_dsc.stroke_dsc.cap = cap;
|
||||
}
|
||||
|
||||
void lv_vector_dsc_set_stroke_join(lv_vector_dsc_t * dsc, lv_vector_stroke_join_t join)
|
||||
{
|
||||
dsc->current_dsc.stroke_dsc.join = join;
|
||||
}
|
||||
|
||||
void lv_vector_dsc_set_stroke_miter_limit(lv_vector_dsc_t * dsc, uint16_t miter_limit)
|
||||
{
|
||||
dsc->current_dsc.stroke_dsc.miter_limit = miter_limit;
|
||||
}
|
||||
|
||||
void lv_vector_dsc_set_stroke_linear_gradient(lv_vector_dsc_t * dsc, float x1, float y1, float x2, float y2)
|
||||
{
|
||||
dsc->current_dsc.stroke_dsc.style = LV_VECTOR_DRAW_STYLE_GRADIENT;
|
||||
dsc->current_dsc.stroke_dsc.gradient.style = LV_VECTOR_GRADIENT_STYLE_LINEAR;
|
||||
dsc->current_dsc.stroke_dsc.gradient.x1 = x1;
|
||||
dsc->current_dsc.stroke_dsc.gradient.y1 = y1;
|
||||
dsc->current_dsc.stroke_dsc.gradient.x2 = x2;
|
||||
dsc->current_dsc.stroke_dsc.gradient.y2 = y2;
|
||||
}
|
||||
|
||||
void lv_vector_dsc_set_stroke_radial_gradient(lv_vector_dsc_t * dsc, float cx, float cy, float radius)
|
||||
{
|
||||
dsc->current_dsc.stroke_dsc.style = LV_VECTOR_DRAW_STYLE_GRADIENT;
|
||||
dsc->current_dsc.stroke_dsc.gradient.style = LV_VECTOR_GRADIENT_STYLE_RADIAL;
|
||||
dsc->current_dsc.stroke_dsc.gradient.cx = cx;
|
||||
dsc->current_dsc.stroke_dsc.gradient.cy = cy;
|
||||
dsc->current_dsc.stroke_dsc.gradient.cr = radius;
|
||||
}
|
||||
|
||||
void lv_vector_dsc_set_stroke_gradient_spread(lv_vector_dsc_t * dsc, lv_vector_gradient_spread_t spread)
|
||||
{
|
||||
dsc->current_dsc.stroke_dsc.gradient.spread = spread;
|
||||
}
|
||||
|
||||
void lv_vector_dsc_set_stroke_gradient_color_stops(lv_vector_dsc_t * dsc, const lv_grad_stop_t * stops,
|
||||
uint16_t count)
|
||||
{
|
||||
if(count > LV_GRADIENT_MAX_STOPS) {
|
||||
LV_LOG_WARN("Gradient stops limited: %d, max: %d", count, LV_GRADIENT_MAX_STOPS);
|
||||
count = LV_GRADIENT_MAX_STOPS;
|
||||
}
|
||||
|
||||
lv_memcpy(&(dsc->current_dsc.stroke_dsc.gradient.stops), stops, sizeof(lv_grad_stop_t) * count);
|
||||
dsc->current_dsc.stroke_dsc.gradient.stops_count = count;
|
||||
}
|
||||
|
||||
/* draw functions */
|
||||
void lv_vector_dsc_add_path(lv_vector_dsc_t * dsc, const lv_vector_path_t * path)
|
||||
{
|
||||
lv_area_t rect;
|
||||
if(!lv_area_intersect(&rect, &(dsc->layer->_clip_area), &(dsc->current_dsc.scissor_area))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(dsc->current_dsc.fill_dsc.opa == 0
|
||||
&& dsc->current_dsc.stroke_dsc.opa == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!dsc->tasks.task_list) {
|
||||
dsc->tasks.task_list = lv_malloc(sizeof(lv_ll_t));
|
||||
LV_ASSERT_MALLOC(dsc->tasks.task_list);
|
||||
lv_ll_init(dsc->tasks.task_list, sizeof(lv_vector_draw_task));
|
||||
}
|
||||
|
||||
lv_vector_draw_task * new_task = (lv_vector_draw_task *)lv_ll_ins_tail(dsc->tasks.task_list);
|
||||
lv_memset(new_task, 0, sizeof(lv_vector_draw_task));
|
||||
|
||||
new_task->path = lv_vector_path_create(0);
|
||||
|
||||
_copy_draw_dsc(&(new_task->dsc), &(dsc->current_dsc));
|
||||
lv_vector_path_copy(new_task->path, path);
|
||||
new_task->dsc.scissor_area = rect;
|
||||
}
|
||||
|
||||
void lv_vector_clear_area(lv_vector_dsc_t * dsc, const lv_area_t * rect)
|
||||
{
|
||||
lv_area_t r;
|
||||
if(!lv_area_intersect(&r, &(dsc->layer->_clip_area), &(dsc->current_dsc.scissor_area))) {
|
||||
return;
|
||||
}
|
||||
|
||||
lv_area_t final_rect;
|
||||
if(!lv_area_intersect(&final_rect, &r, rect)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!dsc->tasks.task_list) {
|
||||
dsc->tasks.task_list = lv_malloc(sizeof(lv_ll_t));
|
||||
LV_ASSERT_MALLOC(dsc->tasks.task_list);
|
||||
lv_ll_init(dsc->tasks.task_list, sizeof(lv_vector_draw_task));
|
||||
}
|
||||
|
||||
lv_vector_draw_task * new_task = (lv_vector_draw_task *)lv_ll_ins_tail(dsc->tasks.task_list);
|
||||
lv_memset(new_task, 0, sizeof(lv_vector_draw_task));
|
||||
|
||||
new_task->dsc.fill_dsc.color = dsc->current_dsc.fill_dsc.color;
|
||||
new_task->dsc.fill_dsc.opa = dsc->current_dsc.fill_dsc.opa;
|
||||
lv_area_copy(&(new_task->dsc.scissor_area), &final_rect);
|
||||
}
|
||||
|
||||
void lv_draw_vector(lv_vector_dsc_t * dsc)
|
||||
{
|
||||
if(!dsc->tasks.task_list) {
|
||||
return;
|
||||
}
|
||||
|
||||
lv_layer_t * layer = dsc->layer;
|
||||
|
||||
lv_draw_task_t * t = lv_draw_add_task(layer, &(layer->_clip_area), LV_DRAW_TASK_TYPE_VECTOR);
|
||||
lv_memcpy(t->draw_dsc, &(dsc->tasks), sizeof(lv_draw_vector_task_dsc_t));
|
||||
lv_draw_finalize_task_creation(layer, t);
|
||||
dsc->tasks.task_list = NULL;
|
||||
}
|
||||
|
||||
/* draw dsc transform */
|
||||
void lv_vector_dsc_identity(lv_vector_dsc_t * dsc)
|
||||
{
|
||||
lv_matrix_identity(&(dsc->current_dsc.matrix)); /*identity matrix*/
|
||||
}
|
||||
|
||||
void lv_vector_dsc_scale(lv_vector_dsc_t * dsc, float scale_x, float scale_y)
|
||||
{
|
||||
lv_matrix_scale(&(dsc->current_dsc.matrix), scale_x, scale_y);
|
||||
}
|
||||
|
||||
void lv_vector_dsc_rotate(lv_vector_dsc_t * dsc, float degree)
|
||||
{
|
||||
lv_matrix_rotate(&(dsc->current_dsc.matrix), degree);
|
||||
}
|
||||
|
||||
void lv_vector_dsc_translate(lv_vector_dsc_t * dsc, float tx, float ty)
|
||||
{
|
||||
lv_matrix_translate(&(dsc->current_dsc.matrix), tx, ty);
|
||||
}
|
||||
|
||||
void lv_vector_dsc_skew(lv_vector_dsc_t * dsc, float skew_x, float skew_y)
|
||||
{
|
||||
lv_matrix_skew(&(dsc->current_dsc.matrix), skew_x, skew_y);
|
||||
}
|
||||
|
||||
void lv_vector_for_each_destroy_tasks(lv_ll_t * task_list, vector_draw_task_cb cb, void * data)
|
||||
{
|
||||
if(task_list == NULL) return;
|
||||
|
||||
lv_vector_draw_task * task = lv_ll_get_head(task_list);
|
||||
lv_vector_draw_task * next_task = NULL;
|
||||
|
||||
while(task != NULL) {
|
||||
next_task = lv_ll_get_next(task_list, task);
|
||||
lv_ll_remove(task_list, task);
|
||||
|
||||
if(cb) {
|
||||
cb(data, task->path, &(task->dsc));
|
||||
}
|
||||
|
||||
if(task->path) {
|
||||
lv_vector_path_delete(task->path);
|
||||
}
|
||||
lv_array_deinit(&(task->dsc.stroke_dsc.dash_pattern));
|
||||
|
||||
lv_free(task);
|
||||
task = next_task;
|
||||
}
|
||||
lv_free(task_list);
|
||||
}
|
||||
#endif /* LV_USE_VECTOR_GRAPHIC */
|
||||
@@ -0,0 +1,503 @@
|
||||
/**
|
||||
* @file lv_draw_vector.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_VECTOR_H
|
||||
#define LV_DRAW_VECTOR_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../misc/lv_array.h"
|
||||
#include "../misc/lv_matrix.h"
|
||||
#include "lv_draw_image.h"
|
||||
|
||||
#if LV_USE_VECTOR_GRAPHIC
|
||||
|
||||
#if !LV_USE_MATRIX
|
||||
#error "lv_draw_vector needs LV_USE_MATRIX = 1"
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
typedef enum {
|
||||
LV_VECTOR_FILL_NONZERO = 0,
|
||||
LV_VECTOR_FILL_EVENODD,
|
||||
} lv_vector_fill_t;
|
||||
|
||||
typedef enum {
|
||||
LV_VECTOR_STROKE_CAP_BUTT = 0,
|
||||
LV_VECTOR_STROKE_CAP_SQUARE,
|
||||
LV_VECTOR_STROKE_CAP_ROUND,
|
||||
} lv_vector_stroke_cap_t;
|
||||
|
||||
typedef enum {
|
||||
LV_VECTOR_STROKE_JOIN_MITER = 0,
|
||||
LV_VECTOR_STROKE_JOIN_BEVEL,
|
||||
LV_VECTOR_STROKE_JOIN_ROUND,
|
||||
} lv_vector_stroke_join_t;
|
||||
|
||||
typedef enum {
|
||||
LV_VECTOR_PATH_QUALITY_MEDIUM = 0, /* default*/
|
||||
LV_VECTOR_PATH_QUALITY_HIGH,
|
||||
LV_VECTOR_PATH_QUALITY_LOW,
|
||||
} lv_vector_path_quality_t;
|
||||
|
||||
typedef enum {
|
||||
LV_VECTOR_BLEND_SRC_OVER = 0,
|
||||
LV_VECTOR_BLEND_SRC_IN,
|
||||
LV_VECTOR_BLEND_DST_OVER,
|
||||
LV_VECTOR_BLEND_DST_IN,
|
||||
LV_VECTOR_BLEND_SCREEN,
|
||||
LV_VECTOR_BLEND_MULTIPLY,
|
||||
LV_VECTOR_BLEND_NONE,
|
||||
LV_VECTOR_BLEND_ADDITIVE,
|
||||
LV_VECTOR_BLEND_SUBTRACTIVE,
|
||||
} lv_vector_blend_t;
|
||||
|
||||
typedef enum {
|
||||
LV_VECTOR_PATH_OP_MOVE_TO = 0,
|
||||
LV_VECTOR_PATH_OP_LINE_TO,
|
||||
LV_VECTOR_PATH_OP_QUAD_TO,
|
||||
LV_VECTOR_PATH_OP_CUBIC_TO,
|
||||
LV_VECTOR_PATH_OP_CLOSE,
|
||||
} lv_vector_path_op_t;
|
||||
|
||||
typedef enum {
|
||||
LV_VECTOR_DRAW_STYLE_SOLID = 0,
|
||||
LV_VECTOR_DRAW_STYLE_PATTERN,
|
||||
LV_VECTOR_DRAW_STYLE_GRADIENT,
|
||||
} lv_vector_draw_style_t;
|
||||
|
||||
typedef enum {
|
||||
LV_VECTOR_GRADIENT_SPREAD_PAD = 0,
|
||||
LV_VECTOR_GRADIENT_SPREAD_REPEAT,
|
||||
LV_VECTOR_GRADIENT_SPREAD_REFLECT,
|
||||
} lv_vector_gradient_spread_t;
|
||||
|
||||
typedef enum {
|
||||
LV_VECTOR_GRADIENT_STYLE_LINEAR = 0,
|
||||
LV_VECTOR_GRADIENT_STYLE_RADIAL,
|
||||
} lv_vector_gradient_style_t;
|
||||
|
||||
typedef enum {
|
||||
LV_VECTOR_FILL_UNITS_OBJECT_BOUNDING_BOX = 0, /** Relative coordinates relative to the object bounding box. */
|
||||
LV_VECTOR_FILL_UNITS_USER_SPACE_ON_USE, /** Absolute coordinates relative to the layer's coordinate system */
|
||||
} lv_vector_fill_units_t;
|
||||
|
||||
struct _lv_fpoint_t {
|
||||
float x;
|
||||
float y;
|
||||
};
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Transform the coordinates of a point using given matrix
|
||||
* @param matrix pointer to a matrix
|
||||
* @param point pointer to a point
|
||||
*/
|
||||
void lv_matrix_transform_point(const lv_matrix_t * matrix, lv_fpoint_t * point);
|
||||
|
||||
/**
|
||||
* Transform all the coordinates of a path using given matrix
|
||||
* @param matrix pointer to a matrix
|
||||
* @param path pointer to a path
|
||||
*/
|
||||
void lv_matrix_transform_path(const lv_matrix_t * matrix, lv_vector_path_t * path);
|
||||
|
||||
/**
|
||||
* Create a vector graphic path object
|
||||
* @param quality the quality hint of path
|
||||
* @return pointer to the created path object
|
||||
*/
|
||||
lv_vector_path_t * lv_vector_path_create(lv_vector_path_quality_t quality);
|
||||
|
||||
/**
|
||||
* Copy a path data to another
|
||||
* @param target_path pointer to a path
|
||||
* @param path pointer to source path
|
||||
*/
|
||||
void lv_vector_path_copy(lv_vector_path_t * target_path, const lv_vector_path_t * path);
|
||||
|
||||
/**
|
||||
* Clear path data
|
||||
* @param path pointer to a path
|
||||
*/
|
||||
void lv_vector_path_clear(lv_vector_path_t * path);
|
||||
|
||||
/**
|
||||
* Delete the graphic path object
|
||||
* @param path pointer to a path
|
||||
*/
|
||||
void lv_vector_path_delete(lv_vector_path_t * path);
|
||||
|
||||
/**
|
||||
* Begin a new sub path and set a point to path
|
||||
* @param path pointer to a path
|
||||
* @param p pointer to a `lv_fpoint_t` variable
|
||||
*/
|
||||
void lv_vector_path_move_to(lv_vector_path_t * path, const lv_fpoint_t * p);
|
||||
|
||||
/**
|
||||
* Add a line to the path from last point to the point
|
||||
* @param path pointer to a path
|
||||
* @param p pointer to a `lv_fpoint_t` variable
|
||||
*/
|
||||
void lv_vector_path_line_to(lv_vector_path_t * path, const lv_fpoint_t * p);
|
||||
|
||||
/**
|
||||
* Add a quadratic bezier line to the path from last point to the point
|
||||
* @param path pointer to a path
|
||||
* @param p1 pointer to a `lv_fpoint_t` variable for control point
|
||||
* @param p2 pointer to a `lv_fpoint_t` variable for end point
|
||||
*/
|
||||
void lv_vector_path_quad_to(lv_vector_path_t * path, const lv_fpoint_t * p1, const lv_fpoint_t * p2);
|
||||
|
||||
/**
|
||||
* Add a cubic bezier line to the path from last point to the point
|
||||
* @param path pointer to a path
|
||||
* @param p1 pointer to a `lv_fpoint_t` variable for first control point
|
||||
* @param p2 pointer to a `lv_fpoint_t` variable for second control point
|
||||
* @param p3 pointer to a `lv_fpoint_t` variable for end point
|
||||
*/
|
||||
void lv_vector_path_cubic_to(lv_vector_path_t * path, const lv_fpoint_t * p1, const lv_fpoint_t * p2,
|
||||
const lv_fpoint_t * p3);
|
||||
|
||||
/**
|
||||
* Close the sub path
|
||||
* @param path pointer to a path
|
||||
*/
|
||||
void lv_vector_path_close(lv_vector_path_t * path);
|
||||
|
||||
/**
|
||||
* Get the bounding box of a path
|
||||
* @param path pointer to a path
|
||||
* @param area pointer to a `lv_area_t` variable for bounding box
|
||||
*/
|
||||
void lv_vector_path_get_bounding(const lv_vector_path_t * path, lv_area_t * area);
|
||||
|
||||
/**
|
||||
* Add a rectangle to the path
|
||||
* @param path pointer to a path
|
||||
* @param rect pointer to a `lv_area_t` variable
|
||||
* @param rx the horizontal radius for rounded rectangle
|
||||
* @param ry the vertical radius for rounded rectangle
|
||||
*/
|
||||
void lv_vector_path_append_rect(lv_vector_path_t * path, const lv_area_t * rect, float rx, float ry);
|
||||
|
||||
/**
|
||||
* Add a circle to the path
|
||||
* @param path pointer to a path
|
||||
* @param c pointer to a `lv_fpoint_t` variable for center of the circle
|
||||
* @param rx the horizontal radius for circle
|
||||
* @param ry the vertical radius for circle
|
||||
*/
|
||||
void lv_vector_path_append_circle(lv_vector_path_t * path, const lv_fpoint_t * c, float rx, float ry);
|
||||
|
||||
/**
|
||||
* Add a arc to the path
|
||||
* @param path pointer to a path
|
||||
* @param c pointer to a `lv_fpoint_t` variable for center of the circle
|
||||
* @param radius the radius for arc
|
||||
* @param start_angle the start angle for arc
|
||||
* @param sweep the sweep angle for arc, could be negative
|
||||
* @param pie true: draw a pie, false: draw a arc
|
||||
*/
|
||||
void lv_vector_path_append_arc(lv_vector_path_t * path, const lv_fpoint_t * c, float radius, float start_angle,
|
||||
float sweep, bool pie);
|
||||
|
||||
/**
|
||||
* Add an sub path to the path
|
||||
* @param path pointer to a path
|
||||
* @param subpath pointer to another path which will be added
|
||||
*/
|
||||
void lv_vector_path_append_path(lv_vector_path_t * path, const lv_vector_path_t * subpath);
|
||||
|
||||
/**
|
||||
* Create a vector graphic descriptor
|
||||
* @param layer pointer to a layer
|
||||
* @return pointer to the created descriptor
|
||||
*/
|
||||
lv_vector_dsc_t * lv_vector_dsc_create(lv_layer_t * layer);
|
||||
|
||||
/**
|
||||
* Delete the vector graphic descriptor
|
||||
* @param dsc pointer to a vector graphic descriptor
|
||||
*/
|
||||
void lv_vector_dsc_delete(lv_vector_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Set a matrix to current transformation matrix
|
||||
* @param dsc pointer to a vector graphic descriptor
|
||||
* @param matrix pointer to a matrix
|
||||
*/
|
||||
void lv_vector_dsc_set_transform(lv_vector_dsc_t * dsc, const lv_matrix_t * matrix);
|
||||
|
||||
/**
|
||||
* Set blend mode for descriptor
|
||||
* @param dsc pointer to a vector graphic descriptor
|
||||
* @param blend the blend mode to be set in `lv_vector_blend_t`
|
||||
*/
|
||||
void lv_vector_dsc_set_blend_mode(lv_vector_dsc_t * dsc, lv_vector_blend_t blend);
|
||||
|
||||
/**
|
||||
* Set fill color for descriptor
|
||||
* @param dsc pointer to a vector graphic descriptor
|
||||
* @param color the color to be set in lv_color32_t format
|
||||
*/
|
||||
void lv_vector_dsc_set_fill_color32(lv_vector_dsc_t * dsc, lv_color32_t color);
|
||||
|
||||
/**
|
||||
* Set fill color for descriptor
|
||||
* @param dsc pointer to a vector graphic descriptor
|
||||
* @param color the color to be set in lv_color_t format
|
||||
*/
|
||||
void lv_vector_dsc_set_fill_color(lv_vector_dsc_t * dsc, lv_color_t color);
|
||||
|
||||
/**
|
||||
* Set fill opacity for descriptor
|
||||
* @param dsc pointer to a vector graphic descriptor
|
||||
* @param opa the opacity to be set in lv_opa_t format
|
||||
*/
|
||||
void lv_vector_dsc_set_fill_opa(lv_vector_dsc_t * dsc, lv_opa_t opa);
|
||||
|
||||
/**
|
||||
* Set fill rule for descriptor
|
||||
* @param dsc pointer to a vector graphic descriptor
|
||||
* @param rule the fill rule to be set in lv_vector_fill_t format
|
||||
*/
|
||||
void lv_vector_dsc_set_fill_rule(lv_vector_dsc_t * dsc, lv_vector_fill_t rule);
|
||||
|
||||
/**
|
||||
* Set the fill units for descriptor.
|
||||
* @param dsc pointer to a vector graphic descriptor
|
||||
* @param units the units to be set in lv_vector_fill_units_t format
|
||||
* @note The units can be either relative to the object bounding box or absolute in user space.
|
||||
* This API specifically affects the drawing position of the fill image and does not impact other elements.
|
||||
*/
|
||||
void lv_vector_dsc_set_fill_units(lv_vector_dsc_t * dsc, const lv_vector_fill_units_t units);
|
||||
|
||||
/**
|
||||
* Set fill image for descriptor
|
||||
* @param dsc pointer to a vector graphic descriptor
|
||||
* @param img_dsc pointer to a `lv_draw_image_dsc_t` variable
|
||||
*/
|
||||
void lv_vector_dsc_set_fill_image(lv_vector_dsc_t * dsc, const lv_draw_image_dsc_t * img_dsc);
|
||||
|
||||
/**
|
||||
* Set fill linear gradient for descriptor
|
||||
* @param dsc pointer to a vector graphic descriptor
|
||||
* @param x1 the x for start point
|
||||
* @param y1 the y for start point
|
||||
* @param x2 the x for end point
|
||||
* @param y2 the y for end point
|
||||
*/
|
||||
void lv_vector_dsc_set_fill_linear_gradient(lv_vector_dsc_t * dsc, float x1, float y1, float x2, float y2);
|
||||
|
||||
/**
|
||||
|
||||
* Set fill radial gradient radius for descriptor
|
||||
* @param dsc pointer to a vector graphic descriptor
|
||||
* @param cx the x for center of the circle
|
||||
* @param cy the y for center of the circle
|
||||
* @param radius the radius for circle
|
||||
*/
|
||||
void lv_vector_dsc_set_fill_radial_gradient(lv_vector_dsc_t * dsc, float cx, float cy, float radius);
|
||||
|
||||
/**
|
||||
* Set fill radial gradient spread for descriptor
|
||||
* @param dsc pointer to a vector graphic descriptor
|
||||
* @param spread the gradient spread to be set in lv_vector_gradient_spread_t format
|
||||
*/
|
||||
void lv_vector_dsc_set_fill_gradient_spread(lv_vector_dsc_t * dsc, lv_vector_gradient_spread_t spread);
|
||||
|
||||
/**
|
||||
* Set fill gradient color stops for descriptor
|
||||
* @param dsc pointer to a vector graphic descriptor
|
||||
* @param stops an array of `lv_grad_stop_t` variables
|
||||
* @param count the number of stops in the array, range: 0..LV_GRADIENT_MAX_STOPS
|
||||
*/
|
||||
void lv_vector_dsc_set_fill_gradient_color_stops(lv_vector_dsc_t * dsc, const lv_grad_stop_t * stops,
|
||||
uint16_t count);
|
||||
|
||||
/**
|
||||
* Set a matrix to current fill transformation matrix
|
||||
* @param dsc pointer to a vector graphic descriptor
|
||||
* @param matrix pointer to a matrix
|
||||
*/
|
||||
void lv_vector_dsc_set_fill_transform(lv_vector_dsc_t * dsc, const lv_matrix_t * matrix);
|
||||
|
||||
/**
|
||||
* Set stroke color for descriptor
|
||||
* @param dsc pointer to a vector graphic descriptor
|
||||
* @param color the color to be set in lv_color32_t format
|
||||
*/
|
||||
void lv_vector_dsc_set_stroke_color32(lv_vector_dsc_t * dsc, lv_color32_t color);
|
||||
|
||||
/**
|
||||
* Set stroke color for descriptor
|
||||
* @param dsc pointer to a vector graphic descriptor
|
||||
* @param color the color to be set in lv_color_t format
|
||||
*/
|
||||
void lv_vector_dsc_set_stroke_color(lv_vector_dsc_t * dsc, lv_color_t color);
|
||||
|
||||
/**
|
||||
* Set stroke opacity for descriptor
|
||||
* @param dsc pointer to a vector graphic descriptor
|
||||
* @param opa the opacity to be set in lv_opa_t format
|
||||
*/
|
||||
void lv_vector_dsc_set_stroke_opa(lv_vector_dsc_t * dsc, lv_opa_t opa);
|
||||
|
||||
/**
|
||||
* Set stroke line width for descriptor
|
||||
* @param dsc pointer to a vector graphic descriptor
|
||||
* @param width the stroke line width
|
||||
*/
|
||||
void lv_vector_dsc_set_stroke_width(lv_vector_dsc_t * dsc, float width);
|
||||
|
||||
/**
|
||||
* Set stroke line dash pattern for descriptor
|
||||
* @param dsc pointer to a vector graphic descriptor
|
||||
* @param dash_pattern an array of values that specify the segments of dash line
|
||||
* @param dash_count the length of dash pattern array
|
||||
*/
|
||||
void lv_vector_dsc_set_stroke_dash(lv_vector_dsc_t * dsc, float * dash_pattern, uint16_t dash_count);
|
||||
|
||||
/**
|
||||
* Set stroke line cap style for descriptor
|
||||
* @param dsc pointer to a vector graphic descriptor
|
||||
* @param cap the line cap to be set in lv_vector_stroke_cap_t format
|
||||
*/
|
||||
void lv_vector_dsc_set_stroke_cap(lv_vector_dsc_t * dsc, lv_vector_stroke_cap_t cap);
|
||||
|
||||
/**
|
||||
* Set stroke line join style for descriptor
|
||||
* @param dsc pointer to a vector graphic descriptor
|
||||
* @param join the line join to be set in lv_vector_stroke_join_t format
|
||||
*/
|
||||
void lv_vector_dsc_set_stroke_join(lv_vector_dsc_t * dsc, lv_vector_stroke_join_t join);
|
||||
|
||||
/**
|
||||
* Set stroke miter limit for descriptor
|
||||
* @param dsc pointer to a vector graphic descriptor
|
||||
* @param miter_limit the stroke miter_limit
|
||||
*/
|
||||
void lv_vector_dsc_set_stroke_miter_limit(lv_vector_dsc_t * dsc, uint16_t miter_limit);
|
||||
|
||||
/**
|
||||
* Set stroke linear gradient for descriptor
|
||||
* @param dsc pointer to a vector graphic descriptor
|
||||
* @param x1 the x for start point
|
||||
* @param y1 the y for start point
|
||||
* @param x2 the x for end point
|
||||
* @param y2 the y for end point
|
||||
*/
|
||||
void lv_vector_dsc_set_stroke_linear_gradient(lv_vector_dsc_t * dsc, float x1, float y1, float x2, float y2);
|
||||
/**
|
||||
* Set stroke radial gradient for descriptor
|
||||
* @param dsc pointer to a vector graphic descriptor
|
||||
* @param cx the x for center of the circle
|
||||
* @param cy the y for center of the circle
|
||||
* @param radius the radius for circle
|
||||
*/
|
||||
void lv_vector_dsc_set_stroke_radial_gradient(lv_vector_dsc_t * dsc, float cx, float cy, float radius);
|
||||
|
||||
/**
|
||||
* Set stroke color stops for descriptor
|
||||
* @param dsc pointer to a vector graphic descriptor
|
||||
* @param spread the gradient spread to be set in lv_vector_gradient_spread_t format
|
||||
*/
|
||||
void lv_vector_dsc_set_stroke_gradient_spread(lv_vector_dsc_t * dsc, lv_vector_gradient_spread_t spread);
|
||||
|
||||
/**
|
||||
* Set stroke color stops for descriptor
|
||||
* @param dsc pointer to a vector graphic descriptor
|
||||
* @param stops an array of `lv_grad_stop_t` variables
|
||||
* @param count the number of stops in the array
|
||||
*/
|
||||
void lv_vector_dsc_set_stroke_gradient_color_stops(lv_vector_dsc_t * dsc, const lv_grad_stop_t * stops,
|
||||
uint16_t count);
|
||||
|
||||
/**
|
||||
* Set a matrix to current stroke transformation matrix
|
||||
* @param dsc pointer to a vector graphic descriptor
|
||||
* @param matrix pointer to a matrix
|
||||
*/
|
||||
void lv_vector_dsc_set_stroke_transform(lv_vector_dsc_t * dsc, const lv_matrix_t * matrix);
|
||||
|
||||
/**
|
||||
* Set current transformation matrix to identity matrix
|
||||
* @param dsc pointer to a vector graphic descriptor
|
||||
*/
|
||||
void lv_vector_dsc_identity(lv_vector_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Change the scale factor of current transformation matrix
|
||||
* @param dsc pointer to a vector graphic descriptor
|
||||
* @param scale_x the scale factor for the X direction
|
||||
* @param scale_y the scale factor for the Y direction
|
||||
*/
|
||||
void lv_vector_dsc_scale(lv_vector_dsc_t * dsc, float scale_x, float scale_y);
|
||||
|
||||
/**
|
||||
* Rotate current transformation matrix with origin
|
||||
* @param dsc pointer to a vector graphic descriptor
|
||||
* @param degree angle to rotate
|
||||
*/
|
||||
void lv_vector_dsc_rotate(lv_vector_dsc_t * dsc, float degree);
|
||||
|
||||
/**
|
||||
* Translate current transformation matrix to new position
|
||||
* @param dsc pointer to a vector graphic descriptor
|
||||
* @param tx the amount of translate in x direction
|
||||
* @param tx the amount of translate in y direction
|
||||
*/
|
||||
void lv_vector_dsc_translate(lv_vector_dsc_t * dsc, float tx, float ty);
|
||||
|
||||
/**
|
||||
* Change the skew factor of current transformation matrix
|
||||
* @param dsc pointer to a vector graphic descriptor
|
||||
* @param skew_x the skew factor for x direction
|
||||
* @param skew_y the skew factor for y direction
|
||||
*/
|
||||
void lv_vector_dsc_skew(lv_vector_dsc_t * dsc, float skew_x, float skew_y);
|
||||
|
||||
/**
|
||||
* Add a graphic path to the draw list
|
||||
* @param dsc pointer to a vector graphic descriptor
|
||||
* @param path pointer to a path
|
||||
*/
|
||||
void lv_vector_dsc_add_path(lv_vector_dsc_t * dsc, const lv_vector_path_t * path);
|
||||
|
||||
/**
|
||||
* Clear a rectangle area use current fill color
|
||||
* @param dsc pointer to a vector graphic descriptor
|
||||
* @param rect the area to clear in the buffer
|
||||
*/
|
||||
void lv_vector_clear_area(lv_vector_dsc_t * dsc, const lv_area_t * rect);
|
||||
|
||||
/**
|
||||
* Draw all the vector graphic paths
|
||||
* @param dsc pointer to a vector graphic descriptor
|
||||
*/
|
||||
void lv_draw_vector(lv_vector_dsc_t * dsc);
|
||||
|
||||
/* Traverser for task list */
|
||||
typedef void (*vector_draw_task_cb)(void * ctx, const lv_vector_path_t * path, const lv_vector_draw_dsc_t * dsc);
|
||||
|
||||
#endif /* LV_USE_VECTOR_GRAPHIC */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* LV_DRAW_VECTOR_H */
|
||||
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* @file lv_draw_vector_private.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_VECTOR_PRIVATE_H
|
||||
#define LV_DRAW_VECTOR_PRIVATE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_vector.h"
|
||||
|
||||
#if LV_USE_VECTOR_GRAPHIC
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
struct _lv_vector_path_t {
|
||||
lv_vector_path_quality_t quality;
|
||||
lv_array_t ops;
|
||||
lv_array_t points;
|
||||
};
|
||||
|
||||
struct _lv_vector_gradient_t {
|
||||
lv_vector_gradient_style_t style;
|
||||
lv_grad_stop_t stops[LV_GRADIENT_MAX_STOPS]; /**< A gradient stop array */
|
||||
uint16_t stops_count; /**< The number of used stops in the array */
|
||||
float x1;
|
||||
float y1;
|
||||
float x2;
|
||||
float y2;
|
||||
float cx;
|
||||
float cy;
|
||||
float cr;
|
||||
lv_vector_gradient_spread_t spread;
|
||||
};
|
||||
|
||||
struct _lv_vector_fill_dsc_t {
|
||||
lv_vector_draw_style_t style;
|
||||
lv_color32_t color;
|
||||
lv_opa_t opa;
|
||||
lv_vector_fill_t fill_rule;
|
||||
lv_vector_fill_units_t fill_units;
|
||||
lv_draw_image_dsc_t img_dsc;
|
||||
lv_vector_gradient_t gradient;
|
||||
lv_matrix_t matrix;
|
||||
};
|
||||
|
||||
struct _lv_vector_stroke_dsc_t {
|
||||
lv_vector_draw_style_t style;
|
||||
lv_color32_t color;
|
||||
lv_opa_t opa;
|
||||
float width;
|
||||
lv_array_t dash_pattern;
|
||||
lv_vector_stroke_cap_t cap;
|
||||
lv_vector_stroke_join_t join;
|
||||
uint16_t miter_limit;
|
||||
lv_vector_gradient_t gradient;
|
||||
lv_matrix_t matrix;
|
||||
};
|
||||
|
||||
struct _lv_vector_draw_dsc_t {
|
||||
lv_vector_fill_dsc_t fill_dsc;
|
||||
lv_vector_stroke_dsc_t stroke_dsc;
|
||||
lv_matrix_t matrix;
|
||||
lv_vector_blend_t blend_mode;
|
||||
lv_area_t scissor_area;
|
||||
};
|
||||
|
||||
struct _lv_draw_vector_task_dsc_t {
|
||||
lv_draw_dsc_base_t base;
|
||||
lv_ll_t * task_list; /*draw task list.*/
|
||||
};
|
||||
|
||||
struct _lv_vector_dsc_t {
|
||||
lv_layer_t * layer;
|
||||
lv_vector_draw_dsc_t current_dsc;
|
||||
/* private data */
|
||||
lv_draw_vector_task_dsc_t tasks;
|
||||
};
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
void lv_vector_for_each_destroy_tasks(lv_ll_t * task_list, vector_draw_task_cb cb, void * data);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /* LV_USE_VECTOR_GRAPHIC */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_VECTOR_PRIVATE_H*/
|
||||
@@ -0,0 +1,417 @@
|
||||
/**
|
||||
* @file lv_image_decoder.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_image_decoder_private.h"
|
||||
#include "../misc/lv_assert.h"
|
||||
#include "../draw/lv_draw_image.h"
|
||||
#include "../misc/lv_ll.h"
|
||||
#include "../stdlib/lv_string.h"
|
||||
#include "../core/lv_global.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define img_decoder_ll_p &(LV_GLOBAL_DEFAULT()->img_decoder_ll)
|
||||
#define img_cache_p (LV_GLOBAL_DEFAULT()->img_cache)
|
||||
#define img_header_cache_p (LV_GLOBAL_DEFAULT()->img_header_cache)
|
||||
#define image_cache_draw_buf_handlers &(LV_GLOBAL_DEFAULT()->image_cache_draw_buf_handlers)
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static uint32_t img_width_to_stride(lv_image_header_t * header);
|
||||
|
||||
/**
|
||||
* Get the header info of an image source, and return the a pointer to the decoder that can open it.
|
||||
* @param dsc Image descriptor containing the source and type of the image and other info.
|
||||
* @param header The header of the image
|
||||
* @return The decoder that can open the image source or NULL if not found (or can't open it).
|
||||
*/
|
||||
static lv_image_decoder_t * image_decoder_get_info(lv_image_decoder_dsc_t * dsc, lv_image_header_t * header);
|
||||
|
||||
static lv_result_t try_cache(lv_image_decoder_dsc_t * dsc);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize the image decoder module
|
||||
*/
|
||||
void lv_image_decoder_init(uint32_t image_cache_size, uint32_t image_header_count)
|
||||
{
|
||||
lv_ll_init(img_decoder_ll_p, sizeof(lv_image_decoder_t));
|
||||
|
||||
/*Initialize the cache*/
|
||||
lv_image_cache_init(image_cache_size);
|
||||
lv_image_header_cache_init(image_header_count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deinitialize the image decoder module
|
||||
*/
|
||||
void lv_image_decoder_deinit(void)
|
||||
{
|
||||
lv_cache_destroy(img_cache_p, NULL);
|
||||
lv_cache_destroy(img_header_cache_p, NULL);
|
||||
|
||||
lv_ll_clear(img_decoder_ll_p);
|
||||
}
|
||||
|
||||
lv_result_t lv_image_decoder_get_info(const void * src, lv_image_header_t * header)
|
||||
{
|
||||
lv_image_decoder_dsc_t dsc;
|
||||
lv_memzero(&dsc, sizeof(lv_image_decoder_dsc_t));
|
||||
dsc.src = src;
|
||||
dsc.src_type = lv_image_src_get_type(src);
|
||||
|
||||
lv_image_decoder_t * decoder = image_decoder_get_info(&dsc, header);
|
||||
if(decoder == NULL) return LV_RESULT_INVALID;
|
||||
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
|
||||
lv_result_t lv_image_decoder_open(lv_image_decoder_dsc_t * dsc, const void * src, const lv_image_decoder_args_t * args)
|
||||
{
|
||||
lv_memzero(dsc, sizeof(lv_image_decoder_dsc_t));
|
||||
|
||||
if(src == NULL) return LV_RESULT_INVALID;
|
||||
dsc->src = src;
|
||||
dsc->src_type = lv_image_src_get_type(src);
|
||||
|
||||
if(lv_image_cache_is_enabled()) {
|
||||
dsc->cache = img_cache_p;
|
||||
/*Try cache first, unless we are told to ignore cache.*/
|
||||
if(!(args && args->no_cache)) {
|
||||
/*
|
||||
* Check the cache first
|
||||
* If the image is found in the cache, just return it.*/
|
||||
if(try_cache(dsc) == LV_RESULT_OK) return LV_RESULT_OK;
|
||||
}
|
||||
}
|
||||
|
||||
/*Find the decoder that can open the image source, and get the header info in the same time.*/
|
||||
dsc->decoder = image_decoder_get_info(dsc, &dsc->header);
|
||||
if(dsc->decoder == NULL) return LV_RESULT_INVALID;
|
||||
|
||||
/*Make a copy of args*/
|
||||
dsc->args = args ? *args : (lv_image_decoder_args_t) {
|
||||
.stride_align = LV_DRAW_BUF_STRIDE_ALIGN != 1,
|
||||
.premultiply = false,
|
||||
.no_cache = false,
|
||||
.use_indexed = false,
|
||||
.flush_cache = false,
|
||||
};
|
||||
|
||||
/*
|
||||
* We assume that if a decoder can get the info, it can open the image.
|
||||
* If decoder open failed, free the source and return error.
|
||||
* If decoder open succeed, add the image to cache if enabled.
|
||||
* */
|
||||
lv_result_t res = dsc->decoder->open_cb(dsc->decoder, dsc);
|
||||
|
||||
if(res == LV_RESULT_OK && dsc->decoded != NULL) {
|
||||
LV_ASSERT_MSG(dsc->decoded->unaligned_data && dsc->decoded->handlers, "Invalid draw buffer");
|
||||
|
||||
/* Flush the D-Cache if enabled and the image was successfully opened */
|
||||
if(dsc->args.flush_cache) {
|
||||
lv_draw_buf_flush_cache(dsc->decoded, NULL);
|
||||
LV_LOG_INFO("Flushed D-cache: src %p (%s) (W%d x H%d, data: %p cf: %d)",
|
||||
src,
|
||||
dsc->src_type == LV_IMAGE_SRC_FILE ? (const char *)src : "c-array",
|
||||
dsc->decoded->header.w,
|
||||
dsc->decoded->header.h,
|
||||
(void *)dsc->decoded->data,
|
||||
dsc->decoded->header.cf);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
lv_result_t lv_image_decoder_get_area(lv_image_decoder_dsc_t * dsc, const lv_area_t * full_area,
|
||||
lv_area_t * decoded_area)
|
||||
{
|
||||
lv_result_t res = LV_RESULT_INVALID;
|
||||
if(dsc->decoder->get_area_cb) res = dsc->decoder->get_area_cb(dsc->decoder, dsc, full_area, decoded_area);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void lv_image_decoder_close(lv_image_decoder_dsc_t * dsc)
|
||||
{
|
||||
if(dsc->decoder) {
|
||||
if(dsc->decoder->close_cb) dsc->decoder->close_cb(dsc->decoder, dsc);
|
||||
|
||||
if(lv_image_cache_is_enabled() && dsc->cache && dsc->cache_entry) {
|
||||
/*Decoded data is in cache, release it from cache's callback*/
|
||||
lv_cache_release(dsc->cache, dsc->cache_entry, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new image decoder
|
||||
* @return pointer to the new image decoder
|
||||
*/
|
||||
lv_image_decoder_t * lv_image_decoder_create(void)
|
||||
{
|
||||
lv_image_decoder_t * decoder;
|
||||
decoder = lv_ll_ins_head(img_decoder_ll_p);
|
||||
LV_ASSERT_MALLOC(decoder);
|
||||
if(decoder == NULL) return NULL;
|
||||
|
||||
lv_memzero(decoder, sizeof(lv_image_decoder_t));
|
||||
|
||||
return decoder;
|
||||
}
|
||||
|
||||
void lv_image_decoder_delete(lv_image_decoder_t * decoder)
|
||||
{
|
||||
lv_ll_remove(img_decoder_ll_p, decoder);
|
||||
lv_free(decoder);
|
||||
}
|
||||
|
||||
lv_image_decoder_t * lv_image_decoder_get_next(lv_image_decoder_t * decoder)
|
||||
{
|
||||
if(decoder == NULL)
|
||||
return lv_ll_get_head(img_decoder_ll_p);
|
||||
else
|
||||
return lv_ll_get_next(img_decoder_ll_p, decoder);
|
||||
}
|
||||
|
||||
void lv_image_decoder_set_info_cb(lv_image_decoder_t * decoder, lv_image_decoder_info_f_t info_cb)
|
||||
{
|
||||
decoder->info_cb = info_cb;
|
||||
}
|
||||
|
||||
void lv_image_decoder_set_open_cb(lv_image_decoder_t * decoder, lv_image_decoder_open_f_t open_cb)
|
||||
{
|
||||
decoder->open_cb = open_cb;
|
||||
}
|
||||
|
||||
void lv_image_decoder_set_get_area_cb(lv_image_decoder_t * decoder, lv_image_decoder_get_area_cb_t get_area_cb)
|
||||
{
|
||||
decoder->get_area_cb = get_area_cb;
|
||||
}
|
||||
|
||||
void lv_image_decoder_set_close_cb(lv_image_decoder_t * decoder, lv_image_decoder_close_f_t close_cb)
|
||||
{
|
||||
decoder->close_cb = close_cb;
|
||||
}
|
||||
|
||||
lv_cache_entry_t * lv_image_decoder_add_to_cache(lv_image_decoder_t * decoder,
|
||||
lv_image_cache_data_t * search_key,
|
||||
const lv_draw_buf_t * decoded, void * user_data)
|
||||
{
|
||||
lv_cache_entry_t * cache_entry = lv_cache_add(img_cache_p, search_key, NULL);
|
||||
if(cache_entry == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lv_image_cache_data_t * cached_data;
|
||||
cached_data = lv_cache_entry_get_data(cache_entry);
|
||||
|
||||
/*Set the cache entry to decoder data*/
|
||||
cached_data->decoded = decoded;
|
||||
if(cached_data->src_type == LV_IMAGE_SRC_FILE) {
|
||||
cached_data->src = lv_strdup(cached_data->src);
|
||||
}
|
||||
cached_data->user_data = user_data; /*Need to free data on cache invalidate instead of decoder_close*/
|
||||
cached_data->decoder = decoder;
|
||||
|
||||
return cache_entry;
|
||||
}
|
||||
|
||||
lv_draw_buf_t * lv_image_decoder_post_process(lv_image_decoder_dsc_t * dsc, lv_draw_buf_t * decoded)
|
||||
{
|
||||
if(decoded == NULL) return NULL; /*No need to adjust*/
|
||||
|
||||
lv_image_decoder_args_t * args = &dsc->args;
|
||||
if(args->stride_align && decoded->header.cf != LV_COLOR_FORMAT_RGB565A8) {
|
||||
uint32_t stride_expect = lv_draw_buf_width_to_stride(decoded->header.w, decoded->header.cf);
|
||||
if(decoded->header.stride != stride_expect) {
|
||||
LV_LOG_TRACE("Stride mismatch");
|
||||
lv_result_t res = lv_draw_buf_adjust_stride(decoded, stride_expect);
|
||||
if(res != LV_RESULT_OK) {
|
||||
lv_draw_buf_t * aligned = lv_draw_buf_create_ex(image_cache_draw_buf_handlers, decoded->header.w, decoded->header.h,
|
||||
decoded->header.cf, stride_expect);
|
||||
if(aligned == NULL) {
|
||||
LV_LOG_ERROR("No memory for Stride adjust.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lv_draw_buf_copy(aligned, NULL, decoded, NULL);
|
||||
decoded = aligned;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*Premultiply alpha channel*/
|
||||
if(args->premultiply
|
||||
&& !LV_COLOR_FORMAT_IS_ALPHA_ONLY(decoded->header.cf)
|
||||
&& lv_color_format_has_alpha(decoded->header.cf)
|
||||
&& !lv_draw_buf_has_flag(decoded, LV_IMAGE_FLAGS_PREMULTIPLIED) /*Hasn't done yet*/
|
||||
) {
|
||||
LV_LOG_TRACE("Alpha premultiply.");
|
||||
if(lv_draw_buf_has_flag(decoded, LV_IMAGE_FLAGS_MODIFIABLE)) {
|
||||
/*Do it directly*/
|
||||
lv_draw_buf_premultiply(decoded);
|
||||
}
|
||||
else {
|
||||
decoded = lv_draw_buf_dup_ex(image_cache_draw_buf_handlers, decoded);
|
||||
if(decoded == NULL) {
|
||||
LV_LOG_ERROR("No memory for premultiplying.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lv_draw_buf_premultiply(decoded);
|
||||
}
|
||||
}
|
||||
|
||||
return decoded;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static lv_image_decoder_t * image_decoder_get_info(lv_image_decoder_dsc_t * dsc, lv_image_header_t * header)
|
||||
{
|
||||
lv_memzero(header, sizeof(lv_image_header_t));
|
||||
|
||||
const void * src = dsc->src;
|
||||
lv_image_src_t src_type = dsc->src_type;
|
||||
|
||||
if(src_type == LV_IMAGE_SRC_VARIABLE) {
|
||||
const lv_image_dsc_t * img_dsc = src;
|
||||
if(img_dsc->data == NULL) return NULL;
|
||||
}
|
||||
|
||||
if(src_type == LV_IMAGE_SRC_FILE) LV_LOG_TRACE("Try to find decoder for %s", (const char *)src);
|
||||
else LV_LOG_TRACE("Try to find decoder for %p", src);
|
||||
|
||||
lv_image_decoder_t * decoder;
|
||||
bool is_header_cache_enabled = lv_image_header_cache_is_enabled();
|
||||
|
||||
if(is_header_cache_enabled && src_type == LV_IMAGE_SRC_FILE) {
|
||||
lv_image_header_cache_data_t search_key;
|
||||
search_key.src_type = src_type;
|
||||
search_key.src = src;
|
||||
|
||||
lv_cache_entry_t * entry = lv_cache_acquire(img_header_cache_p, &search_key, NULL);
|
||||
|
||||
if(entry) {
|
||||
lv_image_header_cache_data_t * cached_data = lv_cache_entry_get_data(entry);
|
||||
*header = cached_data->header;
|
||||
decoder = cached_data->decoder;
|
||||
lv_cache_release(img_header_cache_p, entry, NULL);
|
||||
|
||||
LV_LOG_TRACE("Found decoder %s in header cache", decoder->name);
|
||||
return decoder;
|
||||
}
|
||||
}
|
||||
|
||||
if(src_type == LV_IMAGE_SRC_FILE) {
|
||||
lv_fs_res_t fs_res = lv_fs_open(&dsc->file, src, LV_FS_MODE_RD);
|
||||
if(fs_res != LV_FS_RES_OK) {
|
||||
LV_LOG_ERROR("File open failed: %" LV_PRIu32, (uint32_t)fs_res);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*Search the decoders*/
|
||||
LV_LL_READ(img_decoder_ll_p, decoder) {
|
||||
/*Info and Open callbacks are required*/
|
||||
if(decoder->info_cb && decoder->open_cb) {
|
||||
lv_fs_seek(&dsc->file, 0, LV_FS_SEEK_SET);
|
||||
lv_result_t res = decoder->info_cb(decoder, dsc, header);
|
||||
|
||||
if(res == LV_RESULT_OK) {
|
||||
if(header->stride == 0) {
|
||||
LV_LOG_INFO("Image decoder didn't set stride. Calculate it from width.");
|
||||
header->stride = img_width_to_stride(header);
|
||||
}
|
||||
break;
|
||||
}
|
||||
else {
|
||||
LV_LOG_TRACE("Can't open image with decoder %s. Trying next decoder.", decoder->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(decoder == NULL) LV_LOG_TRACE("No decoder found");
|
||||
else LV_LOG_TRACE("Found decoder %s", decoder->name);
|
||||
|
||||
if(src_type == LV_IMAGE_SRC_FILE) {
|
||||
lv_fs_close(&dsc->file);
|
||||
}
|
||||
|
||||
if(is_header_cache_enabled && src_type == LV_IMAGE_SRC_FILE && decoder) {
|
||||
lv_cache_entry_t * entry;
|
||||
lv_image_header_cache_data_t search_key;
|
||||
search_key.src_type = src_type;
|
||||
search_key.src = lv_strdup(src);
|
||||
search_key.decoder = decoder;
|
||||
search_key.header = *header;
|
||||
entry = lv_cache_add(img_header_cache_p, &search_key, NULL);
|
||||
|
||||
if(entry == NULL) {
|
||||
if(src_type == LV_IMAGE_SRC_FILE) lv_free((void *)search_key.src);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lv_cache_release(img_header_cache_p, entry, NULL);
|
||||
}
|
||||
|
||||
return decoder;
|
||||
}
|
||||
|
||||
static uint32_t img_width_to_stride(lv_image_header_t * header)
|
||||
{
|
||||
if(header->cf == LV_COLOR_FORMAT_RGB565A8) {
|
||||
return header->w * 2;
|
||||
}
|
||||
else {
|
||||
return ((uint32_t)header->w * lv_color_format_get_bpp(header->cf) + 7) >> 3;
|
||||
}
|
||||
}
|
||||
|
||||
static lv_result_t try_cache(lv_image_decoder_dsc_t * dsc)
|
||||
{
|
||||
lv_cache_t * cache = dsc->cache;
|
||||
|
||||
lv_image_cache_data_t search_key;
|
||||
search_key.src_type = dsc->src_type;
|
||||
search_key.src = dsc->src;
|
||||
|
||||
lv_cache_entry_t * entry = lv_cache_acquire(cache, &search_key, NULL);
|
||||
|
||||
if(entry) {
|
||||
lv_image_cache_data_t * cached_data = lv_cache_entry_get_data(entry);
|
||||
dsc->decoded = cached_data->decoded;
|
||||
dsc->decoder = (lv_image_decoder_t *)cached_data->decoder;
|
||||
dsc->cache_entry = entry; /*Save the cache to release it in decoder_close*/
|
||||
return LV_RESULT_OK;
|
||||
}
|
||||
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
/**
|
||||
* @file lv_image_decoder.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_IMAGE_DECODER_H
|
||||
#define LV_IMAGE_DECODER_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../lv_conf_internal.h"
|
||||
|
||||
#include "lv_draw_buf.h"
|
||||
#include "../misc/lv_fs.h"
|
||||
#include "../misc/lv_types.h"
|
||||
#include "../misc/lv_area.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Source of image.*/
|
||||
typedef enum {
|
||||
LV_IMAGE_SRC_VARIABLE, /** Binary/C variable*/
|
||||
LV_IMAGE_SRC_FILE, /** File in filesystem*/
|
||||
LV_IMAGE_SRC_SYMBOL, /** Symbol (@ref lv_symbol_def.h)*/
|
||||
LV_IMAGE_SRC_UNKNOWN, /** Unknown source*/
|
||||
} lv_image_src_t;
|
||||
|
||||
/**
|
||||
* Get info from an image and store in the `header`
|
||||
* @param decoder pointer to decoder object
|
||||
* @param dsc pointer to decoder descriptor
|
||||
* @param header store the info here
|
||||
* @return LV_RESULT_OK: info written correctly; LV_RESULT_INVALID: failed
|
||||
*/
|
||||
typedef lv_result_t (*lv_image_decoder_info_f_t)(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc,
|
||||
lv_image_header_t * header);
|
||||
|
||||
/**
|
||||
* Open an image for decoding. Prepare it as it is required to read it later
|
||||
* @param decoder pointer to the decoder the function associated with
|
||||
* @param dsc pointer to decoder descriptor. `src`, `color` are already initialized in it.
|
||||
*/
|
||||
typedef lv_result_t (*lv_image_decoder_open_f_t)(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Decode `full_area` pixels incrementally by calling in a loop. Set `decoded_area` values to `LV_COORD_MIN` on first call.
|
||||
* Required only if the "open" function can't return with the whole decoded pixel array.
|
||||
* @param decoder pointer to the decoder the function associated with
|
||||
* @param dsc pointer to decoder descriptor
|
||||
* @param full_area input parameter. the full area to decode after enough subsequent calls
|
||||
* @param decoded_area input+output parameter. set the values to `LV_COORD_MIN` for the first call and to reset decoding.
|
||||
* the decoded area is stored here after each call.
|
||||
* @return LV_RESULT_OK: ok; LV_RESULT_INVALID: failed or there is nothing left to decode
|
||||
*/
|
||||
typedef lv_result_t (*lv_image_decoder_get_area_cb_t)(lv_image_decoder_t * decoder,
|
||||
lv_image_decoder_dsc_t * dsc,
|
||||
const lv_area_t * full_area, lv_area_t * decoded_area);
|
||||
|
||||
/**
|
||||
* Close the pending decoding. Free resources etc.
|
||||
* @param decoder pointer to the decoder the function associated with
|
||||
* @param dsc pointer to decoder descriptor
|
||||
*/
|
||||
typedef void (*lv_image_decoder_close_f_t)(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Custom drawing functions for special image formats.
|
||||
* @param layer pointer to a layer
|
||||
* @param dsc pointer to decoder descriptor
|
||||
* @param coords the coordinates of the image
|
||||
* @param draw_dsc the draw image descriptor
|
||||
* @param clip_area the clip area of the image
|
||||
*/
|
||||
typedef void (*lv_image_decoder_custom_draw_t)(lv_layer_t * layer, const lv_image_decoder_dsc_t * dsc,
|
||||
const lv_area_t * coords, const lv_draw_image_dsc_t * draw_dsc, const lv_area_t * clip_area);
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Get information about an image.
|
||||
* Try the created image decoder one by one. Once one is able to get info that info will be used.
|
||||
* @param src the image source. Can be
|
||||
* 1) File name: E.g. "S:folder/img1.png" (The drivers needs to registered via `lv_fs_drv_register()`)
|
||||
* 2) Variable: Pointer to an `lv_image_dsc_t` variable
|
||||
* 3) Symbol: E.g. `LV_SYMBOL_OK`
|
||||
* @param header the image info will be stored here
|
||||
* @return LV_RESULT_OK: success; LV_RESULT_INVALID: wasn't able to get info about the image
|
||||
*/
|
||||
lv_result_t lv_image_decoder_get_info(const void * src, lv_image_header_t * header);
|
||||
|
||||
/**
|
||||
* Open an image.
|
||||
* Try the created image decoders one by one. Once one is able to open the image that decoder is saved in `dsc`
|
||||
* @param dsc describes a decoding session. Simply a pointer to an `lv_image_decoder_dsc_t` variable.
|
||||
* @param src the image source. Can be
|
||||
* 1) File name: E.g. "S:folder/img1.png" (The drivers needs to registered via `lv_fs_drv_register())`)
|
||||
* 2) Variable: Pointer to an `lv_image_dsc_t` variable
|
||||
* 3) Symbol: E.g. `LV_SYMBOL_OK`
|
||||
* @param args args about how the image should be opened.
|
||||
* @return LV_RESULT_OK: opened the image. `dsc->decoded` and `dsc->header` are set.
|
||||
* LV_RESULT_INVALID: none of the registered image decoders were able to open the image.
|
||||
*/
|
||||
lv_result_t lv_image_decoder_open(lv_image_decoder_dsc_t * dsc, const void * src, const lv_image_decoder_args_t * args);
|
||||
|
||||
/**
|
||||
* Decode `full_area` pixels incrementally by calling in a loop. Set `decoded_area` to `LV_COORD_MIN` on first call.
|
||||
* @param dsc image decoder descriptor
|
||||
* @param full_area input parameter. the full area to decode after enough subsequent calls
|
||||
* @param decoded_area input+output parameter. set the values to `LV_COORD_MIN` for the first call and to reset decoding.
|
||||
* the decoded area is stored here after each call.
|
||||
* @return LV_RESULT_OK: success; LV_RESULT_INVALID: an error occurred or there is nothing left to decode
|
||||
*/
|
||||
lv_result_t lv_image_decoder_get_area(lv_image_decoder_dsc_t * dsc, const lv_area_t * full_area,
|
||||
lv_area_t * decoded_area);
|
||||
|
||||
/**
|
||||
* Close a decoding session
|
||||
* @param dsc pointer to `lv_image_decoder_dsc_t` used in `lv_image_decoder_open`
|
||||
*/
|
||||
void lv_image_decoder_close(lv_image_decoder_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Create a new image decoder
|
||||
* @return pointer to the new image decoder
|
||||
*/
|
||||
lv_image_decoder_t * lv_image_decoder_create(void);
|
||||
|
||||
/**
|
||||
* Delete an image decoder
|
||||
* @param decoder pointer to an image decoder
|
||||
*/
|
||||
void lv_image_decoder_delete(lv_image_decoder_t * decoder);
|
||||
|
||||
/**
|
||||
* Get the next image decoder in the linked list of image decoders
|
||||
* @param decoder pointer to an image decoder or NULL to get the first one
|
||||
* @return the next image decoder or NULL if no more image decoder exists
|
||||
*/
|
||||
lv_image_decoder_t * lv_image_decoder_get_next(lv_image_decoder_t * decoder);
|
||||
|
||||
/**
|
||||
* Set a callback to get information about the image
|
||||
* @param decoder pointer to an image decoder
|
||||
* @param info_cb a function to collect info about an image (fill an `lv_image_header_t` struct)
|
||||
*/
|
||||
void lv_image_decoder_set_info_cb(lv_image_decoder_t * decoder, lv_image_decoder_info_f_t info_cb);
|
||||
|
||||
/**
|
||||
* Set a callback to open an image
|
||||
* @param decoder pointer to an image decoder
|
||||
* @param open_cb a function to open an image
|
||||
*/
|
||||
void lv_image_decoder_set_open_cb(lv_image_decoder_t * decoder, lv_image_decoder_open_f_t open_cb);
|
||||
|
||||
/**
|
||||
* Set a callback to a decoded line of an image
|
||||
* @param decoder pointer to an image decoder
|
||||
* @param read_line_cb a function to read a line of an image
|
||||
*/
|
||||
void lv_image_decoder_set_get_area_cb(lv_image_decoder_t * decoder, lv_image_decoder_get_area_cb_t read_line_cb);
|
||||
|
||||
/**
|
||||
* Set a callback to close a decoding session. E.g. close files and free other resources.
|
||||
* @param decoder pointer to an image decoder
|
||||
* @param close_cb a function to close a decoding session
|
||||
*/
|
||||
void lv_image_decoder_set_close_cb(lv_image_decoder_t * decoder, lv_image_decoder_close_f_t close_cb);
|
||||
|
||||
lv_cache_entry_t * lv_image_decoder_add_to_cache(lv_image_decoder_t * decoder,
|
||||
lv_image_cache_data_t * search_key,
|
||||
const lv_draw_buf_t * decoded, void * user_data);
|
||||
|
||||
/**
|
||||
* Check the decoded image, make any modification if decoder `args` requires.
|
||||
* @note A new draw buf will be allocated if provided `decoded` is not modifiable or stride mismatch etc.
|
||||
* @param dsc pointer to a decoder descriptor
|
||||
* @param decoded pointer to a decoded image to post process to meet dsc->args requirement.
|
||||
* @return post processed draw buffer, when it differs with `decoded`, it's newly allocated.
|
||||
*/
|
||||
lv_draw_buf_t * lv_image_decoder_post_process(lv_image_decoder_dsc_t * dsc, lv_draw_buf_t * decoded);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_IMAGE_DECODER_H*/
|
||||
@@ -0,0 +1,144 @@
|
||||
/**
|
||||
* @file lv_image_decoder_private.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_IMAGE_DECODER_PRIVATE_H
|
||||
#define LV_IMAGE_DECODER_PRIVATE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_image_decoder.h"
|
||||
#include "../misc/cache/lv_cache.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Image decoder args.
|
||||
* It determines how to decoder an image, e.g. whether to premultiply the alpha or not.
|
||||
* It should be passed to lv_img_decoder_open() function. If NULL is provided, default
|
||||
* args are used.
|
||||
*
|
||||
* Default args:
|
||||
* all field are zero or false.
|
||||
*/
|
||||
struct _lv_image_decoder_args_t {
|
||||
bool stride_align; /**< Whether stride should be aligned */
|
||||
bool premultiply; /**< Whether image should be premultiplied or not after decoding */
|
||||
bool no_cache; /**< When set, decoded image won't be put to cache, and decoder open will also ignore cache. */
|
||||
bool use_indexed; /**< Decoded indexed image as is. Convert to ARGB8888 if false. */
|
||||
bool flush_cache; /**< Whether to flush the data cache after decoding */
|
||||
};
|
||||
|
||||
struct _lv_image_decoder_t {
|
||||
lv_image_decoder_info_f_t info_cb;
|
||||
lv_image_decoder_open_f_t open_cb;
|
||||
lv_image_decoder_get_area_cb_t get_area_cb;
|
||||
lv_image_decoder_close_f_t close_cb;
|
||||
|
||||
lv_image_decoder_custom_draw_t custom_draw_cb;
|
||||
|
||||
const char * name;
|
||||
|
||||
void * user_data;
|
||||
};
|
||||
|
||||
struct _lv_image_cache_data_t {
|
||||
lv_cache_slot_size_t slot;
|
||||
|
||||
const void * src;
|
||||
lv_image_src_t src_type;
|
||||
|
||||
const lv_draw_buf_t * decoded;
|
||||
const lv_image_decoder_t * decoder;
|
||||
void * user_data;
|
||||
};
|
||||
|
||||
struct _lv_image_header_cache_data_t {
|
||||
const void * src;
|
||||
lv_image_src_t src_type;
|
||||
|
||||
lv_image_header_t header;
|
||||
lv_image_decoder_t * decoder;
|
||||
};
|
||||
|
||||
/**Describe an image decoding session. Stores data about the decoding*/
|
||||
struct _lv_image_decoder_dsc_t {
|
||||
/**The decoder which was able to open the image source*/
|
||||
lv_image_decoder_t * decoder;
|
||||
|
||||
/**A copy of parameters of how this image is decoded*/
|
||||
lv_image_decoder_args_t args;
|
||||
|
||||
/**The image source. A file path like "S:my_img.png" or pointer to an `lv_image_dsc_t` variable*/
|
||||
const void * src;
|
||||
|
||||
/**Type of the source: file or variable. Can be set in `open` function if required*/
|
||||
lv_image_src_t src_type;
|
||||
|
||||
lv_fs_file_t file;
|
||||
|
||||
/**Info about the opened image: color format, size, etc. MUST be set in `open` function*/
|
||||
lv_image_header_t header;
|
||||
|
||||
/** Pointer to a draw buffer where the image's data (pixels) are stored in a decoded, plain format.
|
||||
* MUST be set in `open` or `get_area_cb`function*/
|
||||
const lv_draw_buf_t * decoded;
|
||||
|
||||
const lv_color32_t * palette;
|
||||
uint32_t palette_size;
|
||||
|
||||
/** How much time did it take to open the image. [ms]
|
||||
* If not set `lv_image_cache` will measure and set the time to open*/
|
||||
uint32_t time_to_open;
|
||||
|
||||
/**A text to display instead of the image when the image can't be opened.
|
||||
* Can be set in `open` function or set NULL.*/
|
||||
const char * error_msg;
|
||||
|
||||
lv_cache_t * cache;
|
||||
|
||||
/**Point to cache entry information*/
|
||||
lv_cache_entry_t * cache_entry;
|
||||
|
||||
/**Store any custom data here is required*/
|
||||
void * user_data;
|
||||
};
|
||||
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Initialize the image decoder module
|
||||
* @param image_cache_size Image cache size in bytes. 0 to disable cache.
|
||||
* @param image_header_count Number of header cache entries. 0 to disable header cache.
|
||||
*/
|
||||
void lv_image_decoder_init(uint32_t image_cache_size, uint32_t image_header_count);
|
||||
|
||||
/**
|
||||
* Deinitialize the image decoder module
|
||||
*/
|
||||
void lv_image_decoder_deinit(void);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_IMAGE_DECODER_PRIVATE_H*/
|
||||
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* @file lv_image_dsc.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_IMAGE_DSC_H
|
||||
#define LV_IMAGE_DSC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../lv_conf_internal.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/** Magic number for lvgl image, 9 means lvgl version 9
|
||||
* It must be neither a valid ASCII character nor larger than 0x80. See `lv_image_src_get_type`.
|
||||
*/
|
||||
#define LV_IMAGE_HEADER_MAGIC (0x19)
|
||||
LV_EXPORT_CONST_INT(LV_IMAGE_HEADER_MAGIC);
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef enum _lvimage_flags_t {
|
||||
/**
|
||||
* For RGB map of the image data, mark if it's pre-multiplied with alpha.
|
||||
* For indexed image, this bit indicated palette data is pre-multiplied with alpha.
|
||||
*/
|
||||
LV_IMAGE_FLAGS_PREMULTIPLIED = 0x0001,
|
||||
/**
|
||||
* The image data is compressed, so decoder needs to decode image firstly.
|
||||
* If this flag is set, the whole image will be decompressed upon decode, and
|
||||
* `get_area_cb` won't be necessary.
|
||||
*/
|
||||
LV_IMAGE_FLAGS_COMPRESSED = 0x0008,
|
||||
|
||||
/*Below flags are applicable only for draw buffer header.*/
|
||||
|
||||
/**
|
||||
* The image is allocated from heap, thus should be freed after use.
|
||||
*/
|
||||
LV_IMAGE_FLAGS_ALLOCATED = 0x0010,
|
||||
|
||||
/**
|
||||
* If the image data is malloced and can be processed in place.
|
||||
* In image decoder post processing, this flag means we modify it in-place.
|
||||
*/
|
||||
LV_IMAGE_FLAGS_MODIFIABLE = 0x0020,
|
||||
|
||||
/**
|
||||
* The image has custom drawing methods.
|
||||
*/
|
||||
LV_IMAGE_FLAGS_CUSTOM_DRAW = 0x0040,
|
||||
|
||||
/**
|
||||
* Flags reserved for user, lvgl won't use these bits.
|
||||
*/
|
||||
LV_IMAGE_FLAGS_USER1 = 0x0100,
|
||||
LV_IMAGE_FLAGS_USER2 = 0x0200,
|
||||
LV_IMAGE_FLAGS_USER3 = 0x0400,
|
||||
LV_IMAGE_FLAGS_USER4 = 0x0800,
|
||||
LV_IMAGE_FLAGS_USER5 = 0x1000,
|
||||
LV_IMAGE_FLAGS_USER6 = 0x2000,
|
||||
LV_IMAGE_FLAGS_USER7 = 0x4000,
|
||||
LV_IMAGE_FLAGS_USER8 = 0x8000,
|
||||
} lv_image_flags_t;
|
||||
|
||||
typedef enum {
|
||||
LV_IMAGE_COMPRESS_NONE = 0,
|
||||
LV_IMAGE_COMPRESS_RLE, /**< LVGL custom RLE compression */
|
||||
LV_IMAGE_COMPRESS_LZ4,
|
||||
} lv_image_compress_t;
|
||||
|
||||
#if LV_BIG_ENDIAN_SYSTEM
|
||||
typedef struct {
|
||||
uint32_t reserved_2: 16; /**< Reserved to be used later*/
|
||||
uint32_t stride: 16; /**< Number of bytes in a row*/
|
||||
uint32_t h: 16;
|
||||
uint32_t w: 16;
|
||||
uint32_t flags: 16; /**< Image flags, see `lv_image_flags_t`*/
|
||||
uint32_t cf : 8; /**< Color format: See `lv_color_format_t`*/
|
||||
uint32_t magic: 8; /**< Magic number. Must be LV_IMAGE_HEADER_MAGIC*/
|
||||
} lv_image_header_t;
|
||||
#else
|
||||
typedef struct {
|
||||
uint32_t magic: 8; /**< Magic number. Must be LV_IMAGE_HEADER_MAGIC*/
|
||||
uint32_t cf : 8; /**< Color format: See `lv_color_format_t`*/
|
||||
uint32_t flags: 16; /**< Image flags, see `lv_image_flags_t`*/
|
||||
|
||||
uint32_t w: 16;
|
||||
uint32_t h: 16;
|
||||
uint32_t stride: 16; /**< Number of bytes in a row*/
|
||||
uint32_t reserved_2: 16; /**< Reserved to be used later*/
|
||||
} lv_image_header_t;
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
void * buf;
|
||||
uint32_t stride; /**< Number of bytes in a row*/
|
||||
} lv_yuv_plane_t;
|
||||
|
||||
typedef union {
|
||||
lv_yuv_plane_t yuv; /**< packed format*/
|
||||
struct {
|
||||
lv_yuv_plane_t y;
|
||||
lv_yuv_plane_t u;
|
||||
lv_yuv_plane_t v;
|
||||
} planar; /**< planar format with 3 plane*/
|
||||
struct {
|
||||
lv_yuv_plane_t y;
|
||||
lv_yuv_plane_t uv;
|
||||
} semi_planar; /**< planar format with 2 plane*/
|
||||
} lv_yuv_buf_t;
|
||||
|
||||
/**
|
||||
* Struct to describe a constant image resource.
|
||||
* It's similar to lv_draw_buf_t, but the data is constant.
|
||||
*/
|
||||
typedef struct {
|
||||
lv_image_header_t header; /**< A header describing the basics of the image*/
|
||||
uint32_t data_size; /**< Size of the image in bytes*/
|
||||
const uint8_t * data; /**< Pointer to the data of the image*/
|
||||
const void * reserved; /**< A reserved field to make it has same size as lv_draw_buf_t*/
|
||||
const void * reserved_2; /**< A reserved field to make it has same size as lv_draw_buf_t*/
|
||||
} lv_image_dsc_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_IMAGE_DSC_H*/
|
||||
@@ -0,0 +1,405 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008-24 Think Silicon Single Member PC
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next paragraph)
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file lv_draw_nema_gfx.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../../core/lv_refr.h"
|
||||
|
||||
#if LV_USE_NEMA_GFX
|
||||
|
||||
#include "lv_draw_nema_gfx.h"
|
||||
#include "../../font/lv_font.h"
|
||||
#include "../../font/lv_font_fmt_txt.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#define DRAW_UNIT_ID_NEMA_GFX 7
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
#if LV_USE_OS
|
||||
/**
|
||||
* Structure of pending nema_gfx draw task
|
||||
*/
|
||||
typedef struct _nema_gfx_draw_task_t {
|
||||
lv_draw_task_t * task;
|
||||
bool flushed;
|
||||
} nema_gfx_draw_task_t;
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
#if LV_USE_OS
|
||||
static void nema_gfx_render_thread_cb(void * ptr);
|
||||
#endif
|
||||
|
||||
static void nema_gfx_execute_drawing(lv_draw_nema_gfx_unit_t * u);
|
||||
|
||||
static int32_t nema_gfx_dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer);
|
||||
|
||||
static int32_t nema_gfx_evaluate(lv_draw_unit_t * draw_unit, lv_draw_task_t * task);
|
||||
|
||||
static int32_t nema_gfx_delete(lv_draw_unit_t * draw_unit);
|
||||
|
||||
static int32_t nema_gfx_wait_for_finish(lv_draw_unit_t * draw_unit);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_nema_gfx_init(void)
|
||||
{
|
||||
lv_draw_nema_gfx_unit_t * draw_nema_gfx_unit = lv_draw_create_unit(sizeof(lv_draw_nema_gfx_unit_t));
|
||||
/*Initialize NemaGFX*/
|
||||
nema_init();
|
||||
|
||||
draw_nema_gfx_unit->base_unit.dispatch_cb = nema_gfx_dispatch;
|
||||
draw_nema_gfx_unit->base_unit.evaluate_cb = nema_gfx_evaluate;
|
||||
draw_nema_gfx_unit->base_unit.delete_cb = nema_gfx_delete;
|
||||
draw_nema_gfx_unit->base_unit.wait_for_finish_cb = nema_gfx_wait_for_finish;
|
||||
draw_nema_gfx_unit->base_unit.name = "NEMA_GFX";
|
||||
|
||||
#if LV_USE_NEMA_VG
|
||||
/*Initialize NemaVG */
|
||||
nema_vg_init(LV_NEMA_GFX_MAX_RESX, LV_NEMA_GFX_MAX_RESY);
|
||||
/* Allocate VG Buffers*/
|
||||
draw_nema_gfx_unit->paint = nema_vg_paint_create();
|
||||
draw_nema_gfx_unit->gradient = nema_vg_grad_create();
|
||||
draw_nema_gfx_unit->path = nema_vg_path_create();
|
||||
/*Initialize Freetype Support*/
|
||||
lv_draw_nema_gfx_label_init(&(draw_nema_gfx_unit->base_unit));
|
||||
#endif
|
||||
/*Create GPU Command List*/
|
||||
draw_nema_gfx_unit->cl = nema_cl_create();
|
||||
/*Bind Command List*/
|
||||
nema_cl_bind_circular(&(draw_nema_gfx_unit->cl));
|
||||
|
||||
|
||||
#if LV_USE_OS
|
||||
lv_thread_init(&draw_nema_gfx_unit->thread, "nemagfx", LV_DRAW_THREAD_PRIO, nema_gfx_render_thread_cb, 2 * 1024,
|
||||
draw_nema_gfx_unit);
|
||||
#endif
|
||||
}
|
||||
|
||||
void lv_draw_nema_gfx_deinit(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static int32_t nema_gfx_wait_for_finish(lv_draw_unit_t * draw_unit)
|
||||
{
|
||||
lv_draw_nema_gfx_unit_t * draw_nema_gfx_unit = (lv_draw_nema_gfx_unit_t *)draw_unit;
|
||||
nema_cl_submit(&(draw_nema_gfx_unit->cl));
|
||||
nema_cl_wait(&(draw_nema_gfx_unit->cl));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int32_t nema_gfx_evaluate(lv_draw_unit_t * draw_unit, lv_draw_task_t * task)
|
||||
{
|
||||
lv_draw_nema_gfx_unit_t * draw_nema_gfx_unit = (lv_draw_nema_gfx_unit_t *)draw_unit;
|
||||
|
||||
switch(task->type) {
|
||||
case LV_DRAW_TASK_TYPE_LAYER: {
|
||||
if(task->preference_score > 80) {
|
||||
task->preference_score = 80;
|
||||
task->preferred_draw_unit_id = DRAW_UNIT_ID_NEMA_GFX;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#if LV_USE_NEMA_VG
|
||||
case LV_DRAW_TASK_TYPE_TRIANGLE:
|
||||
case LV_DRAW_TASK_TYPE_ARC:
|
||||
case LV_DRAW_TASK_TYPE_FILL: {
|
||||
if(task->preference_score > 80) {
|
||||
task->preference_score = 80;
|
||||
task->preferred_draw_unit_id = DRAW_UNIT_ID_NEMA_GFX;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
case LV_DRAW_TASK_TYPE_FILL: {
|
||||
lv_draw_fill_dsc_t * draw_fill_dsc = (lv_draw_fill_dsc_t *) task->draw_dsc;
|
||||
if((draw_fill_dsc->grad.dir == (lv_grad_dir_t)LV_GRAD_DIR_NONE)) {
|
||||
if(task->preference_score > 80) {
|
||||
task->preference_score = 80;
|
||||
task->preferred_draw_unit_id = DRAW_UNIT_ID_NEMA_GFX;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case LV_DRAW_TASK_TYPE_TRIANGLE: {
|
||||
lv_draw_triangle_dsc_t * draw_triangle_dsc = (lv_draw_triangle_dsc_t *) task->draw_dsc;
|
||||
if((draw_triangle_dsc->grad.dir == (lv_grad_dir_t)LV_GRAD_DIR_NONE)) {
|
||||
if(task->preference_score > 80) {
|
||||
task->preference_score = 80;
|
||||
task->preferred_draw_unit_id = DRAW_UNIT_ID_NEMA_GFX;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case LV_DRAW_TASK_TYPE_IMAGE: {
|
||||
lv_draw_image_dsc_t * draw_image_dsc = (lv_draw_image_dsc_t *) task->draw_dsc;
|
||||
/*Guard for previous NemaGFX Version*/
|
||||
#ifndef NEMA_BLOP_RECOLOR
|
||||
if(draw_image_dsc->recolor_opa > LV_OPA_MIN)
|
||||
break;
|
||||
#endif
|
||||
const lv_image_dsc_t * img_dsc = draw_image_dsc->src;
|
||||
if(!lv_nemagfx_is_cf_supported(img_dsc->header.cf))
|
||||
break;
|
||||
|
||||
if(draw_image_dsc->blend_mode != LV_BLEND_MODE_SUBTRACTIVE) {
|
||||
if(task->preference_score > 80) {
|
||||
task->preference_score = 80;
|
||||
task->preferred_draw_unit_id = DRAW_UNIT_ID_NEMA_GFX;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case LV_DRAW_TASK_TYPE_LABEL: {
|
||||
lv_draw_label_dsc_t * draw_label_dsc = (lv_draw_label_dsc_t *) task->draw_dsc;
|
||||
lv_font_fmt_txt_dsc_t * fdsc = (lv_font_fmt_txt_dsc_t *)(draw_label_dsc->font->dsc);
|
||||
if(fdsc->bitmap_format != LV_FONT_FMT_TXT_COMPRESSED) {
|
||||
if(task->preference_score > 80) {
|
||||
task->preference_score = 80;
|
||||
task->preferred_draw_unit_id = DRAW_UNIT_ID_NEMA_GFX;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case LV_DRAW_TASK_TYPE_LINE: {
|
||||
lv_draw_line_dsc_t * draw_line_dsc = (lv_draw_line_dsc_t *) task->draw_dsc;
|
||||
bool is_dashed = (draw_line_dsc->dash_width && draw_line_dsc->dash_gap);
|
||||
if(!is_dashed && !(draw_line_dsc->round_end || draw_line_dsc->round_start)) {
|
||||
if(task->preference_score > 80) {
|
||||
task->preference_score = 80;
|
||||
task->preferred_draw_unit_id = DRAW_UNIT_ID_NEMA_GFX;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case LV_DRAW_TASK_TYPE_BORDER: {
|
||||
const lv_draw_border_dsc_t * draw_dsc = (lv_draw_border_dsc_t *) task->draw_dsc;
|
||||
if((!(draw_dsc->side != (lv_border_side_t)LV_BORDER_SIDE_FULL && draw_dsc->radius > 0)) &&
|
||||
(draw_dsc->radius > draw_dsc->width)) {
|
||||
if(task->preference_score > 80) {
|
||||
task->preference_score = 80;
|
||||
task->preferred_draw_unit_id = DRAW_UNIT_ID_NEMA_GFX;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case LV_DRAW_TASK_TYPE_BOX_SHADOW:
|
||||
case LV_DRAW_TASK_TYPE_MASK_RECTANGLE:
|
||||
case LV_DRAW_TASK_TYPE_MASK_BITMAP:
|
||||
#if LV_USE_VECTOR_GRAPHIC
|
||||
case LV_DRAW_TASK_TYPE_VECTOR:
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
nema_cl_wait(&(draw_nema_gfx_unit->cl));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t nema_gfx_dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer)
|
||||
{
|
||||
lv_draw_nema_gfx_unit_t * draw_nema_gfx_unit = (lv_draw_nema_gfx_unit_t *) draw_unit;
|
||||
|
||||
/* Return immediately if it's busy with draw task. */
|
||||
if(draw_nema_gfx_unit->task_act)
|
||||
return 0;
|
||||
|
||||
/* Try to get an ready to draw. */
|
||||
lv_draw_task_t * t = lv_draw_get_available_task(layer, NULL, DRAW_UNIT_ID_NEMA_GFX);
|
||||
|
||||
/* Return 0 is no selection, some tasks can be supported by other units. */
|
||||
if(t == NULL || t->preferred_draw_unit_id != DRAW_UNIT_ID_NEMA_GFX)
|
||||
return LV_DRAW_UNIT_IDLE;
|
||||
|
||||
void * buf = lv_draw_layer_alloc_buf(layer);
|
||||
if(buf == NULL)
|
||||
return LV_DRAW_UNIT_IDLE;
|
||||
|
||||
t->state = LV_DRAW_TASK_STATE_IN_PROGRESS;
|
||||
draw_nema_gfx_unit->task_act = t;
|
||||
|
||||
#if LV_USE_OS
|
||||
/* Let the render thread work. */
|
||||
if(draw_nema_gfx_unit->inited)
|
||||
lv_thread_sync_signal(&draw_nema_gfx_unit->sync);
|
||||
#else
|
||||
nema_gfx_execute_drawing(draw_nema_gfx_unit);
|
||||
|
||||
draw_nema_gfx_unit->task_act->state = LV_DRAW_TASK_STATE_READY;
|
||||
draw_nema_gfx_unit->task_act = NULL;
|
||||
|
||||
/* The draw unit is free now. Request a new dispatching as it can get a new task. */
|
||||
lv_draw_dispatch_request();
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void nema_gfx_execute_drawing(lv_draw_nema_gfx_unit_t * u)
|
||||
{
|
||||
lv_draw_task_t * t = u->task_act;
|
||||
/* remember draw unit for access to unit's context */
|
||||
t->draw_unit = (lv_draw_unit_t *)u;
|
||||
|
||||
switch(t->type) {
|
||||
case LV_DRAW_TASK_TYPE_FILL:
|
||||
lv_draw_nema_gfx_fill(t, t->draw_dsc, &t->area);
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_IMAGE:
|
||||
lv_draw_nema_gfx_img(t, t->draw_dsc, &t->area);
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_TRIANGLE:
|
||||
lv_draw_nema_gfx_triangle(t, t->draw_dsc);
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_LABEL:
|
||||
lv_draw_nema_gfx_label(t, t->draw_dsc, &t->area);
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_LAYER:
|
||||
lv_draw_nema_gfx_layer(t, t->draw_dsc, &t->area);
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_LINE:
|
||||
lv_draw_nema_gfx_line(t, t->draw_dsc);
|
||||
break;
|
||||
#if LV_USE_NEMA_VG
|
||||
case LV_DRAW_TASK_TYPE_ARC:
|
||||
lv_draw_nema_gfx_arc(t, t->draw_dsc, &t->area);
|
||||
break;
|
||||
#endif
|
||||
case LV_DRAW_TASK_TYPE_BORDER:
|
||||
lv_draw_nema_gfx_border(t, t->draw_dsc, &t->area);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t nema_gfx_delete(lv_draw_unit_t * draw_unit)
|
||||
{
|
||||
#if LV_USE_NEMA_VG
|
||||
/*Free VG Buffers*/
|
||||
lv_draw_nema_gfx_unit_t * draw_nema_gfx_unit = (lv_draw_nema_gfx_unit_t *) draw_unit;
|
||||
nema_vg_paint_destroy(draw_nema_gfx_unit->paint);
|
||||
nema_vg_path_destroy(draw_nema_gfx_unit->path);
|
||||
nema_vg_grad_destroy(draw_nema_gfx_unit->gradient);
|
||||
#endif
|
||||
|
||||
#if LV_USE_OS
|
||||
lv_draw_nema_gfx_unit_t * _draw_nema_gfx_unit = (lv_draw_nema_gfx_unit_t *) draw_unit;
|
||||
LV_LOG_INFO("Cancel NemaGFX draw thread.");
|
||||
_draw_nema_gfx_unit->exit_status = true;
|
||||
|
||||
if(_draw_nema_gfx_unit->inited)
|
||||
lv_thread_sync_signal(&_draw_nema_gfx_unit->sync);
|
||||
|
||||
lv_result_t res = lv_thread_delete(&_draw_nema_gfx_unit->thread);
|
||||
|
||||
return res;
|
||||
#endif
|
||||
|
||||
#if LV_USE_NEMA_VG == 0 && LV_USE_OS == LV_OS_NONE
|
||||
LV_UNUSED(draw_unit);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if LV_USE_OS
|
||||
static void nema_gfx_render_thread_cb(void * ptr)
|
||||
{
|
||||
lv_draw_nema_gfx_unit_t * u = ptr;
|
||||
|
||||
lv_thread_sync_init(&u->sync);
|
||||
u->inited = true;
|
||||
|
||||
while(1) {
|
||||
/* Wait for sync if there is no task set. */
|
||||
while(u->task_act == NULL) {
|
||||
if(u->exit_status)
|
||||
break;
|
||||
|
||||
lv_thread_sync_wait(&u->sync);
|
||||
}
|
||||
|
||||
if(u->exit_status) {
|
||||
LV_LOG_INFO("Ready to exit NemaGFX draw thread.");
|
||||
break;
|
||||
}
|
||||
|
||||
if(u->task_act) {
|
||||
nema_gfx_execute_drawing(u);
|
||||
}
|
||||
/* Signal the ready state to dispatcher. */
|
||||
u->task_act->state = LV_DRAW_TASK_STATE_READY;
|
||||
/* Cleanup. */
|
||||
u->task_act = NULL;
|
||||
|
||||
/* The draw unit is free now. Request a new dispatching as it can get a new task. */
|
||||
lv_draw_dispatch_request();
|
||||
}
|
||||
|
||||
u->inited = false;
|
||||
lv_thread_sync_delete(&u->sync);
|
||||
LV_LOG_INFO("Exit NemaGFX draw thread.");
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008-24 Think Silicon Single Member PC
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next paragraph)
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file lv_draw_nema_gfx.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_NEMA_GFX_H
|
||||
#define LV_DRAW_NEMA_GFX_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_NEMA_GFX
|
||||
|
||||
#include "lv_draw_nema_gfx_utils.h"
|
||||
|
||||
#include "../lv_draw_private.h"
|
||||
#include "../lv_draw_buf_private.h"
|
||||
#include "../lv_draw_image_private.h"
|
||||
#include "../lv_image_decoder_private.h"
|
||||
#include "../lv_draw_label_private.h"
|
||||
#include "../lv_draw_mask_private.h"
|
||||
#include "../lv_draw_rect_private.h"
|
||||
#include "../lv_draw_triangle_private.h"
|
||||
#include "../lv_draw_vector_private.h"
|
||||
|
||||
#include "../../misc/lv_area_private.h"
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
typedef struct {
|
||||
lv_draw_unit_t base_unit;
|
||||
lv_draw_task_t * task_act;
|
||||
#if LV_USE_OS
|
||||
lv_thread_sync_t sync;
|
||||
lv_thread_t thread;
|
||||
volatile bool inited;
|
||||
volatile bool exit_status;
|
||||
#endif
|
||||
uint32_t idx;
|
||||
nema_cmdlist_t cl;
|
||||
#if LV_USE_NEMA_VG
|
||||
NEMA_VG_PAINT_HANDLE paint;
|
||||
NEMA_VG_GRAD_HANDLE gradient;
|
||||
NEMA_VG_PATH_HANDLE path;
|
||||
#endif
|
||||
} lv_draw_nema_gfx_unit_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
void lv_draw_nema_gfx_init(void);
|
||||
|
||||
void lv_draw_nema_gfx_deinit(void);
|
||||
|
||||
void lv_draw_nema_gfx_fill(lv_draw_task_t * t,
|
||||
const lv_draw_fill_dsc_t * dsc, const lv_area_t * coords);
|
||||
|
||||
void lv_draw_nema_gfx_triangle(lv_draw_task_t * t, const lv_draw_triangle_dsc_t * dsc);
|
||||
|
||||
void lv_draw_nema_gfx_img(lv_draw_task_t * t, const lv_draw_image_dsc_t * dsc,
|
||||
const lv_area_t * coords);
|
||||
|
||||
void lv_draw_nema_gfx_label(lv_draw_task_t * t, const lv_draw_label_dsc_t * dsc,
|
||||
const lv_area_t * coords);
|
||||
|
||||
void lv_draw_nema_gfx_label_init(lv_draw_unit_t * draw_unit);
|
||||
|
||||
void lv_draw_nema_gfx_layer(lv_draw_task_t * t, const lv_draw_image_dsc_t * draw_dsc,
|
||||
const lv_area_t * coords);
|
||||
|
||||
void lv_draw_nema_gfx_line(lv_draw_task_t * t, const lv_draw_line_dsc_t * dsc);
|
||||
|
||||
void lv_draw_nema_gfx_border(lv_draw_task_t * t, const lv_draw_border_dsc_t * dsc,
|
||||
const lv_area_t * coords);
|
||||
|
||||
void lv_draw_nema_gfx_arc(lv_draw_task_t * t, const lv_draw_arc_dsc_t * dsc,
|
||||
const lv_area_t * coords);
|
||||
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_NEMA_GFX*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_NEMA_GFX_H*/
|
||||
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008-24 Think Silicon Single Member PC
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next paragraph)
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file lv_draw_nema_gfx_arc.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_nema_gfx.h"
|
||||
|
||||
#if LV_USE_NEMA_GFX && LV_USE_NEMA_VG
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
void lv_draw_nema_gfx_arc(lv_draw_task_t * t, const lv_draw_arc_dsc_t * dsc, const lv_area_t * coords)
|
||||
{
|
||||
|
||||
LV_UNUSED(coords);
|
||||
|
||||
if(dsc->opa <= (lv_opa_t)LV_OPA_MIN)
|
||||
return;
|
||||
if(dsc->width == 0)
|
||||
return;
|
||||
if(dsc->start_angle == dsc->end_angle)
|
||||
return;
|
||||
|
||||
lv_draw_nema_gfx_unit_t * draw_nema_gfx_unit = (lv_draw_nema_gfx_unit_t *)t->draw_unit;
|
||||
|
||||
lv_layer_t * layer = t->target_layer;
|
||||
lv_point_t center = {dsc->center.x - layer->buf_area.x1, dsc->center.y - layer->buf_area.y1};
|
||||
|
||||
lv_area_t clip_area;
|
||||
lv_area_copy(&clip_area, &t->clip_area);
|
||||
lv_area_move(&clip_area, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
nema_set_clip(clip_area.x1, clip_area.y1, lv_area_get_width(&clip_area), lv_area_get_height(&clip_area));
|
||||
|
||||
lv_value_precise_t start_angle = dsc->start_angle;
|
||||
lv_value_precise_t end_angle = dsc->end_angle;
|
||||
|
||||
if(start_angle >= end_angle) {
|
||||
end_angle += 360.0f;
|
||||
}
|
||||
|
||||
if(end_angle - start_angle > 360.0f) {
|
||||
start_angle = 0.0f;
|
||||
end_angle = 360.0f;
|
||||
}
|
||||
else {
|
||||
while(end_angle > 360.0f) {
|
||||
start_angle -= 360.0f;
|
||||
end_angle -= 360.0f;
|
||||
}
|
||||
}
|
||||
|
||||
nema_vg_paint_clear(draw_nema_gfx_unit->paint);
|
||||
nema_vg_paint_set_type(draw_nema_gfx_unit->paint, NEMA_VG_PAINT_COLOR);
|
||||
lv_color32_t col32 = lv_color_to_32(dsc->color, dsc->opa);
|
||||
uint32_t bg_color = nema_rgba(col32.red, col32.green, col32.blue, col32.alpha);
|
||||
nema_vg_paint_set_paint_color(draw_nema_gfx_unit->paint, bg_color); // green
|
||||
nema_vg_paint_set_stroke_width(draw_nema_gfx_unit->paint, dsc->width);
|
||||
nema_vg_set_blend(NEMA_BL_SRC_OVER | NEMA_BLOP_SRC_PREMULT);
|
||||
|
||||
if(dsc->rounded == 1) {
|
||||
nema_vg_draw_ring(center.x, center.y, (float)dsc->radius - (float)dsc->width * 0.5f, start_angle, end_angle,
|
||||
draw_nema_gfx_unit->paint);
|
||||
}
|
||||
else {
|
||||
nema_vg_draw_ring_generic(center.x, center.y, (float)dsc->radius - (float)dsc->width * 0.5f, start_angle,
|
||||
end_angle, draw_nema_gfx_unit->paint, 0U);
|
||||
}
|
||||
|
||||
nema_cl_submit(&(draw_nema_gfx_unit->cl));
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,226 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008-24 Think Silicon Single Member PC
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next paragraph)
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file lv_draw_nema_gfx_fill.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_nema_gfx.h"
|
||||
|
||||
#if LV_USE_NEMA_GFX
|
||||
#include <math.h>
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
void lv_draw_nema_gfx_border(lv_draw_task_t * t, const lv_draw_border_dsc_t * dsc, const lv_area_t * coords)
|
||||
{
|
||||
if(dsc->opa <= LV_OPA_MIN)
|
||||
return;
|
||||
if(dsc->width == 0)
|
||||
return;
|
||||
if(dsc->side == LV_BORDER_SIDE_NONE)
|
||||
return;
|
||||
|
||||
lv_draw_nema_gfx_unit_t * draw_nema_gfx_unit = (lv_draw_nema_gfx_unit_t *)t->draw_unit;
|
||||
|
||||
lv_layer_t * layer = t->target_layer;
|
||||
lv_area_t inward_coords;
|
||||
int32_t width = dsc->width;
|
||||
|
||||
/* Move border inwards to align with software rendered border */
|
||||
inward_coords.x1 = coords->x1 + ceil(width / 2.0f);
|
||||
inward_coords.x2 = coords->x2 - floor(width / 2.0f);
|
||||
inward_coords.y1 = coords->y1 + ceil(width / 2.0f);
|
||||
inward_coords.y2 = coords->y2 - floor(width / 2.0f);
|
||||
|
||||
lv_area_move(&inward_coords, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
lv_area_t clip_area;
|
||||
lv_area_copy(&clip_area, &t->clip_area);
|
||||
lv_area_move(&clip_area, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
nema_set_clip(clip_area.x1, clip_area.y1, lv_area_get_width(&clip_area), lv_area_get_height(&clip_area));
|
||||
|
||||
lv_area_t clipped_coords;
|
||||
if(!lv_area_intersect(&clipped_coords, &inward_coords, &clip_area))
|
||||
return; /*Fully clipped, nothing to do*/
|
||||
|
||||
lv_color_format_t dst_cf = layer->draw_buf->header.cf;
|
||||
uint32_t dst_nema_cf = lv_nemagfx_cf_to_nema(dst_cf);
|
||||
|
||||
/* the stride should be computed internally for NEMA_TSC images and images missing a stride value */
|
||||
int32_t stride = (dst_cf >= LV_COLOR_FORMAT_NEMA_TSC_START && dst_cf <= LV_COLOR_FORMAT_NEMA_TSC_END) ?
|
||||
-1 : lv_area_get_width(&(layer->buf_area)) * lv_color_format_get_size(dst_cf);
|
||||
|
||||
nema_bind_dst_tex((uintptr_t)NEMA_VIRT2PHYS(layer->draw_buf->data), lv_area_get_width(&(layer->buf_area)),
|
||||
lv_area_get_height(&(layer->buf_area)), dst_nema_cf, stride);
|
||||
|
||||
/* Recalculate float Dimensions */
|
||||
float x1 = (float)coords->x1 + ((float)width / 2.0f) - (float)layer->buf_area.x1;
|
||||
float x2 = (float)coords->x2 - ((float)width / 2.0f) - (float)layer->buf_area.x1;
|
||||
float y1 = (float)coords->y1 + ((float)width / 2.0f) - (float)layer->buf_area.y1;
|
||||
float y2 = (float)coords->y2 - ((float)width / 2.0f) - (float)layer->buf_area.y1;
|
||||
float coords_bg_w = x2 - x1 + 1;
|
||||
float coords_bg_h = y2 - y1 + 1;
|
||||
int32_t short_side = LV_MIN(coords_bg_w, coords_bg_h);
|
||||
float radius = (float)LV_MIN(dsc->radius, short_side >> 1);
|
||||
|
||||
lv_color32_t col32 = lv_color_to_32(dsc->color, dsc->opa);
|
||||
uint32_t bg_color = nema_rgba(col32.red, col32.green, col32.blue, col32.alpha);
|
||||
|
||||
if(col32.alpha < 255U) {
|
||||
nema_set_blend_fill(NEMA_BL_SRC_OVER);
|
||||
bg_color = nema_premultiply_rgba(bg_color);
|
||||
}
|
||||
else {
|
||||
nema_set_blend_fill(NEMA_BL_SRC);
|
||||
}
|
||||
|
||||
if(radius > 0.0f) {
|
||||
nema_draw_rounded_rect_aa(x1, y1, coords_bg_w, coords_bg_h, radius, width, bg_color);
|
||||
}
|
||||
else {
|
||||
lv_area_t rect_coords = *coords;
|
||||
lv_area_move(&rect_coords, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
int32_t border_width = lv_area_get_width(&rect_coords);
|
||||
int32_t border_height = lv_area_get_height(&rect_coords);
|
||||
|
||||
if(dsc->side & LV_BORDER_SIDE_TOP) {
|
||||
float x = rect_coords.x1 + width;
|
||||
float y = rect_coords.y1;
|
||||
float w = border_width - 2 * width;
|
||||
float h = width;
|
||||
nema_enable_aa(1, 0, 1, 0);
|
||||
nema_fill_rect_f(x, y, w, h, bg_color);
|
||||
}
|
||||
|
||||
if(dsc->side & LV_BORDER_SIDE_BOTTOM) {
|
||||
float x = rect_coords.x1 + width;
|
||||
float y = rect_coords.y1 + border_height - width;
|
||||
float w = border_width - 2 * width;
|
||||
float h = width;
|
||||
nema_enable_aa(1, 0, 1, 0);
|
||||
nema_fill_rect_f(x, y, w, h, bg_color);
|
||||
}
|
||||
|
||||
if(dsc->side & LV_BORDER_SIDE_LEFT) {
|
||||
float x = rect_coords.x1;
|
||||
float y = rect_coords.y1 + width;
|
||||
float w = width;
|
||||
float h = border_height - 2 * width;
|
||||
nema_enable_aa(0, 1, 0, 1);
|
||||
nema_fill_rect_f(x, y, w, h, bg_color);
|
||||
}
|
||||
|
||||
if(dsc->side & LV_BORDER_SIDE_RIGHT) {
|
||||
float x = rect_coords.x1 + border_width - width;
|
||||
float y = rect_coords.y1 + width;
|
||||
float w = width;
|
||||
float h = border_height - 2 * width;
|
||||
nema_enable_aa(0, 1, 0, 1);
|
||||
nema_fill_rect_f(x, y, w, h, bg_color);
|
||||
}
|
||||
|
||||
/*Draw small corner rectangles
|
||||
Top Left*/
|
||||
if(dsc->side & LV_BORDER_SIDE_TOP || dsc->side & LV_BORDER_SIDE_LEFT) {
|
||||
float x = rect_coords.x1;
|
||||
float y = rect_coords.y1;
|
||||
float w = width;
|
||||
float h = width;
|
||||
|
||||
if(!(dsc->side & LV_BORDER_SIDE_TOP))
|
||||
nema_enable_aa(1, 1, 0, 1);
|
||||
else if(!(dsc->side & LV_BORDER_SIDE_LEFT))
|
||||
nema_enable_aa(1, 0, 1, 1);
|
||||
else
|
||||
nema_enable_aa(1, 0, 0, 1);
|
||||
|
||||
nema_fill_rect_f(x, y, w, h, bg_color);
|
||||
}
|
||||
|
||||
/*Top Right*/
|
||||
if(dsc->side & LV_BORDER_SIDE_TOP || dsc->side & LV_BORDER_SIDE_RIGHT) {
|
||||
float x = rect_coords.x1 + border_width - width;
|
||||
float y = rect_coords.y1;
|
||||
float w = width;
|
||||
float h = width;
|
||||
|
||||
if(!(dsc->side & LV_BORDER_SIDE_TOP))
|
||||
nema_enable_aa(1, 1, 0, 1);
|
||||
else if(!(dsc->side & LV_BORDER_SIDE_RIGHT))
|
||||
nema_enable_aa(1, 1, 1, 0);
|
||||
else
|
||||
nema_enable_aa(1, 1, 0, 0);
|
||||
|
||||
nema_fill_rect_f(x, y, w, h, bg_color);
|
||||
}
|
||||
|
||||
/*Bottom Right*/
|
||||
if(dsc->side & LV_BORDER_SIDE_BOTTOM || dsc->side & LV_BORDER_SIDE_RIGHT) {
|
||||
float x = rect_coords.x1 + border_width - width;
|
||||
float y = rect_coords.y1 + border_height - width;
|
||||
float w = width;
|
||||
float h = width;
|
||||
|
||||
if(!(dsc->side & LV_BORDER_SIDE_BOTTOM))
|
||||
nema_enable_aa(0, 1, 1, 1);
|
||||
else if(!(dsc->side & LV_BORDER_SIDE_RIGHT))
|
||||
nema_enable_aa(1, 1, 1, 0);
|
||||
else
|
||||
nema_enable_aa(0, 1, 1, 0);
|
||||
|
||||
nema_fill_rect_f(x, y, w, h, bg_color);
|
||||
}
|
||||
|
||||
/*Bottom Left*/
|
||||
if(dsc->side & LV_BORDER_SIDE_BOTTOM || dsc->side & LV_BORDER_SIDE_LEFT) {
|
||||
float x = rect_coords.x1;
|
||||
float y = rect_coords.y1 + border_height - width;
|
||||
float w = width;
|
||||
float h = width;
|
||||
|
||||
if(!(dsc->side & LV_BORDER_SIDE_BOTTOM))
|
||||
nema_enable_aa(0, 1, 1, 1);
|
||||
else if(!(dsc->side & LV_BORDER_SIDE_LEFT))
|
||||
nema_enable_aa(1, 0, 1, 1);
|
||||
else
|
||||
nema_enable_aa(0, 0, 1, 1);
|
||||
|
||||
nema_fill_rect_f(x, y, w, h, bg_color);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
nema_cl_submit(&(draw_nema_gfx_unit->cl));
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008-24 Think Silicon Single Member PC
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next paragraph)
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file lv_draw_nema_gfx_fill.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_nema_gfx.h"
|
||||
|
||||
#if LV_USE_NEMA_GFX
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
void lv_draw_nema_gfx_fill(lv_draw_task_t * t, const lv_draw_fill_dsc_t * dsc, const lv_area_t * coords)
|
||||
{
|
||||
if(dsc->opa <= LV_OPA_MIN) return;
|
||||
|
||||
lv_draw_nema_gfx_unit_t * draw_nema_gfx_unit = (lv_draw_nema_gfx_unit_t *)t->draw_unit;
|
||||
|
||||
lv_layer_t * layer = t->target_layer;
|
||||
lv_area_t rel_coords;
|
||||
lv_area_copy(&rel_coords, coords);
|
||||
lv_area_move(&rel_coords, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
lv_area_t rel_clip_area;
|
||||
lv_area_copy(&rel_clip_area, &t->clip_area);
|
||||
lv_area_move(&rel_clip_area, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
nema_set_clip(rel_clip_area.x1, rel_clip_area.y1, lv_area_get_width(&rel_clip_area),
|
||||
lv_area_get_height(&rel_clip_area));
|
||||
|
||||
lv_area_t clipped_coords;
|
||||
if(!lv_area_intersect(&clipped_coords, &rel_coords, &rel_clip_area))
|
||||
return; /*Fully clipped, nothing to do*/
|
||||
|
||||
lv_color_format_t dst_cf = layer->draw_buf->header.cf;
|
||||
uint32_t dst_nema_cf = lv_nemagfx_cf_to_nema(dst_cf);
|
||||
|
||||
/* the stride should be computed internally for NEMA_TSC images and images missing a stride value */
|
||||
int32_t stride = (dst_cf >= LV_COLOR_FORMAT_NEMA_TSC_START && dst_cf <= LV_COLOR_FORMAT_NEMA_TSC_END) ?
|
||||
-1 : lv_area_get_width(&(layer->buf_area)) * lv_color_format_get_size(dst_cf);
|
||||
|
||||
nema_bind_dst_tex((uintptr_t)NEMA_VIRT2PHYS(layer->draw_buf->data), lv_area_get_width(&(layer->buf_area)),
|
||||
lv_area_get_height(&(layer->buf_area)), dst_nema_cf, stride);
|
||||
|
||||
int32_t coords_bg_w = lv_area_get_width(&rel_coords);
|
||||
int32_t coords_bg_h = lv_area_get_height(&rel_coords);
|
||||
int32_t short_side = LV_MIN(coords_bg_w, coords_bg_h);
|
||||
int32_t radius = LV_MIN(dsc->radius, short_side >> 1);
|
||||
|
||||
if((dsc->grad.dir == (lv_grad_dir_t)LV_GRAD_DIR_NONE)) {
|
||||
|
||||
lv_color32_t col32 = lv_color_to_32(dsc->color, dsc->opa);
|
||||
uint32_t bg_color = nema_rgba(col32.red, col32.green, col32.blue, col32.alpha);
|
||||
|
||||
if(col32.alpha < 255U) {
|
||||
nema_set_blend_fill(NEMA_BL_SRC_OVER);
|
||||
bg_color = nema_premultiply_rgba(bg_color);
|
||||
}
|
||||
else {
|
||||
nema_set_blend_fill(NEMA_BL_SRC);
|
||||
}
|
||||
|
||||
if(radius > 0.f)
|
||||
nema_fill_rounded_rect_aa(rel_coords.x1, rel_coords.y1, coords_bg_w, coords_bg_h, radius, bg_color);
|
||||
else
|
||||
nema_fill_rect(rel_coords.x1, rel_coords.y1, coords_bg_w, coords_bg_h, bg_color);
|
||||
}
|
||||
#if LV_USE_NEMA_VG
|
||||
else {
|
||||
|
||||
nema_vg_paint_clear(draw_nema_gfx_unit->paint);
|
||||
|
||||
nema_vg_paint_set_type(draw_nema_gfx_unit->paint, NEMA_VG_PAINT_GRAD_LINEAR);
|
||||
nema_vg_set_blend(NEMA_BL_SRC_OVER | NEMA_BLOP_SRC_PREMULT);
|
||||
|
||||
float stops[LV_GRADIENT_MAX_STOPS];
|
||||
color_var_t colors[LV_GRADIENT_MAX_STOPS];
|
||||
|
||||
uint32_t cnt = LV_MAX(dsc->grad.stops_count, LV_GRADIENT_MAX_STOPS);
|
||||
|
||||
for(uint8_t i = 0; i < cnt; i++) {
|
||||
stops[i] = (float)(dsc->grad.stops[i].frac) / 255.f;
|
||||
colors[i].a = LV_OPA_MIX2(dsc->grad.stops[i].opa, dsc->opa);
|
||||
colors[i].r = dsc->grad.stops[i].color.red;
|
||||
colors[i].g = dsc->grad.stops[i].color.green;
|
||||
colors[i].b = dsc->grad.stops[i].color.blue;
|
||||
}
|
||||
|
||||
nema_vg_grad_set(draw_nema_gfx_unit->gradient, cnt, stops, colors);
|
||||
|
||||
float x0, y0, x1, y1;
|
||||
|
||||
if(dsc->grad.dir == LV_GRAD_DIR_HOR) {
|
||||
x0 = rel_coords.x1;
|
||||
x1 = rel_coords.x2;
|
||||
y0 = rel_coords.y1;
|
||||
y1 = rel_coords.y1;
|
||||
}
|
||||
else {
|
||||
x0 = rel_coords.x1;
|
||||
x1 = rel_coords.x1;
|
||||
y0 = rel_coords.y1;
|
||||
y1 = rel_coords.y2;
|
||||
}
|
||||
|
||||
nema_vg_paint_set_grad_linear(draw_nema_gfx_unit->paint, draw_nema_gfx_unit->gradient, x0, y0, x1, y1,
|
||||
NEMA_TEX_CLAMP | NEMA_FILTER_BL);
|
||||
|
||||
if(radius > 0.f)
|
||||
nema_vg_draw_rounded_rect(rel_coords.x1, rel_coords.y1, coords_bg_w, coords_bg_h, radius, radius, NULL,
|
||||
draw_nema_gfx_unit->paint);
|
||||
else
|
||||
nema_vg_draw_rect(rel_coords.x1, rel_coords.y1, coords_bg_w, coords_bg_h, NULL, draw_nema_gfx_unit->paint);
|
||||
}
|
||||
#endif
|
||||
|
||||
nema_cl_submit(&(draw_nema_gfx_unit->cl));
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,283 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008-24 Think Silicon Single Member PC
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next paragraph)
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file lv_draw_nema_gfx_fill.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_nema_gfx.h"
|
||||
|
||||
#if LV_USE_NEMA_GFX
|
||||
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static void _draw_nema_gfx_tile(lv_draw_task_t * t, const lv_draw_image_dsc_t * dsc, const lv_area_t * coords);
|
||||
|
||||
static void _draw_nema_gfx_img(lv_draw_task_t * t, const lv_draw_image_dsc_t * dsc, const lv_area_t * coords);
|
||||
|
||||
static uint32_t lv_nemagfx_mask_cf_to_nema(lv_color_format_t cf);
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void _draw_nema_gfx_tile(lv_draw_task_t * t, const lv_draw_image_dsc_t * dsc, const lv_area_t * coords)
|
||||
{
|
||||
|
||||
lv_image_decoder_dsc_t decoder_dsc;
|
||||
lv_result_t res = lv_image_decoder_open(&decoder_dsc, dsc->src, NULL);
|
||||
if(res != LV_RESULT_OK) {
|
||||
LV_LOG_ERROR("Failed to open image");
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t img_w = dsc->header.w;
|
||||
int32_t img_h = dsc->header.h;
|
||||
|
||||
lv_area_t tile_area;
|
||||
if(lv_area_get_width(&dsc->image_area) >= 0) {
|
||||
tile_area = dsc->image_area;
|
||||
}
|
||||
else {
|
||||
tile_area = *coords;
|
||||
}
|
||||
lv_area_set_width(&tile_area, img_w);
|
||||
lv_area_set_height(&tile_area, img_h);
|
||||
|
||||
int32_t tile_x_start = tile_area.x1;
|
||||
|
||||
while(tile_area.y1 <= t->clip_area.y2) {
|
||||
while(tile_area.x1 <= t->clip_area.x2) {
|
||||
|
||||
lv_area_t clipped_img_area;
|
||||
if(lv_area_intersect(&clipped_img_area, &tile_area, &t->clip_area)) {
|
||||
_draw_nema_gfx_img(t, dsc, &tile_area);
|
||||
}
|
||||
|
||||
tile_area.x1 += img_w;
|
||||
tile_area.x2 += img_w;
|
||||
}
|
||||
|
||||
tile_area.y1 += img_h;
|
||||
tile_area.y2 += img_h;
|
||||
tile_area.x1 = tile_x_start;
|
||||
tile_area.x2 = tile_x_start + img_w - 1;
|
||||
}
|
||||
|
||||
lv_image_decoder_close(&decoder_dsc);
|
||||
}
|
||||
|
||||
static void _draw_nema_gfx_img(lv_draw_task_t * t, const lv_draw_image_dsc_t * dsc, const lv_area_t * coords)
|
||||
{
|
||||
if(dsc->opa <= LV_OPA_MIN) return;
|
||||
|
||||
lv_draw_nema_gfx_unit_t * draw_nema_gfx_unit = (lv_draw_nema_gfx_unit_t *)t->draw_unit;
|
||||
|
||||
lv_layer_t * layer = t->target_layer;
|
||||
const lv_image_dsc_t * img_dsc = dsc->src;
|
||||
|
||||
bool masked = dsc->bitmap_mask_src != NULL;
|
||||
|
||||
lv_area_t blend_area;
|
||||
/*Let's get the blend area which is the intersection of the area to fill and the clip area.*/
|
||||
if(!lv_area_intersect(&blend_area, coords, &t->clip_area))
|
||||
return; /*Fully clipped, nothing to do*/
|
||||
|
||||
lv_area_t rel_clip_area;
|
||||
lv_area_copy(&rel_clip_area, &t->clip_area);
|
||||
lv_area_move(&rel_clip_area, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
bool has_transform = (dsc->rotation != 0 || dsc->scale_x != LV_SCALE_NONE || dsc->scale_y != LV_SCALE_NONE);
|
||||
bool recolor = (dsc->recolor_opa > LV_OPA_MIN);
|
||||
|
||||
/*Make the blend area relative to the buffer*/
|
||||
lv_area_move(&blend_area, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
uint32_t tex_w = lv_area_get_width(coords);
|
||||
uint32_t tex_h = lv_area_get_height(coords);
|
||||
|
||||
nema_set_clip(rel_clip_area.x1, rel_clip_area.y1, lv_area_get_width(&rel_clip_area),
|
||||
lv_area_get_height(&rel_clip_area));
|
||||
|
||||
lv_color_format_t dst_cf = layer->draw_buf->header.cf;
|
||||
uint32_t dst_nema_cf = lv_nemagfx_cf_to_nema(dst_cf);
|
||||
|
||||
const void * src_buf = img_dsc->data;
|
||||
|
||||
uint32_t blending_mode = lv_nemagfx_blending_mode(dsc->blend_mode);
|
||||
|
||||
lv_color_format_t src_cf = img_dsc->header.cf;
|
||||
|
||||
/*Image contains Alpha*/
|
||||
if(src_cf == LV_COLOR_FORMAT_ARGB8888 || src_cf == LV_COLOR_FORMAT_XRGB8888) {
|
||||
blending_mode |= NEMA_BLOP_SRC_PREMULT;
|
||||
}
|
||||
|
||||
uint32_t src_nema_cf = lv_nemagfx_cf_to_nema(src_cf);
|
||||
/* the stride should be computed internally for NEMA_TSC images and images missing a stride value */
|
||||
int32_t src_stride = (src_cf >= LV_COLOR_FORMAT_NEMA_TSC_START && src_cf <= LV_COLOR_FORMAT_NEMA_TSC_END)
|
||||
|| img_dsc->header.stride == 0 ? -1 : (int32_t)img_dsc->header.stride;
|
||||
|
||||
int32_t stride = (dst_cf >= LV_COLOR_FORMAT_NEMA_TSC_START && dst_cf <= LV_COLOR_FORMAT_NEMA_TSC_END) ?
|
||||
-1 : lv_area_get_width(&(layer->buf_area)) * lv_color_format_get_size(dst_cf);
|
||||
|
||||
nema_bind_dst_tex((uintptr_t)NEMA_VIRT2PHYS(layer->draw_buf->data), lv_area_get_width(&(layer->buf_area)),
|
||||
lv_area_get_height(&(layer->buf_area)), dst_nema_cf, stride);
|
||||
|
||||
if(!LV_COLOR_FORMAT_IS_INDEXED(src_cf)) {
|
||||
nema_bind_src_tex((uintptr_t)(src_buf), tex_w, tex_h, src_nema_cf, src_stride,
|
||||
dsc->antialias ? NEMA_FILTER_BL : NEMA_FILTER_PS);
|
||||
}
|
||||
else {
|
||||
nema_bind_lut_tex((uintptr_t)((uint8_t *)src_buf + LV_COLOR_INDEXED_PALETTE_SIZE(src_cf) * 4), tex_w, tex_h,
|
||||
src_nema_cf, src_stride, NEMA_FILTER_PS, (uintptr_t)(src_buf), NEMA_BGRA8888);
|
||||
blending_mode |= NEMA_BLOP_LUT;
|
||||
}
|
||||
|
||||
/*Guard for previous NemaGFX Version*/
|
||||
#ifdef NEMA_BLOP_RECOLOR
|
||||
if(recolor) {
|
||||
lv_color32_t col32 = lv_color_to_32(dsc->recolor, LV_OPA_MIX2(dsc->recolor_opa, dsc->opa));
|
||||
uint32_t color = nema_rgba(col32.red, col32.green, col32.blue, col32.alpha);
|
||||
nema_set_recolor_color(color);
|
||||
blending_mode |= NEMA_BLOP_RECOLOR;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(dsc->opa < 255) {
|
||||
uint32_t rgba = ((uint32_t)dsc->opa << 24U) | ((uint32_t)dsc->opa << 16U) | ((uint32_t)dsc->opa << 8U) | ((
|
||||
uint32_t)dsc->opa);
|
||||
nema_set_const_color(rgba);
|
||||
blending_mode |= NEMA_BLOP_MODULATE_A;
|
||||
}
|
||||
|
||||
if(!has_transform && masked && !recolor) {
|
||||
if(dsc->bitmap_mask_src->header.cf == LV_COLOR_FORMAT_A8 || dsc->bitmap_mask_src->header.cf == LV_COLOR_FORMAT_L8) {
|
||||
blending_mode |= NEMA_BLOP_STENCIL_TXTY;
|
||||
const lv_image_dsc_t * mask = dsc->bitmap_mask_src;
|
||||
const void * mask_buf = mask->data;
|
||||
|
||||
const lv_area_t * image_area;
|
||||
lv_area_t mask_area;
|
||||
if(lv_area_get_width(&dsc->image_area) < 0) image_area = coords;
|
||||
else image_area = &dsc->image_area;
|
||||
|
||||
lv_area_set(&mask_area, 0, 0, dsc->bitmap_mask_src->header.w - 1, dsc->bitmap_mask_src->header.h - 1);
|
||||
lv_area_align(image_area, &mask_area, LV_ALIGN_CENTER, 0, 0);
|
||||
|
||||
mask_buf += dsc->bitmap_mask_src->header.w * (coords->y1 - mask_area.y1) + (coords->x1 - mask_area.x1);
|
||||
|
||||
nema_bind_tex(NEMA_TEX3, (uintptr_t)NEMA_VIRT2PHYS(mask_buf), mask->header.w, mask->header.h,
|
||||
lv_nemagfx_mask_cf_to_nema(mask->header.cf),
|
||||
mask->header.stride, NEMA_FILTER_BL);
|
||||
}
|
||||
}
|
||||
|
||||
nema_set_blend_blit(blending_mode);
|
||||
|
||||
if(!has_transform) {
|
||||
nema_blit_rect((coords->x1 - layer->buf_area.x1),
|
||||
(coords->y1 - layer->buf_area.y1), tex_w, tex_h);
|
||||
}
|
||||
else {
|
||||
/*Calculate the transformed points*/
|
||||
float x0 = (coords->x1 - layer->buf_area.x1);
|
||||
float y0 = (coords->y1 - layer->buf_area.y1);
|
||||
float x1 = x0 + tex_w ;
|
||||
float y1 = y0;
|
||||
float x2 = x0 + tex_w ;
|
||||
float y2 = y0 + tex_h;
|
||||
float x3 = x0 ;
|
||||
float y3 = y0 + tex_h;
|
||||
|
||||
nema_matrix3x3_t m;
|
||||
nema_mat3x3_load_identity(m);
|
||||
nema_mat3x3_translate(m, -x0, -y0);
|
||||
nema_mat3x3_translate(m, -(float)dsc->pivot.x, -(float)dsc->pivot.y);
|
||||
nema_mat3x3_rotate(m, (dsc->rotation / 10.0f)); /* angle is 1/10 degree */
|
||||
float scale_x = 1.f * dsc->scale_x / LV_SCALE_NONE;
|
||||
float scale_y = 1.f * dsc->scale_y / LV_SCALE_NONE;
|
||||
nema_mat3x3_scale(m, (float)scale_x, (float)scale_y);
|
||||
nema_mat3x3_translate(m, (float)dsc->pivot.x, (float)dsc->pivot.y);
|
||||
nema_mat3x3_translate(m, x0, y0);
|
||||
|
||||
/*Apply Transformation Matrix to Vertices*/
|
||||
nema_mat3x3_mul_vec(m, &x0, &y0);
|
||||
nema_mat3x3_mul_vec(m, &x1, &y1);
|
||||
nema_mat3x3_mul_vec(m, &x2, &y2);
|
||||
nema_mat3x3_mul_vec(m, &x3, &y3);
|
||||
|
||||
nema_blit_quad_fit(x0, y0,
|
||||
x1, y1,
|
||||
x2, y2,
|
||||
x3, y3);
|
||||
}
|
||||
|
||||
nema_cl_submit(&(draw_nema_gfx_unit->cl));
|
||||
|
||||
}
|
||||
|
||||
/*NemaGFX does mask operations with A8,A4,A2 and A1 formats*/
|
||||
static uint32_t lv_nemagfx_mask_cf_to_nema(lv_color_format_t cf)
|
||||
{
|
||||
switch(cf) {
|
||||
case LV_COLOR_FORMAT_A1:
|
||||
return NEMA_A1;
|
||||
case LV_COLOR_FORMAT_A2:
|
||||
return NEMA_A2;
|
||||
case LV_COLOR_FORMAT_A4:
|
||||
return NEMA_A4;
|
||||
case LV_COLOR_FORMAT_A8:
|
||||
case LV_COLOR_FORMAT_L8:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NEMA_A8;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
void lv_draw_nema_gfx_img(lv_draw_task_t * t, const lv_draw_image_dsc_t * dsc, const lv_area_t * coords)
|
||||
{
|
||||
|
||||
if(!dsc->tile) {
|
||||
_draw_nema_gfx_img(t, dsc, coords);
|
||||
}
|
||||
else {
|
||||
_draw_nema_gfx_tile(t, dsc, coords);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,850 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008-24 Think Silicon Single Member PC
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next paragraph)
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file lv_draw_nema_gfx_fill.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_nema_gfx.h"
|
||||
|
||||
#if LV_USE_NEMA_GFX
|
||||
#include "../../misc/lv_utils.h"
|
||||
#include "../../misc/lv_bidi_private.h"
|
||||
#include "../../misc/lv_text_private.h"
|
||||
#include "../../lvgl.h"
|
||||
#include "../../libs/freetype/lv_freetype_private.h"
|
||||
#include "../../core/lv_global.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LABEL_RECOLOR_PAR_LENGTH 6
|
||||
#define LV_LABEL_HINT_UPDATE_TH 1024 /*Update the "hint" if the label's y coordinates have changed more then this*/
|
||||
#define FT_F26DOT6_SHIFT 6
|
||||
#define NEMA_COORD_LIMIT 2046
|
||||
|
||||
#define font_draw_buf_handlers &(LV_GLOBAL_DEFAULT()->font_draw_buf_handlers)
|
||||
|
||||
/** After converting the font reference size, it is also necessary to scale the 26dot6 data
|
||||
* in the path to the real physical size
|
||||
*/
|
||||
#define FT_F26DOT6_TO_PATH_SCALE(x) (LV_FREETYPE_F26DOT6_TO_FLOAT(x) / (1 << FT_F26DOT6_SHIFT))
|
||||
|
||||
/*Forward declarations*/
|
||||
void nema_set_matrix(nema_matrix3x3_t m);
|
||||
void nema_raster_rect(int x, int y, int w, int h);
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
enum {
|
||||
RECOLOR_CMD_STATE_WAIT_FOR_PARAMETER,
|
||||
RECOLOR_CMD_STATE_PARAMETER,
|
||||
RECOLOR_CMD_STATE_TEXT_INPUT,
|
||||
};
|
||||
typedef unsigned char cmd_state_t;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static void _draw_nema_gfx_letter(lv_draw_task_t * t, lv_draw_glyph_dsc_t * glyph_draw_dsc,
|
||||
lv_draw_fill_dsc_t * fill_draw_dsc, const lv_area_t * fill_area);
|
||||
|
||||
static void _draw_label_iterate_characters(lv_draw_task_t * t, const lv_draw_label_dsc_t * dsc,
|
||||
const lv_area_t * coords);
|
||||
|
||||
static inline uint8_t _bpp_nema_gfx_format(lv_draw_glyph_dsc_t * glyph_draw_dsc);
|
||||
|
||||
static void _draw_letter(lv_draw_task_t * t, lv_draw_glyph_dsc_t * dsc, const lv_point_t * pos,
|
||||
const lv_font_t * font, uint32_t letter);
|
||||
|
||||
static uint8_t hex_char_to_num(char hex);
|
||||
|
||||
static bool is_raw_bitmap;
|
||||
|
||||
#if LV_USE_FREETYPE && LV_USE_NEMA_VG
|
||||
|
||||
#include "lv_nema_gfx_path.h"
|
||||
|
||||
static void _draw_nema_gfx_outline(lv_draw_task_t * t, lv_draw_glyph_dsc_t * glyph_draw_dsc);
|
||||
|
||||
static void freetype_outline_event_cb(lv_event_t * e);
|
||||
|
||||
static void lv_nema_gfx_outline_push(const lv_freetype_outline_event_param_t * param);
|
||||
|
||||
static void lv_nema_outline_event_alloc(const lv_freetype_outline_event_param_t * param);
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
void lv_draw_nema_gfx_label_init(lv_draw_unit_t * draw_unit)
|
||||
{
|
||||
#if LV_USE_FREETYPE
|
||||
/*Set up the freetype outline event*/
|
||||
lv_freetype_outline_add_event(freetype_outline_event_cb, LV_EVENT_ALL, draw_unit);
|
||||
#else
|
||||
LV_UNUSED(draw_unit);
|
||||
#endif /* LV_USE_FREETYPE */
|
||||
}
|
||||
|
||||
void lv_draw_nema_gfx_label(lv_draw_task_t * t, const lv_draw_label_dsc_t * dsc, const lv_area_t * coords)
|
||||
{
|
||||
if(dsc->opa <= LV_OPA_MIN) return;
|
||||
|
||||
lv_layer_t * layer = t->target_layer;
|
||||
|
||||
lv_area_t clip_area;
|
||||
lv_area_copy(&clip_area, &t->clip_area);
|
||||
lv_area_move(&clip_area, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
lv_color_format_t dst_cf = layer->draw_buf->header.cf;
|
||||
uint32_t dst_nema_cf = lv_nemagfx_cf_to_nema(dst_cf);
|
||||
|
||||
int32_t stride = (dst_cf >= LV_COLOR_FORMAT_NEMA_TSC_START && dst_cf <= LV_COLOR_FORMAT_NEMA_TSC_END) ?
|
||||
-1 : lv_area_get_width(&(layer->buf_area)) * lv_color_format_get_size(dst_cf);
|
||||
|
||||
nema_bind_dst_tex((uintptr_t)NEMA_VIRT2PHYS(layer->draw_buf->data), lv_area_get_width(&(layer->buf_area)),
|
||||
lv_area_get_height(&(layer->buf_area)), dst_nema_cf, stride);
|
||||
|
||||
nema_set_clip(clip_area.x1, clip_area.y1, lv_area_get_width(&clip_area), lv_area_get_height(&clip_area));
|
||||
|
||||
_draw_label_iterate_characters(t, dsc, coords);
|
||||
|
||||
lv_draw_nema_gfx_unit_t * draw_nema_gfx_unit = (lv_draw_nema_gfx_unit_t *)t->draw_unit;
|
||||
nema_cl_submit(&(draw_nema_gfx_unit->cl));
|
||||
nema_cl_wait(&(draw_nema_gfx_unit->cl));
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
#if LV_USE_FREETYPE && LV_USE_NEMA_VG
|
||||
|
||||
static void _draw_nema_gfx_outline(lv_draw_task_t * t, lv_draw_glyph_dsc_t * glyph_draw_dsc)
|
||||
{
|
||||
|
||||
lv_area_t blend_area;
|
||||
if(!_lv_area_intersect(&blend_area, glyph_draw_dsc->letter_coords, &t->clip_area))
|
||||
return;
|
||||
|
||||
lv_draw_nema_gfx_unit_t * draw_nema_gfx_unit = (lv_draw_nema_gfx_unit_t *)t->draw_unit;
|
||||
|
||||
lv_nema_gfx_path_t * nema_gfx_path = (lv_nema_gfx_path_t *)glyph_draw_dsc->glyph_data;
|
||||
|
||||
lv_point_t pos = {glyph_draw_dsc->letter_coords->x1, glyph_draw_dsc->letter_coords->y1};
|
||||
|
||||
float scale = FT_F26DOT6_TO_PATH_SCALE(lv_freetype_outline_get_scale(glyph_draw_dsc->g->resolved_font));
|
||||
|
||||
/*Calculate Path Matrix*/
|
||||
nema_matrix3x3_t matrix;
|
||||
nema_mat3x3_load_identity(matrix);
|
||||
nema_mat3x3_scale(matrix, scale, -scale);
|
||||
nema_mat3x3_translate(matrix, pos.x - glyph_draw_dsc->g->ofs_x,
|
||||
pos.y + glyph_draw_dsc->g->box_h + glyph_draw_dsc->g->ofs_y);
|
||||
|
||||
nema_vg_path_clear(nema_gfx_path->path);
|
||||
nema_vg_paint_clear(nema_gfx_path->paint);
|
||||
|
||||
nema_vg_set_fill_rule(NEMA_VG_FILL_EVEN_ODD);
|
||||
|
||||
nema_vg_path_set_shape(nema_gfx_path->path, nema_gfx_path->seg_size, nema_gfx_path->seg, nema_gfx_path->data_size,
|
||||
nema_gfx_path->data);
|
||||
|
||||
nema_vg_paint_set_type(nema_gfx_path->paint, NEMA_VG_PAINT_COLOR);
|
||||
|
||||
lv_color32_t dsc_col32 = lv_color_to_32(glyph_draw_dsc->color, glyph_draw_dsc->opa);
|
||||
uint32_t nema_dsc_color = nema_rgba(dsc_col32.red, dsc_col32.green, dsc_col32.blue, dsc_col32.alpha);
|
||||
|
||||
nema_vg_paint_set_paint_color(nema_gfx_path->paint, nema_dsc_color);
|
||||
|
||||
nema_vg_path_set_matrix(nema_gfx_path->path, matrix);
|
||||
nema_vg_draw_path(nema_gfx_path->path, nema_gfx_path->paint);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void freetype_outline_event_cb(lv_event_t * e)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
lv_event_code_t code = lv_event_get_code(e);
|
||||
lv_freetype_outline_event_param_t * param = lv_event_get_param(e);
|
||||
|
||||
switch(code) {
|
||||
case LV_EVENT_CREATE:
|
||||
param->outline = lv_nema_gfx_path_create();
|
||||
lv_nema_outline_event_alloc(param);
|
||||
break;
|
||||
case LV_EVENT_DELETE:
|
||||
lv_nema_gfx_path_destroy(param->outline);
|
||||
break;
|
||||
case LV_EVENT_INSERT:
|
||||
lv_nema_gfx_outline_push(param);
|
||||
break;
|
||||
default:
|
||||
LV_LOG_WARN("unknown event code: %d", code);
|
||||
break;
|
||||
}
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
static void lv_nema_gfx_outline_push(const lv_freetype_outline_event_param_t * param)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
lv_nema_gfx_path_t * outline = param->outline;
|
||||
LV_ASSERT_NULL(outline);
|
||||
|
||||
lv_freetype_outline_type_t type = param->type;
|
||||
switch(type) {
|
||||
case LV_FREETYPE_OUTLINE_END:
|
||||
lv_nema_gfx_path_end(outline);
|
||||
break;
|
||||
case LV_FREETYPE_OUTLINE_MOVE_TO:
|
||||
lv_nema_gfx_path_move_to(outline, param->to.x, param->to.y);
|
||||
break;
|
||||
case LV_FREETYPE_OUTLINE_LINE_TO:
|
||||
lv_nema_gfx_path_line_to(outline, param->to.x, param->to.y);
|
||||
break;
|
||||
case LV_FREETYPE_OUTLINE_CUBIC_TO:
|
||||
lv_nema_gfx_path_cubic_to(outline, param->control1.x, param->control1.y,
|
||||
param->control2.x, param->control2.y,
|
||||
param->to.x, param->to.y);
|
||||
break;
|
||||
case LV_FREETYPE_OUTLINE_CONIC_TO:
|
||||
lv_nema_gfx_path_quad_to(outline, param->control1.x, param->control1.y,
|
||||
param->to.x, param->to.y);
|
||||
break;
|
||||
default:
|
||||
LV_LOG_ERROR("unknown point type: %d", type);
|
||||
LV_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
static void lv_nema_outline_event_alloc(const lv_freetype_outline_event_param_t * param)
|
||||
{
|
||||
lv_nema_gfx_path_t * outline = param->outline;
|
||||
outline->data_size = param->sizes.data_size;
|
||||
outline->seg_size = param->sizes.segments_size;
|
||||
lv_nema_gfx_path_alloc(outline);
|
||||
}
|
||||
|
||||
#endif /* LV_USE_FREETYPE && LV_USE_NEMA_VG */
|
||||
|
||||
/**
|
||||
* Convert a hexadecimal characters to a number (0..15)
|
||||
* @param hex Pointer to a hexadecimal character (0..9, A..F)
|
||||
* @return the numerical value of `hex` or 0 on error
|
||||
*/
|
||||
static uint8_t hex_char_to_num(char hex)
|
||||
{
|
||||
if(hex >= '0' && hex <= '9') return hex - '0';
|
||||
if(hex >= 'a') hex -= 'a' - 'A'; /*Convert to upper case*/
|
||||
return 'A' <= hex && hex <= 'F' ? hex - 'A' + 10 : 0;
|
||||
}
|
||||
|
||||
|
||||
static inline uint8_t _bpp_nema_gfx_format(lv_draw_glyph_dsc_t * glyph_draw_dsc)
|
||||
{
|
||||
uint32_t format = glyph_draw_dsc->g->format;
|
||||
|
||||
switch(format) {
|
||||
case LV_FONT_GLYPH_FORMAT_A1:
|
||||
return NEMA_A1;
|
||||
case LV_FONT_GLYPH_FORMAT_A2:
|
||||
return NEMA_A2;
|
||||
case LV_FONT_GLYPH_FORMAT_A4:
|
||||
return NEMA_A4;
|
||||
case LV_FONT_GLYPH_FORMAT_A8:
|
||||
default:
|
||||
return NEMA_A8;
|
||||
}
|
||||
}
|
||||
|
||||
static void _draw_nema_gfx_letter(lv_draw_task_t * t, lv_draw_glyph_dsc_t * glyph_draw_dsc,
|
||||
lv_draw_fill_dsc_t * fill_draw_dsc, const lv_area_t * fill_area)
|
||||
{
|
||||
if(glyph_draw_dsc) {
|
||||
if(glyph_draw_dsc->format == LV_FONT_GLYPH_FORMAT_NONE) {
|
||||
#if LV_USE_FONT_PLACEHOLDER
|
||||
/* Draw a placeholder rectangle*/
|
||||
lv_draw_border_dsc_t border_draw_dsc;
|
||||
lv_draw_border_dsc_init(&border_draw_dsc);
|
||||
border_draw_dsc.opa = glyph_draw_dsc->opa;
|
||||
border_draw_dsc.color = glyph_draw_dsc->color;
|
||||
border_draw_dsc.width = 1;
|
||||
lv_draw_nema_gfx_border(t, &border_draw_dsc, glyph_draw_dsc->bg_coords);
|
||||
#endif
|
||||
}
|
||||
else if(glyph_draw_dsc->format >= LV_FONT_GLYPH_FORMAT_A1 &&
|
||||
glyph_draw_dsc->format <= LV_FONT_GLYPH_FORMAT_A8) {
|
||||
/*Do not draw transparent things*/
|
||||
if(glyph_draw_dsc->opa <= LV_OPA_MIN)
|
||||
return;
|
||||
|
||||
lv_layer_t * layer = t->target_layer;
|
||||
|
||||
lv_area_t blend_area;
|
||||
if(!lv_area_intersect(&blend_area, glyph_draw_dsc->letter_coords, &t->clip_area))
|
||||
return;
|
||||
|
||||
const lv_draw_buf_t * draw_buf = glyph_draw_dsc->glyph_data;
|
||||
const void * mask_buf;
|
||||
uint32_t src_cf;
|
||||
lv_area_t mask_area = *glyph_draw_dsc->letter_coords;
|
||||
|
||||
lv_area_t rel_coords;
|
||||
lv_area_copy(&rel_coords, &blend_area);
|
||||
lv_area_move(&rel_coords, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
int32_t x, y, w, h;
|
||||
|
||||
/*Read the static font*/
|
||||
if(is_raw_bitmap) {
|
||||
mask_buf = glyph_draw_dsc->glyph_data;
|
||||
src_cf = _bpp_nema_gfx_format(glyph_draw_dsc);
|
||||
x = glyph_draw_dsc->letter_coords->x1 - layer->buf_area.x1;
|
||||
y = glyph_draw_dsc->letter_coords->y1 - layer->buf_area.y1;
|
||||
w = glyph_draw_dsc->g->box_w;
|
||||
h = glyph_draw_dsc->g->box_h;
|
||||
}
|
||||
/*Read the draw buffer*/
|
||||
else {
|
||||
mask_buf = draw_buf->data;
|
||||
src_cf = lv_nemagfx_cf_to_nema(draw_buf->header.cf);
|
||||
mask_area.x2 = mask_area.x1 + lv_draw_buf_width_to_stride(lv_area_get_width(&mask_area), LV_COLOR_FORMAT_A8) - 1;
|
||||
mask_buf += draw_buf->header.stride * (blend_area.y1 - mask_area.y1) + (blend_area.x1 - mask_area.x1);
|
||||
x = rel_coords.x1;
|
||||
y = rel_coords.y1;
|
||||
w = lv_area_get_width(&rel_coords);
|
||||
h = lv_area_get_height(&rel_coords);
|
||||
}
|
||||
|
||||
if(is_raw_bitmap && (glyph_draw_dsc->format <= LV_FONT_GLYPH_FORMAT_A4)) {
|
||||
nema_bind_src_tex((uintptr_t)(mask_buf), w * h, 1, src_cf, glyph_draw_dsc->g->stride, NEMA_FILTER_PS);
|
||||
nema_matrix3x3_t m = {
|
||||
{1, w, -x - (y * w) - (0.5 * w)},
|
||||
{0, 1, 0},
|
||||
{0, 0, 1}
|
||||
};
|
||||
nema_set_matrix(m);
|
||||
nema_raster_rect(x, y, w, h);
|
||||
}
|
||||
else {
|
||||
nema_bind_src_tex((uintptr_t)(mask_buf), lv_area_get_width(&mask_area), lv_area_get_height(&mask_area), src_cf,
|
||||
glyph_draw_dsc->g->stride ? glyph_draw_dsc->g->stride : lv_area_get_width(&mask_area),
|
||||
NEMA_FILTER_BL);
|
||||
nema_blit_rect(x, y, w, h);
|
||||
lv_draw_nema_gfx_unit_t * draw_nema_gfx_unit = (lv_draw_nema_gfx_unit_t *)t->draw_unit;
|
||||
nema_cl_submit(&(draw_nema_gfx_unit->cl));
|
||||
nema_cl_wait(&(draw_nema_gfx_unit->cl));
|
||||
}
|
||||
}
|
||||
else if(glyph_draw_dsc->format == LV_FONT_GLYPH_FORMAT_IMAGE) {
|
||||
#if LV_USE_IMGFONT
|
||||
lv_draw_img_dsc_t img_dsc;
|
||||
lv_draw_img_dsc_init(&img_dsc);
|
||||
img_dsc.angle = 0;
|
||||
img_dsc.zoom = LV_ZOOM_NONE;
|
||||
img_dsc.opa = glyph_draw_dsc->opa;
|
||||
img_dsc.src = glyph_draw_dsc->glyph_data;
|
||||
lv_draw_nema_gfx_img(t, &img_dsc, glyph_draw_dsc->letter_coords);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if LV_USE_FREETYPE && LV_USE_NEMA_VG
|
||||
else if(glyph_draw_dsc->format == LV_FONT_GLYPH_FORMAT_VECTOR) {
|
||||
if(lv_freetype_is_outline_font(glyph_draw_dsc->g->resolved_font)) {
|
||||
_draw_nema_gfx_outline(t, glyph_draw_dsc);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
if(fill_draw_dsc && fill_area) {
|
||||
lv_draw_nema_gfx_fill(t, fill_draw_dsc, fill_area);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static inline void _set_color_blend(uint32_t color, uint8_t alpha)
|
||||
{
|
||||
nema_set_tex_color(color);
|
||||
|
||||
if(alpha < 255U) {
|
||||
nema_set_blend_blit(NEMA_BL_SIMPLE | NEMA_BLOP_MODULATE_A);
|
||||
nema_set_const_color(color);
|
||||
}
|
||||
else {
|
||||
nema_set_blend_blit(NEMA_BL_SIMPLE);
|
||||
}
|
||||
}
|
||||
|
||||
static void _draw_label_iterate_characters(lv_draw_task_t * t, const lv_draw_label_dsc_t * dsc,
|
||||
const lv_area_t * coords)
|
||||
{
|
||||
const lv_font_t * font = dsc->font;
|
||||
int32_t w;
|
||||
|
||||
lv_area_t clipped_area;
|
||||
bool clip_ok = lv_area_intersect(&clipped_area, coords, &t->clip_area);
|
||||
if(!clip_ok) return;
|
||||
|
||||
lv_text_align_t align = dsc->align;
|
||||
lv_base_dir_t base_dir = dsc->bidi_dir;
|
||||
|
||||
lv_bidi_calculate_align(&align, &base_dir, dsc->text);
|
||||
|
||||
if((dsc->flag & LV_TEXT_FLAG_EXPAND) == 0) {
|
||||
/*Normally use the label's width as width*/
|
||||
w = lv_area_get_width(coords);
|
||||
}
|
||||
else {
|
||||
/*If EXPAND is enabled then not limit the text's width to the object's width*/
|
||||
lv_point_t p;
|
||||
lv_text_get_size(&p, dsc->text, dsc->font, dsc->letter_space, dsc->line_space, LV_COORD_MAX,
|
||||
dsc->flag);
|
||||
w = p.x;
|
||||
}
|
||||
|
||||
int32_t line_height_font = lv_font_get_line_height(font);
|
||||
int32_t line_height = line_height_font + dsc->line_space;
|
||||
|
||||
/*Init variables for the first line*/
|
||||
int32_t line_width = 0;
|
||||
lv_point_t pos;
|
||||
lv_point_set(&pos, coords->x1, coords->y1);
|
||||
|
||||
int32_t x_ofs = 0;
|
||||
int32_t y_ofs = 0;
|
||||
x_ofs = dsc->ofs_x;
|
||||
y_ofs = dsc->ofs_y;
|
||||
pos.y += y_ofs;
|
||||
|
||||
uint32_t line_start = 0;
|
||||
int32_t last_line_start = -1;
|
||||
|
||||
/*Check the hint to use the cached info*/
|
||||
if(dsc->hint && y_ofs == 0 && coords->y1 < 0) {
|
||||
/*If the label changed too much recalculate the hint.*/
|
||||
if(LV_ABS(dsc->hint->coord_y - coords->y1) > LV_LABEL_HINT_UPDATE_TH - 2 * line_height) {
|
||||
dsc->hint->line_start = -1;
|
||||
}
|
||||
last_line_start = dsc->hint->line_start;
|
||||
}
|
||||
|
||||
/*Use the hint if it's valid*/
|
||||
if(dsc->hint && last_line_start >= 0) {
|
||||
line_start = last_line_start;
|
||||
pos.y += dsc->hint->y;
|
||||
}
|
||||
|
||||
uint32_t remaining_len = dsc->text_length;
|
||||
|
||||
uint32_t line_end = line_start + lv_text_get_next_line(&dsc->text[line_start], remaining_len, font, dsc->letter_space,
|
||||
w, NULL, dsc->flag);
|
||||
|
||||
/*Go the first visible line*/
|
||||
while(pos.y + line_height_font < t->clip_area.y1) {
|
||||
/*Go to next line*/
|
||||
line_start = line_end;
|
||||
line_end += lv_text_get_next_line(&dsc->text[line_start], remaining_len, font, dsc->letter_space, w, NULL, dsc->flag);
|
||||
pos.y += line_height;
|
||||
|
||||
/*Save at the threshold coordinate*/
|
||||
if(dsc->hint && pos.y >= -LV_LABEL_HINT_UPDATE_TH && dsc->hint->line_start < 0) {
|
||||
dsc->hint->line_start = line_start;
|
||||
dsc->hint->y = pos.y - coords->y1;
|
||||
dsc->hint->coord_y = coords->y1;
|
||||
}
|
||||
|
||||
if(dsc->text[line_start] == '\0') return;
|
||||
}
|
||||
|
||||
/*Align to middle*/
|
||||
if(align == LV_TEXT_ALIGN_CENTER) {
|
||||
line_width = lv_text_get_width_with_flags(&dsc->text[line_start], line_end - line_start, font, dsc->letter_space,
|
||||
dsc->flag);
|
||||
|
||||
pos.x += (lv_area_get_width(coords) - line_width) / 2;
|
||||
|
||||
}
|
||||
/*Align to the right*/
|
||||
else if(align == LV_TEXT_ALIGN_RIGHT) {
|
||||
line_width = lv_text_get_width_with_flags(&dsc->text[line_start], line_end - line_start, font, dsc->letter_space,
|
||||
dsc->flag);
|
||||
pos.x += lv_area_get_width(coords) - line_width;
|
||||
}
|
||||
|
||||
uint32_t sel_start = dsc->sel_start;
|
||||
uint32_t sel_end = dsc->sel_end;
|
||||
if(sel_start > sel_end) {
|
||||
uint32_t tmp = sel_start;
|
||||
sel_start = sel_end;
|
||||
sel_end = tmp;
|
||||
}
|
||||
|
||||
lv_area_t bg_coords;
|
||||
lv_draw_glyph_dsc_t draw_letter_dsc;
|
||||
lv_draw_glyph_dsc_init(&draw_letter_dsc);
|
||||
draw_letter_dsc.opa = dsc->opa;
|
||||
draw_letter_dsc.bg_coords = &bg_coords;
|
||||
draw_letter_dsc.color = dsc->color;
|
||||
draw_letter_dsc.rotation = dsc->rotation;
|
||||
|
||||
lv_draw_fill_dsc_t fill_dsc;
|
||||
lv_draw_fill_dsc_init(&fill_dsc);
|
||||
fill_dsc.opa = dsc->opa;
|
||||
int32_t underline_width = font->underline_thickness ? font->underline_thickness : 1;
|
||||
int32_t line_start_x;
|
||||
uint32_t next_char_offset;
|
||||
uint32_t recolor_command_start_index = 0;
|
||||
int32_t letter_w;
|
||||
cmd_state_t recolor_cmd_state = RECOLOR_CMD_STATE_WAIT_FOR_PARAMETER;
|
||||
lv_color_t recolor = lv_color_black(); /* Holds the selected color inside the recolor command */
|
||||
uint8_t is_first_space_after_cmd = 0;
|
||||
|
||||
lv_color32_t dsc_col32 = lv_color_to_32(dsc->color, dsc->opa);
|
||||
uint32_t nema_dsc_color = nema_rgba(dsc_col32.red, dsc_col32.green, dsc_col32.blue, dsc_col32.alpha);
|
||||
lv_color32_t dsc_sel_col32 = lv_color_to_32(dsc->sel_color, dsc->opa);
|
||||
uint32_t nema_dsc_sel_color = nema_rgba(dsc_sel_col32.red, dsc_sel_col32.green, dsc_sel_col32.blue,
|
||||
dsc_sel_col32.alpha);
|
||||
uint32_t blend_color;
|
||||
uint8_t blend_alpha = 255;
|
||||
|
||||
_set_color_blend(nema_dsc_color, dsc_col32.alpha);
|
||||
|
||||
uint8_t cur_state = 2;
|
||||
uint8_t prev_state = 2;
|
||||
|
||||
/*Write out all lines*/
|
||||
while(remaining_len && dsc->text[line_start] != '\0') {
|
||||
pos.x += x_ofs;
|
||||
line_start_x = pos.x;
|
||||
|
||||
/*Write all letter of a line*/
|
||||
recolor_cmd_state = RECOLOR_CMD_STATE_WAIT_FOR_PARAMETER;
|
||||
next_char_offset = 0;
|
||||
#if LV_USE_BIDI
|
||||
char * bidi_txt = lv_malloc(line_end - line_start + 1);
|
||||
LV_ASSERT_MALLOC(bidi_txt);
|
||||
lv_bidi_process_paragraph(dsc->text + line_start, bidi_txt, line_end - line_start, base_dir, NULL, 0);
|
||||
#else
|
||||
const char * bidi_txt = dsc->text + line_start;
|
||||
#endif
|
||||
|
||||
while(next_char_offset < remaining_len && next_char_offset < line_end - line_start) {
|
||||
uint32_t logical_char_pos = 0;
|
||||
|
||||
/* Check if the text selection is enabled */
|
||||
if(sel_start != LV_DRAW_LABEL_NO_TXT_SEL && sel_end != LV_DRAW_LABEL_NO_TXT_SEL) {
|
||||
#if LV_USE_BIDI
|
||||
logical_char_pos = lv_text_encoded_get_char_id(dsc->text, line_start);
|
||||
uint32_t c_idx = lv_text_encoded_get_char_id(bidi_txt, next_char_offset);
|
||||
logical_char_pos += lv_bidi_get_logical_pos(bidi_txt, NULL, line_end - line_start, base_dir, c_idx, NULL);
|
||||
#else
|
||||
logical_char_pos = lv_text_encoded_get_char_id(dsc->text, line_start + next_char_offset);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t letter;
|
||||
uint32_t letter_next;
|
||||
lv_text_encoded_letter_next_2(bidi_txt, &letter, &letter_next, &next_char_offset);
|
||||
|
||||
/* If recolor is enabled */
|
||||
if((dsc->flag & LV_TEXT_FLAG_RECOLOR) != 0) {
|
||||
|
||||
if(letter == (uint32_t)LV_TXT_COLOR_CMD[0]) {
|
||||
/* Handle the recolor command marker depending of the current recolor state */
|
||||
|
||||
if(recolor_cmd_state == RECOLOR_CMD_STATE_WAIT_FOR_PARAMETER) {
|
||||
recolor_command_start_index = next_char_offset;
|
||||
recolor_cmd_state = RECOLOR_CMD_STATE_PARAMETER;
|
||||
continue;
|
||||
}
|
||||
/*Other start char in parameter escaped cmd. char*/
|
||||
else if(recolor_cmd_state == RECOLOR_CMD_STATE_PARAMETER) {
|
||||
recolor_cmd_state = RECOLOR_CMD_STATE_WAIT_FOR_PARAMETER;
|
||||
}
|
||||
/* If letter is LV_TXT_COLOR_CMD and we were in the CMD_STATE_IN then the recolor close marked has been found */
|
||||
else if(recolor_cmd_state == RECOLOR_CMD_STATE_TEXT_INPUT) {
|
||||
recolor_cmd_state = RECOLOR_CMD_STATE_WAIT_FOR_PARAMETER;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find the first space (aka ' ') after the recolor command parameter, we need to skip rendering it */
|
||||
if((recolor_cmd_state == RECOLOR_CMD_STATE_PARAMETER) && (letter == ' ') && (is_first_space_after_cmd == 0)) {
|
||||
is_first_space_after_cmd = 1;
|
||||
}
|
||||
else {
|
||||
is_first_space_after_cmd = 0;
|
||||
}
|
||||
|
||||
/* Skip the color parameter and wait the space after it
|
||||
* Once we have reach the space ' ', then we will extract the color information
|
||||
* and store it into the recolor variable */
|
||||
if(recolor_cmd_state == RECOLOR_CMD_STATE_PARAMETER) {
|
||||
/* Not an space? Continue with the next character */
|
||||
if(letter != ' ') {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*Get the recolor parameter*/
|
||||
if((next_char_offset - recolor_command_start_index) == LABEL_RECOLOR_PAR_LENGTH + 1) {
|
||||
/* Temporary buffer to hold the recolor information */
|
||||
char buf[LABEL_RECOLOR_PAR_LENGTH + 1];
|
||||
lv_memcpy(buf, &bidi_txt[recolor_command_start_index], LABEL_RECOLOR_PAR_LENGTH);
|
||||
buf[LABEL_RECOLOR_PAR_LENGTH] = '\0';
|
||||
|
||||
uint8_t r, g, b;
|
||||
r = (hex_char_to_num(buf[0]) << 4) + hex_char_to_num(buf[1]);
|
||||
g = (hex_char_to_num(buf[2]) << 4) + hex_char_to_num(buf[3]);
|
||||
b = (hex_char_to_num(buf[4]) << 4) + hex_char_to_num(buf[5]);
|
||||
|
||||
recolor = lv_color_make(r, g, b);
|
||||
}
|
||||
else {
|
||||
recolor.red = dsc->color.red;
|
||||
recolor.blue = dsc->color.blue;
|
||||
recolor.green = dsc->color.green;
|
||||
}
|
||||
|
||||
/*After the parameter the text is in the command*/
|
||||
recolor_cmd_state = RECOLOR_CMD_STATE_TEXT_INPUT;
|
||||
}
|
||||
|
||||
/* Don't draw the first space after the recolor command */
|
||||
if(is_first_space_after_cmd) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we're in the CMD_STATE_IN state then we need to subtract the recolor command length */
|
||||
if(((dsc->flag & LV_TEXT_FLAG_RECOLOR) != 0) && (recolor_cmd_state == RECOLOR_CMD_STATE_TEXT_INPUT)) {
|
||||
logical_char_pos -= (LABEL_RECOLOR_PAR_LENGTH + 1);
|
||||
}
|
||||
|
||||
letter_w = lv_font_get_glyph_width(font, letter, letter_next);
|
||||
|
||||
/*Always set the bg_coordinates for placeholder drawing*/
|
||||
bg_coords.x1 = pos.x;
|
||||
bg_coords.y1 = pos.y;
|
||||
bg_coords.x2 = pos.x + letter_w - 1;
|
||||
bg_coords.y2 = pos.y + line_height - 1;
|
||||
|
||||
if(next_char_offset >= line_end - line_start) {
|
||||
if(dsc->decor & LV_TEXT_DECOR_UNDERLINE) {
|
||||
lv_area_t fill_area;
|
||||
fill_area.x1 = line_start_x;
|
||||
fill_area.x2 = pos.x + letter_w - 1;
|
||||
fill_area.y1 = pos.y + font->line_height - font->base_line - font->underline_position;
|
||||
fill_area.y2 = fill_area.y1 + underline_width - 1;
|
||||
|
||||
fill_dsc.color = dsc->color;
|
||||
lv_draw_nema_gfx_fill(t, &fill_dsc, &fill_area);
|
||||
}
|
||||
if(dsc->decor & LV_TEXT_DECOR_STRIKETHROUGH) {
|
||||
lv_area_t fill_area;
|
||||
fill_area.x1 = line_start_x;
|
||||
fill_area.x2 = pos.x + letter_w - 1;
|
||||
fill_area.y1 = pos.y + (font->line_height - font->base_line) * 2 / 3 + font->underline_thickness / 2;
|
||||
fill_area.y2 = fill_area.y1 + underline_width - 1;
|
||||
|
||||
fill_dsc.color = dsc->color;
|
||||
lv_draw_nema_gfx_fill(t, &fill_dsc, &fill_area);
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle text selection */
|
||||
if(sel_start != LV_DRAW_LABEL_NO_TXT_SEL && sel_end != LV_DRAW_LABEL_NO_TXT_SEL
|
||||
&& logical_char_pos >= sel_start && logical_char_pos < sel_end) {
|
||||
draw_letter_dsc.color = dsc->sel_color;
|
||||
fill_dsc.color = dsc->sel_bg_color;
|
||||
lv_draw_nema_gfx_fill(t, &fill_dsc, &bg_coords);
|
||||
cur_state = 0 ;
|
||||
blend_alpha = dsc_sel_col32.alpha;
|
||||
blend_color = nema_dsc_sel_color;
|
||||
}
|
||||
else if(recolor_cmd_state == RECOLOR_CMD_STATE_TEXT_INPUT) {
|
||||
draw_letter_dsc.color = recolor;
|
||||
cur_state = 1 ;
|
||||
blend_alpha = dsc_col32.alpha;
|
||||
lv_color32_t dsc_recolor_col32 = lv_color_to_32(recolor, dsc->opa);
|
||||
blend_color = nema_rgba(dsc_recolor_col32.red, dsc_recolor_col32.green, dsc_recolor_col32.blue,
|
||||
dsc_recolor_col32.alpha);
|
||||
}
|
||||
else {
|
||||
draw_letter_dsc.color = dsc->color;
|
||||
cur_state = 2;
|
||||
blend_alpha = dsc_col32.alpha;
|
||||
blend_color = nema_dsc_color;
|
||||
}
|
||||
|
||||
if(cur_state != prev_state) {
|
||||
_set_color_blend(blend_color, blend_alpha);
|
||||
prev_state = cur_state;
|
||||
}
|
||||
|
||||
_draw_letter(t, &draw_letter_dsc, &pos, font, letter);
|
||||
|
||||
if(letter_w > 0) {
|
||||
pos.x += letter_w + dsc->letter_space;
|
||||
}
|
||||
}
|
||||
|
||||
#if LV_USE_BIDI
|
||||
lv_free(bidi_txt);
|
||||
bidi_txt = NULL;
|
||||
#endif
|
||||
/*Go to next line*/
|
||||
remaining_len -= line_end - line_start;
|
||||
line_start = line_end;
|
||||
if(remaining_len) {
|
||||
line_end += lv_text_get_next_line(&dsc->text[line_start], remaining_len, font, dsc->letter_space, w, NULL, dsc->flag);
|
||||
}
|
||||
|
||||
pos.x = coords->x1;
|
||||
/*Align to middle*/
|
||||
if(align == LV_TEXT_ALIGN_CENTER) {
|
||||
line_width =
|
||||
lv_text_get_width_with_flags(&dsc->text[line_start], line_end - line_start, font, dsc->letter_space, dsc->flag);
|
||||
|
||||
pos.x += (lv_area_get_width(coords) - line_width) / 2;
|
||||
}
|
||||
/*Align to the right*/
|
||||
else if(align == LV_TEXT_ALIGN_RIGHT) {
|
||||
line_width =
|
||||
lv_text_get_width_with_flags(&dsc->text[line_start], line_end - line_start, font, dsc->letter_space, dsc->flag);
|
||||
pos.x += lv_area_get_width(coords) - line_width;
|
||||
}
|
||||
|
||||
/*Go the next line position*/
|
||||
pos.y += line_height;
|
||||
|
||||
if(pos.y > t->clip_area.y2) break;
|
||||
}
|
||||
|
||||
if(draw_letter_dsc._draw_buf) lv_draw_buf_destroy(draw_letter_dsc._draw_buf);
|
||||
|
||||
LV_ASSERT_MEM_INTEGRITY();
|
||||
}
|
||||
|
||||
static void _draw_letter(lv_draw_task_t * t, lv_draw_glyph_dsc_t * dsc, const lv_point_t * pos,
|
||||
const lv_font_t * font, uint32_t letter)
|
||||
{
|
||||
lv_font_glyph_dsc_t g;
|
||||
|
||||
if(lv_text_is_marker(letter)) /*Markers are valid letters but should not be rendered.*/
|
||||
return;
|
||||
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
bool g_ret = lv_font_get_glyph_dsc(font, &g, letter, '\0');
|
||||
if(g_ret == false) {
|
||||
/*Add warning if the dsc is not found*/
|
||||
LV_LOG_WARN("lv_draw_letter: glyph dsc. not found for U+%" LV_PRIX32, letter);
|
||||
}
|
||||
|
||||
/*Don't draw anything if the character is empty. E.g. space*/
|
||||
if((g.box_h == 0) || (g.box_w == 0)) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
|
||||
lv_area_t letter_coords;
|
||||
letter_coords.x1 = pos->x + g.ofs_x;
|
||||
letter_coords.x2 = letter_coords.x1 + g.box_w - 1;
|
||||
letter_coords.y1 = pos->y + (font->line_height - font->base_line) - g.box_h - g.ofs_y;
|
||||
letter_coords.y2 = letter_coords.y1 + g.box_h - 1;
|
||||
lv_area_move(&letter_coords, -dsc->pivot.x, -dsc->pivot.y);
|
||||
|
||||
/*If the letter is completely out of mask don't draw it*/
|
||||
if(lv_area_is_out(&letter_coords, &t->clip_area, 0) &&
|
||||
dsc->bg_coords &&
|
||||
lv_area_is_out(dsc->bg_coords, &t->clip_area, 0)) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
|
||||
if(g.resolved_font) {
|
||||
lv_draw_buf_t * draw_buf = NULL;
|
||||
if(LV_FONT_GLYPH_FORMAT_NONE < g.format && g.format < LV_FONT_GLYPH_FORMAT_IMAGE) {
|
||||
/*Only check draw buf for bitmap glyph*/
|
||||
draw_buf = lv_draw_buf_reshape(dsc->_draw_buf, 0, g.box_w, g.box_h, LV_STRIDE_AUTO);
|
||||
if(draw_buf == NULL) {
|
||||
if(dsc->_draw_buf) lv_draw_buf_destroy(dsc->_draw_buf);
|
||||
|
||||
uint32_t h = LV_ROUND_UP(g.box_h, 32); /*Assume a larger size to avoid many reallocations*/
|
||||
draw_buf = lv_draw_buf_create_ex(font_draw_buf_handlers, g.box_w, h, LV_COLOR_FORMAT_A8, LV_STRIDE_AUTO);
|
||||
LV_ASSERT_MALLOC(draw_buf);
|
||||
draw_buf->header.h = g.box_h;
|
||||
dsc->_draw_buf = draw_buf;
|
||||
}
|
||||
}
|
||||
|
||||
/* Performance Optimization for lv_font_fmt_txt_dsc_t fonts, always request raw bitmaps */
|
||||
/*Exception for w*h >= NEMA_COORD_LIMIT due to HW limitation on data handling*/
|
||||
is_raw_bitmap = false;
|
||||
if(g.box_h * g.box_w <= NEMA_COORD_LIMIT) {
|
||||
g.req_raw_bitmap = 1;
|
||||
if(font->get_glyph_bitmap == lv_font_get_bitmap_fmt_txt) {
|
||||
lv_font_fmt_txt_dsc_t * fdsc = (lv_font_fmt_txt_dsc_t *)font->dsc;
|
||||
if(fdsc->bitmap_format == LV_FONT_FMT_TXT_PLAIN) {
|
||||
is_raw_bitmap = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dsc->glyph_data = g.resolved_font->get_glyph_bitmap(&g, draw_buf);
|
||||
|
||||
dsc->format = dsc->glyph_data ? g.format : LV_FONT_GLYPH_FORMAT_NONE;
|
||||
}
|
||||
else {
|
||||
dsc->format = LV_FONT_GLYPH_FORMAT_NONE;
|
||||
}
|
||||
|
||||
dsc->letter_coords = &letter_coords;
|
||||
dsc->g = &g;
|
||||
_draw_nema_gfx_letter(t, dsc, NULL, NULL);
|
||||
|
||||
if(g.resolved_font && font->release_glyph) {
|
||||
lv_draw_nema_gfx_unit_t * draw_nema_gfx_unit = (lv_draw_nema_gfx_unit_t *)t->draw_unit;
|
||||
nema_cl_submit(&(draw_nema_gfx_unit->cl));
|
||||
nema_cl_wait(&(draw_nema_gfx_unit->cl));
|
||||
font->release_glyph(font, &g);
|
||||
}
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
#endif /*LV_USE_NEMA_GFX*/
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008-24 Think Silicon Single Member PC
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next paragraph)
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file lv_draw_nema_gfx_fill.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_nema_gfx.h"
|
||||
|
||||
#if LV_USE_NEMA_GFX
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_nema_gfx_layer(lv_draw_task_t * t, const lv_draw_image_dsc_t * draw_dsc, const lv_area_t * coords)
|
||||
{
|
||||
lv_layer_t * layer_to_draw = (lv_layer_t *)draw_dsc->src;
|
||||
|
||||
/*It can happen that nothing was draw on a layer and therefore its buffer is not allocated.
|
||||
*In this case just return. */
|
||||
if(layer_to_draw->draw_buf == NULL) return;
|
||||
|
||||
lv_draw_image_dsc_t new_draw_dsc = *draw_dsc;
|
||||
new_draw_dsc.src = layer_to_draw->draw_buf;
|
||||
|
||||
lv_draw_nema_gfx_img(t, &new_draw_dsc, coords);
|
||||
}
|
||||
|
||||
#endif /*LV_USE_NEMA_GFX*/
|
||||
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008-24 Think Silicon Single Member PC
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next paragraph)
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file lv_draw_nema_gfx_fill.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_nema_gfx.h"
|
||||
|
||||
#if LV_USE_NEMA_GFX
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
void lv_draw_nema_gfx_line(lv_draw_task_t * t, const lv_draw_line_dsc_t * dsc)
|
||||
{
|
||||
if(dsc->width == 0)
|
||||
return;
|
||||
if(dsc->opa <= (lv_opa_t)LV_OPA_MIN)
|
||||
return;
|
||||
if(dsc->p1.x == dsc->p2.x && dsc->p1.y == dsc->p2.y)
|
||||
return;
|
||||
|
||||
lv_draw_nema_gfx_unit_t * draw_nema_gfx_unit = (lv_draw_nema_gfx_unit_t *)t->draw_unit;
|
||||
|
||||
lv_layer_t * layer = t->target_layer;
|
||||
lv_area_t clip_area;
|
||||
clip_area.x1 = LV_MIN(dsc->p1.x, dsc->p2.x) - dsc->width / 2;
|
||||
clip_area.x2 = LV_MAX(dsc->p1.x, dsc->p2.x) + dsc->width / 2;
|
||||
clip_area.y1 = LV_MIN(dsc->p1.y, dsc->p2.y) - dsc->width / 2;
|
||||
clip_area.y2 = LV_MAX(dsc->p1.y, dsc->p2.y) + dsc->width / 2;
|
||||
|
||||
if(!lv_area_intersect(&clip_area, &clip_area, &t->clip_area))
|
||||
return; /*Fully clipped, nothing to do*/
|
||||
|
||||
lv_area_move(&clip_area, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
lv_point_t point1 = {dsc->p1.x - layer->buf_area.x1, dsc->p1.y - layer->buf_area.y1};
|
||||
lv_point_t point2 = {dsc->p2.x - layer->buf_area.x1, dsc->p2.y - layer->buf_area.y1};
|
||||
|
||||
nema_set_clip(clip_area.x1, clip_area.y1, lv_area_get_width(&clip_area), lv_area_get_height(&clip_area));
|
||||
|
||||
lv_color32_t col32 = lv_color_to_32(dsc->color, dsc->opa);
|
||||
|
||||
uint32_t bg_color = nema_rgba(col32.red, col32.green, col32.blue, col32.alpha);
|
||||
|
||||
lv_color_format_t dst_cf = layer->draw_buf->header.cf;
|
||||
uint32_t dst_nema_cf = lv_nemagfx_cf_to_nema(dst_cf);
|
||||
|
||||
/* the stride should be computed internally for NEMA_TSC images and images missing a stride value */
|
||||
int32_t stride = (dst_cf >= LV_COLOR_FORMAT_NEMA_TSC_START && dst_cf <= LV_COLOR_FORMAT_NEMA_TSC_END) ?
|
||||
-1 : lv_area_get_width(&(layer->buf_area)) * lv_color_format_get_size(dst_cf);
|
||||
|
||||
nema_bind_dst_tex((uintptr_t)NEMA_VIRT2PHYS(layer->draw_buf->data), lv_area_get_width(&(layer->buf_area)),
|
||||
lv_area_get_height(&(layer->buf_area)), dst_nema_cf, stride);
|
||||
|
||||
if(col32.alpha < 255U) {
|
||||
nema_set_blend_fill(NEMA_BL_SIMPLE);
|
||||
}
|
||||
else {
|
||||
nema_set_blend_fill(NEMA_BL_SRC);
|
||||
}
|
||||
|
||||
nema_draw_line_aa(point1.x, point1.y, point2.x, point2.y, dsc->width, bg_color);
|
||||
|
||||
nema_cl_submit(&(draw_nema_gfx_unit->cl));
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,254 @@
|
||||
/**
|
||||
* @file lv_draw_nema_gfx_hal.c
|
||||
*
|
||||
* Global functions that implement some HAL functionality
|
||||
* which Nema will call directly.
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../lv_conf_internal.h"
|
||||
#if LV_USE_NEMA_GFX
|
||||
|
||||
#if LV_USE_NEMA_HAL == LV_NEMA_HAL_STM32
|
||||
|
||||
#include "../../misc/lv_types.h"
|
||||
#include "../../misc/lv_assert.h"
|
||||
#include "../../stdlib/lv_string.h"
|
||||
|
||||
#include <nema_sys_defs.h>
|
||||
#include <nema_core.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include LV_NEMA_STM32_HAL_INCLUDE
|
||||
|
||||
#include "tsi_malloc.h"
|
||||
|
||||
extern GPU2D_HandleTypeDef hgpu2d;
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#define RING_SIZE 1024 /* Ring Buffer Size in byte */
|
||||
|
||||
/* NemaGFX byte pool size in bytes.
|
||||
* One byte per peixel for masking/stencling plus 10240 for additional allocations.
|
||||
*/
|
||||
#if defined(LV_NEMA_GFX_MAX_RESX) && defined(LV_NEMA_GFX_MAX_RESY)
|
||||
#define NEMAGFX_MEM_POOL_SIZE ((LV_NEMA_GFX_MAX_RESX * LV_NEMA_GFX_MAX_RESY) + 10240)
|
||||
#else
|
||||
/* LV_USE_NEMA_VG is 0 so masking/stencling memory is not needed. */
|
||||
#define NEMAGFX_MEM_POOL_SIZE 10240
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
#if (USE_HAL_GPU2D_REGISTER_CALLBACKS == 1)
|
||||
static void GPU2D_CommandListCpltCallback(GPU2D_HandleTypeDef * hgpu2d, uint32_t CmdListID);
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
static uint8_t nemagfx_pool_mem[NEMAGFX_MEM_POOL_SIZE]; /* NemaGFX memory pool */
|
||||
|
||||
static nema_ringbuffer_t ring_buffer_str;
|
||||
static volatile int last_cl_id = -1;
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#if (USE_HAL_GPU2D_REGISTER_CALLBACKS == 1)
|
||||
static void GPU2D_CommandListCpltCallback(GPU2D_HandleTypeDef * hgpu2d, uint32_t CmdListID)
|
||||
#else
|
||||
void HAL_GPU2D_CommandListCpltCallback(GPU2D_HandleTypeDef * hgpu2d, uint32_t CmdListID)
|
||||
#endif
|
||||
{
|
||||
LV_UNUSED(hgpu2d);
|
||||
|
||||
last_cl_id = CmdListID;
|
||||
}
|
||||
|
||||
int32_t nema_sys_init(void)
|
||||
{
|
||||
int error_code = 0;
|
||||
|
||||
/* Setup GPU2D Callback */
|
||||
#if (USE_HAL_GPU2D_REGISTER_CALLBACKS == 1)
|
||||
/* Register Command List Complete Callback */
|
||||
HAL_GPU2D_RegisterCommandListCpltCallback(&hgpu2d, GPU2D_CommandListCpltCallback);
|
||||
#endif
|
||||
|
||||
/* Initialise Mem Space */
|
||||
error_code = tsi_malloc_init_pool_aligned(0, (void *)nemagfx_pool_mem, (uintptr_t)nemagfx_pool_mem,
|
||||
NEMAGFX_MEM_POOL_SIZE, 1, 8);
|
||||
LV_ASSERT(error_code == 0);
|
||||
|
||||
/* Allocate ring_buffer memory */
|
||||
ring_buffer_str.bo = nema_buffer_create(RING_SIZE);
|
||||
LV_ASSERT(ring_buffer_str.bo.base_virt);
|
||||
|
||||
/* Initialize Ring Buffer */
|
||||
error_code = nema_rb_init(&ring_buffer_str, 1);
|
||||
if(error_code < 0) {
|
||||
return error_code;
|
||||
}
|
||||
|
||||
/* Reset last_cl_id counter */
|
||||
last_cl_id = 0;
|
||||
|
||||
return error_code;
|
||||
}
|
||||
|
||||
uint32_t nema_reg_read(uint32_t reg)
|
||||
{
|
||||
return HAL_GPU2D_ReadRegister(&hgpu2d, reg);
|
||||
}
|
||||
|
||||
void nema_reg_write(uint32_t reg, uint32_t value)
|
||||
{
|
||||
HAL_GPU2D_WriteRegister(&hgpu2d, reg, value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int nema_wait_irq(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int nema_wait_irq_cl(int cl_id)
|
||||
{
|
||||
while(last_cl_id < cl_id) {
|
||||
(void)nema_wait_irq();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nema_wait_irq_brk(int brk_id)
|
||||
{
|
||||
while(nema_reg_read(GPU2D_BREAKPOINT) == 0U) {
|
||||
(void)nema_wait_irq();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nema_host_free(void * ptr)
|
||||
{
|
||||
tsi_free(ptr);
|
||||
}
|
||||
|
||||
void * nema_host_malloc(unsigned size)
|
||||
{
|
||||
return tsi_malloc(size);
|
||||
}
|
||||
|
||||
nema_buffer_t nema_buffer_create(int size)
|
||||
{
|
||||
nema_buffer_t bo;
|
||||
lv_memset(&bo, 0, sizeof(bo));
|
||||
bo.base_virt = tsi_malloc(size);
|
||||
bo.base_phys = (uint32_t)bo.base_virt;
|
||||
bo.size = size;
|
||||
LV_ASSERT_MSG(bo.base_virt != 0, "Unable to allocate memory in nema_buffer_create");
|
||||
|
||||
return bo;
|
||||
}
|
||||
|
||||
nema_buffer_t nema_buffer_create_pool(int pool, int size)
|
||||
{
|
||||
LV_UNUSED(pool);
|
||||
|
||||
return nema_buffer_create(size);
|
||||
}
|
||||
|
||||
void * nema_buffer_map(nema_buffer_t * bo)
|
||||
{
|
||||
return bo->base_virt;
|
||||
}
|
||||
|
||||
void nema_buffer_unmap(nema_buffer_t * bo)
|
||||
{
|
||||
LV_UNUSED(bo);
|
||||
}
|
||||
|
||||
void nema_buffer_destroy(nema_buffer_t * bo)
|
||||
{
|
||||
if(bo->fd == -1) {
|
||||
return; /* Buffer weren't allocated! */
|
||||
}
|
||||
|
||||
tsi_free(bo->base_virt);
|
||||
|
||||
bo->base_virt = (void *)0;
|
||||
bo->base_phys = 0;
|
||||
bo->size = 0;
|
||||
bo->fd = -1; /* Buffer not allocated */
|
||||
}
|
||||
|
||||
uintptr_t nema_buffer_phys(nema_buffer_t * bo)
|
||||
{
|
||||
return bo->base_phys;
|
||||
}
|
||||
|
||||
void nema_buffer_flush(nema_buffer_t * bo)
|
||||
{
|
||||
LV_UNUSED(bo);
|
||||
}
|
||||
|
||||
int nema_mutex_lock(int mutex_id)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
LV_UNUSED(mutex_id);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int nema_mutex_unlock(int mutex_id)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
LV_UNUSED(mutex_id);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void platform_disable_cache(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void platform_invalidate_cache(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#endif /* LV_USE_NEMA_HAL == LV_NEMA_HAL_STM32 */
|
||||
|
||||
#endif /* LV_USE_NEMA_GFX */
|
||||
@@ -0,0 +1,171 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008-24 Think Silicon Single Member PC
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next paragraph)
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file lv_draw_nema_gfx_fill.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_nema_gfx.h"
|
||||
|
||||
#if LV_USE_NEMA_GFX
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
void lv_draw_nema_gfx_triangle(lv_draw_task_t * t, const lv_draw_triangle_dsc_t * dsc)
|
||||
{
|
||||
if(dsc->opa <= LV_OPA_MIN) return;
|
||||
|
||||
lv_draw_nema_gfx_unit_t * draw_nema_gfx_unit = (lv_draw_nema_gfx_unit_t *)t->draw_unit;
|
||||
|
||||
lv_layer_t * layer = t->target_layer;
|
||||
|
||||
lv_area_t rel_clip_area;
|
||||
lv_area_copy(&rel_clip_area, &t->clip_area);
|
||||
lv_area_move(&rel_clip_area, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
lv_area_t coords;
|
||||
coords.x1 = (int32_t)LV_MIN3(dsc->p[0].x, dsc->p[1].x, dsc->p[2].x);
|
||||
coords.y1 = (int32_t)LV_MIN3(dsc->p[0].y, dsc->p[1].y, dsc->p[2].y);
|
||||
coords.x2 = (int32_t)LV_MAX3(dsc->p[0].x, dsc->p[1].x, dsc->p[2].x);
|
||||
coords.y2 = (int32_t)LV_MAX3(dsc->p[0].y, dsc->p[1].y, dsc->p[2].y);
|
||||
|
||||
lv_area_move(&coords, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
lv_area_t clipped_coords;
|
||||
if(!lv_area_intersect(&clipped_coords, &coords, &rel_clip_area))
|
||||
return; /* Fully clipped, nothing to do */
|
||||
|
||||
nema_set_clip(rel_clip_area.x1, rel_clip_area.y1, lv_area_get_width(&rel_clip_area),
|
||||
lv_area_get_height(&rel_clip_area));
|
||||
|
||||
lv_color_format_t dst_cf = layer->draw_buf->header.cf;
|
||||
uint32_t dst_nema_cf = lv_nemagfx_cf_to_nema(dst_cf);
|
||||
|
||||
/* the stride should be computed internally for NEMA_TSC images and images missing a stride value */
|
||||
int32_t stride = (dst_cf >= LV_COLOR_FORMAT_NEMA_TSC_START && dst_cf <= LV_COLOR_FORMAT_NEMA_TSC_END) ?
|
||||
-1 : lv_area_get_width(&(layer->buf_area)) * lv_color_format_get_size(dst_cf);
|
||||
|
||||
nema_bind_dst_tex((uintptr_t)NEMA_VIRT2PHYS(layer->draw_buf->data), lv_area_get_width(&(layer->buf_area)),
|
||||
lv_area_get_height(&(layer->buf_area)), dst_nema_cf, stride);
|
||||
|
||||
if(dsc->grad.dir == (lv_grad_dir_t)LV_GRAD_DIR_NONE) {
|
||||
|
||||
lv_color32_t col32 = lv_color_to_32(dsc->color, dsc->opa);
|
||||
|
||||
if(col32.alpha < 255U) {
|
||||
nema_set_blend_fill(NEMA_BL_SIMPLE);
|
||||
}
|
||||
else {
|
||||
nema_set_blend_fill(NEMA_BL_SRC);
|
||||
}
|
||||
|
||||
uint32_t bg_color = nema_rgba(col32.red, col32.green, col32.blue, col32.alpha);
|
||||
|
||||
nema_enable_aa(1, 1, 1, 0);
|
||||
nema_fill_triangle(dsc->p[0].x, dsc->p[0].y, dsc->p[1].x, dsc->p[1].y, dsc->p[2].x, dsc->p[2].y, bg_color);
|
||||
}
|
||||
#if LV_USE_NEMA_VG
|
||||
else {
|
||||
|
||||
nema_vg_path_clear(draw_nema_gfx_unit->path);
|
||||
nema_vg_paint_clear(draw_nema_gfx_unit->paint);
|
||||
|
||||
nema_vg_paint_set_type(draw_nema_gfx_unit->paint, NEMA_VG_PAINT_GRAD_LINEAR);
|
||||
nema_vg_set_blend(NEMA_BL_SRC_OVER | NEMA_BLOP_SRC_PREMULT);
|
||||
nema_vg_set_fill_rule(NEMA_VG_FILL_EVEN_ODD);
|
||||
|
||||
|
||||
float stops[LV_GRADIENT_MAX_STOPS];
|
||||
color_var_t colors[LV_GRADIENT_MAX_STOPS];
|
||||
|
||||
uint32_t cnt = LV_MAX(dsc->grad.stops_count, LV_GRADIENT_MAX_STOPS);
|
||||
|
||||
for(uint8_t i = 0; i < cnt; i++) {
|
||||
stops[i] = (float)(dsc->grad.stops[i].frac) / 255.f;
|
||||
colors[i].a = dsc->grad.stops[i].opa;
|
||||
colors[i].r = dsc->grad.stops[i].color.red;
|
||||
colors[i].g = dsc->grad.stops[i].color.green;
|
||||
colors[i].b = dsc->grad.stops[i].color.blue;
|
||||
}
|
||||
|
||||
nema_vg_grad_set(draw_nema_gfx_unit->gradient, cnt, stops, colors);
|
||||
|
||||
//Calculate Bounding Box
|
||||
float min_x = LV_MIN(dsc->p[0].x, dsc->p[1].x);
|
||||
min_x = LV_MIN(dsc->p[2].x, min_x);
|
||||
|
||||
float min_y = LV_MIN(dsc->p[0].y, dsc->p[1].y);
|
||||
min_y = LV_MIN(dsc->p[2].y, min_y);
|
||||
|
||||
float max_x = LV_MAX(dsc->p[0].x, dsc->p[1].x);
|
||||
max_x = LV_MAX(dsc->p[2].x, max_x);
|
||||
|
||||
float max_y = LV_MAX(dsc->p[0].y, dsc->p[1].y);
|
||||
max_y = LV_MAX(dsc->p[2].y, max_y);
|
||||
|
||||
float x0, x1, y0, y1;
|
||||
|
||||
if(dsc->grad.dir == LV_GRAD_DIR_HOR) {
|
||||
x0 = min_x;
|
||||
x1 = max_x;
|
||||
y0 = min_y;
|
||||
y1 = min_y;
|
||||
}
|
||||
else {
|
||||
x0 = min_x;
|
||||
x1 = min_x;
|
||||
y0 = min_y;
|
||||
y1 = max_y;
|
||||
}
|
||||
|
||||
y0 -= (float) layer->buf_area.y1;
|
||||
y1 -= (float) layer->buf_area.y1;
|
||||
x0 -= (float) layer->buf_area.x1;
|
||||
x1 -= (float) layer->buf_area.x1;
|
||||
|
||||
uint8_t cmds_polygon[] = {NEMA_VG_PRIM_MOVE, NEMA_VG_PRIM_POLYGON};
|
||||
float triangle_coords[] = {dsc->p[0].x - layer->buf_area.x1, dsc->p[0].y - layer->buf_area.y1,
|
||||
4.0f,
|
||||
dsc->p[1].x - layer->buf_area.x1, dsc->p[1].y - layer->buf_area.y1,
|
||||
dsc->p[2].x - layer->buf_area.x1, dsc->p[2].y - layer->buf_area.y1
|
||||
};
|
||||
nema_enable_aa(0, 0, 0, 0);
|
||||
nema_vg_paint_set_grad_linear(draw_nema_gfx_unit->paint, draw_nema_gfx_unit->gradient, x0, y0, x1, y1,
|
||||
NEMA_TEX_CLAMP | NEMA_FILTER_BL);
|
||||
nema_vg_path_set_shape(draw_nema_gfx_unit->path, 2, cmds_polygon, 7, triangle_coords);
|
||||
nema_vg_draw_path(draw_nema_gfx_unit->path, draw_nema_gfx_unit->paint);
|
||||
}
|
||||
#endif
|
||||
|
||||
nema_cl_submit(&(draw_nema_gfx_unit->cl));
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,143 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008-24 Think Silicon Single Member PC
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next paragraph)
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file lv_draw_nema_gfx_utils.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_nema_gfx.h"
|
||||
|
||||
#if LV_USE_NEMA_GFX
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
uint32_t lv_nemagfx_cf_to_nema(lv_color_format_t cf)
|
||||
{
|
||||
switch(cf) {
|
||||
case LV_COLOR_FORMAT_A1:
|
||||
return NEMA_A1;
|
||||
case LV_COLOR_FORMAT_A2:
|
||||
return NEMA_A2;
|
||||
case LV_COLOR_FORMAT_A4:
|
||||
return NEMA_A4;
|
||||
case LV_COLOR_FORMAT_A8:
|
||||
return NEMA_A8;
|
||||
case LV_COLOR_FORMAT_I1:
|
||||
return NEMA_L1;
|
||||
case LV_COLOR_FORMAT_I2:
|
||||
return NEMA_L2;
|
||||
case LV_COLOR_FORMAT_I4:
|
||||
return NEMA_L4;
|
||||
case LV_COLOR_FORMAT_L8:
|
||||
case LV_COLOR_FORMAT_I8:
|
||||
return NEMA_L8;
|
||||
case LV_COLOR_FORMAT_RGB565:
|
||||
return NEMA_RGB565;
|
||||
case LV_COLOR_FORMAT_RGB888:
|
||||
return NEMA_BGR24;
|
||||
case LV_COLOR_FORMAT_ARGB8888:
|
||||
return NEMA_BGRA8888;
|
||||
case LV_COLOR_FORMAT_XRGB8888:
|
||||
return NEMA_BGRX8888;
|
||||
case LV_COLOR_FORMAT_NEMA_TSC4:
|
||||
return NEMA_TSC4;
|
||||
case LV_COLOR_FORMAT_NEMA_TSC6:
|
||||
return NEMA_TSC6;
|
||||
case LV_COLOR_FORMAT_NEMA_TSC6A:
|
||||
return NEMA_TSC6A;
|
||||
case LV_COLOR_FORMAT_NEMA_TSC12:
|
||||
return NEMA_TSC12;
|
||||
case LV_COLOR_FORMAT_NEMA_TSC12A:
|
||||
return NEMA_TSC12A;
|
||||
/*Guard for previous NemaGFX Version*/
|
||||
#ifdef NEMA_TSC6AP
|
||||
case LV_COLOR_FORMAT_NEMA_TSC6AP:
|
||||
return NEMA_TSC6AP;
|
||||
#endif
|
||||
default:
|
||||
return LV_NEMA_GFX_COLOR_FORMAT;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t lv_nemagfx_blending_mode(lv_blend_mode_t lv_blend_mode)
|
||||
{
|
||||
uint32_t blending_mode;
|
||||
switch(lv_blend_mode) {
|
||||
case LV_BLEND_MODE_NORMAL:
|
||||
blending_mode = NEMA_BL_SIMPLE;
|
||||
break;
|
||||
case LV_BLEND_MODE_ADDITIVE:
|
||||
blending_mode = NEMA_BL_ADD;
|
||||
break;
|
||||
case LV_BLEND_MODE_MULTIPLY:
|
||||
blending_mode = nema_blending_mode(NEMA_BF_DESTCOLOR, NEMA_BF_INVSRCALPHA, NEMA_BLOP_SRC_PREMULT);
|
||||
break;
|
||||
default:
|
||||
blending_mode = NEMA_BL_SIMPLE;
|
||||
break;
|
||||
}
|
||||
return blending_mode;
|
||||
}
|
||||
|
||||
void lv_nemagfx_grad_set(NEMA_VG_GRAD_HANDLE gradient, lv_grad_dsc_t lv_grad, lv_opa_t opa)
|
||||
{
|
||||
|
||||
float stops[LV_GRADIENT_MAX_STOPS];
|
||||
color_var_t colors[LV_GRADIENT_MAX_STOPS];
|
||||
|
||||
uint32_t cnt = LV_MAX(lv_grad.stops_count, LV_GRADIENT_MAX_STOPS);
|
||||
|
||||
for(uint8_t i = 0; i < cnt; i++) {
|
||||
stops[i] = (float)(lv_grad.stops[i].frac) / 255.f;
|
||||
colors[i].a = LV_OPA_MIX2(lv_grad.stops[i].opa, opa);
|
||||
colors[i].r = lv_grad.stops[i].color.red;
|
||||
colors[i].g = lv_grad.stops[i].color.green;
|
||||
colors[i].b = lv_grad.stops[i].color.blue;
|
||||
}
|
||||
|
||||
nema_vg_grad_set(gradient, cnt, stops, colors);
|
||||
}
|
||||
|
||||
bool lv_nemagfx_is_cf_supported(lv_color_format_t cf)
|
||||
{
|
||||
|
||||
switch(cf) {
|
||||
case LV_COLOR_FORMAT_ARGB8565:
|
||||
case LV_COLOR_FORMAT_RGB565A8:
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /*LV_USE_NEMA_GFX*/
|
||||
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008-24 Think Silicon Single Member PC
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next paragraph)
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file lv_draw_nema_gfx.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_NEMA_GFX_UTILS_H
|
||||
#define LV_DRAW_NEMA_GFX_UTILS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_NEMA_GFX
|
||||
#include "../sw/lv_draw_sw.h"
|
||||
|
||||
#include "nema_core.h"
|
||||
#include "nema_utils.h"
|
||||
#include "nema_error.h"
|
||||
#include "nema_provisional.h"
|
||||
#include "nema_vg.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#ifndef NEMA_VIRT2PHYS
|
||||
#define NEMA_VIRT2PHYS
|
||||
#else
|
||||
uintptr_t NEMA_VIRT2PHYS(void * addr);
|
||||
#endif
|
||||
|
||||
/*Color depth: 1 (1 byte per pixel), 8 (RGB332), 16 (RGB565), 32 (ARGB8888)*/
|
||||
#if LV_COLOR_DEPTH == 8
|
||||
#define LV_NEMA_GFX_COLOR_FORMAT NEMA_L8
|
||||
#define LV_NEMA_GFX_FORMAT_MULTIPLIER 1
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
#define LV_NEMA_GFX_COLOR_FORMAT NEMA_RGB565
|
||||
#define LV_NEMA_GFX_FORMAT_MULTIPLIER 2
|
||||
#elif LV_COLOR_DEPTH == 24
|
||||
#define LV_NEMA_GFX_COLOR_FORMAT NEMA_BGR24
|
||||
#define LV_NEMA_GFX_FORMAT_MULTIPLIER 3
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
#define LV_NEMA_GFX_COLOR_FORMAT NEMA_BGRA8888
|
||||
#define LV_NEMA_GFX_FORMAT_MULTIPLIER 4
|
||||
#else
|
||||
/*Can't use GPU with other formats*/
|
||||
#error Selected Color Depth Not Supported
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Check if `lv_color_format_t` is supported.
|
||||
* @param cf The LVGL color format
|
||||
* @return True/false
|
||||
*/
|
||||
bool lv_nemagfx_is_cf_supported(lv_color_format_t cf);
|
||||
|
||||
/**
|
||||
* Convert a `lv_color_format_t` to a Nema color format.
|
||||
* @param cf The LVGL color format
|
||||
* @return The Nema color format
|
||||
*/
|
||||
uint32_t lv_nemagfx_cf_to_nema(lv_color_format_t cf);
|
||||
|
||||
/**
|
||||
* Get NemaGFX blending mode
|
||||
*
|
||||
* @param[in] lv_blend_mode The LVGL blend mode
|
||||
*
|
||||
* @return NemaGFX blending mode
|
||||
*
|
||||
*/
|
||||
uint32_t lv_nemagfx_blending_mode(lv_blend_mode_t lv_blend_mode);
|
||||
|
||||
|
||||
/**
|
||||
* Get NemaGFX blending mode
|
||||
*
|
||||
* @param[in] gradient NemaGFX Gradient Buffer
|
||||
*
|
||||
* @param[in] lv_grad Gradient descriptor
|
||||
*
|
||||
* @param[in] opa Descriptor's opacity
|
||||
*
|
||||
*/
|
||||
void lv_nemagfx_grad_set(NEMA_VG_GRAD_HANDLE gradient, lv_grad_dsc_t lv_grad, lv_opa_t opa);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_NEMA_GFX*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_NEMA_GFX_UTILS_H*/
|
||||
@@ -0,0 +1,159 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008-24 Think Silicon Single Member PC
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next paragraph)
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file lv_nema_gfx_path.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../../core/lv_refr.h"
|
||||
|
||||
#if LV_USE_NEMA_GFX
|
||||
#if LV_USE_NEMA_VG
|
||||
|
||||
#include "lv_nema_gfx_path.h"
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static int data_point = 0;
|
||||
static int seg_point = 0;
|
||||
|
||||
lv_nema_gfx_path_t * lv_nema_gfx_path_create(void)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
lv_nema_gfx_path_t * nema_gfx_path = lv_malloc_zeroed(sizeof(lv_nema_gfx_path_t));
|
||||
LV_ASSERT_MALLOC(nema_gfx_path);
|
||||
nema_gfx_path->seg = NULL;
|
||||
nema_gfx_path->data = NULL;
|
||||
nema_gfx_path->seg_size = 0;
|
||||
nema_gfx_path->data_size = 0;
|
||||
data_point = 0;
|
||||
seg_point = 0;
|
||||
LV_PROFILER_DRAW_END;
|
||||
return nema_gfx_path;
|
||||
}
|
||||
|
||||
void lv_nema_gfx_path_alloc(lv_nema_gfx_path_t * nema_gfx_path)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
nema_gfx_path->path = nema_vg_path_create();
|
||||
nema_gfx_path->paint = nema_vg_paint_create();
|
||||
nema_gfx_path->data = (float *) lv_malloc(nema_gfx_path->data_size * sizeof(float));
|
||||
LV_ASSERT_MALLOC(nema_gfx_path->data);
|
||||
nema_gfx_path->seg = (uint8_t *) lv_malloc(nema_gfx_path->seg_size * sizeof(uint8_t));
|
||||
LV_ASSERT_MALLOC(nema_gfx_path->seg);
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
void lv_nema_gfx_path_destroy(lv_nema_gfx_path_t * nema_gfx_path)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
LV_ASSERT_NULL(nema_gfx_path);
|
||||
|
||||
if(nema_gfx_path->path != NULL) {
|
||||
nema_vg_path_destroy(nema_gfx_path->path);
|
||||
nema_gfx_path->path = NULL;
|
||||
}
|
||||
|
||||
if(nema_gfx_path->paint != NULL) {
|
||||
nema_vg_paint_destroy(nema_gfx_path->paint);
|
||||
nema_gfx_path->paint = NULL;
|
||||
}
|
||||
|
||||
if(nema_gfx_path->data != NULL) {
|
||||
lv_free(nema_gfx_path->data);
|
||||
nema_gfx_path->data = NULL;
|
||||
}
|
||||
if(nema_gfx_path->seg != NULL) {
|
||||
lv_free(nema_gfx_path->seg);
|
||||
nema_gfx_path->seg = NULL;
|
||||
}
|
||||
lv_free(nema_gfx_path);
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
void lv_nema_gfx_path_move_to(lv_nema_gfx_path_t * path, float x, float y)
|
||||
{
|
||||
LV_ASSERT_NULL(path);
|
||||
LV_ASSERT(path->data_size > data_point + 1);
|
||||
LV_ASSERT(path->seg_size > seg_point);
|
||||
path->seg[seg_point++] = NEMA_VG_PRIM_MOVE;
|
||||
path->data[data_point++] = x;
|
||||
path->data[data_point++] = y;
|
||||
}
|
||||
|
||||
void lv_nema_gfx_path_line_to(lv_nema_gfx_path_t * path, float x, float y)
|
||||
{
|
||||
LV_ASSERT_NULL(path);
|
||||
LV_ASSERT(path->data_size > data_point + 1);
|
||||
LV_ASSERT(path->seg_size > seg_point);
|
||||
path->seg[seg_point++] = NEMA_VG_PRIM_LINE;
|
||||
path->data[data_point++] = x;
|
||||
path->data[data_point++] = y;
|
||||
|
||||
}
|
||||
|
||||
void lv_nema_gfx_path_quad_to(lv_nema_gfx_path_t * path, float cx, float cy, float x, float y)
|
||||
{
|
||||
LV_ASSERT_NULL(path);
|
||||
LV_ASSERT(path->data_size > data_point + 3);
|
||||
LV_ASSERT(path->seg_size > seg_point);
|
||||
path->seg[seg_point++] = NEMA_VG_PRIM_BEZIER_QUAD;
|
||||
path->data[data_point++] = cx;
|
||||
path->data[data_point++] = cy;
|
||||
path->data[data_point++] = x;
|
||||
path->data[data_point++] = y;
|
||||
}
|
||||
|
||||
void lv_nema_gfx_path_cubic_to(lv_nema_gfx_path_t * path, float cx1, float cy1, float cx2, float cy2, float x, float y)
|
||||
{
|
||||
LV_ASSERT_NULL(path);
|
||||
LV_ASSERT(path->data_size > data_point + 5);
|
||||
LV_ASSERT(path->seg_size > seg_point);
|
||||
path->seg[seg_point++] = NEMA_VG_PRIM_BEZIER_CUBIC;
|
||||
path->data[data_point++] = cx1;
|
||||
path->data[data_point++] = cy1;
|
||||
path->data[data_point++] = cx2;
|
||||
path->data[data_point++] = cy2;
|
||||
path->data[data_point++] = x;
|
||||
path->data[data_point++] = y;
|
||||
}
|
||||
|
||||
void lv_nema_gfx_path_end(lv_nema_gfx_path_t * path)
|
||||
{
|
||||
/* Do Path end jobs....whatever*/
|
||||
seg_point = 0;
|
||||
data_point = 0;
|
||||
|
||||
}
|
||||
|
||||
#endif /*LV_USE_NEMA_VG*/
|
||||
#endif /*LV_USE_NEMA_GFX*/
|
||||
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008-24 Think Silicon Single Member PC
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next paragraph)
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file lv_nema_gfx_path.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_NEMA_GFX_PATH_H
|
||||
#define LV_NEMA_GFX_PATH_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_nema_gfx.h"
|
||||
|
||||
#if LV_USE_NEMA_GFX
|
||||
#if LV_USE_NEMA_VG
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct {
|
||||
NEMA_VG_PATH_HANDLE path;
|
||||
NEMA_VG_PAINT_HANDLE paint;
|
||||
float * data;
|
||||
uint8_t * seg;
|
||||
uint32_t data_size;
|
||||
uint32_t seg_size;
|
||||
} lv_nema_gfx_path_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
lv_nema_gfx_path_t * lv_nema_gfx_path_create(void);
|
||||
|
||||
void lv_nema_gfx_path_alloc(lv_nema_gfx_path_t * nema_gfx_path);
|
||||
|
||||
void lv_nema_gfx_path_destroy(lv_nema_gfx_path_t * nema_gfx_path);
|
||||
|
||||
void lv_nema_gfx_path_move_to(lv_nema_gfx_path_t * nema_gfx_path,
|
||||
float x, float y);
|
||||
|
||||
void lv_nema_gfx_path_line_to(lv_nema_gfx_path_t * nema_gfx_path,
|
||||
float x, float y);
|
||||
|
||||
void lv_nema_gfx_path_quad_to(lv_nema_gfx_path_t * nema_gfx_path,
|
||||
float cx, float cy,
|
||||
float x, float y);
|
||||
|
||||
void lv_nema_gfx_path_cubic_to(lv_nema_gfx_path_t * nema_gfx_path,
|
||||
float cx1, float cy1,
|
||||
float cx2, float cy2,
|
||||
float x, float y);
|
||||
|
||||
void lv_nema_gfx_path_end(lv_nema_gfx_path_t * nema_gfx_path);
|
||||
|
||||
|
||||
|
||||
#endif /*LV_USE_NEMA_VG*/
|
||||
#endif /*LV_USE_NEMA_GFX*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_NEMA_GFX_PATH_H*/
|
||||
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* @file lv_draw_buf_g2d.c
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2024 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_g2d.h"
|
||||
|
||||
#if LV_USE_DRAW_G2D
|
||||
#include "../../lv_draw_buf_private.h"
|
||||
#include "g2d.h"
|
||||
#include "lv_g2d_buf_map.h"
|
||||
#include "lv_g2d_utils.h"
|
||||
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static void * _buf_malloc(size_t size_bytes, lv_color_format_t color_format);
|
||||
|
||||
static void _buf_free(void * buf);
|
||||
|
||||
static void _invalidate_cache(const lv_draw_buf_t * draw_buf, const lv_area_t * area);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_buf_g2d_init_handlers(void)
|
||||
{
|
||||
lv_draw_buf_handlers_t * handlers = lv_draw_buf_get_handlers();
|
||||
|
||||
handlers->buf_malloc_cb = _buf_malloc;
|
||||
handlers->buf_free_cb = _buf_free;
|
||||
handlers->invalidate_cache_cb = _invalidate_cache;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void * _buf_malloc(size_t size_bytes, lv_color_format_t color_format)
|
||||
{
|
||||
LV_UNUSED(color_format);
|
||||
|
||||
size_bytes += LV_DRAW_BUF_ALIGN - 1;
|
||||
struct g2d_buf * buf = g2d_alloc(size_bytes, 1);
|
||||
G2D_ASSERT_MSG(buf, "Failed to alloc buffer.");
|
||||
g2d_insert_buf_map(buf->buf_vaddr, buf);
|
||||
return buf->buf_vaddr;
|
||||
}
|
||||
|
||||
static void _buf_free(void * buf)
|
||||
{
|
||||
g2d_free_item(buf);
|
||||
}
|
||||
|
||||
static void _invalidate_cache(const lv_draw_buf_t * draw_buf, const lv_area_t * area)
|
||||
{
|
||||
LV_UNUSED(area);
|
||||
struct g2d_buf * buf = g2d_search_buf_map(draw_buf->data);
|
||||
G2D_ASSERT_MSG(buf, "Failed to find buffer in map.");
|
||||
g2d_cache_op(buf, G2D_CACHE_FLUSH);
|
||||
}
|
||||
|
||||
#endif /*LV_USE_DRAW_G2D*/
|
||||
@@ -0,0 +1,336 @@
|
||||
/**
|
||||
* @file lv_draw_g2d.c
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2024 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "lv_draw_g2d.h"
|
||||
|
||||
#if LV_USE_DRAW_G2D
|
||||
#include "../../../misc/lv_area_private.h"
|
||||
#include "g2d.h"
|
||||
#include "lv_g2d_buf_map.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#define DRAW_UNIT_ID_G2D 8
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Evaluate a task and set the score and preferred G2D unit.
|
||||
* Return 1 if task is preferred, 0 otherwise (task is not supported).
|
||||
*/
|
||||
static int32_t _g2d_evaluate(lv_draw_unit_t * draw_unit, lv_draw_task_t * task);
|
||||
|
||||
/**
|
||||
* Dispatch a task to the G2D unit.
|
||||
* Return 1 if task was dispatched, 0 otherwise (task not supported).
|
||||
*/
|
||||
static int32_t _g2d_dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer);
|
||||
|
||||
/**
|
||||
* Delete the G2D draw unit.
|
||||
*/
|
||||
static int32_t _g2d_delete(lv_draw_unit_t * draw_unit);
|
||||
|
||||
#if LV_USE_G2D_DRAW_THREAD
|
||||
static void _g2d_render_thread_cb(void * ptr);
|
||||
#endif
|
||||
|
||||
static void _g2d_execute_drawing(lv_draw_task_t * t);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_g2d_init(void)
|
||||
{
|
||||
lv_draw_buf_g2d_init_handlers();
|
||||
|
||||
lv_draw_g2d_unit_t * draw_g2d_unit = lv_draw_create_unit(sizeof(lv_draw_g2d_unit_t));
|
||||
draw_g2d_unit->base_unit.evaluate_cb = _g2d_evaluate;
|
||||
draw_g2d_unit->base_unit.dispatch_cb = _g2d_dispatch;
|
||||
draw_g2d_unit->base_unit.delete_cb = _g2d_delete;
|
||||
draw_g2d_unit->base_unit.name = "G2D";
|
||||
g2d_create_buf_map();
|
||||
if(g2d_open(&draw_g2d_unit->g2d_handle)) {
|
||||
LV_LOG_ERROR("g2d_open fail.\n");
|
||||
}
|
||||
#if LV_USE_G2D_DRAW_THREAD
|
||||
lv_draw_sw_thread_dsc_t * thread_dsc = &draw_g2d_unit->thread_dsc;
|
||||
thread_dsc->idx = 0;
|
||||
thread_dsc->draw_unit = (void *) draw_g2d_unit;
|
||||
lv_thread_init(&thread_dsc->thread, "g2ddraw", LV_DRAW_THREAD_PRIO, _g2d_render_thread_cb, LV_DRAW_THREAD_STACK_SIZE,
|
||||
thread_dsc);
|
||||
#endif
|
||||
}
|
||||
|
||||
void lv_draw_g2d_deinit(void)
|
||||
{
|
||||
g2d_free_buf_map();
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static inline bool _g2d_dest_cf_supported(lv_color_format_t cf)
|
||||
{
|
||||
bool is_cf_supported = false;
|
||||
|
||||
switch(cf) {
|
||||
case LV_COLOR_FORMAT_ARGB8888:
|
||||
case LV_COLOR_FORMAT_XRGB8888:
|
||||
is_cf_supported = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return is_cf_supported;
|
||||
}
|
||||
|
||||
static inline bool _g2d_src_cf_supported(lv_draw_unit_t * drawunit, lv_color_format_t cf)
|
||||
{
|
||||
bool is_cf_supported = false;
|
||||
|
||||
switch(cf) {
|
||||
case LV_COLOR_FORMAT_ARGB8888:
|
||||
case LV_COLOR_FORMAT_XRGB8888:
|
||||
is_cf_supported = true;
|
||||
break;
|
||||
case LV_COLOR_FORMAT_RGB565: {
|
||||
int32_t hw_pxp = 0;
|
||||
lv_draw_g2d_unit_t * u = (lv_draw_g2d_unit_t *)drawunit;
|
||||
g2d_query_hardware(u->g2d_handle, G2D_HARDWARE_PXP, &hw_pxp);
|
||||
if(!hw_pxp) {
|
||||
is_cf_supported = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return is_cf_supported;
|
||||
}
|
||||
|
||||
static bool _g2d_draw_img_supported(const lv_draw_image_dsc_t * draw_dsc)
|
||||
{
|
||||
bool is_tiled = draw_dsc->tile;
|
||||
/* Tiled image (repeat image) is currently not supported. */
|
||||
if(is_tiled)
|
||||
return false;
|
||||
|
||||
bool has_recolor = (draw_dsc->recolor_opa > LV_OPA_MIN);
|
||||
bool has_rotation = (draw_dsc->rotation != 0);
|
||||
|
||||
/* Recolor or rotation are not supported. */
|
||||
if(has_recolor || has_rotation)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int32_t _g2d_evaluate(lv_draw_unit_t * u, lv_draw_task_t * t)
|
||||
{
|
||||
LV_UNUSED(u);
|
||||
|
||||
const lv_draw_dsc_base_t * draw_dsc_base = (lv_draw_dsc_base_t *) t->draw_dsc;
|
||||
lv_draw_buf_t * draw_buf = draw_dsc_base->layer->draw_buf;
|
||||
|
||||
if(!_g2d_dest_cf_supported(draw_dsc_base->layer->color_format))
|
||||
return 0;
|
||||
|
||||
if(draw_buf && !g2d_search_buf_map(draw_buf->data))
|
||||
return 0;
|
||||
|
||||
switch(t->type) {
|
||||
case LV_DRAW_TASK_TYPE_FILL: {
|
||||
const lv_draw_fill_dsc_t * draw_dsc = (lv_draw_fill_dsc_t *) t->draw_dsc;
|
||||
|
||||
/* Most simple case: just a plain rectangle (no radius, no gradient). */
|
||||
if((draw_dsc->radius != 0) || (draw_dsc->grad.dir != (lv_grad_dir_t)LV_GRAD_DIR_NONE))
|
||||
return 0;
|
||||
|
||||
if(t->preference_score > 70) {
|
||||
t->preference_score = 70;
|
||||
t->preferred_draw_unit_id = DRAW_UNIT_ID_G2D;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
case LV_DRAW_TASK_TYPE_IMAGE: {
|
||||
const lv_draw_image_dsc_t * draw_dsc = (lv_draw_image_dsc_t *) t->draw_dsc;
|
||||
|
||||
if(!_g2d_src_cf_supported(u, draw_dsc->header.cf))
|
||||
return 0;
|
||||
|
||||
if(!_g2d_draw_img_supported(draw_dsc))
|
||||
return 0;
|
||||
|
||||
if(t->preference_score > 70) {
|
||||
t->preference_score = 70;
|
||||
t->preferred_draw_unit_id = DRAW_UNIT_ID_G2D;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int32_t _g2d_dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer)
|
||||
{
|
||||
lv_draw_g2d_unit_t * draw_g2d_unit = (lv_draw_g2d_unit_t *) draw_unit;
|
||||
|
||||
#if LV_USE_OS
|
||||
lv_draw_sw_thread_dsc_t * thread_dsc = &draw_g2d_unit->thread_dsc;
|
||||
|
||||
/* Return immediately if it's busy with draw task. */
|
||||
if(thread_dsc->task_act)
|
||||
return 0;
|
||||
#else
|
||||
/* Return immediately if it's busy with draw task. */
|
||||
if(draw_g2d_unit->task_act)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
/* Try to get an ready to draw. */
|
||||
lv_draw_task_t * t = lv_draw_get_available_task(layer, NULL, DRAW_UNIT_ID_G2D);
|
||||
|
||||
if(t == NULL || t->preferred_draw_unit_id != DRAW_UNIT_ID_G2D)
|
||||
return LV_DRAW_UNIT_IDLE;
|
||||
|
||||
if(lv_draw_layer_alloc_buf(layer) == NULL)
|
||||
return LV_DRAW_UNIT_IDLE;
|
||||
|
||||
t->state = LV_DRAW_TASK_STATE_IN_PROGRESS;
|
||||
t->draw_unit = draw_unit;
|
||||
|
||||
#if LV_USE_G2D_DRAW_THREAD
|
||||
thread_dsc->task_act = t;
|
||||
|
||||
/* Let the render thread work. */
|
||||
if(thread_dsc->inited)
|
||||
lv_thread_sync_signal(&thread_dsc->sync);
|
||||
#else
|
||||
draw_g2d_unit->task_act = t;
|
||||
|
||||
_g2d_execute_drawing(t);
|
||||
|
||||
draw_g2d_unit->task_act->state = LV_DRAW_TASK_STATE_READY;
|
||||
draw_g2d_unit->task_act = NULL;
|
||||
|
||||
/* The draw unit is free now. Request a new dispatching as it can get a new task. */
|
||||
lv_draw_dispatch_request();
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int32_t _g2d_delete(lv_draw_unit_t * draw_unit)
|
||||
{
|
||||
lv_draw_g2d_unit_t * draw_g2d_unit = (lv_draw_g2d_unit_t *) draw_unit;
|
||||
lv_result_t res = LV_RESULT_OK;
|
||||
|
||||
#if LV_USE_G2D_DRAW_THREAD
|
||||
lv_draw_sw_thread_dsc_t * thread_dsc = &draw_g2d_unit->thread_dsc;
|
||||
LV_LOG_INFO("Cancel G2D draw thread.");
|
||||
thread_dsc->exit_status = true;
|
||||
|
||||
if(thread_dsc->inited)
|
||||
lv_thread_sync_signal(&thread_dsc->sync);
|
||||
|
||||
res = lv_thread_delete(&thread_dsc->thread);
|
||||
#endif
|
||||
g2d_close(draw_g2d_unit->g2d_handle);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void _g2d_execute_drawing(lv_draw_task_t * t)
|
||||
{
|
||||
lv_layer_t * layer = t->target_layer;
|
||||
lv_draw_buf_t * draw_buf = layer->draw_buf;
|
||||
|
||||
/* Invalidate only the drawing area */
|
||||
lv_draw_buf_invalidate_cache(draw_buf, NULL);
|
||||
|
||||
switch(t->type) {
|
||||
case LV_DRAW_TASK_TYPE_FILL:
|
||||
lv_draw_g2d_fill(t);
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_IMAGE:
|
||||
lv_draw_g2d_img(t);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if LV_USE_G2D_DRAW_THREAD
|
||||
static void _g2d_render_thread_cb(void * ptr)
|
||||
{
|
||||
lv_draw_sw_thread_dsc_t * thread_dsc = ptr;
|
||||
|
||||
lv_thread_sync_init(&thread_dsc->sync);
|
||||
thread_dsc->inited = true;
|
||||
|
||||
while(1) {
|
||||
/* Wait for sync if there is no task set. */
|
||||
while(thread_dsc->task_act == NULL) {
|
||||
if(thread_dsc->exit_status)
|
||||
break;
|
||||
|
||||
lv_thread_sync_wait(&thread_dsc->sync);
|
||||
}
|
||||
|
||||
if(thread_dsc->exit_status) {
|
||||
LV_LOG_INFO("Ready to exit G2D draw thread.");
|
||||
break;
|
||||
}
|
||||
|
||||
_g2d_execute_drawing(thread_dsc->task_act);
|
||||
|
||||
/* Signal the ready state to dispatcher. */
|
||||
thread_dsc->task_act->state = LV_DRAW_TASK_STATE_READY;
|
||||
|
||||
/* Cleanup. */
|
||||
thread_dsc->task_act = NULL;
|
||||
|
||||
/* The draw unit is free now. Request a new dispatching as it can get a new task. */
|
||||
lv_draw_dispatch_request();
|
||||
}
|
||||
|
||||
thread_dsc->inited = false;
|
||||
lv_thread_sync_delete(&thread_dsc->sync);
|
||||
LV_LOG_INFO("Exit G2D draw thread.");
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*LV_USE_DRAW_G2D*/
|
||||
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* @file lv_draw_g2d.h
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2024 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_G2D_H
|
||||
#define LV_DRAW_G2D_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_DRAW_G2D
|
||||
#include "../../sw/lv_draw_sw_private.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct lv_draw_g2d_unit {
|
||||
lv_draw_unit_t base_unit;
|
||||
#if LV_USE_OS
|
||||
lv_draw_sw_thread_dsc_t thread_dsc;
|
||||
#else
|
||||
lv_draw_task_t * task_act;
|
||||
#endif
|
||||
|
||||
void * g2d_handle;
|
||||
} lv_draw_g2d_unit_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
void lv_draw_g2d_init(void);
|
||||
|
||||
void lv_draw_g2d_deinit(void);
|
||||
|
||||
void lv_draw_buf_g2d_init_handlers(void);
|
||||
|
||||
void lv_draw_g2d_fill(lv_draw_task_t * t);
|
||||
|
||||
void lv_draw_g2d_img(lv_draw_task_t * t);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_DRAW_G2D*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_G2D_H*/
|
||||
@@ -0,0 +1,178 @@
|
||||
/**
|
||||
* @file lv_draw_g2d_fill.c
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2024 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_g2d.h"
|
||||
|
||||
#if LV_USE_DRAW_G2D
|
||||
#include <stdlib.h>
|
||||
#include "g2d.h"
|
||||
#include "../../../misc/lv_area_private.h"
|
||||
#include "lv_g2d_buf_map.h"
|
||||
#include "lv_g2d_utils.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/* Blit simple w/ opa and alpha channel */
|
||||
static void _g2d_fill(void * g2d_handle, struct g2d_surface * dst_surf);
|
||||
static void _g2d_fill_with_opa(void * g2d_handle, struct g2d_surface * dst_surf, struct g2d_surface * src_surf);
|
||||
|
||||
static void _g2d_set_src_surf(struct g2d_surface * src_surf, struct g2d_buf * buf, const lv_area_t * area,
|
||||
lv_color_t color, lv_opa_t opa);
|
||||
|
||||
static void _g2d_set_dst_surf(struct g2d_surface * dst_surf, struct g2d_buf * buf, const lv_area_t * area,
|
||||
int32_t stride, lv_color_t color);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_g2d_fill(lv_draw_task_t * t)
|
||||
{
|
||||
lv_draw_fill_dsc_t * dsc = t->draw_dsc;
|
||||
|
||||
if(dsc->opa <= (lv_opa_t)LV_OPA_MIN)
|
||||
return;
|
||||
|
||||
lv_draw_g2d_unit_t * u = (lv_draw_g2d_unit_t *)t->draw_unit;
|
||||
lv_layer_t * layer = t->target_layer;
|
||||
lv_draw_buf_t * draw_buf = layer->draw_buf;
|
||||
lv_area_t * coords = &t->area;
|
||||
|
||||
lv_area_t rel_coords;
|
||||
lv_area_copy(&rel_coords, coords);
|
||||
lv_area_move(&rel_coords, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
lv_area_t rel_clip_area;
|
||||
lv_area_copy(&rel_clip_area, &t->clip_area);
|
||||
lv_area_move(&rel_clip_area, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
lv_area_t blend_area;
|
||||
if(!lv_area_intersect(&blend_area, &rel_coords, &rel_clip_area))
|
||||
return; /*Fully clipped, nothing to do*/
|
||||
|
||||
/* G2D takes stride in pixels. */
|
||||
int32_t stride = draw_buf->header.stride / (lv_color_format_get_bpp(draw_buf->header.cf) / 8);
|
||||
|
||||
/* Destination buffer */
|
||||
struct g2d_buf * dst_buf = g2d_search_buf_map(draw_buf->data);
|
||||
|
||||
bool has_opa = (dsc->opa < (lv_opa_t)LV_OPA_MAX);
|
||||
struct g2d_surface dst_surf;
|
||||
_g2d_set_dst_surf(&dst_surf, dst_buf, &blend_area, stride, dsc->color);
|
||||
|
||||
if(has_opa) {
|
||||
struct g2d_buf * tmp_buf = g2d_alloc(lv_area_get_width(&blend_area) * lv_area_get_height(&blend_area) * sizeof(
|
||||
lv_color32_t), 1);
|
||||
G2D_ASSERT_MSG(tmp_buf, "Failed to alloc temporary buffer.");
|
||||
struct g2d_surface src_surf;
|
||||
_g2d_set_src_surf(&src_surf, tmp_buf, &blend_area, dsc->color, dsc->opa);
|
||||
_g2d_fill_with_opa(u->g2d_handle, &dst_surf, &src_surf);
|
||||
g2d_free(tmp_buf);
|
||||
}
|
||||
else {
|
||||
_g2d_fill(u->g2d_handle, &dst_surf);
|
||||
}
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void _g2d_set_src_surf(struct g2d_surface * src_surf, struct g2d_buf * buf, const lv_area_t * area,
|
||||
lv_color_t color, lv_opa_t opa)
|
||||
{
|
||||
int32_t width = lv_area_get_width(area);
|
||||
int32_t height = lv_area_get_height(area);
|
||||
|
||||
src_surf->format = G2D_RGBA8888;
|
||||
|
||||
src_surf->left = 0;
|
||||
src_surf->top = 0;
|
||||
src_surf->right = width;
|
||||
src_surf->bottom = height;
|
||||
src_surf->stride = width;
|
||||
src_surf->width = width;
|
||||
src_surf->height = height;
|
||||
|
||||
src_surf->planes[0] = buf->buf_paddr;
|
||||
src_surf->rot = G2D_ROTATION_0;
|
||||
|
||||
src_surf->clrcolor = g2d_rgba_to_u32(color);
|
||||
src_surf->global_alpha = opa;
|
||||
src_surf->blendfunc = G2D_ONE | G2D_PRE_MULTIPLIED_ALPHA;
|
||||
}
|
||||
|
||||
static void _g2d_set_dst_surf(struct g2d_surface * dst_surf, struct g2d_buf * buf, const lv_area_t * area,
|
||||
int32_t stride, lv_color_t color)
|
||||
{
|
||||
int32_t width = lv_area_get_width(area);
|
||||
int32_t height = lv_area_get_height(area);
|
||||
|
||||
dst_surf->format = G2D_RGBA8888;
|
||||
|
||||
dst_surf->left = area->x1;
|
||||
dst_surf->top = area->y1;
|
||||
dst_surf->right = area->x1 + width;
|
||||
dst_surf->bottom = area->y1 + height;
|
||||
dst_surf->stride = stride;
|
||||
dst_surf->width = width;
|
||||
dst_surf->height = height;
|
||||
|
||||
dst_surf->planes[0] = buf->buf_paddr;
|
||||
dst_surf->rot = G2D_ROTATION_0;
|
||||
|
||||
dst_surf->clrcolor = g2d_rgba_to_u32(color);
|
||||
dst_surf->global_alpha = 0xff;
|
||||
dst_surf->blendfunc = G2D_ONE_MINUS_SRC_ALPHA | G2D_PRE_MULTIPLIED_ALPHA;
|
||||
}
|
||||
|
||||
static void _g2d_fill_with_opa(void * g2d_handle, struct g2d_surface * dst_surf, struct g2d_surface * src_surf)
|
||||
{
|
||||
g2d_clear(g2d_handle, src_surf);
|
||||
|
||||
g2d_enable(g2d_handle, G2D_BLEND);
|
||||
g2d_enable(g2d_handle, G2D_GLOBAL_ALPHA);
|
||||
g2d_blit(g2d_handle, src_surf, dst_surf);
|
||||
g2d_finish(g2d_handle);
|
||||
g2d_disable(g2d_handle, G2D_GLOBAL_ALPHA);
|
||||
g2d_disable(g2d_handle, G2D_BLEND);
|
||||
}
|
||||
|
||||
static void _g2d_fill(void * g2d_handle, struct g2d_surface * dst_surf)
|
||||
{
|
||||
g2d_clear(g2d_handle, dst_surf);
|
||||
|
||||
g2d_finish(g2d_handle);
|
||||
}
|
||||
|
||||
#endif /*LV_USE_DRAW_G2D*/
|
||||
@@ -0,0 +1,214 @@
|
||||
/**
|
||||
* @file lv_draw_g2d_img.c
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2024 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_g2d.h"
|
||||
|
||||
#if LV_USE_DRAW_G2D
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include "g2d.h"
|
||||
#include "../../../misc/lv_area_private.h"
|
||||
#include "lv_g2d_utils.h"
|
||||
#include "lv_g2d_buf_map.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static struct g2d_buf * _g2d_handle_src_buf(const lv_image_dsc_t * data);
|
||||
|
||||
static void _g2d_set_src_surf(struct g2d_surface * src_surf, struct g2d_buf * buf, const lv_area_t * area,
|
||||
int32_t stride, lv_color_format_t cf, lv_opa_t opa);
|
||||
|
||||
static void _g2d_set_dst_surf(struct g2d_surface * dst_surf, struct g2d_buf * buf, const lv_area_t * area,
|
||||
int32_t stride, lv_color_format_t cf, const lv_draw_image_dsc_t * dsc);
|
||||
|
||||
/* Blit simple w/ opa and alpha channel */
|
||||
static void _g2d_blit(void * g2d_handle, struct g2d_surface * dst_surf, struct g2d_surface * src_surf);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_g2d_img(lv_draw_task_t * t)
|
||||
{
|
||||
lv_draw_image_dsc_t * dsc = t->draw_dsc;
|
||||
|
||||
if(dsc->opa <= (lv_opa_t)LV_OPA_MIN)
|
||||
return;
|
||||
|
||||
lv_draw_g2d_unit_t * u = (lv_draw_g2d_unit_t *)t->draw_unit;
|
||||
lv_layer_t * layer = t->target_layer;
|
||||
lv_draw_buf_t * draw_buf = layer->draw_buf;
|
||||
const lv_image_dsc_t * img_dsc = dsc->src;
|
||||
lv_area_t * coords = &t->area;
|
||||
|
||||
lv_area_t rel_coords;
|
||||
lv_area_copy(&rel_coords, coords);
|
||||
lv_area_move(&rel_coords, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
lv_area_t clip_area;
|
||||
lv_area_copy(&clip_area, &t->clip_area);
|
||||
lv_area_move(&clip_area, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
lv_area_t blend_area;
|
||||
bool has_transform = (dsc->rotation != 0 || dsc->scale_x != LV_SCALE_NONE || dsc->scale_y != LV_SCALE_NONE);
|
||||
if(has_transform)
|
||||
lv_area_copy(&blend_area, &rel_coords);
|
||||
else if(!lv_area_intersect(&blend_area, &rel_coords, &clip_area))
|
||||
return; /*Fully clipped, nothing to do*/
|
||||
|
||||
lv_area_t src_area;
|
||||
src_area.x1 = blend_area.x1 - (coords->x1 - layer->buf_area.x1);
|
||||
src_area.y1 = blend_area.y1 - (coords->y1 - layer->buf_area.y1);
|
||||
src_area.x2 = src_area.x1 + lv_area_get_width(&blend_area);
|
||||
src_area.y2 = src_area.y1 + lv_area_get_height(&blend_area);
|
||||
int32_t src_stride = img_dsc->header.stride / (lv_color_format_get_bpp(img_dsc->header.cf) / 8);
|
||||
lv_color_format_t src_cf = img_dsc->header.cf;
|
||||
|
||||
/* Source image */
|
||||
struct g2d_buf * src_buf = _g2d_handle_src_buf(img_dsc);
|
||||
|
||||
/* Destination buffer */
|
||||
struct g2d_buf * dst_buf = g2d_search_buf_map(draw_buf->data);
|
||||
|
||||
/* G2D takes stride in pixels. */
|
||||
int32_t dest_stride = draw_buf->header.stride / (lv_color_format_get_bpp(draw_buf->header.cf) / 8);
|
||||
lv_color_format_t dest_cf = draw_buf->header.cf;
|
||||
|
||||
struct g2d_surface src_surf;
|
||||
struct g2d_surface dst_surf;
|
||||
|
||||
_g2d_set_src_surf(&src_surf, src_buf, &src_area, src_stride, src_cf, dsc->opa);
|
||||
_g2d_set_dst_surf(&dst_surf, dst_buf, &blend_area, dest_stride, dest_cf, dsc);
|
||||
|
||||
_g2d_blit(u->g2d_handle, &dst_surf, &src_surf);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static struct g2d_buf * _g2d_handle_src_buf(const lv_image_dsc_t * img_dsc)
|
||||
{
|
||||
struct g2d_buf * src_buf = g2d_search_buf_map((void *)img_dsc->data);
|
||||
|
||||
if(src_buf == NULL) {
|
||||
src_buf = g2d_alloc(img_dsc->data_size, 1);
|
||||
G2D_ASSERT_MSG(src_buf, "Failed to alloc source buffer.");
|
||||
memcpy((uint8_t *)src_buf->buf_vaddr, img_dsc->data, img_dsc->data_size);
|
||||
g2d_cache_op(src_buf, G2D_CACHE_FLUSH);
|
||||
g2d_insert_buf_map((void *)img_dsc->data, src_buf);
|
||||
}
|
||||
|
||||
return src_buf;
|
||||
}
|
||||
|
||||
static void _g2d_set_src_surf(struct g2d_surface * src_surf, struct g2d_buf * buf, const lv_area_t * area,
|
||||
int32_t stride, lv_color_format_t cf, lv_opa_t opa)
|
||||
{
|
||||
src_surf->format = g2d_get_buf_format(cf);
|
||||
|
||||
src_surf->left = area->x1;
|
||||
src_surf->top = area->y1;
|
||||
src_surf->right = area->x2;
|
||||
src_surf->bottom = area->y2;
|
||||
src_surf->stride = stride;
|
||||
src_surf->width = area->x2 - area->x1;
|
||||
src_surf->height = area->y2 - area->y1;
|
||||
|
||||
src_surf->planes[0] = buf->buf_paddr;
|
||||
src_surf->rot = G2D_ROTATION_0;
|
||||
|
||||
src_surf->clrcolor = g2d_rgba_to_u32(lv_color_black());
|
||||
src_surf->global_alpha = opa;
|
||||
src_surf->blendfunc = G2D_ONE | G2D_PRE_MULTIPLIED_ALPHA;
|
||||
}
|
||||
|
||||
static void _g2d_set_dst_surf(struct g2d_surface * dst_surf, struct g2d_buf * buf, const lv_area_t * area,
|
||||
int32_t stride, lv_color_format_t cf, const lv_draw_image_dsc_t * dsc)
|
||||
{
|
||||
int32_t width = lv_area_get_width(area);
|
||||
int32_t height = lv_area_get_height(area);
|
||||
|
||||
lv_point_t pivot = dsc->pivot;
|
||||
/*The offsets are now relative to the transformation result with pivot ULC*/
|
||||
int32_t piv_offset_x = 0;
|
||||
int32_t piv_offset_y = 0;
|
||||
int32_t trim_x = 0;
|
||||
int32_t trim_y = 0;
|
||||
int32_t dest_w;
|
||||
int32_t dest_h;
|
||||
|
||||
float fp_scale_x = (float)dsc->scale_x / LV_SCALE_NONE;
|
||||
float fp_scale_y = (float)dsc->scale_y / LV_SCALE_NONE;
|
||||
int32_t int_scale_x = (int32_t)fp_scale_x;
|
||||
int32_t int_scale_y = (int32_t)fp_scale_y;
|
||||
|
||||
/*Any scale_factor in (k, k + 1] will result in a trim equal to k*/
|
||||
trim_x = (fp_scale_x == int_scale_x) ? int_scale_x - 1 : int_scale_x;
|
||||
trim_y = (fp_scale_y == int_scale_y) ? int_scale_y - 1 : int_scale_y;
|
||||
|
||||
dest_w = width * fp_scale_x + trim_x;
|
||||
dest_h = height * fp_scale_y + trim_y;
|
||||
|
||||
/*Final pivot offset = scale_factor * rotation_pivot_offset + scaling_pivot_offset*/
|
||||
piv_offset_x = floor(fp_scale_x * piv_offset_x) - floor((fp_scale_x - 1) * pivot.x);
|
||||
piv_offset_y = floor(fp_scale_y * piv_offset_y) - floor((fp_scale_y - 1) * pivot.y);
|
||||
|
||||
dst_surf->format = g2d_get_buf_format(cf);
|
||||
|
||||
dst_surf->left = area->x1 + piv_offset_x;
|
||||
dst_surf->top = area->y1 + piv_offset_y;
|
||||
dst_surf->right = area->x1 + piv_offset_x + dest_w - trim_x;
|
||||
dst_surf->bottom = area->y1 + piv_offset_y + dest_h - trim_y;
|
||||
dst_surf->stride = stride;
|
||||
dst_surf->width = dest_w - trim_x;
|
||||
dst_surf->height = dest_h - trim_y;
|
||||
|
||||
dst_surf->planes[0] = buf->buf_paddr;
|
||||
dst_surf->rot = G2D_ROTATION_0;
|
||||
|
||||
dst_surf->clrcolor = g2d_rgba_to_u32(lv_color_black());
|
||||
dst_surf->global_alpha = 0xff;
|
||||
dst_surf->blendfunc = G2D_ONE_MINUS_SRC_ALPHA | G2D_PRE_MULTIPLIED_ALPHA;
|
||||
}
|
||||
|
||||
static void _g2d_blit(void * g2d_handle, struct g2d_surface * dst_surf, struct g2d_surface * src_surf)
|
||||
{
|
||||
g2d_enable(g2d_handle, G2D_BLEND);
|
||||
g2d_enable(g2d_handle, G2D_GLOBAL_ALPHA);
|
||||
g2d_blit(g2d_handle, src_surf, dst_surf);
|
||||
g2d_finish(g2d_handle);
|
||||
g2d_disable(g2d_handle, G2D_GLOBAL_ALPHA);
|
||||
g2d_disable(g2d_handle, G2D_BLEND);
|
||||
}
|
||||
#endif /*LV_USE_DRAW_G2D*/
|
||||
@@ -0,0 +1,247 @@
|
||||
/**
|
||||
* @file lv_g2d_buf_map.c
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2024 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "lv_g2d_buf_map.h"
|
||||
|
||||
#if LV_USE_DRAW_G2D
|
||||
#include <stdio.h>
|
||||
#include "lv_g2d_utils.h"
|
||||
#include "g2d.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static unsigned long _map_hash_function(void * ptr);
|
||||
|
||||
static lv_map_item_t * _map_create_item(void * key, struct g2d_buf * value);
|
||||
|
||||
static void _map_free_item(lv_map_item_t * item);
|
||||
|
||||
static void _handle_collision(unsigned long index, lv_map_item_t * item);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
static lv_buf_map_t * table;
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void g2d_create_buf_map(void)
|
||||
{
|
||||
table = (lv_buf_map_t *) lv_malloc(sizeof(lv_buf_map_t));
|
||||
table->size = LV_G2D_HASH_TABLE_SIZE;
|
||||
table->count = 0;
|
||||
table->items = (lv_map_item_t **) lv_malloc_zeroed(table->size * sizeof(lv_map_item_t *));
|
||||
table->overflow_list = (lv_array_t **) lv_malloc_zeroed(table->size * sizeof(lv_array_t *));
|
||||
}
|
||||
|
||||
void g2d_free_buf_map(void)
|
||||
{
|
||||
for(int i = 0; i < table->size; i++) {
|
||||
if(table->overflow_list[i]) {
|
||||
lv_array_deinit(table->overflow_list[i]);
|
||||
lv_free(table->overflow_list[i]);
|
||||
}
|
||||
|
||||
lv_map_item_t * item = table->items[i];
|
||||
if(item != NULL)
|
||||
_map_free_item(item);
|
||||
}
|
||||
|
||||
lv_free(table->items);
|
||||
lv_free(table->overflow_list);
|
||||
lv_free(table);
|
||||
}
|
||||
|
||||
void g2d_insert_buf_map(void * key, struct g2d_buf * value)
|
||||
{
|
||||
lv_map_item_t * item = _map_create_item(key, value);
|
||||
int index = _map_hash_function(key);
|
||||
|
||||
if(table->items[index] == NULL) {
|
||||
/* Key not found. */
|
||||
if(table->count == table->size) {
|
||||
/* Table is full. */
|
||||
_map_free_item(item);
|
||||
G2D_ASSERT_MSG(false, "Hash table is full.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(table->items[index]->key == key) {
|
||||
/* Key already exists, update value. */
|
||||
table->items[index]->value = value;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
/* Handle the collision */
|
||||
_handle_collision(index, item);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Insert item. */
|
||||
table->items[index] = item;
|
||||
table->count++;
|
||||
}
|
||||
|
||||
struct g2d_buf * g2d_search_buf_map(void * key)
|
||||
{
|
||||
int index = _map_hash_function(key);
|
||||
lv_map_item_t * item = table->items[index];
|
||||
lv_array_t * list = (lv_array_t *)table->overflow_list[index];
|
||||
|
||||
if(item == NULL)
|
||||
return NULL;
|
||||
|
||||
if(item->key == key)
|
||||
return item->value;
|
||||
|
||||
if(list == NULL)
|
||||
return NULL;
|
||||
|
||||
for(uint32_t i = 0; i < lv_array_size(list); i++) {
|
||||
item = (lv_map_item_t *)lv_array_at(list, i);
|
||||
if(item->key == key)
|
||||
return item->value;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void g2d_free_item(void * key)
|
||||
{
|
||||
/* Delete an item from the table. */
|
||||
int index = _map_hash_function(key);
|
||||
lv_map_item_t * item = table->items[index];
|
||||
lv_array_t * list = (lv_array_t *)table->overflow_list[index];
|
||||
|
||||
if(item == NULL) {
|
||||
return;
|
||||
}
|
||||
else if(list == NULL && item->key == key) {
|
||||
/* No collision chain, just remove item. */
|
||||
table->items[index] = NULL;
|
||||
_map_free_item(item);
|
||||
table->count--;
|
||||
return;
|
||||
}
|
||||
else if(list != NULL) {
|
||||
/* Collision chain exists. */
|
||||
for(uint32_t i = 0; i < lv_array_size(list); i++) {
|
||||
item = (lv_map_item_t *)lv_array_at(list, i);
|
||||
if(item->key == key) {
|
||||
lv_array_remove(list, i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void g2d_print_table(void)
|
||||
{
|
||||
LV_LOG("\nHash Table\n-------------------\n");
|
||||
|
||||
for(int i = 0; i < table->size; i++) {
|
||||
if(table->items[i]) {
|
||||
LV_LOG("Index:%d, Key:%p, Value:%p\n", i, table->items[i] -> key, (void *)table->items[i]->value);
|
||||
if(table->overflow_list[i]) {
|
||||
for(uint32_t j = 0 ; j < lv_array_size(table->overflow_list[i]); j++) {
|
||||
lv_map_item_t * item = (lv_map_item_t *)lv_array_at(table->overflow_list[i], j);
|
||||
LV_LOG("Index:%d, Key:%p, Value:%p\n", i, item -> key, (void *)item->value);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LV_LOG("-------------------\n\n");
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static unsigned long _map_hash_function(void * ptr)
|
||||
{
|
||||
unsigned long i = 0;
|
||||
char str[64];
|
||||
G2D_ASSERT_MSG(ptr, "Key is null.");
|
||||
sprintf(str, "%p", ptr);
|
||||
|
||||
for(int j = 0; str[j]; j++)
|
||||
i += str[j];
|
||||
|
||||
return i % LV_G2D_HASH_TABLE_SIZE;
|
||||
}
|
||||
|
||||
static void _handle_collision(unsigned long index, lv_map_item_t * item)
|
||||
{
|
||||
if(table->overflow_list[index] == NULL) {
|
||||
/* Create the list. */
|
||||
lv_array_t * list = (lv_array_t *) lv_malloc(sizeof(lv_array_t));;
|
||||
lv_array_init(list, LV_ARRAY_DEFAULT_CAPACITY, sizeof(lv_map_item_t));
|
||||
lv_array_push_back(list, item);
|
||||
table->overflow_list[index] = list;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
lv_array_t * list = (lv_array_t *)table->overflow_list[index];
|
||||
for(uint32_t i = 0; i < lv_array_size(list); i++) {
|
||||
lv_map_item_t * it = (lv_map_item_t *)lv_array_at(list, i);
|
||||
if(it->key == item->key) {
|
||||
/* Key exists, update value. */
|
||||
it->value = item->value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* Insert to the list. */
|
||||
lv_array_push_back(table->overflow_list[index], item);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static lv_map_item_t * _map_create_item(void * key, struct g2d_buf * value)
|
||||
{
|
||||
lv_map_item_t * item = (lv_map_item_t *) lv_malloc(sizeof(lv_map_item_t));
|
||||
G2D_ASSERT_MSG(item, "Failed to alloc item.");
|
||||
item->key = key;
|
||||
item->value = value;
|
||||
return item;
|
||||
}
|
||||
|
||||
static void _map_free_item(lv_map_item_t * item)
|
||||
{
|
||||
/* Also free the g2d_buf. */
|
||||
g2d_free(item->value);
|
||||
item->key = NULL;
|
||||
item->value = NULL;
|
||||
lv_free(item);
|
||||
item = NULL;
|
||||
}
|
||||
|
||||
#endif /*LV_USE_DRAW_G2D*/
|
||||
@@ -0,0 +1,81 @@
|
||||
|
||||
/**
|
||||
* @file lv_g2d_buf_map.h
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2024 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef LV_G2D_BUF_MAP_H
|
||||
#define LV_G2D_BUF_MAP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_DRAW_G2D
|
||||
|
||||
#include "../../../misc/lv_array.h"
|
||||
#include <string.h>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/* Map item definition. */
|
||||
typedef struct lv_map_item {
|
||||
/* Virtual address buffer. */
|
||||
void * key;
|
||||
struct g2d_buf * value;
|
||||
} lv_map_item_t;
|
||||
|
||||
/*Buf map definition. */
|
||||
typedef struct lv_buf_map {
|
||||
lv_map_item_t ** items;
|
||||
lv_array_t ** overflow_list;
|
||||
|
||||
int size;
|
||||
int count;
|
||||
} lv_buf_map_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
void g2d_create_buf_map(void);
|
||||
|
||||
void g2d_free_buf_map(void);
|
||||
|
||||
void g2d_insert_buf_map(void * key, struct g2d_buf * value);
|
||||
|
||||
struct g2d_buf * g2d_search_buf_map(void * key);
|
||||
|
||||
void g2d_free_item(void * key);
|
||||
|
||||
void g2d_print_table(void);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_DRAW_G2D*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /* LV_G2D_BUF_MAP_H */
|
||||
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* @file lv_g2d_utils.c
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2024 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_g2d_utils.h"
|
||||
|
||||
#if LV_USE_DRAW_G2D
|
||||
#include "lv_g2d_buf_map.h"
|
||||
#include "lv_draw_g2d.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
g2d_format_t g2d_get_buf_format(lv_color_format_t cf)
|
||||
{
|
||||
g2d_format_t color_f = G2D_RGB565;
|
||||
|
||||
switch(cf) {
|
||||
case LV_COLOR_FORMAT_RGB565:
|
||||
color_f = G2D_RGB565;
|
||||
break;
|
||||
case LV_COLOR_FORMAT_ARGB8888:
|
||||
color_f = G2D_BGRA8888;
|
||||
break;
|
||||
case LV_COLOR_FORMAT_XRGB8888:
|
||||
color_f = G2D_BGRX8888;
|
||||
break;
|
||||
case LV_COLOR_FORMAT_RGB888:
|
||||
color_f = G2D_BGR888;
|
||||
break;
|
||||
case LV_COLOR_FORMAT_NV12:
|
||||
color_f = G2D_NV12;
|
||||
break;
|
||||
case LV_COLOR_FORMAT_I420:
|
||||
color_f = G2D_I420;
|
||||
break;
|
||||
case LV_COLOR_FORMAT_NV21:
|
||||
color_f = G2D_NV21;
|
||||
break;
|
||||
case LV_COLOR_FORMAT_YUY2:
|
||||
color_f = G2D_YUYV;
|
||||
break;
|
||||
case LV_COLOR_FORMAT_UYVY:
|
||||
color_f = G2D_UYVY;
|
||||
break;
|
||||
default:
|
||||
G2D_ASSERT_MSG(false, "Unsupported color format.");
|
||||
break;
|
||||
}
|
||||
return color_f;
|
||||
}
|
||||
|
||||
uint32_t g2d_rgba_to_u32(lv_color_t color)
|
||||
{
|
||||
return (uint32_t)((color.red) + (color.green << 8) + (color.blue << 16) + ((uint32_t)0xff << 24));
|
||||
}
|
||||
|
||||
int32_t g2d_get_buf_fd(const lv_draw_buf_t * draw_buf)
|
||||
{
|
||||
struct g2d_buf * buf = g2d_search_buf_map(draw_buf->data);
|
||||
G2D_ASSERT_MSG(buf, "Failed to find buffer in map.");
|
||||
return g2d_buf_export_fd(buf);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_DRAW_G2D*/
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* @file lv_g2d_utils.h
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2024 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef LV_G2D_UTILS_H
|
||||
#define LV_G2D_UTILS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_DRAW_G2D
|
||||
#include "../../sw/lv_draw_sw_private.h"
|
||||
#include "g2d.h"
|
||||
#include "g2dExt.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#if LV_USE_G2D_ASSERT
|
||||
#define G2D_ASSERT(expr) LV_ASSERT(expr)
|
||||
#else
|
||||
#define G2D_ASSERT(expr)
|
||||
#endif
|
||||
|
||||
#define G2D_ASSERT_MSG(expr, msg) \
|
||||
do { \
|
||||
if(!(expr)) { \
|
||||
LV_LOG_ERROR(msg); \
|
||||
G2D_ASSERT(false); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef enum g2d_format g2d_format_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
g2d_format_t g2d_get_buf_format(lv_color_format_t cf);
|
||||
|
||||
uint32_t g2d_rgba_to_u32(lv_color_t color);
|
||||
|
||||
int32_t g2d_get_buf_fd(const lv_draw_buf_t * draw_buf);
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_DRAW_G2D*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_G2D_UTILS_H*/
|
||||
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* @file lv_draw_buf_pxp.c
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2023-2024 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_pxp.h"
|
||||
|
||||
#if LV_USE_PXP
|
||||
#if LV_USE_DRAW_PXP
|
||||
#include "../../lv_draw_buf_private.h"
|
||||
#include "lv_pxp_cfg.h"
|
||||
#include "lv_pxp_utils.h"
|
||||
|
||||
#include "lvgl_support.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static void _invalidate_cache(const lv_draw_buf_t * draw_buf, const lv_area_t * area);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_buf_pxp_init_handlers(void)
|
||||
{
|
||||
lv_draw_buf_handlers_t * handlers = lv_draw_buf_get_handlers();
|
||||
lv_draw_buf_handlers_t * font_handlers = lv_draw_buf_get_font_handlers();
|
||||
lv_draw_buf_handlers_t * image_handlers = lv_draw_buf_get_image_handlers();
|
||||
|
||||
handlers->invalidate_cache_cb = _invalidate_cache;
|
||||
font_handlers->invalidate_cache_cb = _invalidate_cache;
|
||||
image_handlers->invalidate_cache_cb = _invalidate_cache;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void _invalidate_cache(const lv_draw_buf_t * draw_buf, const lv_area_t * area)
|
||||
{
|
||||
const lv_image_header_t * header = &draw_buf->header;
|
||||
uint32_t stride = header->stride;
|
||||
lv_color_format_t cf = header->cf;
|
||||
|
||||
if(area->y1 == 0) {
|
||||
uint32_t size = stride * lv_area_get_height(area);
|
||||
|
||||
/* Invalidate full buffer. */
|
||||
DEMO_CleanInvalidateCacheByAddr((void *)draw_buf->data, size);
|
||||
return;
|
||||
}
|
||||
|
||||
const uint8_t * buf_u8 = draw_buf->data;
|
||||
/* ARM require a 32 byte aligned address. */
|
||||
uint8_t align_bytes = 32;
|
||||
uint8_t bits_per_pixel = lv_color_format_get_bpp(cf);
|
||||
|
||||
uint16_t align_pixels = align_bytes * 8 / bits_per_pixel;
|
||||
uint16_t offset_x = 0;
|
||||
|
||||
if(area->x1 >= (int32_t)(area->x1 % align_pixels)) {
|
||||
uint16_t shift_x = area->x1 - (area->x1 % align_pixels);
|
||||
|
||||
offset_x = area->x1 - shift_x;
|
||||
buf_u8 += (shift_x * bits_per_pixel) / 8;
|
||||
}
|
||||
|
||||
if(area->y1) {
|
||||
uint16_t shift_y = area->y1;
|
||||
|
||||
buf_u8 += shift_y * stride;
|
||||
}
|
||||
|
||||
/* Area to clear can start from a different offset in buffer.
|
||||
* Invalidate the area line by line.
|
||||
*/
|
||||
uint16_t line_pixels = offset_x + lv_area_get_width(area);
|
||||
uint16_t line_size = (line_pixels * bits_per_pixel) / 8;
|
||||
uint16_t area_height = lv_area_get_height(area);
|
||||
|
||||
for(uint16_t y = 0; y < area_height; y++) {
|
||||
const void * line_addr = buf_u8 + y * stride;
|
||||
|
||||
DEMO_CleanInvalidateCacheByAddr((void *)line_addr, line_size);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /*LV_USE_DRAW_PXP*/
|
||||
#endif /*LV_USE_PXP*/
|
||||
@@ -0,0 +1,501 @@
|
||||
/**
|
||||
* @file lv_draw_pxp.c
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2022-2024 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_pxp.h"
|
||||
|
||||
#if LV_USE_PXP
|
||||
#if LV_USE_DRAW_PXP || LV_USE_ROTATE_PXP
|
||||
#include "lv_pxp_cfg.h"
|
||||
#include "lv_pxp_utils.h"
|
||||
|
||||
#if LV_USE_PARALLEL_DRAW_DEBUG
|
||||
#include "../../../core/lv_global.h"
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#define DRAW_UNIT_ID_PXP 3
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/*
|
||||
* Evaluate a task and set the score and preferred PXP unit.
|
||||
* Return 1 if task is preferred, 0 otherwise (task is not supported).
|
||||
*/
|
||||
static int32_t _pxp_evaluate(lv_draw_unit_t * draw_unit, lv_draw_task_t * task);
|
||||
|
||||
/*
|
||||
* Dispatch a task to the PXP unit.
|
||||
* Return 1 if task was dispatched, 0 otherwise (task not supported).
|
||||
*/
|
||||
static int32_t _pxp_dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer);
|
||||
|
||||
/*
|
||||
* Delete the PXP draw unit.
|
||||
*/
|
||||
static int32_t _pxp_delete(lv_draw_unit_t * draw_unit);
|
||||
|
||||
#if LV_USE_PXP_DRAW_THREAD
|
||||
static void _pxp_render_thread_cb(void * ptr);
|
||||
#endif
|
||||
|
||||
static void _pxp_execute_drawing(lv_draw_pxp_unit_t * u);
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
#if LV_USE_PARALLEL_DRAW_DEBUG
|
||||
#define _draw_info LV_GLOBAL_DEFAULT()->draw_info
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_pxp_init(void)
|
||||
{
|
||||
lv_pxp_init();
|
||||
|
||||
#if LV_USE_DRAW_PXP
|
||||
lv_draw_buf_pxp_init_handlers();
|
||||
|
||||
lv_draw_pxp_unit_t * draw_pxp_unit = lv_draw_create_unit(sizeof(lv_draw_pxp_unit_t));
|
||||
draw_pxp_unit->base_unit.evaluate_cb = _pxp_evaluate;
|
||||
draw_pxp_unit->base_unit.dispatch_cb = _pxp_dispatch;
|
||||
draw_pxp_unit->base_unit.delete_cb = _pxp_delete;
|
||||
draw_pxp_unit->base_unit.name = "NXP_PXP";
|
||||
|
||||
#if LV_USE_PXP_DRAW_THREAD
|
||||
lv_thread_init(&draw_pxp_unit->thread, "pxpdraw", LV_DRAW_THREAD_PRIO, _pxp_render_thread_cb, 2 * 1024, draw_pxp_unit);
|
||||
#endif
|
||||
#endif /*LV_USE_DRAW_PXP*/
|
||||
}
|
||||
|
||||
void lv_draw_pxp_deinit(void)
|
||||
{
|
||||
lv_pxp_deinit();
|
||||
}
|
||||
|
||||
void lv_draw_pxp_rotate(const void * src_buf, void * dest_buf, int32_t src_width, int32_t src_height,
|
||||
int32_t src_stride, int32_t dest_stride, lv_display_rotation_t rotation,
|
||||
lv_color_format_t cf)
|
||||
{
|
||||
lv_pxp_reset();
|
||||
|
||||
/* Convert rotation angle
|
||||
* To be in sync with CPU, the received angle is counterclockwise
|
||||
* and the PXP constants are for clockwise rotation
|
||||
*
|
||||
* counterclockwise clockwise
|
||||
* LV_DISPLAY_ROTATION_90 -> kPXP_Rotate270
|
||||
* LV_DISPLAY_ROTATION_270 -> kPXP_Rotate90
|
||||
*/
|
||||
pxp_rotate_degree_t pxp_rotation;
|
||||
switch(rotation) {
|
||||
case LV_DISPLAY_ROTATION_0:
|
||||
pxp_rotation = kPXP_Rotate0;
|
||||
break;
|
||||
case LV_DISPLAY_ROTATION_270:
|
||||
pxp_rotation = kPXP_Rotate90;
|
||||
break;
|
||||
case LV_DISPLAY_ROTATION_180:
|
||||
pxp_rotation = kPXP_Rotate180;
|
||||
break;
|
||||
case LV_DISPLAY_ROTATION_90:
|
||||
pxp_rotation = kPXP_Rotate270;
|
||||
break;
|
||||
default:
|
||||
pxp_rotation = kPXP_Rotate0;
|
||||
break;
|
||||
}
|
||||
PXP_SetRotateConfig(PXP_ID, kPXP_RotateOutputBuffer, pxp_rotation, kPXP_FlipDisable);
|
||||
|
||||
/*Simple blit, no effect - Disable PS buffer*/
|
||||
PXP_SetProcessSurfacePosition(PXP_ID, 0xFFFFU, 0xFFFFU, 0U, 0U);
|
||||
|
||||
/*AS buffer - source image*/
|
||||
pxp_as_buffer_config_t asBufferConfig = {
|
||||
.pixelFormat = pxp_get_as_px_format(cf),
|
||||
.bufferAddr = (uint32_t)src_buf,
|
||||
.pitchBytes = src_stride
|
||||
};
|
||||
PXP_SetAlphaSurfaceBufferConfig(PXP_ID, &asBufferConfig);
|
||||
PXP_SetAlphaSurfacePosition(PXP_ID, 0U, 0U, src_width - 1U, src_height - 1U);
|
||||
PXP_EnableAlphaSurfaceOverlayColorKey(PXP_ID, false);
|
||||
|
||||
/*Output buffer.*/
|
||||
pxp_output_buffer_config_t outputBufferConfig = {
|
||||
.pixelFormat = pxp_get_out_px_format(cf),
|
||||
.interlacedMode = kPXP_OutputProgressive,
|
||||
.buffer0Addr = (uint32_t)dest_buf,
|
||||
.buffer1Addr = (uint32_t)0U,
|
||||
.pitchBytes = dest_stride,
|
||||
.width = src_width,
|
||||
.height = src_height
|
||||
};
|
||||
PXP_SetOutputBufferConfig(PXP_ID, &outputBufferConfig);
|
||||
|
||||
lv_pxp_run();
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
#if LV_USE_DRAW_PXP
|
||||
static inline bool _pxp_src_cf_supported(lv_color_format_t cf)
|
||||
{
|
||||
bool is_cf_supported = false;
|
||||
|
||||
switch(cf) {
|
||||
case LV_COLOR_FORMAT_RGB565:
|
||||
case LV_COLOR_FORMAT_ARGB8888:
|
||||
case LV_COLOR_FORMAT_XRGB8888:
|
||||
is_cf_supported = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return is_cf_supported;
|
||||
}
|
||||
|
||||
static inline bool _pxp_dest_cf_supported(lv_color_format_t cf)
|
||||
{
|
||||
bool is_cf_supported = false;
|
||||
|
||||
switch(cf) {
|
||||
case LV_COLOR_FORMAT_RGB565:
|
||||
case LV_COLOR_FORMAT_RGB888:
|
||||
case LV_COLOR_FORMAT_ARGB8888:
|
||||
case LV_COLOR_FORMAT_XRGB8888:
|
||||
is_cf_supported = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return is_cf_supported;
|
||||
}
|
||||
|
||||
static bool _pxp_draw_img_supported(const lv_draw_image_dsc_t * draw_dsc)
|
||||
{
|
||||
const lv_image_dsc_t * img_dsc = draw_dsc->src;
|
||||
|
||||
bool is_tiled = draw_dsc->tile;
|
||||
/* Tiled image (repeat image) is currently not supported. */
|
||||
if(is_tiled)
|
||||
return false;
|
||||
|
||||
bool has_recolor = (draw_dsc->recolor_opa > LV_OPA_MIN);
|
||||
bool has_transform = (draw_dsc->rotation != 0 || draw_dsc->scale_x != LV_SCALE_NONE ||
|
||||
draw_dsc->scale_y != LV_SCALE_NONE);
|
||||
|
||||
/* Recolor and transformation are not supported at the same time. */
|
||||
if(has_recolor && has_transform)
|
||||
return false;
|
||||
|
||||
bool has_opa = (draw_dsc->opa < (lv_opa_t)LV_OPA_MAX);
|
||||
bool src_has_alpha = (img_dsc->header.cf == LV_COLOR_FORMAT_ARGB8888);
|
||||
|
||||
/*
|
||||
* Recolor or transformation for images w/ opa or alpha channel can't
|
||||
* be obtained in a single PXP configuration. Two steps are required.
|
||||
*/
|
||||
if((has_recolor || has_transform) && (has_opa || src_has_alpha))
|
||||
return false;
|
||||
|
||||
/* PXP can only rotate at 90x angles. */
|
||||
if(draw_dsc->rotation % 900)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* PXP is set to process 16x16 blocks to optimize the system for memory
|
||||
* bandwidth and image processing time.
|
||||
* The output engine essentially truncates any output pixels after the
|
||||
* desired number of pixels has been written.
|
||||
* When rotating a source image and the output is not divisible by the block
|
||||
* size, the incorrect pixels could be truncated and the final output image
|
||||
* can look shifted.
|
||||
*
|
||||
* No combination of rotate with flip, scaling or decimation is possible
|
||||
* if buffer is unaligned.
|
||||
*/
|
||||
if(has_transform && (img_dsc->header.w % 16 || img_dsc->header.h % 16))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int32_t _pxp_evaluate(lv_draw_unit_t * u, lv_draw_task_t * t)
|
||||
{
|
||||
LV_UNUSED(u);
|
||||
|
||||
const lv_draw_dsc_base_t * draw_dsc_base = (lv_draw_dsc_base_t *) t->draw_dsc;
|
||||
|
||||
if(!_pxp_dest_cf_supported(draw_dsc_base->layer->color_format))
|
||||
return 0;
|
||||
|
||||
switch(t->type) {
|
||||
case LV_DRAW_TASK_TYPE_FILL: {
|
||||
const lv_draw_fill_dsc_t * draw_dsc = (lv_draw_fill_dsc_t *) t->draw_dsc;
|
||||
|
||||
/* Most simple case: just a plain rectangle (no radius, no gradient). */
|
||||
if((draw_dsc->radius != 0) || (draw_dsc->grad.dir != (lv_grad_dir_t)LV_GRAD_DIR_NONE))
|
||||
return 0;
|
||||
|
||||
if(t->preference_score > 70) {
|
||||
t->preference_score = 70;
|
||||
t->preferred_draw_unit_id = DRAW_UNIT_ID_PXP;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
case LV_DRAW_TASK_TYPE_LAYER: {
|
||||
const lv_draw_image_dsc_t * draw_dsc = (lv_draw_image_dsc_t *) t->draw_dsc;
|
||||
lv_layer_t * layer_to_draw = (lv_layer_t *)draw_dsc->src;
|
||||
|
||||
if(!_pxp_src_cf_supported(layer_to_draw->color_format))
|
||||
return 0;
|
||||
|
||||
if(!_pxp_draw_img_supported(draw_dsc))
|
||||
return 0;
|
||||
|
||||
if(t->preference_score > 70) {
|
||||
t->preference_score = 70;
|
||||
t->preferred_draw_unit_id = DRAW_UNIT_ID_PXP;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
case LV_DRAW_TASK_TYPE_IMAGE: {
|
||||
lv_draw_image_dsc_t * draw_dsc = (lv_draw_image_dsc_t *) t->draw_dsc;
|
||||
const lv_image_dsc_t * img_dsc = draw_dsc->src;
|
||||
|
||||
if(img_dsc->header.cf >= LV_COLOR_FORMAT_PROPRIETARY_START)
|
||||
return 0;
|
||||
|
||||
if((!_pxp_src_cf_supported(img_dsc->header.cf)) ||
|
||||
(!pxp_buf_aligned(img_dsc->data, img_dsc->header.stride)))
|
||||
return 0;
|
||||
|
||||
if(!_pxp_draw_img_supported(draw_dsc))
|
||||
return 0;
|
||||
|
||||
if(t->preference_score > 70) {
|
||||
t->preference_score = 70;
|
||||
t->preferred_draw_unit_id = DRAW_UNIT_ID_PXP;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t _pxp_dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer)
|
||||
{
|
||||
lv_draw_pxp_unit_t * draw_pxp_unit = (lv_draw_pxp_unit_t *) draw_unit;
|
||||
|
||||
/* Return immediately if it's busy with draw task. */
|
||||
if(draw_pxp_unit->task_act)
|
||||
return 0;
|
||||
|
||||
/* Try to get an ready to draw. */
|
||||
lv_draw_task_t * t = lv_draw_get_available_task(layer, NULL, DRAW_UNIT_ID_PXP);
|
||||
|
||||
if(t == NULL || t->preferred_draw_unit_id != DRAW_UNIT_ID_PXP)
|
||||
return LV_DRAW_UNIT_IDLE;
|
||||
|
||||
if(lv_draw_layer_alloc_buf(layer) == NULL)
|
||||
return LV_DRAW_UNIT_IDLE;
|
||||
|
||||
t->state = LV_DRAW_TASK_STATE_IN_PROGRESS;
|
||||
draw_pxp_unit->task_act = t;
|
||||
|
||||
#if LV_USE_PXP_DRAW_THREAD
|
||||
/* Let the render thread work. */
|
||||
if(draw_pxp_unit->inited)
|
||||
lv_thread_sync_signal(&draw_pxp_unit->sync);
|
||||
#else
|
||||
_pxp_execute_drawing(draw_pxp_unit);
|
||||
|
||||
draw_pxp_unit->task_act->state = LV_DRAW_TASK_STATE_READY;
|
||||
draw_pxp_unit->task_act = NULL;
|
||||
|
||||
/* The draw unit is free now. Request a new dispatching as it can get a new task. */
|
||||
lv_draw_dispatch_request();
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int32_t _pxp_delete(lv_draw_unit_t * draw_unit)
|
||||
{
|
||||
#if LV_USE_PXP_DRAW_THREAD
|
||||
lv_draw_pxp_unit_t * draw_pxp_unit = (lv_draw_pxp_unit_t *) draw_unit;
|
||||
|
||||
LV_LOG_INFO("Cancel PXP draw thread.");
|
||||
draw_pxp_unit->exit_status = true;
|
||||
|
||||
if(draw_pxp_unit->inited)
|
||||
lv_thread_sync_signal(&draw_pxp_unit->sync);
|
||||
|
||||
lv_result_t res = lv_thread_delete(&draw_pxp_unit->thread);
|
||||
|
||||
return res;
|
||||
#else
|
||||
LV_UNUSED(draw_unit);
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void _pxp_execute_drawing(lv_draw_pxp_unit_t * u)
|
||||
{
|
||||
lv_draw_task_t * t = u->task_act;
|
||||
lv_layer_t * layer = t->target_layer;
|
||||
lv_draw_buf_t * draw_buf = layer->draw_buf;
|
||||
|
||||
lv_area_t draw_area;
|
||||
if(!lv_area_intersect(&draw_area, &t->area, &t->clip_area))
|
||||
return; /*Fully clipped, nothing to do*/
|
||||
|
||||
/* Make area relative to the buffer */
|
||||
lv_area_move(&draw_area, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
/* Invalidate only the drawing area */
|
||||
lv_draw_buf_invalidate_cache(draw_buf, &draw_area);
|
||||
|
||||
#if LV_USE_PARALLEL_DRAW_DEBUG
|
||||
t->draw_unit = &u->base_unit;
|
||||
#endif
|
||||
|
||||
switch(t->type) {
|
||||
case LV_DRAW_TASK_TYPE_FILL:
|
||||
lv_draw_pxp_fill(t);
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_IMAGE:
|
||||
lv_draw_pxp_img(t);
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_LAYER:
|
||||
lv_draw_pxp_layer(t);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
#if LV_USE_PARALLEL_DRAW_DEBUG
|
||||
/*Layers manage it for themselves*/
|
||||
if(t->type != LV_DRAW_TASK_TYPE_LAYER) {
|
||||
lv_area_t draw_area;
|
||||
if(!lv_area_intersect(&draw_area, &t->area, &t->clip_area))
|
||||
return;
|
||||
|
||||
int32_t idx = u->base_unit.idx;
|
||||
|
||||
lv_draw_rect_dsc_t rect_dsc;
|
||||
lv_draw_rect_dsc_init(&rect_dsc);
|
||||
rect_dsc.bg_color = lv_palette_main(idx % LV_PALETTE_LAST);
|
||||
rect_dsc.border_color = rect_dsc.bg_color;
|
||||
rect_dsc.bg_opa = LV_OPA_10;
|
||||
rect_dsc.border_opa = LV_OPA_80;
|
||||
rect_dsc.border_width = 1;
|
||||
lv_draw_sw_fill((lv_draw_unit_t *)u, &rect_dsc, &draw_area);
|
||||
|
||||
lv_point_t txt_size;
|
||||
lv_text_get_size(&txt_size, "W", LV_FONT_DEFAULT, 0, 0, 100, LV_TEXT_FLAG_NONE);
|
||||
|
||||
lv_area_t txt_area;
|
||||
txt_area.x1 = draw_area.x1;
|
||||
txt_area.y1 = draw_area.y1;
|
||||
txt_area.x2 = draw_area.x1 + txt_size.x - 1;
|
||||
txt_area.y2 = draw_area.y1 + txt_size.y - 1;
|
||||
|
||||
lv_draw_rect_dsc_init(&rect_dsc);
|
||||
rect_dsc.bg_color = lv_color_white();
|
||||
lv_draw_sw_fill((lv_draw_unit_t *)u, &rect_dsc, &txt_area);
|
||||
|
||||
char buf[8];
|
||||
lv_snprintf(buf, sizeof(buf), "%d", idx);
|
||||
lv_draw_label_dsc_t label_dsc;
|
||||
lv_draw_label_dsc_init(&label_dsc);
|
||||
label_dsc.color = lv_color_black();
|
||||
label_dsc.text = buf;
|
||||
lv_draw_sw_label((lv_draw_unit_t *)u, &label_dsc, &txt_area);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if LV_USE_PXP_DRAW_THREAD
|
||||
static void _pxp_render_thread_cb(void * ptr)
|
||||
{
|
||||
lv_draw_pxp_unit_t * u = ptr;
|
||||
|
||||
lv_thread_sync_init(&u->sync);
|
||||
u->inited = true;
|
||||
|
||||
while(1) {
|
||||
/* Wait for sync if there is no task set. */
|
||||
while(u->task_act == NULL) {
|
||||
if(u->exit_status)
|
||||
break;
|
||||
|
||||
lv_thread_sync_wait(&u->sync);
|
||||
}
|
||||
|
||||
if(u->exit_status) {
|
||||
LV_LOG_INFO("Ready to exit PXP draw thread.");
|
||||
break;
|
||||
}
|
||||
|
||||
_pxp_execute_drawing(u);
|
||||
|
||||
/* Signal the ready state to dispatcher. */
|
||||
u->task_act->state = LV_DRAW_TASK_STATE_READY;
|
||||
|
||||
/* Cleanup. */
|
||||
u->task_act = NULL;
|
||||
|
||||
/* The draw unit is free now. Request a new dispatching as it can get a new task. */
|
||||
lv_draw_dispatch_request();
|
||||
}
|
||||
|
||||
u->inited = false;
|
||||
lv_thread_sync_delete(&u->sync);
|
||||
LV_LOG_INFO("Exit PXP draw thread.");
|
||||
}
|
||||
#endif
|
||||
#endif /*LV_USE_DRAW_PXP*/
|
||||
#endif /*LV_USE_DRAW_PXP || LV_USE_ROTATE_PXP*/
|
||||
#endif /*LV_USE_PXP*/
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* @file lv_draw_pxp.h
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2022-2024 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_PXP_H
|
||||
#define LV_DRAW_PXP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_PXP
|
||||
#if LV_USE_DRAW_PXP || LV_USE_ROTATE_PXP
|
||||
#include "../../lv_draw_private.h"
|
||||
#include "../../../display/lv_display_private.h"
|
||||
#include "../../../misc/lv_area_private.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct lv_draw_pxp_unit_t {
|
||||
lv_draw_unit_t base_unit;
|
||||
lv_draw_task_t * task_act;
|
||||
#if LV_USE_OS
|
||||
lv_thread_sync_t sync;
|
||||
lv_thread_t thread;
|
||||
volatile bool inited;
|
||||
volatile bool exit_status;
|
||||
#endif
|
||||
} lv_draw_pxp_unit_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
void lv_draw_pxp_init(void);
|
||||
|
||||
void lv_draw_pxp_deinit(void);
|
||||
|
||||
void lv_draw_pxp_rotate(const void * src_buf, void * dest_buf, int32_t src_width, int32_t src_height,
|
||||
int32_t src_stride, int32_t dest_stride, lv_display_rotation_t rotation,
|
||||
lv_color_format_t cf);
|
||||
|
||||
#if LV_USE_DRAW_PXP
|
||||
void lv_draw_buf_pxp_init_handlers(void);
|
||||
|
||||
void lv_draw_pxp_fill(lv_draw_task_t * t);
|
||||
|
||||
void lv_draw_pxp_img(lv_draw_task_t * t);
|
||||
|
||||
void lv_draw_pxp_layer(lv_draw_task_t * t);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
#endif /*LV_USE_DRAW_PXP*/
|
||||
#endif /*LV_USE_DRAW_PXP || LV_USE_ROTATE_PXP*/
|
||||
#endif /*LV_USE_PXP*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_PXP_H*/
|
||||
@@ -0,0 +1,151 @@
|
||||
/**
|
||||
* @file lv_draw_pxp_fill.c
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2020-2024 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_pxp.h"
|
||||
|
||||
#if LV_USE_PXP
|
||||
#if LV_USE_DRAW_PXP
|
||||
#include "lv_pxp_cfg.h"
|
||||
#include "lv_pxp_utils.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static void _pxp_fill(uint8_t * dest_buf, const lv_area_t * dest_area, int32_t dest_stride,
|
||||
lv_color_format_t dest_cf, const lv_draw_fill_dsc_t * dsc);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_pxp_fill(lv_draw_task_t * t)
|
||||
{
|
||||
const lv_draw_fill_dsc_t * dsc = t->draw_dsc;
|
||||
const lv_area_t * coords = &t->area;
|
||||
|
||||
if(dsc->opa <= (lv_opa_t)LV_OPA_MIN)
|
||||
return;
|
||||
|
||||
lv_layer_t * layer = t->target_layer;
|
||||
lv_draw_buf_t * draw_buf = layer->draw_buf;
|
||||
|
||||
lv_area_t rel_coords;
|
||||
lv_area_copy(&rel_coords, coords);
|
||||
lv_area_move(&rel_coords, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
lv_area_t rel_clip_area;
|
||||
lv_area_copy(&rel_clip_area, &t->clip_area);
|
||||
lv_area_move(&rel_clip_area, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
lv_area_t blend_area;
|
||||
if(!lv_area_intersect(&blend_area, &rel_coords, &rel_clip_area))
|
||||
return; /*Fully clipped, nothing to do*/
|
||||
|
||||
_pxp_fill(draw_buf->data, &blend_area, draw_buf->header.stride, draw_buf->header.cf, dsc);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void _pxp_fill(uint8_t * dest_buf, const lv_area_t * dest_area, int32_t dest_stride,
|
||||
lv_color_format_t dest_cf, const lv_draw_fill_dsc_t * dsc)
|
||||
{
|
||||
int32_t dest_w = lv_area_get_width(dest_area);
|
||||
int32_t dest_h = lv_area_get_height(dest_area);
|
||||
|
||||
lv_pxp_reset();
|
||||
|
||||
uint8_t px_size = lv_color_format_get_size(dest_cf);
|
||||
|
||||
/*OUT buffer configure*/
|
||||
pxp_output_buffer_config_t outputConfig = {
|
||||
.pixelFormat = pxp_get_out_px_format(dest_cf),
|
||||
.interlacedMode = kPXP_OutputProgressive,
|
||||
.buffer0Addr = (uint32_t)(dest_buf + dest_stride * dest_area->y1 + px_size * dest_area->x1),
|
||||
.buffer1Addr = (uint32_t)NULL,
|
||||
.pitchBytes = dest_stride,
|
||||
.width = dest_w,
|
||||
.height = dest_h
|
||||
};
|
||||
|
||||
PXP_SetOutputBufferConfig(PXP_ID, &outputConfig);
|
||||
|
||||
if(dsc->opa >= (lv_opa_t)LV_OPA_MAX) {
|
||||
/*Simple color fill without opacity - AS disabled*/
|
||||
PXP_SetAlphaSurfacePosition(PXP_ID, 0xFFFFU, 0xFFFFU, 0U, 0U);
|
||||
|
||||
}
|
||||
else {
|
||||
/*Fill with opacity - AS used as source (same as OUT)*/
|
||||
pxp_as_buffer_config_t asBufferConfig = {
|
||||
.pixelFormat = pxp_get_as_px_format(dest_cf),
|
||||
.bufferAddr = outputConfig.buffer0Addr,
|
||||
.pitchBytes = outputConfig.pitchBytes
|
||||
};
|
||||
|
||||
PXP_SetAlphaSurfaceBufferConfig(PXP_ID, &asBufferConfig);
|
||||
PXP_SetAlphaSurfacePosition(PXP_ID, 0U, 0U, dest_w - 1U, dest_h - 1U);
|
||||
}
|
||||
|
||||
/*Disable PS, use as color generator*/
|
||||
PXP_SetProcessSurfacePosition(PXP_ID, 0xFFFFU, 0xFFFFU, 0U, 0U);
|
||||
PXP_SetProcessSurfaceBackGroundColor(PXP_ID, lv_color_to_u32(dsc->color));
|
||||
|
||||
/**
|
||||
* Configure Porter-Duff blending - src settings are unused for fill without opacity (opa = 0xff).
|
||||
*
|
||||
* Note: srcFactorMode and dstFactorMode are inverted in fsl_pxp.h:
|
||||
* srcFactorMode is actually applied on PS alpha value
|
||||
* dstFactorMode is actually applied on AS alpha value
|
||||
*/
|
||||
pxp_porter_duff_config_t pdConfig = {
|
||||
.enable = 1,
|
||||
.dstColorMode = kPXP_PorterDuffColorNoAlpha,
|
||||
.srcColorMode = kPXP_PorterDuffColorNoAlpha,
|
||||
.dstGlobalAlphaMode = kPXP_PorterDuffGlobalAlpha,
|
||||
.srcGlobalAlphaMode = kPXP_PorterDuffGlobalAlpha,
|
||||
.dstFactorMode = kPXP_PorterDuffFactorStraight,
|
||||
.srcFactorMode = (dsc->opa >= (lv_opa_t)LV_OPA_MAX) ? kPXP_PorterDuffFactorStraight : kPXP_PorterDuffFactorInversed,
|
||||
.dstGlobalAlpha = dsc->opa,
|
||||
.srcGlobalAlpha = dsc->opa,
|
||||
.dstAlphaMode = kPXP_PorterDuffAlphaStraight, /*don't care*/
|
||||
.srcAlphaMode = kPXP_PorterDuffAlphaStraight /*don't care*/
|
||||
};
|
||||
|
||||
PXP_SetPorterDuffConfig(PXP_ID, &pdConfig);
|
||||
|
||||
lv_pxp_run();
|
||||
}
|
||||
|
||||
#endif /*LV_USE_DRAW_PXP*/
|
||||
#endif /*LV_USE_PXP*/
|
||||
@@ -0,0 +1,369 @@
|
||||
/**
|
||||
* @file lv_draw_pxp_img.c
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2020-2024 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_pxp.h"
|
||||
|
||||
#if LV_USE_PXP
|
||||
#if LV_USE_DRAW_PXP
|
||||
#include "lv_pxp_cfg.h"
|
||||
#include "lv_pxp_utils.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/* Blit w/ recolor for images w/o opa and alpha channel */
|
||||
static void _pxp_blit_recolor(uint8_t * dest_buf, const lv_area_t * dest_area, int32_t dest_stride,
|
||||
lv_color_format_t dest_cf, const uint8_t * src_buf, const lv_area_t * src_area,
|
||||
int32_t src_stride, lv_color_format_t src_cf, const lv_draw_image_dsc_t * dsc);
|
||||
|
||||
/* Blit w/ transformation for images w/o opa and alpha channel */
|
||||
static void _pxp_blit_transform(uint8_t * dest_buf, const lv_area_t * dest_area, int32_t dest_stride,
|
||||
lv_color_format_t dest_cf, const uint8_t * src_buf, const lv_area_t * src_area,
|
||||
int32_t src_stride, lv_color_format_t src_cf, const lv_draw_image_dsc_t * dsc);
|
||||
|
||||
/* Blit simple w/ opa and alpha channel */
|
||||
static void _pxp_blit(uint8_t * dest_buf, const lv_area_t * dest_area, int32_t dest_stride,
|
||||
lv_color_format_t dest_cf, const uint8_t * src_buf, const lv_area_t * src_area,
|
||||
int32_t src_stride, lv_color_format_t src_cf, lv_opa_t opa);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_pxp_img(lv_draw_task_t * t)
|
||||
{
|
||||
const lv_draw_image_dsc_t * dsc = t->draw_dsc;
|
||||
const lv_area_t * coords = &t->area;
|
||||
|
||||
if(dsc->opa <= (lv_opa_t)LV_OPA_MIN)
|
||||
return;
|
||||
|
||||
lv_layer_t * layer = t->target_layer;
|
||||
lv_draw_buf_t * draw_buf = layer->draw_buf;
|
||||
const lv_image_dsc_t * img_dsc = dsc->src;
|
||||
|
||||
lv_area_t rel_coords;
|
||||
lv_area_copy(&rel_coords, coords);
|
||||
lv_area_move(&rel_coords, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
lv_area_t rel_clip_area;
|
||||
lv_area_copy(&rel_clip_area, &t->clip_area);
|
||||
lv_area_move(&rel_clip_area, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
lv_area_t blend_area;
|
||||
bool has_transform = (dsc->rotation != 0 || dsc->scale_x != LV_SCALE_NONE || dsc->scale_y != LV_SCALE_NONE);
|
||||
if(has_transform)
|
||||
lv_area_copy(&blend_area, &rel_coords);
|
||||
else if(!lv_area_intersect(&blend_area, &rel_coords, &rel_clip_area))
|
||||
return; /*Fully clipped, nothing to do*/
|
||||
|
||||
const uint8_t * src_buf = img_dsc->data;
|
||||
|
||||
lv_area_t src_area;
|
||||
src_area.x1 = blend_area.x1 - (coords->x1 - layer->buf_area.x1);
|
||||
src_area.y1 = blend_area.y1 - (coords->y1 - layer->buf_area.y1);
|
||||
src_area.x2 = src_area.x1 + lv_area_get_width(&blend_area) - 1;
|
||||
src_area.y2 = src_area.y1 + lv_area_get_height(&blend_area) - 1;
|
||||
int32_t src_stride = img_dsc->header.stride;
|
||||
lv_color_format_t src_cf = img_dsc->header.cf;
|
||||
|
||||
uint8_t * dest_buf = draw_buf->data;
|
||||
int32_t dest_stride = draw_buf->header.stride;
|
||||
lv_color_format_t dest_cf = draw_buf->header.cf;
|
||||
bool has_recolor = (dsc->recolor_opa > LV_OPA_MIN);
|
||||
|
||||
if(has_recolor && !has_transform)
|
||||
_pxp_blit_recolor(dest_buf, &blend_area, dest_stride, dest_cf,
|
||||
src_buf, &src_area, src_stride, src_cf, dsc);
|
||||
else if(has_transform)
|
||||
_pxp_blit_transform(dest_buf, &blend_area, dest_stride, dest_cf,
|
||||
src_buf, &src_area, src_stride, src_cf, dsc);
|
||||
else
|
||||
_pxp_blit(dest_buf, &blend_area, dest_stride, dest_cf,
|
||||
src_buf, &src_area, src_stride, src_cf, dsc->opa);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void _pxp_blit_recolor(uint8_t * dest_buf, const lv_area_t * dest_area, int32_t dest_stride,
|
||||
lv_color_format_t dest_cf, const uint8_t * src_buf, const lv_area_t * src_area,
|
||||
int32_t src_stride, lv_color_format_t src_cf, const lv_draw_image_dsc_t * dsc)
|
||||
{
|
||||
|
||||
int32_t dest_w = lv_area_get_width(dest_area);
|
||||
int32_t dest_h = lv_area_get_height(dest_area);
|
||||
int32_t src_w = lv_area_get_width(src_area);
|
||||
int32_t src_h = lv_area_get_height(src_area);
|
||||
|
||||
bool src_has_alpha = (src_cf == LV_COLOR_FORMAT_ARGB8888);
|
||||
uint8_t src_px_size = lv_color_format_get_size(src_cf);
|
||||
uint8_t dest_px_size = lv_color_format_get_size(dest_cf);
|
||||
|
||||
lv_pxp_reset();
|
||||
|
||||
/*AS buffer - source image*/
|
||||
pxp_as_buffer_config_t asBufferConfig = {
|
||||
.pixelFormat = pxp_get_as_px_format(src_cf),
|
||||
.bufferAddr = (uint32_t)(src_buf + src_stride * src_area->y1 + src_px_size * src_area->x1),
|
||||
.pitchBytes = src_stride
|
||||
};
|
||||
PXP_SetAlphaSurfaceBufferConfig(PXP_ID, &asBufferConfig);
|
||||
PXP_SetAlphaSurfacePosition(PXP_ID, 0U, 0U, src_w - 1U, src_h - 1U);
|
||||
|
||||
/*Disable PS, use as color generator*/
|
||||
PXP_SetProcessSurfacePosition(PXP_ID, 0xFFFFU, 0xFFFFU, 0U, 0U);
|
||||
PXP_SetProcessSurfaceBackGroundColor(PXP_ID, lv_color_to_u32(dsc->recolor));
|
||||
|
||||
/*Output buffer*/
|
||||
pxp_output_buffer_config_t outputBufferConfig = {
|
||||
.pixelFormat = pxp_get_out_px_format(dest_cf),
|
||||
.interlacedMode = kPXP_OutputProgressive,
|
||||
.buffer0Addr = (uint32_t)(dest_buf + dest_stride * dest_area->y1 + dest_px_size * dest_area->x1),
|
||||
.buffer1Addr = (uint32_t)0U,
|
||||
.pitchBytes = dest_stride,
|
||||
.width = dest_w,
|
||||
.height = dest_h
|
||||
};
|
||||
PXP_SetOutputBufferConfig(PXP_ID, &outputBufferConfig);
|
||||
|
||||
/**
|
||||
* Configure Porter-Duff blending.
|
||||
*
|
||||
* Note: srcFactorMode and dstFactorMode are inverted in fsl_pxp.h:
|
||||
* srcFactorMode is actually applied on PS alpha value
|
||||
* dstFactorMode is actually applied on AS alpha value
|
||||
*/
|
||||
pxp_porter_duff_config_t pdConfig = {
|
||||
.enable = 1,
|
||||
.dstColorMode = kPXP_PorterDuffColorWithAlpha,
|
||||
.srcColorMode = kPXP_PorterDuffColorWithAlpha,
|
||||
.dstGlobalAlphaMode = kPXP_PorterDuffGlobalAlpha,
|
||||
.srcGlobalAlphaMode = src_has_alpha ? kPXP_PorterDuffLocalAlpha : kPXP_PorterDuffGlobalAlpha,
|
||||
.dstFactorMode = kPXP_PorterDuffFactorStraight,
|
||||
.srcFactorMode = kPXP_PorterDuffFactorInversed,
|
||||
.dstGlobalAlpha = dsc->recolor_opa,
|
||||
.srcGlobalAlpha = 0xff,
|
||||
.dstAlphaMode = kPXP_PorterDuffAlphaStraight, /*don't care*/
|
||||
.srcAlphaMode = kPXP_PorterDuffAlphaStraight
|
||||
};
|
||||
PXP_SetPorterDuffConfig(PXP_ID, &pdConfig);
|
||||
|
||||
lv_pxp_run();
|
||||
}
|
||||
|
||||
static void _pxp_blit_transform(uint8_t * dest_buf, const lv_area_t * dest_area, int32_t dest_stride,
|
||||
lv_color_format_t dest_cf, const uint8_t * src_buf, const lv_area_t * src_area,
|
||||
int32_t src_stride, lv_color_format_t src_cf, const lv_draw_image_dsc_t * dsc)
|
||||
{
|
||||
int32_t src_w = lv_area_get_width(src_area);
|
||||
int32_t src_h = lv_area_get_height(src_area);
|
||||
int32_t dest_w = lv_area_get_width(dest_area);
|
||||
int32_t dest_h = lv_area_get_height(dest_area);
|
||||
|
||||
lv_point_t pivot = dsc->pivot;
|
||||
/*The offsets are now relative to the transformation result with pivot ULC*/
|
||||
int32_t piv_offset_x = 0;
|
||||
int32_t piv_offset_y = 0;
|
||||
|
||||
int32_t trim_x = 0;
|
||||
int32_t trim_y = 0;
|
||||
|
||||
bool has_rotation = (dsc->rotation != 0);
|
||||
bool has_scale = (dsc->scale_x != LV_SCALE_NONE || dsc->scale_y != LV_SCALE_NONE);
|
||||
uint8_t src_px_size = lv_color_format_get_size(src_cf);
|
||||
uint8_t dest_px_size = lv_color_format_get_size(dest_cf);
|
||||
|
||||
lv_pxp_reset();
|
||||
|
||||
if(has_rotation) {
|
||||
/*Convert rotation angle and calculate offsets caused by pivot*/
|
||||
pxp_rotate_degree_t pxp_angle;
|
||||
switch(dsc->rotation) {
|
||||
case 0:
|
||||
pxp_angle = kPXP_Rotate0;
|
||||
piv_offset_x = 0;
|
||||
piv_offset_y = 0;
|
||||
break;
|
||||
case 900:
|
||||
pxp_angle = kPXP_Rotate90;
|
||||
piv_offset_x = pivot.x + pivot.y - src_h;
|
||||
piv_offset_y = pivot.y - pivot.x;
|
||||
break;
|
||||
case 1800:
|
||||
pxp_angle = kPXP_Rotate180;
|
||||
piv_offset_x = 2 * pivot.x - src_w;
|
||||
piv_offset_y = 2 * pivot.y - src_h;
|
||||
break;
|
||||
case 2700:
|
||||
pxp_angle = kPXP_Rotate270;
|
||||
piv_offset_x = pivot.x - pivot.y;
|
||||
piv_offset_y = pivot.x + pivot.y - src_w;
|
||||
break;
|
||||
default:
|
||||
pxp_angle = kPXP_Rotate0;
|
||||
piv_offset_x = 0;
|
||||
piv_offset_y = 0;
|
||||
}
|
||||
/*PS buffer rotation and decimation does not function at the same time*/
|
||||
PXP_SetRotateConfig(PXP_ID, kPXP_RotateOutputBuffer, pxp_angle, kPXP_FlipDisable);
|
||||
}
|
||||
|
||||
if(has_scale) {
|
||||
float fp_scale_x = (float)dsc->scale_x / LV_SCALE_NONE;
|
||||
float fp_scale_y = (float)dsc->scale_y / LV_SCALE_NONE;
|
||||
int32_t int_scale_x = (int32_t)fp_scale_x;
|
||||
int32_t int_scale_y = (int32_t)fp_scale_y;
|
||||
|
||||
/*Any scale_factor in (k, k + 1] will result in a trim equal to k*/
|
||||
trim_x = (fp_scale_x == int_scale_x) ? int_scale_x - 1 : int_scale_x;
|
||||
trim_y = (fp_scale_y == int_scale_y) ? int_scale_y - 1 : int_scale_y;
|
||||
|
||||
dest_w = src_w * fp_scale_x + trim_x;
|
||||
dest_h = src_h * fp_scale_y + trim_y;
|
||||
|
||||
/*Final pivot offset = scale_factor * rotation_pivot_offset + scaling_pivot_offset*/
|
||||
piv_offset_x = floorf(fp_scale_x * piv_offset_x) - floorf((fp_scale_x - 1) * pivot.x);
|
||||
piv_offset_y = floorf(fp_scale_y * piv_offset_y) - floorf((fp_scale_y - 1) * pivot.y);
|
||||
}
|
||||
|
||||
/*PS buffer - source image*/
|
||||
pxp_ps_buffer_config_t psBufferConfig = {
|
||||
.pixelFormat = pxp_get_ps_px_format(src_cf),
|
||||
.swapByte = false,
|
||||
.bufferAddr = (uint32_t)(src_buf + src_stride * src_area->y1 + src_px_size * src_area->x1),
|
||||
.bufferAddrU = 0,
|
||||
.bufferAddrV = 0,
|
||||
.pitchBytes = src_stride
|
||||
};
|
||||
PXP_SetProcessSurfaceBufferConfig(PXP_ID, &psBufferConfig);
|
||||
PXP_SetProcessSurfacePosition(PXP_ID, 0U, 0U, dest_w - trim_x - 1U, dest_h - trim_y - 1U);
|
||||
|
||||
if(has_scale)
|
||||
PXP_SetProcessSurfaceScaler(PXP_ID, src_w, src_h, dest_w, dest_h);
|
||||
|
||||
/*AS disabled */
|
||||
PXP_SetAlphaSurfacePosition(PXP_ID, 0xFFFFU, 0xFFFFU, 0U, 0U);
|
||||
|
||||
/*Output buffer*/
|
||||
pxp_output_buffer_config_t outputBufferConfig = {
|
||||
.pixelFormat = pxp_get_out_px_format(dest_cf),
|
||||
.interlacedMode = kPXP_OutputProgressive,
|
||||
.buffer0Addr = (uint32_t)(dest_buf + dest_stride * (dest_area->y1 + piv_offset_y) + dest_px_size * (dest_area->x1 + piv_offset_x)),
|
||||
.buffer1Addr = (uint32_t)0U,
|
||||
.pitchBytes = dest_stride,
|
||||
.width = dest_w - trim_x,
|
||||
.height = dest_h - trim_y
|
||||
};
|
||||
PXP_SetOutputBufferConfig(PXP_ID, &outputBufferConfig);
|
||||
|
||||
lv_pxp_run();
|
||||
}
|
||||
|
||||
static void _pxp_blit(uint8_t * dest_buf, const lv_area_t * dest_area, int32_t dest_stride,
|
||||
lv_color_format_t dest_cf, const uint8_t * src_buf, const lv_area_t * src_area,
|
||||
int32_t src_stride, lv_color_format_t src_cf, lv_opa_t opa)
|
||||
{
|
||||
int32_t dest_w = lv_area_get_width(dest_area);
|
||||
int32_t dest_h = lv_area_get_height(dest_area);
|
||||
int32_t src_w = lv_area_get_width(src_area);
|
||||
int32_t src_h = lv_area_get_height(src_area);
|
||||
|
||||
bool src_has_alpha = (src_cf == LV_COLOR_FORMAT_ARGB8888);
|
||||
uint8_t src_px_size = lv_color_format_get_size(src_cf);
|
||||
uint8_t dest_px_size = lv_color_format_get_size(dest_cf);
|
||||
|
||||
lv_pxp_reset();
|
||||
|
||||
pxp_as_blend_config_t asBlendConfig = {
|
||||
.alpha = opa,
|
||||
.invertAlpha = false,
|
||||
.alphaMode = kPXP_AlphaRop,
|
||||
.ropMode = kPXP_RopMergeAs
|
||||
};
|
||||
|
||||
if(opa >= (lv_opa_t)LV_OPA_MAX && !src_has_alpha) {
|
||||
/*Simple blit, no effect - Disable PS buffer*/
|
||||
PXP_SetProcessSurfacePosition(PXP_ID, 0xFFFFU, 0xFFFFU, 0U, 0U);
|
||||
}
|
||||
else {
|
||||
/*PS must be enabled to fetch background pixels.
|
||||
PS and OUT buffers are the same, blend will be done in-place*/
|
||||
pxp_ps_buffer_config_t psBufferConfig = {
|
||||
.pixelFormat = pxp_get_ps_px_format(dest_cf),
|
||||
.swapByte = false,
|
||||
.bufferAddr = (uint32_t)(dest_buf + dest_stride * dest_area->y1 + dest_px_size * dest_area->x1),
|
||||
.bufferAddrU = 0U,
|
||||
.bufferAddrV = 0U,
|
||||
.pitchBytes = dest_stride
|
||||
};
|
||||
|
||||
if(opa >= (lv_opa_t)LV_OPA_MAX)
|
||||
asBlendConfig.alphaMode = src_has_alpha ? kPXP_AlphaEmbedded : kPXP_AlphaOverride;
|
||||
else
|
||||
asBlendConfig.alphaMode = src_has_alpha ? kPXP_AlphaMultiply : kPXP_AlphaOverride;
|
||||
|
||||
PXP_SetProcessSurfaceBufferConfig(PXP_ID, &psBufferConfig);
|
||||
PXP_SetProcessSurfacePosition(PXP_ID, 0U, 0U, dest_w - 1U, dest_h - 1U);
|
||||
}
|
||||
|
||||
/*AS buffer - source image*/
|
||||
pxp_as_buffer_config_t asBufferConfig = {
|
||||
.pixelFormat = pxp_get_as_px_format(src_cf),
|
||||
.bufferAddr = (uint32_t)(src_buf + src_stride * src_area->y1 + src_px_size * src_area->x1),
|
||||
.pitchBytes = src_stride
|
||||
};
|
||||
PXP_SetAlphaSurfaceBufferConfig(PXP_ID, &asBufferConfig);
|
||||
PXP_SetAlphaSurfacePosition(PXP_ID, 0U, 0U, src_w - 1U, src_h - 1U);
|
||||
PXP_SetAlphaSurfaceBlendConfig(PXP_ID, &asBlendConfig);
|
||||
PXP_EnableAlphaSurfaceOverlayColorKey(PXP_ID, false);
|
||||
|
||||
/*Output buffer.*/
|
||||
pxp_output_buffer_config_t outputBufferConfig = {
|
||||
.pixelFormat = pxp_get_out_px_format(dest_cf),
|
||||
.interlacedMode = kPXP_OutputProgressive,
|
||||
.buffer0Addr = (uint32_t)(dest_buf + dest_stride * dest_area->y1 + dest_px_size * dest_area->x1),
|
||||
.buffer1Addr = (uint32_t)0U,
|
||||
.pitchBytes = dest_stride,
|
||||
.width = dest_w,
|
||||
.height = dest_h
|
||||
};
|
||||
PXP_SetOutputBufferConfig(PXP_ID, &outputBufferConfig);
|
||||
|
||||
lv_pxp_run();
|
||||
}
|
||||
|
||||
#endif /*LV_USE_DRAW_PXP*/
|
||||
#endif /*LV_USE_PXP*/
|
||||
@@ -0,0 +1,157 @@
|
||||
/**
|
||||
* @file lv_draw_pxp_layer.c
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2023-2024 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_pxp.h"
|
||||
|
||||
#if LV_USE_PXP
|
||||
#if LV_USE_DRAW_PXP
|
||||
|
||||
#include "../../../stdlib/lv_string.h"
|
||||
#if LV_USE_PARALLEL_DRAW_DEBUG
|
||||
#include "../../../core/lv_global.h"
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
#if LV_USE_PARALLEL_DRAW_DEBUG
|
||||
#define _draw_info LV_GLOBAL_DEFAULT()->draw_info
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_pxp_layer(lv_draw_task_t * t)
|
||||
{
|
||||
lv_draw_image_dsc_t * draw_dsc = t->draw_dsc;
|
||||
|
||||
lv_layer_t * layer_to_draw = (lv_layer_t *)draw_dsc->src;
|
||||
const lv_draw_buf_t * draw_buf = layer_to_draw->draw_buf;
|
||||
|
||||
/* It can happen that nothing was draw on a layer and therefore its buffer is not allocated.
|
||||
* In this case just return.
|
||||
*/
|
||||
if(draw_buf == NULL)
|
||||
return;
|
||||
|
||||
const lv_area_t area_to_draw = {
|
||||
.x1 = 0,
|
||||
.y1 = 0,
|
||||
.x2 = draw_buf->header.w - 1,
|
||||
.y2 = draw_buf->header.h - 1
|
||||
};
|
||||
lv_draw_buf_invalidate_cache(draw_buf, &area_to_draw);
|
||||
|
||||
lv_draw_image_dsc_t new_draw_dsc = *draw_dsc;
|
||||
new_draw_dsc.src = draw_buf;
|
||||
t->draw_dsc = &new_draw_dsc;
|
||||
lv_draw_pxp_img(t);
|
||||
t->draw_dsc = draw_dsc;
|
||||
|
||||
#if LV_USE_LAYER_DEBUG || LV_USE_PARALLEL_DRAW_DEBUG
|
||||
const lv_area_t * coords = &t->area;
|
||||
lv_area_t area_rot;
|
||||
lv_area_copy(&area_rot, coords);
|
||||
if(draw_dsc->rotation || draw_dsc->scale_x != LV_SCALE_NONE || draw_dsc->scale_y != LV_SCALE_NONE) {
|
||||
int32_t w = lv_area_get_width(coords);
|
||||
int32_t h = lv_area_get_height(coords);
|
||||
|
||||
lv_image_buf_get_transformed_area(&area_rot, w, h, draw_dsc->rotation, draw_dsc->scale_x, draw_dsc->scale_y,
|
||||
&draw_dsc->pivot);
|
||||
|
||||
area_rot.x1 += coords->x1;
|
||||
area_rot.y1 += coords->y1;
|
||||
area_rot.x2 += coords->x1;
|
||||
area_rot.y2 += coords->y1;
|
||||
}
|
||||
lv_area_t draw_area;
|
||||
if(!lv_area_intersect(&draw_area, &area_rot, &t->clip_area)) return;
|
||||
#endif
|
||||
|
||||
#if LV_USE_LAYER_DEBUG
|
||||
lv_draw_fill_dsc_t fill_dsc;
|
||||
lv_draw_fill_dsc_init(&fill_dsc);
|
||||
fill_dsc.color = lv_color_hex(layer_to_draw->color_format == LV_COLOR_FORMAT_ARGB8888 ? 0xff0000 : 0x00ff00);
|
||||
fill_dsc.opa = LV_OPA_20;
|
||||
lv_draw_sw_fill(t, &fill_dsc, &area_rot);
|
||||
|
||||
lv_draw_border_dsc_t border_dsc;
|
||||
lv_draw_border_dsc_init(&border_dsc);
|
||||
border_dsc.color = fill_dsc.color;
|
||||
border_dsc.opa = LV_OPA_60;
|
||||
border_dsc.width = 2;
|
||||
lv_draw_sw_border(t, &border_dsc, &area_rot);
|
||||
|
||||
#endif
|
||||
|
||||
#if LV_USE_PARALLEL_DRAW_DEBUG
|
||||
int32_t idx = t->draw_unit->idx;
|
||||
|
||||
lv_draw_fill_dsc_t fill_dsc;
|
||||
lv_draw_rect_dsc_init(&fill_dsc);
|
||||
fill_dsc.color = lv_palette_main(idx % LV_PALETTE_LAST);
|
||||
fill_dsc.opa = LV_OPA_10;
|
||||
lv_draw_sw_fill(t, &fill_dsc, &area_rot);
|
||||
|
||||
lv_draw_border_dsc_t border_dsc;
|
||||
lv_draw_border_dsc_init(&border_dsc);
|
||||
border_dsc.color = lv_palette_main(idx % LV_PALETTE_LAST);
|
||||
border_dsc.opa = LV_OPA_100;
|
||||
border_dsc.width = 2;
|
||||
lv_draw_sw_border(t, &border_dsc, &area_rot);
|
||||
|
||||
lv_point_t txt_size;
|
||||
lv_text_get_size(&txt_size, "W", LV_FONT_DEFAULT, 0, 0, 100, LV_TEXT_FLAG_NONE);
|
||||
|
||||
lv_area_t txt_area;
|
||||
txt_area.x1 = draw_area.x1;
|
||||
txt_area.x2 = draw_area.x1 + txt_size.x - 1;
|
||||
txt_area.y2 = draw_area.y2;
|
||||
txt_area.y1 = draw_area.y2 - txt_size.y + 1;
|
||||
|
||||
lv_draw_fill_dsc_init(&fill_dsc);
|
||||
fill_dsc.color = lv_color_black();
|
||||
lv_draw_sw_fill(t, &fill_dsc, &txt_area);
|
||||
|
||||
char buf[8];
|
||||
lv_snprintf(buf, sizeof(buf), "%d", idx);
|
||||
lv_draw_label_dsc_t label_dsc;
|
||||
lv_draw_label_dsc_init(&label_dsc);
|
||||
label_dsc.color = lv_color_white();
|
||||
label_dsc.text = buf;
|
||||
lv_draw_sw_label(t, &label_dsc, &txt_area);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /*LV_USE_DRAW_PXP*/
|
||||
#endif /*LV_USE_PXP*/
|
||||
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* @file lv_pxp_cfg.c
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2020-2023 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_pxp_cfg.h"
|
||||
|
||||
#if LV_USE_PXP
|
||||
#if LV_USE_DRAW_PXP || LV_USE_ROTATE_PXP
|
||||
#include "lv_pxp_osa.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
static pxp_cfg_t * _pxp_cfg;
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_pxp_init(void)
|
||||
{
|
||||
_pxp_cfg = pxp_get_default_cfg();
|
||||
|
||||
PXP_Init(PXP_ID);
|
||||
|
||||
PXP_EnableCsc1(PXP_ID, false); /*Disable CSC1, it is enabled by default.*/
|
||||
PXP_SetProcessBlockSize(PXP_ID, kPXP_BlockSize16); /*Block size 16x16 for higher performance*/
|
||||
|
||||
PXP_EnableInterrupts(PXP_ID, kPXP_CompleteInterruptEnable);
|
||||
|
||||
_pxp_cfg->pxp_interrupt_init();
|
||||
}
|
||||
|
||||
void lv_pxp_deinit(void)
|
||||
{
|
||||
_pxp_cfg->pxp_interrupt_deinit();
|
||||
PXP_DisableInterrupts(PXP_ID, kPXP_CompleteInterruptEnable);
|
||||
PXP_Deinit(PXP_ID);
|
||||
}
|
||||
|
||||
void lv_pxp_reset(void)
|
||||
{
|
||||
PXP_ResetControl(PXP_ID);
|
||||
|
||||
PXP_EnableCsc1(PXP_ID, false); /*Disable CSC1, it is enabled by default.*/
|
||||
PXP_SetProcessBlockSize(PXP_ID, kPXP_BlockSize16); /*Block size 16x16 for higher performance*/
|
||||
}
|
||||
|
||||
void lv_pxp_run(void)
|
||||
{
|
||||
_pxp_cfg->pxp_run();
|
||||
_pxp_cfg->pxp_wait();
|
||||
}
|
||||
|
||||
void lv_pxp_wait(void)
|
||||
{
|
||||
_pxp_cfg->pxp_wait();
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_DRAW_PXP || LV_USE_ROTATE_PXP*/
|
||||
#endif /*LV_USE_PXP*/
|
||||
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* @file lv_pxp_cfg.h
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2020-2023 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef LV_PXP_CFG_H
|
||||
#define LV_PXP_CFG_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_PXP
|
||||
#if LV_USE_DRAW_PXP || LV_USE_ROTATE_PXP
|
||||
#include "fsl_cache.h"
|
||||
#include "fsl_pxp.h"
|
||||
|
||||
#include "../../../misc/lv_log.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/** PXP module instance to use*/
|
||||
#define PXP_ID PXP
|
||||
|
||||
/** PXP interrupt line ID*/
|
||||
#define PXP_IRQ_ID PXP_IRQn
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* NXP PXP device configuration.
|
||||
*/
|
||||
typedef struct {
|
||||
/** Callback for PXP interrupt initialization*/
|
||||
void (*pxp_interrupt_init)(void);
|
||||
|
||||
/** Callback for PXP interrupt de-initialization*/
|
||||
void (*pxp_interrupt_deinit)(void);
|
||||
|
||||
/** Callback for PXP start*/
|
||||
void (*pxp_run)(void);
|
||||
|
||||
/** Callback for waiting of PXP completion*/
|
||||
void (*pxp_wait)(void);
|
||||
} pxp_cfg_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Reset and initialize PXP device. This function should be called as a part
|
||||
* of display init sequence.
|
||||
*/
|
||||
void lv_pxp_init(void);
|
||||
|
||||
/**
|
||||
* Disable PXP device. Should be called during display deinit sequence.
|
||||
*/
|
||||
void lv_pxp_deinit(void);
|
||||
|
||||
/**
|
||||
* Reset PXP device.
|
||||
*/
|
||||
void lv_pxp_reset(void);
|
||||
|
||||
/**
|
||||
* Clear cache and start PXP.
|
||||
*/
|
||||
void lv_pxp_run(void);
|
||||
|
||||
/**
|
||||
* Wait for PXP completion.
|
||||
*/
|
||||
void lv_pxp_wait(void);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_DRAW_PXP || LV_USE_ROTATE_PXP*/
|
||||
#endif /*LV_USE_PXP*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_PXP_CFG_H*/
|
||||
@@ -0,0 +1,188 @@
|
||||
/**
|
||||
* @file lv_pxp_osa.c
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2020, 2022-2023 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_pxp_osa.h"
|
||||
|
||||
#if LV_USE_PXP
|
||||
#if LV_USE_DRAW_PXP || LV_USE_ROTATE_PXP
|
||||
#include "lv_pxp_utils.h"
|
||||
#include "../../../misc/lv_log.h"
|
||||
#include "../../../osal/lv_os.h"
|
||||
#include "fsl_pxp.h"
|
||||
|
||||
#if defined(SDK_OS_FREE_RTOS)
|
||||
#include "FreeRTOS.h"
|
||||
#endif
|
||||
|
||||
#if defined(__ZEPHYR__)
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/irq.h>
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* PXP interrupt initialization.
|
||||
*/
|
||||
static void _pxp_interrupt_init(void);
|
||||
|
||||
/**
|
||||
* PXP interrupt de-initialization.
|
||||
*/
|
||||
static void _pxp_interrupt_deinit(void);
|
||||
|
||||
/**
|
||||
* Start the PXP job.
|
||||
*/
|
||||
static void _pxp_run(void);
|
||||
|
||||
/**
|
||||
* Wait for PXP completion.
|
||||
*/
|
||||
static void _pxp_wait(void);
|
||||
|
||||
#if defined(__ZEPHYR__)
|
||||
/**
|
||||
* Interrupt handler for Zephyr IRQ
|
||||
*/
|
||||
static void _pxp_zephyr_irq_handler(void *);
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
#if LV_USE_OS
|
||||
static lv_thread_sync_t pxp_sync;
|
||||
#endif
|
||||
static volatile bool ucPXPIdle;
|
||||
|
||||
static pxp_cfg_t _pxp_default_cfg = {
|
||||
.pxp_interrupt_init = _pxp_interrupt_init,
|
||||
.pxp_interrupt_deinit = _pxp_interrupt_deinit,
|
||||
.pxp_run = _pxp_run,
|
||||
.pxp_wait = _pxp_wait,
|
||||
};
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void PXP_IRQHandler(void)
|
||||
{
|
||||
if(kPXP_CompleteFlag & PXP_GetStatusFlags(PXP_ID)) {
|
||||
PXP_ClearStatusFlags(PXP_ID, kPXP_CompleteFlag);
|
||||
#if LV_USE_OS
|
||||
lv_thread_sync_signal_isr(&pxp_sync);
|
||||
#else
|
||||
ucPXPIdle = true;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
pxp_cfg_t * pxp_get_default_cfg(void)
|
||||
{
|
||||
return &_pxp_default_cfg;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#if defined(__ZEPHYR__)
|
||||
static void _pxp_zephyr_irq_handler(void *)
|
||||
{
|
||||
PXP_IRQHandler();
|
||||
}
|
||||
#endif
|
||||
|
||||
static void _pxp_interrupt_init(void)
|
||||
{
|
||||
#if LV_USE_OS
|
||||
if(lv_thread_sync_init(&pxp_sync) != LV_RESULT_OK) {
|
||||
PXP_ASSERT_MSG(false, "Failed to init thread_sync.");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__ZEPHYR__)
|
||||
IRQ_CONNECT(DT_IRQN(DT_NODELABEL(pxp)), CONFIG_LV_Z_PXP_INTERRUPT_PRIORITY, _pxp_zephyr_irq_handler, NULL, 0);
|
||||
irq_enable(DT_IRQN(DT_NODELABEL(pxp)));
|
||||
#elif defined(SDK_OS_FREE_RTOS)
|
||||
NVIC_SetPriority(PXP_IRQ_ID, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1);
|
||||
#endif
|
||||
|
||||
#if !defined(__ZEPHYR__)
|
||||
NVIC_EnableIRQ(PXP_IRQ_ID);
|
||||
#endif
|
||||
|
||||
ucPXPIdle = true;
|
||||
}
|
||||
|
||||
static void _pxp_interrupt_deinit(void)
|
||||
{
|
||||
#if defined(__ZEPHYR__)
|
||||
irq_disable(DT_IRQN(DT_NODELABEL(pxp)));
|
||||
#else
|
||||
NVIC_DisableIRQ(PXP_IRQ_ID);
|
||||
#endif
|
||||
|
||||
#if LV_USE_OS
|
||||
lv_thread_sync_delete(&pxp_sync);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to start PXP job.
|
||||
*/
|
||||
static void _pxp_run(void)
|
||||
{
|
||||
ucPXPIdle = false;
|
||||
|
||||
PXP_EnableInterrupts(PXP_ID, kPXP_CompleteInterruptEnable);
|
||||
PXP_Start(PXP_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to wait for PXP completion.
|
||||
*/
|
||||
static void _pxp_wait(void)
|
||||
{
|
||||
if(ucPXPIdle == true)
|
||||
return;
|
||||
#if LV_USE_OS
|
||||
if(lv_thread_sync_wait(&pxp_sync) == LV_RESULT_OK)
|
||||
ucPXPIdle = true;
|
||||
#else
|
||||
while(ucPXPIdle == false) {
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /*LV_USE_DRAW_PXP || LV_USE_ROTATE_PXP*/
|
||||
#endif /*LV_USE_PXP*/
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* @file lv_pxp_osa.h
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2020, 2022-2023 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef LV_PXP_OSA_H
|
||||
#define LV_PXP_OSA_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_PXP
|
||||
#if LV_USE_DRAW_PXP || LV_USE_ROTATE_PXP
|
||||
#include "lv_pxp_cfg.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* PXP device interrupt handler. Used to check PXP task completion status.
|
||||
*/
|
||||
void PXP_IRQHandler(void);
|
||||
|
||||
/**
|
||||
* Get the PXP default configuration.
|
||||
*/
|
||||
pxp_cfg_t * pxp_get_default_cfg(void);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_DRAW_PXP || LV_USE_ROTATE_PXP*/
|
||||
#endif /*LV_USE_PXP*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_PXP_OSA_H*/
|
||||
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
* @file lv_pxp_utils.c
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2023-2024 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_pxp_utils.h"
|
||||
|
||||
#if LV_USE_PXP
|
||||
#if LV_USE_DRAW_PXP || LV_USE_ROTATE_PXP
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
pxp_output_pixel_format_t pxp_get_out_px_format(lv_color_format_t cf)
|
||||
{
|
||||
pxp_output_pixel_format_t out_px_format = kPXP_OutputPixelFormatRGB565;
|
||||
|
||||
switch(cf) {
|
||||
case LV_COLOR_FORMAT_RGB565:
|
||||
out_px_format = kPXP_OutputPixelFormatRGB565;
|
||||
break;
|
||||
case LV_COLOR_FORMAT_RGB888:
|
||||
out_px_format = kPXP_OutputPixelFormatRGB888P;
|
||||
break;
|
||||
case LV_COLOR_FORMAT_ARGB8888:
|
||||
out_px_format = kPXP_OutputPixelFormatARGB8888;
|
||||
break;
|
||||
case LV_COLOR_FORMAT_XRGB8888:
|
||||
out_px_format = kPXP_OutputPixelFormatRGB888;
|
||||
break;
|
||||
|
||||
default:
|
||||
PXP_ASSERT_MSG(false, "Unsupported color format.");
|
||||
break;
|
||||
}
|
||||
|
||||
return out_px_format;
|
||||
}
|
||||
|
||||
pxp_as_pixel_format_t pxp_get_as_px_format(lv_color_format_t cf)
|
||||
{
|
||||
pxp_as_pixel_format_t as_px_format = kPXP_AsPixelFormatRGB565;
|
||||
|
||||
switch(cf) {
|
||||
case LV_COLOR_FORMAT_RGB565:
|
||||
as_px_format = kPXP_AsPixelFormatRGB565;
|
||||
break;
|
||||
case LV_COLOR_FORMAT_RGB888:
|
||||
PXP_ASSERT_MSG(false, "Unsupported color format.");
|
||||
break;
|
||||
case LV_COLOR_FORMAT_ARGB8888:
|
||||
as_px_format = kPXP_AsPixelFormatARGB8888;
|
||||
break;
|
||||
case LV_COLOR_FORMAT_XRGB8888:
|
||||
as_px_format = kPXP_AsPixelFormatRGB888;
|
||||
break;
|
||||
|
||||
default:
|
||||
PXP_ASSERT_MSG(false, "Unsupported color format.");
|
||||
break;
|
||||
}
|
||||
|
||||
return as_px_format;
|
||||
}
|
||||
|
||||
#if LV_USE_DRAW_PXP
|
||||
pxp_ps_pixel_format_t pxp_get_ps_px_format(lv_color_format_t cf)
|
||||
{
|
||||
pxp_ps_pixel_format_t ps_px_format = kPXP_PsPixelFormatRGB565;
|
||||
|
||||
switch(cf) {
|
||||
case LV_COLOR_FORMAT_RGB565:
|
||||
ps_px_format = kPXP_PsPixelFormatRGB565;
|
||||
break;
|
||||
case LV_COLOR_FORMAT_RGB888:
|
||||
PXP_ASSERT_MSG(false, "Unsupported color format.");
|
||||
break;
|
||||
case LV_COLOR_FORMAT_ARGB8888:
|
||||
#if (!(defined(FSL_FEATURE_PXP_HAS_NO_EXTEND_PIXEL_FORMAT) && FSL_FEATURE_PXP_HAS_NO_EXTEND_PIXEL_FORMAT)) && \
|
||||
(!(defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3))
|
||||
ps_px_format = kPXP_PsPixelFormatARGB8888;
|
||||
#else
|
||||
PXP_ASSERT_MSG(false, "Unsupported color format.");
|
||||
#endif
|
||||
break;
|
||||
case LV_COLOR_FORMAT_XRGB8888:
|
||||
#if (!(defined(FSL_FEATURE_PXP_HAS_NO_EXTEND_PIXEL_FORMAT) && FSL_FEATURE_PXP_HAS_NO_EXTEND_PIXEL_FORMAT)) && \
|
||||
(!(defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3))
|
||||
ps_px_format = kPXP_PsPixelFormatARGB8888;
|
||||
#else
|
||||
ps_px_format = kPXP_PsPixelFormatRGB888;
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
PXP_ASSERT_MSG(false, "Unsupported color format.");
|
||||
break;
|
||||
}
|
||||
|
||||
return ps_px_format;
|
||||
}
|
||||
|
||||
bool pxp_buf_aligned(const void * buf, uint32_t stride)
|
||||
{
|
||||
/* Test for pointer alignment */
|
||||
if((uintptr_t)buf % 64)
|
||||
return false;
|
||||
|
||||
/* Test for invalid stride (no stride alignment required) */
|
||||
if(stride == 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_DRAW_PXP*/
|
||||
#endif /*LV_USE_DRAW_PXP || LV_USE_ROTATE_PXP*/
|
||||
#endif /*LV_USE_PXP*/
|
||||
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* @file lv_pxp_utils.h
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2023-2024 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef LV_PXP_UTILS_H
|
||||
#define LV_PXP_UTILS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_PXP
|
||||
#if LV_USE_DRAW_PXP || LV_USE_ROTATE_PXP
|
||||
#include "fsl_pxp.h"
|
||||
#include "../../../misc/lv_color.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#if LV_USE_PXP_ASSERT
|
||||
#define PXP_ASSERT(expr) LV_ASSERT(expr)
|
||||
#else
|
||||
#define PXP_ASSERT(expr)
|
||||
#endif
|
||||
|
||||
#define PXP_ASSERT_MSG(expr, msg) \
|
||||
do { \
|
||||
if(!(expr)) { \
|
||||
LV_LOG_ERROR(msg); \
|
||||
PXP_ASSERT(false); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
pxp_output_pixel_format_t pxp_get_out_px_format(lv_color_format_t cf);
|
||||
|
||||
pxp_as_pixel_format_t pxp_get_as_px_format(lv_color_format_t cf);
|
||||
|
||||
#if LV_USE_DRAW_PXP
|
||||
pxp_ps_pixel_format_t pxp_get_ps_px_format(lv_color_format_t cf);
|
||||
|
||||
bool pxp_buf_aligned(const void * buf, uint32_t stride);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_DRAW_PXP*/
|
||||
#endif /*LV_USE_DRAW_PXP || LV_USE_ROTATE_PXP*/
|
||||
#endif /*LV_USE_PXP*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_PXP_UTILS_H*/
|
||||
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* @file lv_draw_buf_vglite.c
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2023-2024 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_vglite.h"
|
||||
|
||||
#if LV_USE_DRAW_VGLITE
|
||||
#include "../../lv_draw_buf_private.h"
|
||||
#include "lv_vglite_buf.h"
|
||||
#include "lv_vglite_utils.h"
|
||||
|
||||
#include "lvgl_support.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static void _invalidate_cache(const lv_draw_buf_t * draw_buf, const lv_area_t * area);
|
||||
static uint32_t _width_to_stride(uint32_t w, lv_color_format_t cf);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_buf_vglite_init_handlers(void)
|
||||
{
|
||||
lv_draw_buf_handlers_t * handlers = lv_draw_buf_get_handlers();
|
||||
lv_draw_buf_handlers_t * font_handlers = lv_draw_buf_get_font_handlers();
|
||||
lv_draw_buf_handlers_t * image_handlers = lv_draw_buf_get_image_handlers();
|
||||
|
||||
handlers->invalidate_cache_cb = _invalidate_cache;
|
||||
font_handlers->invalidate_cache_cb = _invalidate_cache;
|
||||
image_handlers->invalidate_cache_cb = _invalidate_cache;
|
||||
|
||||
handlers->width_to_stride_cb = _width_to_stride;
|
||||
font_handlers->width_to_stride_cb = _width_to_stride;
|
||||
image_handlers->width_to_stride_cb = _width_to_stride;
|
||||
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void _invalidate_cache(const lv_draw_buf_t * draw_buf, const lv_area_t * area)
|
||||
{
|
||||
const lv_image_header_t * header = &draw_buf->header;
|
||||
uint32_t stride = header->stride;
|
||||
lv_color_format_t cf = header->cf;
|
||||
|
||||
if(area->y1 == 0) {
|
||||
uint32_t size = stride * lv_area_get_height(area);
|
||||
|
||||
/* Invalidate full buffer. */
|
||||
DEMO_CleanInvalidateCacheByAddr((void *)draw_buf->data, size);
|
||||
return;
|
||||
}
|
||||
|
||||
const uint8_t * buf_u8 = draw_buf->data;
|
||||
/* ARM require a 32 byte aligned address. */
|
||||
uint8_t align_bytes = 32;
|
||||
uint8_t bits_per_pixel = lv_color_format_get_bpp(cf);
|
||||
|
||||
uint16_t align_pixels = align_bytes * 8 / bits_per_pixel;
|
||||
uint16_t offset_x = 0;
|
||||
|
||||
if(area->x1 >= (int32_t)(area->x1 % align_pixels)) {
|
||||
uint16_t shift_x = area->x1 - (area->x1 % align_pixels);
|
||||
|
||||
offset_x = area->x1 - shift_x;
|
||||
buf_u8 += (shift_x * bits_per_pixel) / 8;
|
||||
}
|
||||
|
||||
if(area->y1) {
|
||||
uint16_t shift_y = area->y1;
|
||||
|
||||
buf_u8 += shift_y * stride;
|
||||
}
|
||||
|
||||
/* Area to clear can start from a different offset in buffer.
|
||||
* Invalidate the area line by line.
|
||||
*/
|
||||
uint16_t line_pixels = offset_x + lv_area_get_width(area);
|
||||
uint16_t line_size = (line_pixels * bits_per_pixel) / 8;
|
||||
uint16_t area_height = lv_area_get_height(area);
|
||||
|
||||
for(uint16_t y = 0; y < area_height; y++) {
|
||||
const void * line_addr = buf_u8 + y * stride;
|
||||
|
||||
DEMO_CleanInvalidateCacheByAddr((void *)line_addr, line_size);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t _width_to_stride(uint32_t w, lv_color_format_t cf)
|
||||
{
|
||||
uint8_t bits_per_pixel = lv_color_format_get_bpp(cf);
|
||||
uint32_t width_bits = LV_ROUND_UP(w * bits_per_pixel, 8);
|
||||
uint32_t width_bytes = width_bits / 8;
|
||||
uint8_t align_bytes = vglite_get_stride_alignment(cf);
|
||||
|
||||
return LV_ROUND_UP(width_bytes, align_bytes);
|
||||
}
|
||||
|
||||
#endif /*LV_USE_DRAW_VGLITE*/
|
||||
@@ -0,0 +1,638 @@
|
||||
/**
|
||||
* @file lv_draw_vglite.c
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2023-2024 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_vglite.h"
|
||||
|
||||
#if LV_USE_DRAW_VGLITE
|
||||
#include "lv_vglite_buf.h"
|
||||
#include "lv_vglite_utils.h"
|
||||
|
||||
#include "../../../core/lv_global.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#define DRAW_UNIT_ID_VGLITE 2
|
||||
|
||||
#if LV_USE_VGLITE_DRAW_ASYNC
|
||||
#define VGLITE_TASK_BUF_SIZE 100
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
#if LV_USE_VGLITE_DRAW_ASYNC
|
||||
/**
|
||||
* Structure of pending vglite draw task
|
||||
*/
|
||||
typedef struct _vglite_flush_task {
|
||||
vglite_draw_task_t * task;
|
||||
bool flushed;
|
||||
} vglite_flush_task_t;
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static inline void _vglite_cleanup_task(vglite_draw_task_t * task);
|
||||
|
||||
/*
|
||||
* Evaluate a task and set the score and preferred VGLite draw unit.
|
||||
* Return 1 if task is preferred, 0 otherwise (task is not supported).
|
||||
*/
|
||||
static int32_t _vglite_evaluate(lv_draw_unit_t * draw_unit, lv_draw_task_t * task);
|
||||
|
||||
/*
|
||||
* Dispatch (assign) a task to VGLite draw unit (itself).
|
||||
* Return 1 if task was dispatched, 0 otherwise (task not supported).
|
||||
*/
|
||||
static int32_t _vglite_dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer);
|
||||
|
||||
/*
|
||||
* Wait for VG-Lite draw unit to finish.
|
||||
*/
|
||||
#if LV_USE_VGLITE_DRAW_ASYNC
|
||||
static int32_t _vglite_wait_for_finish(lv_draw_unit_t * draw_unit);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Delete the VGLite draw unit.
|
||||
*/
|
||||
static int32_t _vglite_delete(lv_draw_unit_t * draw_unit);
|
||||
|
||||
#if LV_USE_VGLITE_DRAW_THREAD
|
||||
static void _vglite_render_thread_cb(void * ptr);
|
||||
#endif
|
||||
|
||||
static void _vglite_execute_drawing(lv_draw_vglite_unit_t * u);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
#define _draw_info LV_GLOBAL_DEFAULT()->draw_info
|
||||
|
||||
#if LV_USE_VGLITE_DRAW_ASYNC
|
||||
/*
|
||||
* Circular buffer to hold the queued and the flushed tasks.
|
||||
* Two indexes, _head and _tail, are used to signal the beginning
|
||||
* and the end of the valid tasks that are pending.
|
||||
*/
|
||||
static vglite_flush_task_t _draw_task_buf[VGLITE_TASK_BUF_SIZE];
|
||||
static volatile int _head = 0;
|
||||
static volatile int _tail = 0;
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_vglite_init(void)
|
||||
{
|
||||
lv_draw_buf_vglite_init_handlers();
|
||||
|
||||
lv_draw_vglite_unit_t * draw_vglite_unit = lv_draw_create_unit(sizeof(lv_draw_vglite_unit_t));
|
||||
draw_vglite_unit->base_unit.evaluate_cb = _vglite_evaluate;
|
||||
draw_vglite_unit->base_unit.dispatch_cb = _vglite_dispatch;
|
||||
#if LV_USE_VGLITE_DRAW_ASYNC
|
||||
draw_vglite_unit->base_unit.wait_for_finish_cb = _vglite_wait_for_finish;
|
||||
#endif
|
||||
draw_vglite_unit->base_unit.delete_cb = _vglite_delete;
|
||||
draw_vglite_unit->base_unit.name = "NXP_VGLITE";
|
||||
|
||||
#if LV_USE_VGLITE_DRAW_THREAD
|
||||
lv_thread_init(&draw_vglite_unit->thread, "vglitedraw", LV_DRAW_THREAD_PRIO, _vglite_render_thread_cb, 4 * 1024,
|
||||
draw_vglite_unit);
|
||||
#endif
|
||||
}
|
||||
|
||||
void lv_draw_vglite_deinit(void)
|
||||
{
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static inline bool _vglite_src_cf_supported(lv_color_format_t cf)
|
||||
{
|
||||
bool is_cf_supported = false;
|
||||
|
||||
switch(cf) {
|
||||
#if CHIPID == 0x255 || CHIPID == 0x555
|
||||
case LV_COLOR_FORMAT_I1:
|
||||
case LV_COLOR_FORMAT_I2:
|
||||
case LV_COLOR_FORMAT_I4:
|
||||
case LV_COLOR_FORMAT_I8:
|
||||
#endif
|
||||
case LV_COLOR_FORMAT_A4:
|
||||
case LV_COLOR_FORMAT_A8:
|
||||
case LV_COLOR_FORMAT_L8:
|
||||
case LV_COLOR_FORMAT_RGB565:
|
||||
#if CHIPID == 0x555
|
||||
case LV_COLOR_FORMAT_ARGB8565:
|
||||
case LV_COLOR_FORMAT_RGB888:
|
||||
#endif
|
||||
case LV_COLOR_FORMAT_ARGB8888:
|
||||
case LV_COLOR_FORMAT_XRGB8888:
|
||||
is_cf_supported = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return is_cf_supported;
|
||||
}
|
||||
|
||||
static inline bool _vglite_dest_cf_supported(lv_color_format_t cf)
|
||||
{
|
||||
bool is_cf_supported = false;
|
||||
|
||||
switch(cf) {
|
||||
case LV_COLOR_FORMAT_A8:
|
||||
#if CHIPID == 0x255 || CHIPID == 0x555
|
||||
case LV_COLOR_FORMAT_L8:
|
||||
#endif
|
||||
case LV_COLOR_FORMAT_RGB565:
|
||||
#if CHIPID == 0x555
|
||||
case LV_COLOR_FORMAT_ARGB8565:
|
||||
case LV_COLOR_FORMAT_RGB888:
|
||||
#endif
|
||||
case LV_COLOR_FORMAT_ARGB8888:
|
||||
case LV_COLOR_FORMAT_XRGB8888:
|
||||
is_cf_supported = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return is_cf_supported;
|
||||
}
|
||||
|
||||
static int32_t _vglite_evaluate(lv_draw_unit_t * u, lv_draw_task_t * t)
|
||||
{
|
||||
LV_UNUSED(u);
|
||||
|
||||
const lv_draw_dsc_base_t * draw_dsc_base = (lv_draw_dsc_base_t *) t->draw_dsc;
|
||||
|
||||
if(!_vglite_dest_cf_supported(draw_dsc_base->layer->color_format))
|
||||
return 0;
|
||||
|
||||
switch(t->type) {
|
||||
case LV_DRAW_TASK_TYPE_FILL:
|
||||
if(t->preference_score > 80) {
|
||||
t->preference_score = 80;
|
||||
t->preferred_draw_unit_id = DRAW_UNIT_ID_VGLITE;
|
||||
}
|
||||
return 1;
|
||||
|
||||
case LV_DRAW_TASK_TYPE_LINE:
|
||||
case LV_DRAW_TASK_TYPE_ARC:
|
||||
case LV_DRAW_TASK_TYPE_TRIANGLE:
|
||||
if(t->preference_score > 90) {
|
||||
t->preference_score = 90;
|
||||
t->preferred_draw_unit_id = DRAW_UNIT_ID_VGLITE;
|
||||
}
|
||||
return 1;
|
||||
|
||||
case LV_DRAW_TASK_TYPE_LABEL:
|
||||
if(t->preference_score > 95) {
|
||||
t->preference_score = 95;
|
||||
t->preferred_draw_unit_id = DRAW_UNIT_ID_VGLITE;
|
||||
}
|
||||
return 1;
|
||||
|
||||
case LV_DRAW_TASK_TYPE_BORDER: {
|
||||
if(t->preference_score > 90) {
|
||||
t->preference_score = 90;
|
||||
t->preferred_draw_unit_id = DRAW_UNIT_ID_VGLITE;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
case LV_DRAW_TASK_TYPE_LAYER: {
|
||||
const lv_draw_image_dsc_t * draw_dsc = (lv_draw_image_dsc_t *) t->draw_dsc;
|
||||
lv_layer_t * layer_to_draw = (lv_layer_t *)draw_dsc->src;
|
||||
|
||||
#if LV_USE_VGLITE_BLIT_SPLIT
|
||||
bool has_transform = (draw_dsc->rotation != 0 || draw_dsc->scale_x != LV_SCALE_NONE ||
|
||||
draw_dsc->scale_y != LV_SCALE_NONE);
|
||||
#endif
|
||||
if(!_vglite_src_cf_supported(layer_to_draw->color_format)
|
||||
#if LV_USE_VGLITE_BLIT_SPLIT
|
||||
|| has_transform
|
||||
#endif
|
||||
)
|
||||
return 0;
|
||||
|
||||
if(t->preference_score > 80) {
|
||||
t->preference_score = 80;
|
||||
t->preferred_draw_unit_id = DRAW_UNIT_ID_VGLITE;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
case LV_DRAW_TASK_TYPE_IMAGE: {
|
||||
lv_draw_image_dsc_t * draw_dsc = (lv_draw_image_dsc_t *) t->draw_dsc;
|
||||
const lv_image_dsc_t * img_dsc = draw_dsc->src;
|
||||
|
||||
if(img_dsc->header.cf >= LV_COLOR_FORMAT_PROPRIETARY_START) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if CHIPID == 0x255
|
||||
if(draw_dsc->tile)
|
||||
return 0;
|
||||
#endif
|
||||
#if LV_USE_VGLITE_BLIT_SPLIT
|
||||
bool has_transform = (draw_dsc->rotation != 0 || draw_dsc->scale_x != LV_SCALE_NONE ||
|
||||
draw_dsc->scale_y != LV_SCALE_NONE);
|
||||
bool is_tiled = draw_dsc->tile;
|
||||
#endif
|
||||
|
||||
if((!_vglite_src_cf_supported(img_dsc->header.cf))
|
||||
#if LV_USE_VGLITE_BLIT_SPLIT
|
||||
|| has_transform || is_tiled
|
||||
#endif
|
||||
|| (!vglite_src_buf_aligned(img_dsc->data, img_dsc->header.stride, img_dsc->header.cf))
|
||||
)
|
||||
return 0;
|
||||
|
||||
if(t->preference_score > 80) {
|
||||
t->preference_score = 80;
|
||||
t->preferred_draw_unit_id = DRAW_UNIT_ID_VGLITE;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t _vglite_dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer)
|
||||
{
|
||||
lv_draw_vglite_unit_t * draw_vglite_unit = (lv_draw_vglite_unit_t *) draw_unit;
|
||||
|
||||
/* Return immediately if draw unit is busy. */
|
||||
if(draw_vglite_unit->task_act
|
||||
#if LV_USE_VGLITE_DRAW_ASYNC
|
||||
|| draw_vglite_unit->wait_for_finish
|
||||
#endif
|
||||
)
|
||||
return 0;
|
||||
|
||||
/* Try to get an ready to draw. */
|
||||
lv_draw_task_t * t = lv_draw_get_available_task(layer, NULL, DRAW_UNIT_ID_VGLITE);
|
||||
|
||||
if(t == NULL)
|
||||
return LV_DRAW_UNIT_IDLE;
|
||||
|
||||
if(t->preferred_draw_unit_id != DRAW_UNIT_ID_VGLITE) {
|
||||
/* Let the preferred known unit to draw this task. */
|
||||
if(t->preferred_draw_unit_id != LV_DRAW_UNIT_NONE) {
|
||||
return LV_DRAW_UNIT_IDLE;
|
||||
}
|
||||
else {
|
||||
/* Fake unsupported tasks as ready. */
|
||||
t->state = LV_DRAW_TASK_STATE_READY;
|
||||
/* Request a new dispatching as it can get a new task. */
|
||||
lv_draw_dispatch_request();
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
vglite_draw_task_t * vglite_task = lv_malloc_zeroed(sizeof(vglite_draw_task_t));
|
||||
LV_ASSERT_MALLOC(vglite_task);
|
||||
|
||||
vglite_task->t = t;
|
||||
|
||||
if(lv_draw_layer_alloc_buf(layer) == NULL)
|
||||
return LV_DRAW_UNIT_IDLE;
|
||||
t->state = LV_DRAW_TASK_STATE_IN_PROGRESS;
|
||||
draw_vglite_unit->task_act = vglite_task;
|
||||
|
||||
#if LV_USE_VGLITE_DRAW_THREAD
|
||||
/* Let the render thread work. */
|
||||
if(draw_vglite_unit->inited)
|
||||
lv_thread_sync_signal(&draw_vglite_unit->sync);
|
||||
#else
|
||||
_vglite_execute_drawing(draw_vglite_unit);
|
||||
|
||||
draw_vglite_unit->task_act->t->state = LV_DRAW_TASK_STATE_READY;
|
||||
_vglite_cleanup_task(draw_vglite_unit->task_act);
|
||||
draw_vglite_unit->task_act = NULL;
|
||||
|
||||
/* The draw unit is free now. Request a new dispatching as it can get a new task. */
|
||||
lv_draw_dispatch_request();
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if LV_USE_VGLITE_DRAW_ASYNC
|
||||
static int32_t _vglite_wait_for_finish(lv_draw_unit_t * draw_unit)
|
||||
{
|
||||
lv_draw_vglite_unit_t * draw_vglite_unit = (lv_draw_vglite_unit_t *) draw_unit;
|
||||
draw_vglite_unit->wait_for_finish = true;
|
||||
|
||||
/* Signal draw unit to finish its tasks and return READY state after completion. */
|
||||
if(draw_vglite_unit->inited)
|
||||
lv_thread_sync_signal(&draw_vglite_unit->sync);
|
||||
|
||||
/* Wait for finish now. */
|
||||
lv_draw_dispatch_wait_for_request();
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int32_t _vglite_delete(lv_draw_unit_t * draw_unit)
|
||||
{
|
||||
#if LV_USE_VGLITE_DRAW_THREAD
|
||||
lv_draw_vglite_unit_t * draw_vglite_unit = (lv_draw_vglite_unit_t *) draw_unit;
|
||||
|
||||
LV_LOG_INFO("Cancel VGLite draw thread.");
|
||||
draw_vglite_unit->exit_status = true;
|
||||
|
||||
if(draw_vglite_unit->inited)
|
||||
lv_thread_sync_signal(&draw_vglite_unit->sync);
|
||||
|
||||
lv_result_t res = lv_thread_delete(&draw_vglite_unit->thread);
|
||||
|
||||
return res;
|
||||
#else
|
||||
LV_UNUSED(draw_unit);
|
||||
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void _vglite_execute_drawing(lv_draw_vglite_unit_t * u)
|
||||
{
|
||||
vglite_draw_task_t * vglite_task = u->task_act;
|
||||
lv_layer_t * layer = vglite_task->t->target_layer;
|
||||
lv_draw_buf_t * draw_buf = layer->draw_buf;
|
||||
|
||||
/* Set target buffer */
|
||||
vglite_set_dest_buf(draw_buf->data, draw_buf->header.w, draw_buf->header.h, draw_buf->header.stride,
|
||||
draw_buf->header.cf);
|
||||
|
||||
lv_area_t clip_area;
|
||||
lv_area_copy(&clip_area, &vglite_task->t->clip_area);
|
||||
lv_area_move(&clip_area, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
lv_area_t draw_area;
|
||||
lv_area_copy(&draw_area, &vglite_task->t->area);
|
||||
lv_area_move(&draw_area, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
if(!lv_area_intersect(&draw_area, &draw_area, &clip_area))
|
||||
return; /*Fully clipped, nothing to do*/
|
||||
|
||||
if(_draw_info.unit_cnt > 1)
|
||||
lv_draw_buf_invalidate_cache(draw_buf, &draw_area);
|
||||
|
||||
#if LV_USE_PARALLEL_DRAW_DEBUG
|
||||
/* remember draw unit for debug purposes */
|
||||
vglite_task->t->draw_unit = &u->base_unit;
|
||||
#endif
|
||||
|
||||
/* Set scissor area, excluding the split blit case */
|
||||
#if LV_USE_VGLITE_BLIT_SPLIT
|
||||
if(vglite_task->t->type != LV_DRAW_TASK_TYPE_IMAGE || vglite_task->t->type != LV_DRAW_TASK_TYPE_LAYER)
|
||||
#endif
|
||||
vglite_set_scissor(&clip_area);
|
||||
|
||||
switch(vglite_task->t->type) {
|
||||
case LV_DRAW_TASK_TYPE_LABEL:
|
||||
lv_draw_vglite_label(vglite_task);
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_FILL:
|
||||
lv_draw_vglite_fill(vglite_task);
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_BORDER:
|
||||
lv_draw_vglite_border(vglite_task);
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_IMAGE:
|
||||
lv_draw_vglite_img(vglite_task);
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_ARC:
|
||||
lv_draw_vglite_arc(vglite_task);
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_LINE:
|
||||
lv_draw_vglite_line(vglite_task);
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_LAYER:
|
||||
lv_draw_vglite_layer(vglite_task);
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_TRIANGLE:
|
||||
lv_draw_vglite_triangle(vglite_task);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Disable scissor */
|
||||
vglite_set_scissor(&layer->buf_area);
|
||||
|
||||
#if LV_USE_PARALLEL_DRAW_DEBUG
|
||||
/*Layers manage it for themselves*/
|
||||
if(vglite_task->t->type != LV_DRAW_TASK_TYPE_LAYER) {
|
||||
lv_area_t draw_area;
|
||||
if(!lv_area_intersect(&draw_area, &vglite_task->t->area, &vglite_task->t->clip_area))
|
||||
return;
|
||||
|
||||
int32_t idx = u->base_unit.idx;
|
||||
|
||||
lv_draw_rect_dsc_t rect_dsc;
|
||||
lv_draw_rect_dsc_init(&rect_dsc);
|
||||
rect_dsc.bg_color = lv_palette_main(idx % LV_PALETTE_LAST);
|
||||
rect_dsc.border_color = rect_dsc.bg_color;
|
||||
rect_dsc.bg_opa = LV_OPA_10;
|
||||
rect_dsc.border_opa = LV_OPA_80;
|
||||
rect_dsc.border_width = 1;
|
||||
lv_draw_sw_fill(vglite_task->t, &rect_dsc, &draw_area);
|
||||
|
||||
lv_point_t txt_size;
|
||||
lv_text_get_size(&txt_size, "W", LV_FONT_DEFAULT, 0, 0, 100, LV_TEXT_FLAG_NONE);
|
||||
|
||||
lv_area_t txt_area;
|
||||
txt_area.x1 = draw_area.x1;
|
||||
txt_area.y1 = draw_area.y1;
|
||||
txt_area.x2 = draw_area.x1 + txt_size.x - 1;
|
||||
txt_area.y2 = draw_area.y1 + txt_size.y - 1;
|
||||
|
||||
lv_draw_rect_dsc_init(&rect_dsc);
|
||||
rect_dsc.bg_color = lv_color_white();
|
||||
lv_draw_sw_fill(vglite_task->t, &rect_dsc, &txt_area);
|
||||
|
||||
char buf[8];
|
||||
lv_snprintf(buf, sizeof(buf), "%d", idx);
|
||||
lv_draw_label_dsc_t label_dsc;
|
||||
lv_draw_label_dsc_init(&label_dsc);
|
||||
label_dsc.color = lv_color_black();
|
||||
label_dsc.text = buf;
|
||||
lv_draw_sw_label(vglite_task->t, &label_dsc, &txt_area);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void _vglite_cleanup_task(vglite_draw_task_t * task)
|
||||
{
|
||||
if(task->path != NULL) {
|
||||
VGLITE_CHECK_ERROR(vg_lite_clear_path(task->path));
|
||||
lv_free(task->path);
|
||||
}
|
||||
if(task->gradient != NULL) {
|
||||
VGLITE_CHECK_ERROR(vg_lite_clear_grad(task->gradient));
|
||||
lv_free(task->gradient);
|
||||
}
|
||||
if(task->path_data != NULL)
|
||||
lv_free(task->path_data);
|
||||
|
||||
lv_free(task);
|
||||
}
|
||||
|
||||
#if LV_USE_VGLITE_DRAW_ASYNC
|
||||
static inline void _vglite_queue_task(vglite_draw_task_t * task)
|
||||
{
|
||||
VGLITE_ASSERT_MSG(((_tail + 1) % VGLITE_TASK_BUF_SIZE) != _head, "VGLite task buffer full.");
|
||||
|
||||
_draw_task_buf[_tail].task = task;
|
||||
_draw_task_buf[_tail].flushed = false;
|
||||
_tail = (_tail + 1) % VGLITE_TASK_BUF_SIZE;
|
||||
}
|
||||
|
||||
static inline void _vglite_signal_task_ready(vglite_draw_task_t * task)
|
||||
{
|
||||
/* Signal the ready state to dispatcher. */
|
||||
task->t->state = LV_DRAW_TASK_STATE_READY;
|
||||
_head = (_head + 1) % VGLITE_TASK_BUF_SIZE;
|
||||
|
||||
_vglite_cleanup_task(task);
|
||||
/* No need to cleanup the tasks in buffer as we advance with the _head. */
|
||||
}
|
||||
|
||||
static inline void _vglite_signal_all_task_ready(void)
|
||||
{
|
||||
int end = (_head <= _tail) ? _tail : _tail + VGLITE_TASK_BUF_SIZE;
|
||||
|
||||
for(int i = _head; i < end; i++) {
|
||||
vglite_draw_task_t * task = _draw_task_buf[i % VGLITE_TASK_BUF_SIZE].task;
|
||||
|
||||
_vglite_signal_task_ready(task);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void _vglite_signal_flushed_task_ready(void)
|
||||
{
|
||||
if(vglite_cmd_buf_is_flushed()) {
|
||||
int end = (_head <= _tail) ? _tail : _tail + VGLITE_TASK_BUF_SIZE;
|
||||
|
||||
for(int i = _head; i < end; i++) {
|
||||
if(_draw_task_buf[i % VGLITE_TASK_BUF_SIZE].flushed) {
|
||||
vglite_draw_task_t * task = _draw_task_buf[i % VGLITE_TASK_BUF_SIZE].task;
|
||||
|
||||
_vglite_signal_task_ready(task);
|
||||
|
||||
}
|
||||
else {
|
||||
/* Those tasks have been flushed now. */
|
||||
_draw_task_buf[i % VGLITE_TASK_BUF_SIZE].flushed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LV_USE_VGLITE_DRAW_THREAD
|
||||
static void _vglite_render_thread_cb(void * ptr)
|
||||
{
|
||||
lv_draw_vglite_unit_t * u = ptr;
|
||||
|
||||
lv_thread_sync_init(&u->sync);
|
||||
u->inited = true;
|
||||
|
||||
while(1) {
|
||||
/* Wait for sync if there is no task set. */
|
||||
while(u->task_act == NULL
|
||||
#if LV_USE_VGLITE_DRAW_ASYNC
|
||||
/*
|
||||
* Wait for sync if wait_for_finish is triggered.
|
||||
* The thread will have to run and mark as complete any pending tasks.
|
||||
*/
|
||||
&& !u->wait_for_finish
|
||||
#endif
|
||||
) {
|
||||
if(u->exit_status)
|
||||
break;
|
||||
|
||||
lv_thread_sync_wait(&u->sync);
|
||||
}
|
||||
|
||||
if(u->exit_status) {
|
||||
LV_LOG_INFO("Ready to exit VGLite draw thread.");
|
||||
break;
|
||||
}
|
||||
|
||||
if(u->task_act) {
|
||||
#if LV_USE_VGLITE_DRAW_ASYNC
|
||||
_vglite_queue_task((void *)u->task_act);
|
||||
#endif
|
||||
_vglite_execute_drawing(u);
|
||||
}
|
||||
#if LV_USE_VGLITE_DRAW_ASYNC
|
||||
if(u->wait_for_finish) {
|
||||
vglite_wait_for_finish();
|
||||
_vglite_signal_all_task_ready();
|
||||
}
|
||||
else { /* u->task_act */
|
||||
_vglite_signal_flushed_task_ready();
|
||||
}
|
||||
#else
|
||||
/* Signal the ready state to dispatcher. */
|
||||
u->task_act->t->state = LV_DRAW_TASK_STATE_READY;
|
||||
_vglite_cleanup_task(u->task_act);
|
||||
#endif
|
||||
|
||||
/* Cleanup draw unit running condition. */
|
||||
#if LV_USE_VGLITE_DRAW_ASYNC
|
||||
if(u->wait_for_finish)
|
||||
u->wait_for_finish = false;
|
||||
else
|
||||
u->task_act = NULL;
|
||||
#else
|
||||
u->task_act = NULL;
|
||||
#endif
|
||||
|
||||
/* The draw unit is free now. Request a new dispatching as it can get a new task. */
|
||||
lv_draw_dispatch_request();
|
||||
}
|
||||
|
||||
u->inited = false;
|
||||
lv_thread_sync_delete(&u->sync);
|
||||
LV_LOG_INFO("Exit VGLite draw thread.");
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*LV_USE_DRAW_VGLITE*/
|
||||
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* @file lv_draw_vglite.h
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2023-2024 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_VGLITE_H
|
||||
#define LV_DRAW_VGLITE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_DRAW_VGLITE
|
||||
#include "../../lv_draw_private.h"
|
||||
#include "../../../display/lv_display_private.h"
|
||||
#include "../../../misc/lv_area_private.h"
|
||||
|
||||
#include "../../lv_draw_triangle.h"
|
||||
#include "../../lv_draw_label.h"
|
||||
#include "../../lv_draw_image.h"
|
||||
#include "../../lv_draw_line.h"
|
||||
#include "../../lv_draw_arc.h"
|
||||
#include "vg_lite.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct vglite_draw_task {
|
||||
lv_draw_task_t * t;
|
||||
vg_lite_path_t * path;
|
||||
vg_lite_linear_gradient_t * gradient;
|
||||
int32_t * path_data;
|
||||
} vglite_draw_task_t;
|
||||
|
||||
typedef struct lv_draw_vglite_unit {
|
||||
lv_draw_unit_t base_unit;
|
||||
vglite_draw_task_t * task_act;
|
||||
#if LV_USE_OS
|
||||
lv_thread_sync_t sync;
|
||||
lv_thread_t thread;
|
||||
volatile bool inited;
|
||||
volatile bool exit_status;
|
||||
#endif
|
||||
#if LV_USE_VGLITE_DRAW_ASYNC
|
||||
volatile bool wait_for_finish;
|
||||
#endif
|
||||
} lv_draw_vglite_unit_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
void lv_draw_buf_vglite_init_handlers(void);
|
||||
|
||||
void lv_draw_vglite_init(void);
|
||||
|
||||
void lv_draw_vglite_deinit(void);
|
||||
|
||||
void lv_draw_vglite_arc(vglite_draw_task_t * vglite_task);
|
||||
|
||||
void lv_draw_vglite_border(vglite_draw_task_t * vglite_task);
|
||||
|
||||
void lv_draw_vglite_fill(vglite_draw_task_t * vglite_task);
|
||||
|
||||
void lv_draw_vglite_img(vglite_draw_task_t * vglite_task);
|
||||
|
||||
void lv_draw_vglite_label(vglite_draw_task_t * vglite_task);
|
||||
|
||||
void lv_draw_vglite_layer(vglite_draw_task_t * vglite_task);
|
||||
|
||||
void lv_draw_vglite_line(vglite_draw_task_t * vglite_task);
|
||||
|
||||
void lv_draw_vglite_triangle(vglite_draw_task_t * vglite_task);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
#endif /*LV_USE_DRAW_VGLITE*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_VGLITE_H*/
|
||||
@@ -0,0 +1,684 @@
|
||||
/**
|
||||
* @file lv_draw_vglite_arc.c
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2021-2024 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_vglite.h"
|
||||
|
||||
#if LV_USE_DRAW_VGLITE
|
||||
#include "lv_vglite_buf.h"
|
||||
#include "lv_vglite_path.h"
|
||||
#include "lv_vglite_utils.h"
|
||||
|
||||
#include "../../../stdlib/lv_string.h"
|
||||
#include <math.h>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#define T_FRACTION 16384.0f
|
||||
|
||||
#define DICHOTO_ITER 5
|
||||
|
||||
static const uint16_t TperDegree[90] = {
|
||||
0, 174, 348, 522, 697, 873, 1049, 1226, 1403, 1581,
|
||||
1759, 1938, 2117, 2297, 2477, 2658, 2839, 3020, 3202, 3384,
|
||||
3567, 3749, 3933, 4116, 4300, 4484, 4668, 4852, 5037, 5222,
|
||||
5407, 5592, 5777, 5962, 6148, 6334, 6519, 6705, 6891, 7077,
|
||||
7264, 7450, 7636, 7822, 8008, 8193, 8378, 8564, 8750, 8936,
|
||||
9122, 9309, 9495, 9681, 9867, 10052, 10238, 10424, 10609, 10794,
|
||||
10979, 11164, 11349, 11534, 11718, 11902, 12086, 12270, 12453, 12637,
|
||||
12819, 13002, 13184, 13366, 13547, 13728, 13909, 14089, 14269, 14448,
|
||||
14627, 14805, 14983, 15160, 15337, 15513, 15689, 15864, 16038, 16212
|
||||
};
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/* intermediate arc params */
|
||||
typedef struct _vg_arc {
|
||||
uint32_t angle; /* angle <90deg */
|
||||
int32_t quarter; /* 0-3 counter-clockwise */
|
||||
int32_t rad; /* radius */
|
||||
int32_t p0x; /* point P0 */
|
||||
int32_t p0y;
|
||||
int32_t p1x; /* point P1 */
|
||||
int32_t p1y;
|
||||
int32_t p2x; /* point P2 */
|
||||
int32_t p2y;
|
||||
int32_t p3x; /* point P3 */
|
||||
int32_t p3y;
|
||||
} vg_arc;
|
||||
|
||||
typedef struct _cubic_cont_pt {
|
||||
float p0;
|
||||
float p1;
|
||||
float p2;
|
||||
float p3;
|
||||
} cubic_cont_pt;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Draw arc shape with effects
|
||||
*
|
||||
* @param[in] center Arc center with relative coordinates
|
||||
* @param[in] clip_area Clip area with relative coordinates to dest buff
|
||||
* @param[in] dsc Arc description structure (width, rounded ending, opacity)
|
||||
*
|
||||
*/
|
||||
static void _vglite_draw_arc(vglite_draw_task_t * vglite_task, const lv_point_t * center,
|
||||
const lv_area_t * clip_area, const lv_draw_arc_dsc_t * dsc);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_vglite_arc(vglite_draw_task_t * vglite_task)
|
||||
{
|
||||
lv_draw_task_t * t = vglite_task->t;
|
||||
const lv_draw_arc_dsc_t * dsc = t->draw_dsc;
|
||||
|
||||
if(dsc->opa <= (lv_opa_t)LV_OPA_MIN)
|
||||
return;
|
||||
if(dsc->width == 0)
|
||||
return;
|
||||
if(dsc->start_angle == dsc->end_angle)
|
||||
return;
|
||||
|
||||
lv_layer_t * layer = t->target_layer;
|
||||
lv_point_t center = {dsc->center.x - layer->buf_area.x1, dsc->center.y - layer->buf_area.y1};
|
||||
|
||||
lv_area_t clip_area;
|
||||
lv_area_copy(&clip_area, &t->clip_area);
|
||||
lv_area_move(&clip_area, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
_vglite_draw_arc(vglite_task, ¢er, &clip_area, dsc);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void _copy_arc(vg_arc * dst, vg_arc * src)
|
||||
{
|
||||
dst->quarter = src->quarter;
|
||||
dst->rad = src->rad;
|
||||
dst->angle = src->angle;
|
||||
dst->p0x = src->p0x;
|
||||
dst->p1x = src->p1x;
|
||||
dst->p2x = src->p2x;
|
||||
dst->p3x = src->p3x;
|
||||
dst->p0y = src->p0y;
|
||||
dst->p1y = src->p1y;
|
||||
dst->p2y = src->p2y;
|
||||
dst->p3y = src->p3y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate the point according given rotation angle rotation center is 0,0
|
||||
*/
|
||||
static void _rotate_point(int16_t angle, int32_t * x, int32_t * y)
|
||||
{
|
||||
int32_t ori_x = *x;
|
||||
int32_t ori_y = *y;
|
||||
int16_t alpha = angle;
|
||||
*x = ((lv_trigo_cos(alpha) * ori_x) / LV_TRIGO_SIN_MAX) - ((lv_trigo_sin(alpha) * ori_y) / LV_TRIGO_SIN_MAX);
|
||||
*y = ((lv_trigo_sin(alpha) * ori_x) / LV_TRIGO_SIN_MAX) + ((lv_trigo_cos(alpha) * ori_y) / LV_TRIGO_SIN_MAX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set full arc control points depending on quarter.
|
||||
* Control points match the best approximation of a circle.
|
||||
* Arc Quarter position is:
|
||||
* Q2 | Q3
|
||||
* ---+---
|
||||
* Q1 | Q0
|
||||
*/
|
||||
static void _set_full_arc(vg_arc * fullarc)
|
||||
{
|
||||
/* the tangent length for the bezier circle approx */
|
||||
float tang = ((float)fullarc->rad) * BEZIER_OPTIM_CIRCLE;
|
||||
switch(fullarc->quarter) {
|
||||
case 0:
|
||||
/* first quarter */
|
||||
fullarc->p0x = fullarc->rad;
|
||||
fullarc->p0y = 0;
|
||||
fullarc->p1x = fullarc->rad;
|
||||
fullarc->p1y = (int32_t)tang;
|
||||
fullarc->p2x = (int32_t)tang;
|
||||
fullarc->p2y = fullarc->rad;
|
||||
fullarc->p3x = 0;
|
||||
fullarc->p3y = fullarc->rad;
|
||||
break;
|
||||
case 1:
|
||||
/* second quarter */
|
||||
fullarc->p0x = 0;
|
||||
fullarc->p0y = fullarc->rad;
|
||||
fullarc->p1x = 0 - (int32_t)tang;
|
||||
fullarc->p1y = fullarc->rad;
|
||||
fullarc->p2x = 0 - fullarc->rad;
|
||||
fullarc->p2y = (int32_t)tang;
|
||||
fullarc->p3x = 0 - fullarc->rad;
|
||||
fullarc->p3y = 0;
|
||||
break;
|
||||
case 2:
|
||||
/* third quarter */
|
||||
fullarc->p0x = 0 - fullarc->rad;
|
||||
fullarc->p0y = 0;
|
||||
fullarc->p1x = 0 - fullarc->rad;
|
||||
fullarc->p1y = 0 - (int32_t)tang;
|
||||
fullarc->p2x = 0 - (int32_t)tang;
|
||||
fullarc->p2y = 0 - fullarc->rad;
|
||||
fullarc->p3x = 0;
|
||||
fullarc->p3y = 0 - fullarc->rad;
|
||||
break;
|
||||
case 3:
|
||||
/* fourth quarter */
|
||||
fullarc->p0x = 0;
|
||||
fullarc->p0y = 0 - fullarc->rad;
|
||||
fullarc->p1x = (int32_t)tang;
|
||||
fullarc->p1y = 0 - fullarc->rad;
|
||||
fullarc->p2x = fullarc->rad;
|
||||
fullarc->p2y = 0 - (int32_t)tang;
|
||||
fullarc->p3x = fullarc->rad;
|
||||
fullarc->p3y = 0;
|
||||
break;
|
||||
default:
|
||||
VGLITE_ASSERT_MSG(false, "Invalid arc quarter.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Linear interpolation between two points 'a' and 'b'
|
||||
* 't' parameter is the proportion ratio expressed in range [0 ; T_FRACTION ]
|
||||
*/
|
||||
static inline float _lerp(float coord_a, float coord_b, uint16_t t)
|
||||
{
|
||||
float tf = (float)t;
|
||||
return ((T_FRACTION - tf) * coord_a + tf * coord_b) / T_FRACTION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a point of bezier curve given 't' param
|
||||
*/
|
||||
static inline float _comp_bezier_point(float t, cubic_cont_pt cp)
|
||||
{
|
||||
float t_sq = t * t;
|
||||
float inv_t_sq = (1.0f - t) * (1.0f - t);
|
||||
float apt = (1.0f - t) * inv_t_sq * cp.p0 + 3.0f * inv_t_sq * t * cp.p1 + 3.0f * (1.0f - t) * t_sq * cp.p2 + t * t_sq *
|
||||
cp.p3;
|
||||
return apt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find parameter 't' in curve at point 'pt'
|
||||
* proceed by dichotomy on only 1 dimension,
|
||||
* works only if the curve is monotonic
|
||||
* bezier curve is defined by control points [p0 p1 p2 p3]
|
||||
* 'dec' tells if curve is decreasing (true) or increasing (false)
|
||||
*/
|
||||
static uint16_t _get_bez_t_from_pos(float pt, cubic_cont_pt cp, bool dec)
|
||||
{
|
||||
/* initialize dichotomy with boundary 't' values */
|
||||
float t_low = 0.0f;
|
||||
float t_mid = 0.5f;
|
||||
float t_hig = 1.0f;
|
||||
float a_pt;
|
||||
/* dichotomy loop */
|
||||
for(int i = 0; i < DICHOTO_ITER; i++) {
|
||||
a_pt = _comp_bezier_point(t_mid, cp);
|
||||
/* check mid-point position on bezier curve versus targeted point */
|
||||
if((a_pt > pt) != dec) {
|
||||
t_hig = t_mid;
|
||||
}
|
||||
else {
|
||||
t_low = t_mid;
|
||||
}
|
||||
/* define new 't' param for mid-point */
|
||||
t_mid = (t_low + t_hig) / 2.0f;
|
||||
}
|
||||
/* return parameter 't' in integer range [0 ; T_FRACTION] */
|
||||
return (uint16_t)floorf(t_mid * T_FRACTION + 0.5f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives relative coords of the control points
|
||||
* for the sub-arc starting at angle with given angle span
|
||||
*/
|
||||
static void _get_subarc_control_points(vg_arc * arc, uint32_t span)
|
||||
{
|
||||
vg_arc fullarc = {0};
|
||||
fullarc.angle = arc->angle;
|
||||
fullarc.quarter = arc->quarter;
|
||||
fullarc.rad = arc->rad;
|
||||
_set_full_arc(&fullarc);
|
||||
|
||||
/* special case of full arc */
|
||||
if(arc->angle == 90) {
|
||||
_copy_arc(arc, &fullarc);
|
||||
return;
|
||||
}
|
||||
|
||||
/* compute 1st arc using the geometric construction of curve */
|
||||
uint16_t t2 = TperDegree[arc->angle + span];
|
||||
|
||||
/* lerp for A */
|
||||
float a2x = _lerp((float)fullarc.p0x, (float)fullarc.p1x, t2);
|
||||
float a2y = _lerp((float)fullarc.p0y, (float)fullarc.p1y, t2);
|
||||
/* lerp for B */
|
||||
float b2x = _lerp((float)fullarc.p1x, (float)fullarc.p2x, t2);
|
||||
float b2y = _lerp((float)fullarc.p1y, (float)fullarc.p2y, t2);
|
||||
/* lerp for C */
|
||||
float c2x = _lerp((float)fullarc.p2x, (float)fullarc.p3x, t2);
|
||||
float c2y = _lerp((float)fullarc.p2y, (float)fullarc.p3y, t2);
|
||||
|
||||
/* lerp for D */
|
||||
float d2x = _lerp(a2x, b2x, t2);
|
||||
float d2y = _lerp(a2y, b2y, t2);
|
||||
/* lerp for E */
|
||||
float e2x = _lerp(b2x, c2x, t2);
|
||||
float e2y = _lerp(b2y, c2y, t2);
|
||||
|
||||
float pt2x = _lerp(d2x, e2x, t2);
|
||||
float pt2y = _lerp(d2y, e2y, t2);
|
||||
|
||||
/* compute sub-arc using the geometric construction of curve */
|
||||
uint16_t t1 = TperDegree[arc->angle];
|
||||
|
||||
/* lerp for A */
|
||||
float a1x = _lerp((float)fullarc.p0x, (float)fullarc.p1x, t1);
|
||||
float a1y = _lerp((float)fullarc.p0y, (float)fullarc.p1y, t1);
|
||||
/* lerp for B */
|
||||
float b1x = _lerp((float)fullarc.p1x, (float)fullarc.p2x, t1);
|
||||
float b1y = _lerp((float)fullarc.p1y, (float)fullarc.p2y, t1);
|
||||
/* lerp for C */
|
||||
float c1x = _lerp((float)fullarc.p2x, (float)fullarc.p3x, t1);
|
||||
float c1y = _lerp((float)fullarc.p2y, (float)fullarc.p3y, t1);
|
||||
|
||||
/* lerp for D */
|
||||
float d1x = _lerp(a1x, b1x, t1);
|
||||
float d1y = _lerp(a1y, b1y, t1);
|
||||
/* lerp for E */
|
||||
float e1x = _lerp(b1x, c1x, t1);
|
||||
float e1y = _lerp(b1y, c1y, t1);
|
||||
|
||||
float pt1x = _lerp(d1x, e1x, t1);
|
||||
float pt1y = _lerp(d1y, e1y, t1);
|
||||
|
||||
/* find the 't3' parameter for point P(t1) on the sub-arc [P0 A2 D2 P(t2)] using dichotomy
|
||||
* use position of x axis only */
|
||||
uint16_t t3;
|
||||
t3 = _get_bez_t_from_pos(pt1x,
|
||||
(cubic_cont_pt) {
|
||||
.p0 = ((float)fullarc.p0x), .p1 = a2x, .p2 = d2x, .p3 = pt2x
|
||||
},
|
||||
(bool)(pt2x < (float)fullarc.p0x));
|
||||
|
||||
/* lerp for B */
|
||||
float b3x = _lerp(a2x, d2x, t3);
|
||||
float b3y = _lerp(a2y, d2y, t3);
|
||||
/* lerp for C */
|
||||
float c3x = _lerp(d2x, pt2x, t3);
|
||||
float c3y = _lerp(d2y, pt2y, t3);
|
||||
|
||||
/* lerp for E */
|
||||
float e3x = _lerp(b3x, c3x, t3);
|
||||
float e3y = _lerp(b3y, c3y, t3);
|
||||
|
||||
arc->p0x = (int32_t)floorf(0.5f + pt1x);
|
||||
arc->p0y = (int32_t)floorf(0.5f + pt1y);
|
||||
arc->p1x = (int32_t)floorf(0.5f + e3x);
|
||||
arc->p1y = (int32_t)floorf(0.5f + e3y);
|
||||
arc->p2x = (int32_t)floorf(0.5f + c3x);
|
||||
arc->p2y = (int32_t)floorf(0.5f + c3y);
|
||||
arc->p3x = (int32_t)floorf(0.5f + pt2x);
|
||||
arc->p3y = (int32_t)floorf(0.5f + pt2y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives relative coords of the control points
|
||||
*/
|
||||
static void _get_arc_control_points(vg_arc * arc, bool start)
|
||||
{
|
||||
vg_arc fullarc = {0};
|
||||
fullarc.angle = arc->angle;
|
||||
fullarc.quarter = arc->quarter;
|
||||
fullarc.rad = arc->rad;
|
||||
_set_full_arc(&fullarc);
|
||||
|
||||
/* special case of full arc */
|
||||
if(arc->angle == 90) {
|
||||
_copy_arc(arc, &fullarc);
|
||||
return;
|
||||
}
|
||||
|
||||
/* compute sub-arc using the geometric construction of curve */
|
||||
uint16_t t = TperDegree[arc->angle];
|
||||
/* lerp for A */
|
||||
float ax = _lerp((float)fullarc.p0x, (float)fullarc.p1x, t);
|
||||
float ay = _lerp((float)fullarc.p0y, (float)fullarc.p1y, t);
|
||||
/* lerp for B */
|
||||
float bx = _lerp((float)fullarc.p1x, (float)fullarc.p2x, t);
|
||||
float by = _lerp((float)fullarc.p1y, (float)fullarc.p2y, t);
|
||||
/* lerp for C */
|
||||
float cx = _lerp((float)fullarc.p2x, (float)fullarc.p3x, t);
|
||||
float cy = _lerp((float)fullarc.p2y, (float)fullarc.p3y, t);
|
||||
|
||||
/* lerp for D */
|
||||
float dx = _lerp(ax, bx, t);
|
||||
float dy = _lerp(ay, by, t);
|
||||
/* lerp for E */
|
||||
float ex = _lerp(bx, cx, t);
|
||||
float ey = _lerp(by, cy, t);
|
||||
|
||||
/* sub-arc's control points are tangents of DeCasteljau's algorithm */
|
||||
if(start) {
|
||||
arc->p0x = (int32_t)floorf(0.5f + _lerp(dx, ex, t));
|
||||
arc->p0y = (int32_t)floorf(0.5f + _lerp(dy, ey, t));
|
||||
arc->p1x = (int32_t)floorf(0.5f + ex);
|
||||
arc->p1y = (int32_t)floorf(0.5f + ey);
|
||||
arc->p2x = (int32_t)floorf(0.5f + cx);
|
||||
arc->p2y = (int32_t)floorf(0.5f + cy);
|
||||
arc->p3x = fullarc.p3x;
|
||||
arc->p3y = fullarc.p3y;
|
||||
}
|
||||
else {
|
||||
arc->p0x = fullarc.p0x;
|
||||
arc->p0y = fullarc.p0y;
|
||||
arc->p1x = (int32_t)floorf(0.5f + ax);
|
||||
arc->p1y = (int32_t)floorf(0.5f + ay);
|
||||
arc->p2x = (int32_t)floorf(0.5f + dx);
|
||||
arc->p2y = (int32_t)floorf(0.5f + dy);
|
||||
arc->p3x = (int32_t)floorf(0.5f + _lerp(dx, ex, t));
|
||||
arc->p3y = (int32_t)floorf(0.5f + _lerp(dy, ey, t));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the arc control points into the path data for vglite,
|
||||
* taking into account the real center of the arc (translation).
|
||||
* arc_path: (in/out) the path data array for vglite
|
||||
* pidx: (in/out) index of last element added in arc_path
|
||||
* q_arc: (in) the arc data containing control points
|
||||
* center: (in) the center of the circle in draw coordinates
|
||||
* cw: (in) true if arc is clockwise
|
||||
*/
|
||||
static void _add_split_arc_path(int32_t * arc_path, uint32_t * pidx, vg_arc * q_arc, const lv_point_t * center, bool cw)
|
||||
{
|
||||
/* assumes first control point already in array arc_path[] */
|
||||
uint32_t idx = *pidx;
|
||||
if(cw) {
|
||||
#if BEZIER_DBG_CONTROL_POINTS
|
||||
arc_path[idx++] = VLC_OP_LINE;
|
||||
arc_path[idx++] = q_arc->p1x + center->x;
|
||||
arc_path[idx++] = q_arc->p1y + center->y;
|
||||
arc_path[idx++] = VLC_OP_LINE;
|
||||
arc_path[idx++] = q_arc->p2x + center->x;
|
||||
arc_path[idx++] = q_arc->p2y + center->y;
|
||||
arc_path[idx++] = VLC_OP_LINE;
|
||||
arc_path[idx++] = q_arc->p3x + center->x;
|
||||
arc_path[idx++] = q_arc->p3y + center->y;
|
||||
#else
|
||||
arc_path[idx++] = VLC_OP_CUBIC;
|
||||
arc_path[idx++] = q_arc->p1x + center->x;
|
||||
arc_path[idx++] = q_arc->p1y + center->y;
|
||||
arc_path[idx++] = q_arc->p2x + center->x;
|
||||
arc_path[idx++] = q_arc->p2y + center->y;
|
||||
arc_path[idx++] = q_arc->p3x + center->x;
|
||||
arc_path[idx++] = q_arc->p3y + center->y;
|
||||
#endif
|
||||
}
|
||||
else { /* reverse points order when counter-clockwise */
|
||||
#if BEZIER_DBG_CONTROL_POINTS
|
||||
arc_path[idx++] = VLC_OP_LINE;
|
||||
arc_path[idx++] = q_arc->p2x + center->x;
|
||||
arc_path[idx++] = q_arc->p2y + center->y;
|
||||
arc_path[idx++] = VLC_OP_LINE;
|
||||
arc_path[idx++] = q_arc->p1x + center->x;
|
||||
arc_path[idx++] = q_arc->p1y + center->y;
|
||||
arc_path[idx++] = VLC_OP_LINE;
|
||||
arc_path[idx++] = q_arc->p0x + center->x;
|
||||
arc_path[idx++] = q_arc->p0y + center->y;
|
||||
#else
|
||||
arc_path[idx++] = VLC_OP_CUBIC;
|
||||
arc_path[idx++] = q_arc->p2x + center->x;
|
||||
arc_path[idx++] = q_arc->p2y + center->y;
|
||||
arc_path[idx++] = q_arc->p1x + center->x;
|
||||
arc_path[idx++] = q_arc->p1y + center->y;
|
||||
arc_path[idx++] = q_arc->p0x + center->x;
|
||||
arc_path[idx++] = q_arc->p0y + center->y;
|
||||
#endif
|
||||
}
|
||||
/* update index i n path array*/
|
||||
*pidx = idx;
|
||||
}
|
||||
|
||||
static void _add_arc_path(int32_t * arc_path, uint32_t * pidx, uint32_t radius,
|
||||
int32_t start_angle, int32_t end_angle, const lv_point_t * center, bool cw)
|
||||
{
|
||||
/* set number of arcs to draw */
|
||||
vg_arc q_arc;
|
||||
uint32_t start_arc_angle = start_angle % 90;
|
||||
uint32_t end_arc_angle = end_angle % 90;
|
||||
uint32_t inv_start_arc_angle = (start_arc_angle > 0) ? (90 - start_arc_angle) : 0;
|
||||
uint32_t nbarc = (end_angle - start_angle - inv_start_arc_angle - end_arc_angle) / 90;
|
||||
q_arc.rad = radius;
|
||||
|
||||
/* handle special case of start & end point in the same quarter */
|
||||
if(((start_angle / 90) == (end_angle / 90)) && (nbarc <= 0)) {
|
||||
q_arc.quarter = (start_angle / 90) % 4;
|
||||
q_arc.angle = start_arc_angle;
|
||||
_get_subarc_control_points(&q_arc, end_arc_angle - start_arc_angle);
|
||||
_add_split_arc_path(arc_path, pidx, &q_arc, center, cw);
|
||||
return;
|
||||
}
|
||||
|
||||
if(cw) {
|
||||
/* partial starting arc */
|
||||
if(start_arc_angle > 0) {
|
||||
q_arc.quarter = (start_angle / 90) % 4;
|
||||
q_arc.angle = start_arc_angle;
|
||||
/* get cubic points relative to center */
|
||||
_get_arc_control_points(&q_arc, true);
|
||||
/* put cubic points in arc_path */
|
||||
_add_split_arc_path(arc_path, pidx, &q_arc, center, cw);
|
||||
}
|
||||
/* full arcs */
|
||||
for(uint32_t q = 0; q < nbarc ; q++) {
|
||||
q_arc.quarter = (q + ((start_angle + 89) / 90)) % 4;
|
||||
q_arc.angle = 90;
|
||||
/* get cubic points relative to center */
|
||||
_get_arc_control_points(&q_arc, true); /* 2nd parameter 'start' ignored */
|
||||
/* put cubic points in arc_path */
|
||||
_add_split_arc_path(arc_path, pidx, &q_arc, center, cw);
|
||||
}
|
||||
/* partial ending arc */
|
||||
if(end_arc_angle > 0) {
|
||||
q_arc.quarter = (end_angle / 90) % 4;
|
||||
q_arc.angle = end_arc_angle;
|
||||
/* get cubic points relative to center */
|
||||
_get_arc_control_points(&q_arc, false);
|
||||
/* put cubic points in arc_path */
|
||||
_add_split_arc_path(arc_path, pidx, &q_arc, center, cw);
|
||||
}
|
||||
|
||||
}
|
||||
else { /* counter clockwise */
|
||||
|
||||
/* partial ending arc */
|
||||
if(end_arc_angle > 0) {
|
||||
q_arc.quarter = (end_angle / 90) % 4;
|
||||
q_arc.angle = end_arc_angle;
|
||||
/* get cubic points relative to center */
|
||||
_get_arc_control_points(&q_arc, false);
|
||||
/* put cubic points in arc_path */
|
||||
_add_split_arc_path(arc_path, pidx, &q_arc, center, cw);
|
||||
}
|
||||
/* full arcs */
|
||||
for(int32_t q = nbarc - 1; q >= 0; q--) {
|
||||
q_arc.quarter = (q + ((start_angle + 89) / 90)) % 4;
|
||||
q_arc.angle = 90;
|
||||
/* get cubic points relative to center */
|
||||
_get_arc_control_points(&q_arc, true); /* 2nd parameter 'start' ignored */
|
||||
/* put cubic points in arc_path */
|
||||
_add_split_arc_path(arc_path, pidx, &q_arc, center, cw);
|
||||
}
|
||||
/* partial starting arc */
|
||||
if(start_arc_angle > 0) {
|
||||
q_arc.quarter = (start_angle / 90) % 4;
|
||||
q_arc.angle = start_arc_angle;
|
||||
/* get cubic points relative to center */
|
||||
_get_arc_control_points(&q_arc, true);
|
||||
/* put cubic points in arc_path */
|
||||
_add_split_arc_path(arc_path, pidx, &q_arc, center, cw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _vglite_draw_arc(vglite_draw_task_t * vglite_task, const lv_point_t * center,
|
||||
const lv_area_t * clip_area, const lv_draw_arc_dsc_t * dsc)
|
||||
{
|
||||
vg_lite_path_t * path = lv_malloc_zeroed(sizeof(vg_lite_path_t));
|
||||
LV_ASSERT_MALLOC(path);
|
||||
vglite_task->path = path;
|
||||
int16_t start_angle = dsc->start_angle;
|
||||
int16_t end_angle = dsc->end_angle;
|
||||
|
||||
/* be sure end_angle > start_angle */
|
||||
if(end_angle < start_angle)
|
||||
end_angle += 360;
|
||||
|
||||
bool donut = ((end_angle - start_angle) % 360 == 0) ? true : false;
|
||||
vg_lite_buffer_t * dest_buf = vglite_get_dest_buf();
|
||||
|
||||
int32_t * arc_path = lv_malloc_zeroed(ARC_PATH_DATA_MAX_SIZE * sizeof(int32_t));
|
||||
LV_ASSERT_MALLOC(arc_path);
|
||||
vglite_task->path_data = arc_path;
|
||||
|
||||
/*** Init path ***/
|
||||
int32_t width = dsc->width; /* inner arc radius = outer arc radius - width */
|
||||
uint16_t radius = dsc->radius;
|
||||
|
||||
if(width > radius)
|
||||
width = radius;
|
||||
|
||||
uint32_t pidx = 0;
|
||||
int32_t cp_x, cp_y; /* control point coords */
|
||||
|
||||
/* first control point of curve */
|
||||
cp_x = radius;
|
||||
cp_y = 0;
|
||||
_rotate_point(start_angle, &cp_x, &cp_y);
|
||||
arc_path[pidx++] = VLC_OP_MOVE;
|
||||
arc_path[pidx++] = center->x + cp_x;
|
||||
arc_path[pidx++] = center->y + cp_y;
|
||||
|
||||
/* draw 1-5 outer quarters */
|
||||
_add_arc_path(arc_path, &pidx, radius, start_angle, end_angle, center, true);
|
||||
|
||||
if(donut) {
|
||||
/* close outer circle */
|
||||
cp_x = radius;
|
||||
cp_y = 0;
|
||||
_rotate_point(start_angle, &cp_x, &cp_y);
|
||||
arc_path[pidx++] = VLC_OP_LINE;
|
||||
arc_path[pidx++] = center->x + cp_x;
|
||||
arc_path[pidx++] = center->y + cp_y;
|
||||
/* start inner circle */
|
||||
cp_x = radius - width;
|
||||
cp_y = 0;
|
||||
_rotate_point(start_angle, &cp_x, &cp_y);
|
||||
arc_path[pidx++] = VLC_OP_MOVE;
|
||||
arc_path[pidx++] = center->x + cp_x;
|
||||
arc_path[pidx++] = center->y + cp_y;
|
||||
|
||||
}
|
||||
else if(dsc->rounded != 0U) { /* 1st rounded arc ending */
|
||||
cp_x = radius - width / 2;
|
||||
cp_y = 0;
|
||||
_rotate_point(end_angle, &cp_x, &cp_y);
|
||||
lv_point_t round_center = {center->x + cp_x, center->y + cp_y};
|
||||
_add_arc_path(arc_path, &pidx, width / 2, end_angle, (end_angle + 180),
|
||||
&round_center, true);
|
||||
|
||||
}
|
||||
else { /* 1st flat ending */
|
||||
cp_x = radius - width;
|
||||
cp_y = 0;
|
||||
_rotate_point(end_angle, &cp_x, &cp_y);
|
||||
arc_path[pidx++] = VLC_OP_LINE;
|
||||
arc_path[pidx++] = center->x + cp_x;
|
||||
arc_path[pidx++] = center->y + cp_y;
|
||||
}
|
||||
|
||||
/* draw 1-5 inner quarters */
|
||||
_add_arc_path(arc_path, &pidx, radius - width, start_angle, end_angle, center, false);
|
||||
|
||||
/* last control point of curve */
|
||||
if(donut) { /* close the loop */
|
||||
cp_x = radius - width;
|
||||
cp_y = 0;
|
||||
_rotate_point(start_angle, &cp_x, &cp_y);
|
||||
arc_path[pidx++] = VLC_OP_LINE;
|
||||
arc_path[pidx++] = center->x + cp_x;
|
||||
arc_path[pidx++] = center->y + cp_y;
|
||||
|
||||
}
|
||||
else if(dsc->rounded != 0U) { /* 2nd rounded arc ending */
|
||||
cp_x = radius - width / 2;
|
||||
cp_y = 0;
|
||||
_rotate_point(start_angle, &cp_x, &cp_y);
|
||||
lv_point_t round_center = {center->x + cp_x, center->y + cp_y};
|
||||
_add_arc_path(arc_path, &pidx, width / 2, (start_angle + 180), (start_angle + 360),
|
||||
&round_center, true);
|
||||
|
||||
}
|
||||
else { /* 2nd flat ending */
|
||||
cp_x = radius;
|
||||
cp_y = 0;
|
||||
_rotate_point(start_angle, &cp_x, &cp_y);
|
||||
arc_path[pidx++] = VLC_OP_LINE;
|
||||
arc_path[pidx++] = center->x + cp_x;
|
||||
arc_path[pidx++] = center->y + cp_y;
|
||||
}
|
||||
|
||||
arc_path[pidx++] = VLC_OP_END;
|
||||
|
||||
VGLITE_CHECK_ERROR(vg_lite_init_path(path, VG_LITE_S32, VG_LITE_HIGH, (uint32_t)pidx * sizeof(int32_t), arc_path,
|
||||
(vg_lite_float_t)clip_area->x1, (vg_lite_float_t)clip_area->y1,
|
||||
((vg_lite_float_t)clip_area->x2) + 1.0f, ((vg_lite_float_t)clip_area->y2) + 1.0f));
|
||||
|
||||
lv_color32_t col32 = lv_color_to_32(dsc->color, dsc->opa);
|
||||
vg_lite_color_t vgcol = vglite_get_color(col32, false);
|
||||
|
||||
/*** Draw arc ***/
|
||||
VGLITE_CHECK_ERROR(vg_lite_draw(dest_buf, path, VG_LITE_FILL_NON_ZERO, NULL, VG_LITE_BLEND_SRC_OVER, vgcol));
|
||||
|
||||
vglite_run();
|
||||
}
|
||||
|
||||
#endif /*LV_USE_DRAW_VGLITE*/
|
||||
@@ -0,0 +1,248 @@
|
||||
/**
|
||||
* @file lv_draw_vglite_border.c
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2022-2024 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_vglite.h"
|
||||
|
||||
#if LV_USE_DRAW_VGLITE
|
||||
#include "lv_vglite_buf.h"
|
||||
#include "lv_vglite_path.h"
|
||||
#include "lv_vglite_utils.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/*** Define maximum numbers of rectangles needed to clip partial borders ***/
|
||||
#define MAX_NUM_RECTANGLES 4
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct scissoring_rects {
|
||||
vg_lite_rectangle_t rect[MAX_NUM_RECTANGLES];
|
||||
uint32_t num_rect;
|
||||
} scissoring_rects_t ;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Draw rectangle border/outline shape with effects (rounded corners, opacity)
|
||||
*
|
||||
* @param[in] coords Coordinates of the rectangle border/outline (relative to dest buff)
|
||||
* @param[in] clip_area Clip area with relative coordinates to dest buff
|
||||
* @param[in] dsc Description of the rectangle border/outline
|
||||
*
|
||||
*/
|
||||
static void _vglite_draw_border(vglite_draw_task_t * task, const lv_area_t * coords,
|
||||
const lv_area_t * clip_area, const lv_draw_border_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Create scissor area based on the border side
|
||||
*
|
||||
* @param[in] coords Coordinates of the rectangle border/outline (relative to dest buff)
|
||||
* @param[in] line_width Width of the line
|
||||
* @param[in] border_side Sides of the border
|
||||
* @param[in] radius Radius of the border
|
||||
* @param[out] scissoring_rects Struct that contains the array of scissors
|
||||
*
|
||||
*/
|
||||
|
||||
static void _border_set_scissoring(const lv_area_t * coords, int32_t line_width,
|
||||
uint32_t border_side, int32_t radius,
|
||||
scissoring_rects_t * scissoring_rects);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_vglite_border(vglite_draw_task_t * vglite_task)
|
||||
{
|
||||
const lv_draw_border_dsc_t * dsc = vglite_task->t->draw_dsc;
|
||||
const lv_area_t * coords = &vglite_task->t->area;
|
||||
|
||||
if(dsc->opa <= (lv_opa_t)LV_OPA_MIN)
|
||||
return;
|
||||
if(dsc->width == 0)
|
||||
return;
|
||||
if(dsc->side == (lv_border_side_t)LV_BORDER_SIDE_NONE)
|
||||
return;
|
||||
|
||||
lv_layer_t * layer = vglite_task->t->target_layer;
|
||||
lv_area_t inward_coords;
|
||||
int32_t width = dsc->width;
|
||||
|
||||
/* Move border inwards to align with software rendered border */
|
||||
inward_coords.x1 = coords->x1 + ceil(width / 2.0f);
|
||||
inward_coords.x2 = coords->x2 - floor(width / 2.0f);
|
||||
inward_coords.y1 = coords->y1 + ceil(width / 2.0f);
|
||||
inward_coords.y2 = coords->y2 - floor(width / 2.0f);
|
||||
|
||||
lv_area_move(&inward_coords, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
lv_area_t clip_area;
|
||||
lv_area_copy(&clip_area, &vglite_task->t->clip_area);
|
||||
lv_area_move(&clip_area, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
lv_area_t clipped_coords;
|
||||
if(!lv_area_intersect(&clipped_coords, &inward_coords, &clip_area))
|
||||
return; /*Fully clipped, nothing to do*/
|
||||
|
||||
_vglite_draw_border(vglite_task, &inward_coords, &clip_area, dsc);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void _border_set_scissoring(const lv_area_t * coords, int32_t line_width,
|
||||
uint32_t border_side, int32_t radius,
|
||||
scissoring_rects_t * scissoring_rects)
|
||||
{
|
||||
int32_t rect_width = coords->x2 - coords->x1;
|
||||
int32_t rect_height = coords->y2 - coords->y1;
|
||||
int32_t shortest_side = LV_MIN(rect_width, rect_height);
|
||||
int32_t final_radius = LV_MIN(radius, shortest_side / 2);
|
||||
|
||||
if(border_side & LV_BORDER_SIDE_TOP) {
|
||||
scissoring_rects->rect[scissoring_rects->num_rect].x = coords->x1 - ceil(line_width / 2.0f);
|
||||
scissoring_rects->rect[scissoring_rects->num_rect].y = coords->y1 - ceil(line_width / 2.0f);
|
||||
scissoring_rects->rect[scissoring_rects->num_rect].width = coords->x2 - coords->x1 + line_width;
|
||||
scissoring_rects->rect[scissoring_rects->num_rect].height = final_radius + ceil(line_width / 2.0f);
|
||||
scissoring_rects->num_rect++;
|
||||
}
|
||||
|
||||
if(border_side & LV_BORDER_SIDE_LEFT) {
|
||||
scissoring_rects->rect[scissoring_rects->num_rect].x = coords->x1 - ceil(line_width / 2.0f);
|
||||
scissoring_rects->rect[scissoring_rects->num_rect].y = coords->y1 - ceil(line_width / 2.0f);
|
||||
scissoring_rects->rect[scissoring_rects->num_rect].width = final_radius + ceil(line_width / 2.0f);
|
||||
scissoring_rects->rect[scissoring_rects->num_rect].height = coords->y2 - coords->y1 + line_width + 1;
|
||||
scissoring_rects->num_rect++;
|
||||
}
|
||||
|
||||
if(border_side & LV_BORDER_SIDE_RIGHT) {
|
||||
scissoring_rects->rect[scissoring_rects->num_rect].x = coords->x2 - final_radius + 1;
|
||||
scissoring_rects->rect[scissoring_rects->num_rect].y = coords->y1 - ceil(line_width / 2.0f);
|
||||
scissoring_rects->rect[scissoring_rects->num_rect].width = final_radius + ceil(line_width / 2.0f);
|
||||
scissoring_rects->rect[scissoring_rects->num_rect].height = coords->y2 - coords->y1 + line_width + 1;
|
||||
scissoring_rects->num_rect++;
|
||||
}
|
||||
|
||||
if(border_side & LV_BORDER_SIDE_BOTTOM) {
|
||||
scissoring_rects->rect[scissoring_rects->num_rect].x = coords->x1 - ceil(line_width / 2.0f);
|
||||
scissoring_rects->rect[scissoring_rects->num_rect].y = coords->y2 - final_radius + 1;
|
||||
scissoring_rects->rect[scissoring_rects->num_rect].width = coords->x2 - coords->x1 + line_width;
|
||||
scissoring_rects->rect[scissoring_rects->num_rect].height = final_radius + ceil(line_width / 2.0f);
|
||||
scissoring_rects->num_rect++;
|
||||
}
|
||||
}
|
||||
|
||||
static void _vglite_draw_border(vglite_draw_task_t * vglite_task, const lv_area_t * coords,
|
||||
const lv_area_t * clip_area, const lv_draw_border_dsc_t * dsc)
|
||||
{
|
||||
int32_t radius = dsc->radius;
|
||||
vg_lite_buffer_t * buf = vglite_get_dest_buf();
|
||||
|
||||
if(radius < 0)
|
||||
return;
|
||||
|
||||
int32_t border_half = (int32_t)floor(dsc->width / 2.0f);
|
||||
if(radius > border_half)
|
||||
radius = radius - border_half;
|
||||
|
||||
vg_lite_cap_style_t cap_style = (radius) ? VG_LITE_CAP_ROUND : VG_LITE_CAP_BUTT;
|
||||
vg_lite_join_style_t join_style = (radius) ? VG_LITE_JOIN_ROUND : VG_LITE_JOIN_MITER;
|
||||
|
||||
/*** Init path ***/
|
||||
int32_t * path_data = lv_malloc_zeroed(RECT_PATH_DATA_MAX_SIZE * sizeof(int32_t));
|
||||
LV_ASSERT_MALLOC(path_data);
|
||||
vglite_task->path_data = path_data;
|
||||
|
||||
uint32_t path_data_size;
|
||||
vglite_create_rect_path_data(path_data, &path_data_size, radius, coords);
|
||||
vg_lite_quality_t path_quality = radius > 0 ? VG_LITE_HIGH : VG_LITE_MEDIUM;
|
||||
|
||||
vg_lite_path_t * path = lv_malloc_zeroed(sizeof(vg_lite_path_t));
|
||||
LV_ASSERT_MALLOC(path);
|
||||
vglite_task->path = path;
|
||||
VGLITE_CHECK_ERROR(vg_lite_init_path(path, VG_LITE_S32, path_quality, path_data_size, path_data,
|
||||
(vg_lite_float_t)clip_area->x1, (vg_lite_float_t)clip_area->y1,
|
||||
((vg_lite_float_t)clip_area->x2) + 1.0f, ((vg_lite_float_t)clip_area->y2) + 1.0f));
|
||||
|
||||
lv_color32_t col32 = lv_color_to_32(dsc->color, dsc->opa);
|
||||
vg_lite_color_t vgcol = vglite_get_color(col32, false);
|
||||
|
||||
int32_t line_width = dsc->width;
|
||||
lv_border_side_t border_side = dsc->side;
|
||||
|
||||
scissoring_rects_t scissoring_rects;
|
||||
scissoring_rects.num_rect = 0;
|
||||
|
||||
bool has_vg_mask_feat = vg_lite_query_feature(gcFEATURE_BIT_VG_MASK);
|
||||
|
||||
VGLITE_CHECK_ERROR(vg_lite_set_draw_path_type(path, VG_LITE_DRAW_STROKE_PATH));
|
||||
|
||||
VGLITE_CHECK_ERROR(vg_lite_set_stroke(path, cap_style, join_style, line_width, 8, NULL, 0, 0, vgcol));
|
||||
|
||||
VGLITE_CHECK_ERROR(vg_lite_update_stroke(path));
|
||||
|
||||
if(border_side != LV_BORDER_SIDE_FULL) {
|
||||
_border_set_scissoring(coords, line_width, border_side, radius, &scissoring_rects);
|
||||
|
||||
if(has_vg_mask_feat) {
|
||||
/*** Enable scissor and apply scissor rects ***/
|
||||
VGLITE_CHECK_ERROR(vg_lite_enable_scissor());
|
||||
VGLITE_CHECK_ERROR(vg_lite_scissor_rects(buf, scissoring_rects.num_rect, scissoring_rects.rect));
|
||||
|
||||
/*** Draw border ***/
|
||||
VGLITE_CHECK_ERROR(vg_lite_draw(buf, path, VG_LITE_FILL_NON_ZERO, NULL, VG_LITE_BLEND_SRC_OVER, vgcol));
|
||||
|
||||
/*** Disable scissor ***/
|
||||
VGLITE_CHECK_ERROR(vg_lite_disable_scissor());
|
||||
}
|
||||
else {
|
||||
for(uint32_t i = 0; i < scissoring_rects.num_rect; i++) {
|
||||
VGLITE_CHECK_ERROR(vg_lite_set_scissor(scissoring_rects.rect[i].x, scissoring_rects.rect[i].y,
|
||||
scissoring_rects.rect[i].x + scissoring_rects.rect[i].width,
|
||||
scissoring_rects.rect[i].y + scissoring_rects.rect[i].height));
|
||||
VGLITE_CHECK_ERROR(vg_lite_draw(buf, path, VG_LITE_FILL_NON_ZERO, NULL, VG_LITE_BLEND_SRC_OVER, vgcol));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/*** Draw border ***/
|
||||
VGLITE_CHECK_ERROR(vg_lite_draw(buf, path, VG_LITE_FILL_NON_ZERO, NULL, VG_LITE_BLEND_SRC_OVER, vgcol));
|
||||
}
|
||||
|
||||
vglite_run();
|
||||
}
|
||||
|
||||
#endif /*LV_USE_DRAW_VGLITE*/
|
||||
@@ -0,0 +1,269 @@
|
||||
/**
|
||||
* @file lv_draw_vglite_fill.c
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2020-2024 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_vglite.h"
|
||||
|
||||
#if LV_USE_DRAW_VGLITE
|
||||
#include "lv_vglite_buf.h"
|
||||
#include "lv_vglite_path.h"
|
||||
#include "lv_vglite_utils.h"
|
||||
|
||||
#include "../../../stdlib/lv_string.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Set rectangle path data
|
||||
*
|
||||
* @param[in/out] path_data Coordinates of the rectangle
|
||||
* @param[in/out] path_data_size Size of path_data (bytes)
|
||||
* @param[in] p Points of the rectangle
|
||||
*
|
||||
*/
|
||||
static void _vglite_set_rectangle(int32_t * path_data, uint32_t * path_data_size,
|
||||
const lv_area_t * dest_area);
|
||||
|
||||
/**
|
||||
* Fill area, with optional opacity.
|
||||
*
|
||||
* @param[in] dest_area Area with relative coordinates of destination buffer
|
||||
* @param[in] dsc Description of the area to fill (color, opa)
|
||||
*
|
||||
*/
|
||||
static void _vglite_fill(vglite_draw_task_t * task, const lv_area_t * dest_area,
|
||||
const lv_draw_fill_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Draw rectangle background with effects (rounded corners, gradient)
|
||||
*
|
||||
* @param[in] coords Coordinates of the rectangle background (relative to dest buff)
|
||||
* @param[in] clip_area Clip area with relative coordinates to dest buff
|
||||
* @param[in] dsc Description of the rectangle background
|
||||
*
|
||||
*/
|
||||
static void _vglite_draw_rect(vglite_draw_task_t * task, const lv_area_t * coords,
|
||||
const lv_area_t * clip_area, const lv_draw_fill_dsc_t * dsc);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_vglite_fill(vglite_draw_task_t * vglite_task)
|
||||
{
|
||||
const lv_draw_fill_dsc_t * dsc = vglite_task->t->draw_dsc;
|
||||
const lv_area_t * coords = &vglite_task->t->area;
|
||||
|
||||
if(dsc->opa <= (lv_opa_t)LV_OPA_MIN)
|
||||
return;
|
||||
|
||||
lv_layer_t * layer = vglite_task->t->target_layer;
|
||||
lv_area_t relative_coords;
|
||||
lv_area_copy(&relative_coords, coords);
|
||||
lv_area_move(&relative_coords, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
lv_area_t clip_area;
|
||||
lv_area_copy(&clip_area, &vglite_task->t->clip_area);
|
||||
lv_area_move(&clip_area, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
lv_area_t clipped_coords;
|
||||
if(!lv_area_intersect(&clipped_coords, &relative_coords, &clip_area))
|
||||
return; /*Fully clipped, nothing to do*/
|
||||
|
||||
/*
|
||||
* Most simple case: just a plain rectangle (no radius, no gradient)
|
||||
*/
|
||||
if((dsc->radius == 0) && (dsc->grad.dir == (lv_grad_dir_t)LV_GRAD_DIR_NONE))
|
||||
_vglite_fill(vglite_task, &clipped_coords, dsc);
|
||||
else
|
||||
_vglite_draw_rect(vglite_task, &relative_coords, &clip_area, dsc);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void _vglite_set_rectangle(int32_t * path_data, uint32_t * path_data_size, const lv_area_t * dest_area)
|
||||
{
|
||||
uint32_t pidx = 0;
|
||||
path_data[pidx++] = VLC_OP_MOVE;
|
||||
path_data[pidx++] = dest_area->x1;
|
||||
path_data[pidx++] = dest_area->y1;
|
||||
path_data[pidx++] = VLC_OP_LINE;
|
||||
path_data[pidx++] = dest_area->x2 + 1;
|
||||
path_data[pidx++] = dest_area->y1;
|
||||
path_data[pidx++] = VLC_OP_LINE;
|
||||
path_data[pidx++] = dest_area->x2 + 1;
|
||||
path_data[pidx++] = dest_area->y2 + 1;
|
||||
path_data[pidx++] = VLC_OP_LINE;
|
||||
path_data[pidx++] = dest_area->x1;
|
||||
path_data[pidx++] = dest_area->y2 + 1;
|
||||
path_data[pidx++] = VLC_OP_LINE;
|
||||
path_data[pidx++] = dest_area->x1;
|
||||
path_data[pidx++] = dest_area->y1;
|
||||
path_data[pidx++] = VLC_OP_END;
|
||||
|
||||
*path_data_size = pidx * sizeof(int32_t);
|
||||
}
|
||||
|
||||
static void _vglite_fill(vglite_draw_task_t * vglite_task, const lv_area_t * dest_area,
|
||||
const lv_draw_fill_dsc_t * dsc)
|
||||
{
|
||||
vg_lite_buffer_t * dest_buf = vglite_get_dest_buf();
|
||||
|
||||
lv_color32_t col32 = lv_color_to_32(dsc->color, dsc->opa);
|
||||
vg_lite_color_t vgcol = vglite_get_color(col32, false);
|
||||
|
||||
if(dsc->opa >= (lv_opa_t)LV_OPA_MAX) { /*Opaque fill*/
|
||||
vg_lite_rectangle_t rect = {
|
||||
.x = dest_area->x1,
|
||||
.y = dest_area->y1,
|
||||
.width = lv_area_get_width(dest_area),
|
||||
.height = lv_area_get_height(dest_area)
|
||||
};
|
||||
|
||||
VGLITE_CHECK_ERROR(vg_lite_clear(dest_buf, &rect, vgcol));
|
||||
|
||||
vglite_run();
|
||||
}
|
||||
else { /*fill with transparency*/
|
||||
|
||||
vg_lite_path_t * path = lv_malloc_zeroed(sizeof(vg_lite_path_t));
|
||||
LV_ASSERT_MALLOC(path);
|
||||
vglite_task->path = path;
|
||||
|
||||
uint32_t path_data_size;
|
||||
int32_t * path_data = lv_malloc_zeroed(16 * sizeof(int32_t));
|
||||
LV_ASSERT_MALLOC(path_data);
|
||||
vglite_task->path_data = path_data;
|
||||
_vglite_set_rectangle(path_data, &path_data_size, dest_area);
|
||||
|
||||
VGLITE_CHECK_ERROR(vg_lite_init_path(path, VG_LITE_S32, VG_LITE_MEDIUM, path_data_size, path_data,
|
||||
(vg_lite_float_t) dest_area->x1, (vg_lite_float_t) dest_area->y1,
|
||||
((vg_lite_float_t) dest_area->x2) + 1.0f, ((vg_lite_float_t) dest_area->y2) + 1.0f));
|
||||
|
||||
/*Draw rectangle*/
|
||||
VGLITE_CHECK_ERROR(vg_lite_draw(dest_buf, path, VG_LITE_FILL_EVEN_ODD, NULL, VG_LITE_BLEND_SRC_OVER, vgcol));
|
||||
|
||||
vglite_run();
|
||||
}
|
||||
}
|
||||
|
||||
static void _vglite_draw_rect(vglite_draw_task_t * vglite_task, const lv_area_t * coords,
|
||||
const lv_area_t * clip_area, const lv_draw_fill_dsc_t * dsc)
|
||||
{
|
||||
int32_t width = lv_area_get_width(coords);
|
||||
int32_t height = lv_area_get_height(coords);
|
||||
int32_t radius = dsc->radius;
|
||||
lv_opa_t opa = dsc->opa;
|
||||
vg_lite_buffer_t * dest_buf = vglite_get_dest_buf();
|
||||
|
||||
if(dsc->radius < 0)
|
||||
return;
|
||||
|
||||
/*** Init path ***/
|
||||
int32_t * path_data = lv_malloc_zeroed(RECT_PATH_DATA_MAX_SIZE * sizeof(int32_t));
|
||||
LV_ASSERT_MALLOC(path_data);
|
||||
vglite_task->path_data = path_data;
|
||||
|
||||
uint32_t path_data_size;
|
||||
vglite_create_rect_path_data(path_data, &path_data_size, radius, coords);
|
||||
vg_lite_quality_t path_quality = dsc->radius > 0 ? VG_LITE_HIGH : VG_LITE_MEDIUM;
|
||||
|
||||
vg_lite_path_t * path = lv_malloc_zeroed(sizeof(vg_lite_path_t));
|
||||
LV_ASSERT_MALLOC(path);
|
||||
vglite_task->path = path;
|
||||
VGLITE_CHECK_ERROR(vg_lite_init_path(path, VG_LITE_S32, path_quality, path_data_size, path_data,
|
||||
(vg_lite_float_t)clip_area->x1, (vg_lite_float_t)clip_area->y1,
|
||||
((vg_lite_float_t)clip_area->x2) + 1.0f, ((vg_lite_float_t)clip_area->y2) + 1.0f));
|
||||
|
||||
/*** Init Color ***/
|
||||
lv_color32_t col32 = lv_color_to_32(dsc->color, opa);
|
||||
vg_lite_color_t vgcol = vglite_get_color(col32, false);
|
||||
|
||||
vg_lite_linear_gradient_t * gradient;
|
||||
bool has_gradient = (dsc->grad.dir != (lv_grad_dir_t)LV_GRAD_DIR_NONE);
|
||||
|
||||
/*** Init Gradient ***/
|
||||
if(has_gradient) {
|
||||
gradient = lv_malloc_zeroed(sizeof(vg_lite_linear_gradient_t));
|
||||
LV_ASSERT_MALLOC(gradient);
|
||||
vglite_task->gradient = gradient;
|
||||
|
||||
vg_lite_matrix_t * grad_matrix;
|
||||
|
||||
vg_lite_uint32_t colors[LV_GRADIENT_MAX_STOPS];
|
||||
vg_lite_uint32_t stops[LV_GRADIENT_MAX_STOPS];
|
||||
lv_color32_t col32[LV_GRADIENT_MAX_STOPS];
|
||||
|
||||
/* Gradient setup */
|
||||
vg_lite_uint32_t cnt = LV_MIN(dsc->grad.stops_count, LV_GRADIENT_MAX_STOPS);
|
||||
lv_opa_t opa;
|
||||
|
||||
for(uint8_t i = 0; i < cnt; i++) {
|
||||
stops[i] = dsc->grad.stops[i].frac;
|
||||
|
||||
opa = LV_OPA_MIX2(dsc->grad.stops[i].opa, dsc->opa);
|
||||
|
||||
col32[i] = lv_color_to_32(dsc->grad.stops[i].color, opa);
|
||||
colors[i] = vglite_get_color(col32[i], true);
|
||||
}
|
||||
|
||||
VGLITE_CHECK_ERROR(vg_lite_init_grad(gradient));
|
||||
|
||||
VGLITE_CHECK_ERROR(vg_lite_set_grad(gradient, cnt, colors, stops));
|
||||
|
||||
VGLITE_CHECK_ERROR(vg_lite_update_grad(gradient));
|
||||
|
||||
grad_matrix = vg_lite_get_grad_matrix(gradient);
|
||||
vg_lite_identity(grad_matrix);
|
||||
vg_lite_translate((float)coords->x1, (float)coords->y1, grad_matrix);
|
||||
|
||||
if(dsc->grad.dir == (lv_grad_dir_t)LV_GRAD_DIR_VER) {
|
||||
vg_lite_scale(1.0f, (float)height / 256.0f, grad_matrix);
|
||||
vg_lite_rotate(90.0f, grad_matrix);
|
||||
}
|
||||
else { /*LV_GRAD_DIR_HOR*/
|
||||
vg_lite_scale((float)width / 256.0f, 1.0f, grad_matrix);
|
||||
}
|
||||
|
||||
VGLITE_CHECK_ERROR(vg_lite_draw_gradient(dest_buf, path, VG_LITE_FILL_EVEN_ODD, NULL, gradient,
|
||||
VG_LITE_BLEND_SRC_OVER));
|
||||
}
|
||||
else {
|
||||
VGLITE_CHECK_ERROR(vg_lite_draw(dest_buf, path, VG_LITE_FILL_EVEN_ODD, NULL, VG_LITE_BLEND_SRC_OVER, vgcol));
|
||||
}
|
||||
|
||||
vglite_run();
|
||||
}
|
||||
|
||||
#endif /*LV_USE_DRAW_VGLITE*/
|
||||
@@ -0,0 +1,449 @@
|
||||
/**
|
||||
* @file lv_draw_vglite_blend.c
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2020-2024 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_vglite.h"
|
||||
|
||||
#if LV_USE_DRAW_VGLITE
|
||||
#include "lv_vglite_buf.h"
|
||||
#include "lv_vglite_matrix.h"
|
||||
#include "lv_vglite_utils.h"
|
||||
#include "lv_vglite_path.h"
|
||||
|
||||
#include "../../../misc/lv_log.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#if LV_USE_VGLITE_BLIT_SPLIT
|
||||
/**
|
||||
* BLIT split threshold - BLITs with width or height higher than this value will
|
||||
* be done in multiple steps. Value must be multiple of stride alignment in px.
|
||||
* For most color formats the alignment is 16px (except the index formats).
|
||||
*/
|
||||
#define VGLITE_BLIT_SPLIT_THR 352
|
||||
|
||||
/* Enable for logging debug traces. */
|
||||
#define VGLITE_LOG_TRACE 0
|
||||
|
||||
#if VGLITE_LOG_TRACE
|
||||
#define VGLITE_TRACE(fmt, ...) \
|
||||
do { \
|
||||
LV_LOG(fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
#else
|
||||
#define VGLITE_TRACE(fmt, ...) \
|
||||
do { \
|
||||
} while (0)
|
||||
#endif
|
||||
#endif /*LV_USE_VGLITE_BLIT_SPLIT*/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
#if LV_USE_VGLITE_BLIT_SPLIT
|
||||
/**
|
||||
* Move buffer pointer as close as possible to area, but with respect to alignment requirements.
|
||||
*
|
||||
* @param[in] buf Buffer address pointer
|
||||
* @param[in] area Area with relative coordinates to the buffer
|
||||
* @param[in] stride Stride of buffer in bytes
|
||||
* @param[in] cf Color format of buffer
|
||||
*/
|
||||
static void _move_buf_close_to_area(void ** buf, lv_area_t * area, uint32_t stride, lv_color_format_t cf);
|
||||
|
||||
/**
|
||||
* BLock Image Transfer - copy rectangular image from src_buf to dest_buf with effects.
|
||||
* By default, image is copied directly, with optional opacity.
|
||||
*
|
||||
* @param dest_buf Destination buffer
|
||||
* @param[in] dest_area Destination area with relative coordinates to dest buffer
|
||||
* @param[in] dest_stride Stride of destination buffer in bytes
|
||||
* @param[in] dest_cf Color format of destination buffer
|
||||
* @param[in] src_buf Source buffer
|
||||
* @param[in] src_area Source area with relative coordinates to src buffer
|
||||
* @param[in] src_stride Stride of source buffer in bytes
|
||||
* @param[in] src_cf Color format of source buffer
|
||||
* @param[in] dsc Image descriptor
|
||||
*
|
||||
*/
|
||||
static void _vglite_blit_split(void * dest_buf, lv_area_t * dest_area, uint32_t dest_stride, lv_color_format_t dest_cf,
|
||||
const void * src_buf, lv_area_t * src_area, uint32_t src_stride, lv_color_format_t src_cf,
|
||||
const lv_draw_image_dsc_t * dsc);
|
||||
#endif /*LV_USE_VGLITE_BLIT_SPLIT*/
|
||||
|
||||
/**
|
||||
* VGlite blit - fill a path with an image pattern
|
||||
*
|
||||
*
|
||||
* @param[in] dest_area Destination area with relative coordinates to dest buffer
|
||||
* @param[in] clip_area Clip area with relative coordinates to dest buff
|
||||
* @param[in] coords Coordinates of the image (relative to dest buff)
|
||||
* @param[in] dsc Image descriptor
|
||||
*
|
||||
*/
|
||||
static void _vglite_draw_pattern(vglite_draw_task_t * vglite_task, const lv_area_t * clip_area,
|
||||
const lv_area_t * coords,
|
||||
const lv_draw_image_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* BLock Image Transfer - copy rectangular image from src_buf to dest_buf with or without effects.
|
||||
*
|
||||
* @param[in] src_area Source area with relative coordinates to src buffer
|
||||
* @param[in] dsc Image descriptor
|
||||
*
|
||||
*/
|
||||
static void _vglite_blit(const lv_area_t * src_area, const lv_draw_image_dsc_t * dsc);
|
||||
|
||||
static vg_lite_color_t _vglite_recolor(const lv_draw_image_dsc_t * dsc);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_vglite_img(vglite_draw_task_t * vglite_task)
|
||||
{
|
||||
const lv_draw_image_dsc_t * dsc = vglite_task->t->draw_dsc;
|
||||
const lv_area_t * coords = &vglite_task->t->area;
|
||||
|
||||
if(dsc->opa <= (lv_opa_t)LV_OPA_MIN)
|
||||
return;
|
||||
|
||||
lv_layer_t * layer = vglite_task->t->target_layer;
|
||||
const lv_image_dsc_t * img_dsc = dsc->src;
|
||||
|
||||
lv_area_t relative_coords;
|
||||
lv_area_copy(&relative_coords, coords);
|
||||
lv_area_move(&relative_coords, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
lv_area_t clip_area;
|
||||
lv_area_copy(&clip_area, &vglite_task->t->clip_area);
|
||||
lv_area_move(&clip_area, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
lv_area_t blend_area;
|
||||
bool has_transform = (dsc->rotation != 0 || dsc->scale_x != LV_SCALE_NONE || dsc->scale_y != LV_SCALE_NONE);
|
||||
if(has_transform)
|
||||
lv_area_copy(&blend_area, &relative_coords);
|
||||
else if(!lv_area_intersect(&blend_area, &relative_coords, &clip_area))
|
||||
return; /*Fully clipped, nothing to do*/
|
||||
|
||||
const void * src_buf = img_dsc->data;
|
||||
|
||||
lv_area_t src_area;
|
||||
src_area.x1 = blend_area.x1 - (coords->x1 - layer->buf_area.x1);
|
||||
src_area.y1 = blend_area.y1 - (coords->y1 - layer->buf_area.y1);
|
||||
src_area.x2 = img_dsc->header.w - 1;
|
||||
src_area.y2 = img_dsc->header.h - 1;
|
||||
|
||||
lv_color_format_t src_cf = img_dsc->header.cf;
|
||||
uint32_t src_stride = img_dsc->header.stride;
|
||||
|
||||
/* Set src_buf structure. */
|
||||
vglite_set_src_buf(src_buf, img_dsc->header.w, img_dsc->header.h, src_stride, src_cf);
|
||||
|
||||
#if LV_USE_VGLITE_BLIT_SPLIT
|
||||
void * dest_buf = layer->draw_buf->data;
|
||||
uint32_t dest_stride = layer->draw_buf->header.stride;
|
||||
lv_color_format_t dest_cf = layer->draw_buf->header.cf;
|
||||
|
||||
if(!has_transform)
|
||||
_vglite_blit_split(dest_buf, &blend_area, dest_stride, dest_cf,
|
||||
src_buf, &src_area, src_stride, src_cf, dsc);
|
||||
#else
|
||||
vglite_set_transformation_matrix(&blend_area, dsc);
|
||||
bool is_tiled = dsc->tile;
|
||||
if(is_tiled)
|
||||
_vglite_draw_pattern(vglite_task, &clip_area, &relative_coords, dsc);
|
||||
else
|
||||
_vglite_blit(&src_area, dsc);
|
||||
#endif /*LV_USE_VGLITE_BLIT_SPLIT*/
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
static void _vglite_blit(const lv_area_t * src_area, const lv_draw_image_dsc_t * dsc)
|
||||
{
|
||||
vg_lite_buffer_t * dest_buf = vglite_get_dest_buf();
|
||||
vg_lite_buffer_t * src_buf = vglite_get_src_buf();
|
||||
|
||||
vg_lite_rectangle_t rect = {
|
||||
.x = (vg_lite_int32_t)src_area->x1,
|
||||
.y = (vg_lite_int32_t)src_area->y1,
|
||||
.width = (vg_lite_int32_t)lv_area_get_width(src_area),
|
||||
.height = (vg_lite_int32_t)lv_area_get_height(src_area)
|
||||
};
|
||||
|
||||
src_buf->image_mode = VG_LITE_MULTIPLY_IMAGE_MODE;
|
||||
src_buf->transparency_mode = VG_LITE_IMAGE_TRANSPARENT;
|
||||
|
||||
vg_lite_color_t vgcol = _vglite_recolor(dsc);
|
||||
|
||||
vg_lite_matrix_t * matrix = vglite_get_matrix();
|
||||
vg_lite_blend_t vgblend = vglite_get_blend_mode(dsc->blend_mode);
|
||||
|
||||
VGLITE_CHECK_ERROR(vg_lite_blit_rect(dest_buf, src_buf, &rect, matrix, vgblend, vgcol, VG_LITE_FILTER_POINT));
|
||||
|
||||
vglite_run();
|
||||
}
|
||||
|
||||
#if LV_USE_VGLITE_BLIT_SPLIT
|
||||
static void _move_buf_close_to_area(void ** buf, lv_area_t * area, uint32_t stride, lv_color_format_t cf)
|
||||
{
|
||||
uint8_t ** buf_u8 = (uint8_t **)buf;
|
||||
uint8_t align_bytes = vglite_get_stride_alignment(cf);
|
||||
uint8_t bits_per_pixel = lv_color_format_get_bpp(cf);
|
||||
|
||||
uint16_t align_pixels = align_bytes * 8 / bits_per_pixel;
|
||||
|
||||
if(area->x1 >= (int32_t)(area->x1 % align_pixels)) {
|
||||
uint16_t shift_x = area->x1 - (area->x1 % align_pixels);
|
||||
|
||||
area->x1 -= shift_x;
|
||||
area->x2 -= shift_x;
|
||||
*buf_u8 += (shift_x * bits_per_pixel) / 8;
|
||||
}
|
||||
|
||||
if(area->y1) {
|
||||
uint16_t shift_y = area->y1;
|
||||
|
||||
area->y1 -= shift_y;
|
||||
area->y2 -= shift_y;
|
||||
*buf_u8 += shift_y * stride;
|
||||
}
|
||||
}
|
||||
|
||||
static void _vglite_blit_split(void * dest_buf, lv_area_t * dest_area, uint32_t dest_stride, lv_color_format_t dest_cf,
|
||||
const void * src_buf, lv_area_t * src_area, uint32_t src_stride, lv_color_format_t src_cf,
|
||||
const lv_draw_image_dsc_t * dsc)
|
||||
{
|
||||
VGLITE_TRACE("Blit "
|
||||
"Area: ([%d,%d], [%d,%d]) -> ([%d,%d], [%d,%d]) | "
|
||||
"Size: ([%dx%d] -> [%dx%d]) | "
|
||||
"Addr: (0x%x -> 0x%x)",
|
||||
src_area->x1, src_area->y1, src_area->x2, src_area->y2,
|
||||
dest_area->x1, dest_area->y1, dest_area->x2, dest_area->y2,
|
||||
lv_area_get_width(src_area), lv_area_get_height(src_area),
|
||||
lv_area_get_width(dest_area), lv_area_get_height(dest_area),
|
||||
(uintptr_t)src_buf, (uintptr_t)dest_buf);
|
||||
|
||||
/* Move starting pointers as close as possible to [x1, y1], so coordinates are as small as possible */
|
||||
_move_buf_close_to_area((void **)&src_buf, src_area, src_stride, src_cf);
|
||||
_move_buf_close_to_area(&dest_buf, dest_area, dest_stride, dest_cf);
|
||||
|
||||
/* Set clip area */
|
||||
vglite_set_scissor(dest_area);
|
||||
|
||||
/* If we're in limit, do a single BLIT */
|
||||
if((src_area->x2 < VGLITE_BLIT_SPLIT_THR) &&
|
||||
(src_area->y2 < VGLITE_BLIT_SPLIT_THR)) {
|
||||
|
||||
/* Set new dest_buf and src_buf memory addresses */
|
||||
vglite_set_dest_buf_ptr(dest_buf);
|
||||
vglite_set_src_buf_ptr(src_buf);
|
||||
|
||||
vglite_set_transformation_matrix(dest_area, dsc);
|
||||
_vglite_blit(src_area, dsc);
|
||||
|
||||
VGLITE_TRACE("Single "
|
||||
"Area: ([%d,%d], [%d,%d]) -> ([%d,%d], [%d,%d]) | "
|
||||
"Size: ([%dx%d] -> [%dx%d]) | "
|
||||
"Addr: (0x%x -> 0x%x)",
|
||||
src_area->x1, src_area->y1, src_area->x2, src_area->y2,
|
||||
dest_area->x1, dest_area->y1, dest_area->x2, dest_area->y2,
|
||||
lv_area_get_width(src_area), lv_area_get_height(src_area),
|
||||
lv_area_get_width(dest_area), lv_area_get_height(dest_area),
|
||||
(uintptr_t)src_buf, (uintptr_t)dest_buf);
|
||||
|
||||
return;
|
||||
};
|
||||
|
||||
/* Split the BLIT into multiple tiles */
|
||||
VGLITE_TRACE("Split "
|
||||
"Area: ([%d,%d], [%d,%d]) -> ([%d,%d], [%d,%d]) | "
|
||||
"Size: ([%dx%d] -> [%dx%d]) | "
|
||||
"Addr: (0x%x -> 0x%x)",
|
||||
src_area->x1, src_area->y1, src_area->x2, src_area->y2,
|
||||
dest_area->x1, dest_area->y1, dest_area->x2, dest_area->y2,
|
||||
lv_area_get_width(src_area), lv_area_get_height(src_area),
|
||||
lv_area_get_width(dest_area), lv_area_get_height(dest_area),
|
||||
(uintptr_t)src_buf, (uintptr_t)dest_buf);
|
||||
|
||||
int32_t width = LV_MIN(lv_area_get_width(src_area), lv_area_get_width(dest_area));
|
||||
int32_t height = LV_MIN(lv_area_get_height(src_area), lv_area_get_height(dest_area));
|
||||
|
||||
/* Number of tiles needed */
|
||||
uint8_t total_tiles_x = (src_area->x1 + width + VGLITE_BLIT_SPLIT_THR - 1) /
|
||||
VGLITE_BLIT_SPLIT_THR;
|
||||
uint8_t total_tiles_y = (src_area->y1 + height + VGLITE_BLIT_SPLIT_THR - 1) /
|
||||
VGLITE_BLIT_SPLIT_THR;
|
||||
|
||||
uint16_t shift_src_x = src_area->x1;
|
||||
uint16_t shift_dest_x = dest_area->x1;
|
||||
|
||||
VGLITE_TRACE("X shift: src: %d, dst: %d", shift_src_x, shift_dest_x);
|
||||
|
||||
uint8_t * tile_dest_buf;
|
||||
lv_area_t tile_dest_area;
|
||||
const uint8_t * tile_src_buf;
|
||||
lv_area_t tile_src_area;
|
||||
|
||||
for(uint8_t y = 0; y < total_tiles_y; y++) {
|
||||
/* y1 always start from 0 */
|
||||
tile_src_area.y1 = 0;
|
||||
|
||||
/* Calculate y2 coordinates */
|
||||
if(y < total_tiles_y - 1)
|
||||
tile_src_area.y2 = VGLITE_BLIT_SPLIT_THR - 1;
|
||||
else
|
||||
tile_src_area.y2 = height - y * VGLITE_BLIT_SPLIT_THR - 1;
|
||||
|
||||
/* No vertical shift, dest y is always in sync with src y */
|
||||
tile_dest_area.y1 = tile_src_area.y1;
|
||||
tile_dest_area.y2 = tile_src_area.y2;
|
||||
|
||||
/* Advance start pointer for every tile, except the first column (y = 0) */
|
||||
tile_src_buf = (uint8_t *)src_buf + y * VGLITE_BLIT_SPLIT_THR * src_stride;
|
||||
tile_dest_buf = (uint8_t *)dest_buf + y * VGLITE_BLIT_SPLIT_THR * dest_stride;
|
||||
|
||||
for(uint8_t x = 0; x < total_tiles_x; x++) {
|
||||
/* x1 always start from the same shift */
|
||||
tile_src_area.x1 = shift_src_x;
|
||||
tile_dest_area.x1 = shift_dest_x;
|
||||
if(x > 0) {
|
||||
/* Advance start pointer for every tile, except the first raw (x = 0) */
|
||||
tile_src_buf += VGLITE_BLIT_SPLIT_THR * lv_color_format_get_bpp(src_cf) / 8;
|
||||
tile_dest_buf += VGLITE_BLIT_SPLIT_THR * lv_color_format_get_bpp(dest_cf) / 8;
|
||||
}
|
||||
|
||||
/* Calculate x2 coordinates */
|
||||
if(x < total_tiles_x - 1)
|
||||
tile_src_area.x2 = VGLITE_BLIT_SPLIT_THR - 1;
|
||||
else
|
||||
tile_src_area.x2 = width - x * VGLITE_BLIT_SPLIT_THR - 1;
|
||||
|
||||
tile_dest_area.x2 = tile_src_area.x2;
|
||||
|
||||
/* Shift x2 coordinates */
|
||||
tile_src_area.x2 += shift_src_x;
|
||||
tile_dest_area.x2 += shift_dest_x;
|
||||
|
||||
/* Set new dest_buf and src_buf memory addresses */
|
||||
vglite_set_dest_buf_ptr(tile_dest_buf);
|
||||
vglite_set_src_buf_ptr(tile_src_buf);
|
||||
|
||||
vglite_set_transformation_matrix(&tile_dest_area, dsc);
|
||||
_vglite_blit(&tile_src_area, dsc);
|
||||
|
||||
VGLITE_TRACE("Tile [%d, %d] "
|
||||
"Area: ([%d,%d], [%d,%d]) -> ([%d,%d], [%d,%d]) | "
|
||||
"Size: ([%dx%d] -> [%dx%d]) | "
|
||||
"Addr: (0x%x -> 0x%x)",
|
||||
x, y,
|
||||
tile_src_area.x1, tile_src_area.y1, tile_src_area.x2, tile_src_area.y2,
|
||||
tile_dest_area.x1, tile_dest_area.y1, tile_dest_area.x2, tile_dest_area.y2,
|
||||
lv_area_get_width(&tile_src_area), lv_area_get_height(&tile_src_area),
|
||||
lv_area_get_width(&tile_dest_area), lv_area_get_height(&tile_dest_area),
|
||||
(uintptr_t)tile_src_buf, (uintptr_t)tile_dest_buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /*LV_USE_VGLITE_BLIT_SPLIT*/
|
||||
|
||||
static void _vglite_draw_pattern(vglite_draw_task_t * vglite_task, const lv_area_t * clip_area,
|
||||
const lv_area_t * coords,
|
||||
const lv_draw_image_dsc_t * dsc)
|
||||
{
|
||||
/* Target buffer */
|
||||
vg_lite_buffer_t * dest_buf = vglite_get_dest_buf();
|
||||
|
||||
/* Path to draw */
|
||||
int32_t * path_data = lv_malloc_zeroed(RECT_PATH_DATA_MAX_SIZE * sizeof(int32_t));
|
||||
LV_ASSERT_MALLOC(path_data);
|
||||
vglite_task->path_data = path_data;
|
||||
|
||||
uint32_t path_data_size;
|
||||
vglite_create_rect_path_data(path_data, &path_data_size, dsc->clip_radius, coords);
|
||||
vg_lite_quality_t path_quality = VG_LITE_MEDIUM;
|
||||
|
||||
vg_lite_path_t * path = lv_malloc_zeroed(sizeof(vg_lite_path_t));
|
||||
LV_ASSERT_MALLOC(path);
|
||||
vglite_task->path = path;
|
||||
VGLITE_CHECK_ERROR(vg_lite_init_path(path, VG_LITE_S32, path_quality, path_data_size, path_data,
|
||||
(vg_lite_float_t)clip_area->x1, (vg_lite_float_t)clip_area->y1,
|
||||
((vg_lite_float_t)clip_area->x2) + 1.0f, ((vg_lite_float_t)clip_area->y2) + 1.0f));
|
||||
|
||||
/* Pattern Image */
|
||||
vg_lite_buffer_t * src_buf = vglite_get_src_buf();
|
||||
src_buf->image_mode = VG_LITE_MULTIPLY_IMAGE_MODE;
|
||||
src_buf->transparency_mode = VG_LITE_IMAGE_TRANSPARENT;
|
||||
|
||||
/* Pattern matrix */
|
||||
vg_lite_matrix_t matrix;
|
||||
vg_lite_identity(&matrix);
|
||||
vg_lite_translate((vg_lite_float_t)dsc->image_area.x1, (vg_lite_float_t)dsc->image_area.y1, &matrix);
|
||||
|
||||
/* Blend mode */
|
||||
vg_lite_blend_t vgblend = vglite_get_blend_mode(dsc->blend_mode);
|
||||
|
||||
vg_lite_color_t vgcol = _vglite_recolor(dsc);
|
||||
|
||||
/* Filter */
|
||||
bool has_transform = (dsc->rotation != 0 || dsc->scale_x != LV_SCALE_NONE || dsc->scale_y != LV_SCALE_NONE);
|
||||
vg_lite_filter_t filter = has_transform ? VG_LITE_FILTER_BI_LINEAR : VG_LITE_FILTER_POINT;
|
||||
|
||||
/* Draw Pattern */
|
||||
VGLITE_CHECK_ERROR(vg_lite_draw_pattern(dest_buf, path, VG_LITE_FILL_NON_ZERO, NULL,
|
||||
src_buf, &matrix, vgblend, VG_LITE_PATTERN_REPEAT,
|
||||
0, vgcol, filter));
|
||||
vglite_run();
|
||||
}
|
||||
|
||||
static vg_lite_color_t _vglite_recolor(const lv_draw_image_dsc_t * dsc)
|
||||
{
|
||||
lv_color_t color;
|
||||
lv_opa_t opa;
|
||||
|
||||
bool has_recolor = (dsc->recolor_opa > LV_OPA_MIN);
|
||||
if(has_recolor) {
|
||||
color = dsc->recolor;
|
||||
opa = LV_OPA_MIX2(dsc->recolor_opa, dsc->opa);
|
||||
}
|
||||
else {
|
||||
color.red = 0xFF;
|
||||
color.green = 0xFF;
|
||||
color.blue = 0xFF;
|
||||
opa = dsc->opa;
|
||||
}
|
||||
|
||||
lv_color32_t col32 = lv_color_to_32(color, opa);
|
||||
|
||||
return vglite_get_color(col32, false);
|
||||
}
|
||||
|
||||
#endif /*LV_USE_DRAW_VGLITE*/
|
||||
@@ -0,0 +1,270 @@
|
||||
/**
|
||||
* @file lv_draw_vglite_label.c
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2023-2024 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_vglite.h"
|
||||
|
||||
#if LV_USE_DRAW_VGLITE
|
||||
#include "lv_vglite_buf.h"
|
||||
#include "lv_vglite_matrix.h"
|
||||
#include "lv_vglite_utils.h"
|
||||
|
||||
#include "../../lv_draw_label_private.h"
|
||||
#include "../../../stdlib/lv_string.h"
|
||||
#include "../../../font/lv_font_fmt_txt_private.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static void _draw_vglite_letter(lv_draw_task_t * t, lv_draw_glyph_dsc_t * glyph_draw_dsc,
|
||||
lv_draw_fill_dsc_t * fill_draw_dsc, const lv_area_t * fill_area);
|
||||
|
||||
/**
|
||||
* Draw letter (character bitmap blend) with optional color and opacity
|
||||
*
|
||||
* @param[in] mask_area Mask area with relative coordinates of source buffer
|
||||
* @param[in] color Color
|
||||
* @param[in] opa Opacity
|
||||
*
|
||||
*/
|
||||
static void _vglite_draw_letter(const lv_area_t * mask_area, lv_color_t color, lv_opa_t opa);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
static bool _use_static_bitmap = false;
|
||||
|
||||
/**********************
|
||||
* GLOBAL VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_vglite_label(vglite_draw_task_t * vglite_task)
|
||||
{
|
||||
const lv_draw_label_dsc_t * dsc = vglite_task->t->draw_dsc;
|
||||
const lv_area_t * coords = &vglite_task->t->area;
|
||||
|
||||
if(dsc->opa <= LV_OPA_MIN) return;
|
||||
|
||||
lv_font_fmt_txt_dsc_t * fdsc = (lv_font_fmt_txt_dsc_t *)dsc->font->dsc;
|
||||
bool is_src_buf_aligned = vglite_src_buf_aligned(fdsc->glyph_bitmap, fdsc->stride, LV_COLOR_FORMAT_A8);
|
||||
bool has_static_bitmap = lv_font_has_static_bitmap(dsc->font);
|
||||
|
||||
_use_static_bitmap = is_src_buf_aligned & has_static_bitmap;
|
||||
|
||||
lv_draw_label_iterate_characters(vglite_task->t, dsc, coords, _draw_vglite_letter);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void _draw_vglite_letter(lv_draw_task_t * t, lv_draw_glyph_dsc_t * glyph_draw_dsc,
|
||||
lv_draw_fill_dsc_t * fill_draw_dsc, const lv_area_t * fill_area)
|
||||
{
|
||||
if(glyph_draw_dsc) {
|
||||
|
||||
switch(glyph_draw_dsc->format) {
|
||||
|
||||
case LV_FONT_GLYPH_FORMAT_NONE: {
|
||||
#if LV_USE_FONT_PLACEHOLDER
|
||||
/* Draw a placeholder rectangle*/
|
||||
vglite_draw_task_t * vglite_task = lv_malloc_zeroed(sizeof(vglite_draw_task_t));
|
||||
LV_ASSERT_MALLOC(vglite_task);
|
||||
|
||||
lv_draw_border_dsc_t border_draw_dsc;
|
||||
|
||||
lv_draw_border_dsc_init(&border_draw_dsc);
|
||||
border_draw_dsc.opa = glyph_draw_dsc->opa;
|
||||
border_draw_dsc.color = glyph_draw_dsc->color;
|
||||
border_draw_dsc.width = 1;
|
||||
|
||||
vglite_task->t = t;
|
||||
vglite_task->t->draw_dsc = &border_draw_dsc;
|
||||
vglite_task->t->area = *glyph_draw_dsc->bg_coords;
|
||||
|
||||
lv_draw_vglite_border(vglite_task);
|
||||
|
||||
/** Cleanup for vglite_task */
|
||||
VGLITE_CHECK_ERROR(vg_lite_finish());
|
||||
if(vglite_task->path) {
|
||||
VGLITE_CHECK_ERROR(vg_lite_clear_path(vglite_task->path));
|
||||
lv_free(vglite_task->path_data);
|
||||
lv_free(vglite_task->path);
|
||||
}
|
||||
lv_free(vglite_task);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case LV_FONT_GLYPH_FORMAT_A1 ... LV_FONT_GLYPH_FORMAT_A8: {
|
||||
/*Do not draw transparent things*/
|
||||
if(glyph_draw_dsc->opa <= LV_OPA_MIN)
|
||||
return;
|
||||
|
||||
lv_layer_t * layer = t->target_layer;
|
||||
|
||||
lv_area_t blend_area;
|
||||
if(!lv_area_intersect(&blend_area, glyph_draw_dsc->letter_coords, &t->clip_area))
|
||||
return;
|
||||
lv_area_move(&blend_area, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
const void * mask_buf = NULL;
|
||||
const lv_draw_buf_t * draw_buf = NULL;
|
||||
uint32_t mask_stride;
|
||||
if(!_use_static_bitmap) {
|
||||
draw_buf = lv_font_get_glyph_bitmap(glyph_draw_dsc->g, glyph_draw_dsc->_draw_buf);
|
||||
if(draw_buf != NULL) {
|
||||
mask_buf = draw_buf->data;
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
mask_stride = draw_buf->header.stride;
|
||||
}
|
||||
else {
|
||||
glyph_draw_dsc->g->req_raw_bitmap = 1;
|
||||
mask_buf = lv_font_get_glyph_static_bitmap(glyph_draw_dsc->g);
|
||||
mask_stride = glyph_draw_dsc->g->stride;
|
||||
}
|
||||
|
||||
uint32_t mask_width = lv_area_get_width(glyph_draw_dsc->letter_coords);
|
||||
uint32_t mask_height = lv_area_get_height(glyph_draw_dsc->letter_coords);
|
||||
|
||||
lv_area_t mask_area;
|
||||
mask_area.x1 = blend_area.x1 - (glyph_draw_dsc->letter_coords->x1 - layer->buf_area.x1);
|
||||
mask_area.y1 = blend_area.y1 - (glyph_draw_dsc->letter_coords->y1 - layer->buf_area.y1);
|
||||
mask_area.x2 = mask_width - 1;
|
||||
mask_area.y2 = mask_height - 1;
|
||||
|
||||
/* Set src_buf structure. */
|
||||
vglite_set_src_buf(mask_buf, mask_width, mask_height, mask_stride, LV_COLOR_FORMAT_A8);
|
||||
|
||||
/* Set matrix. */
|
||||
vglite_set_translation_matrix(&blend_area);
|
||||
|
||||
if(!_use_static_bitmap)
|
||||
lv_draw_buf_invalidate_cache(draw_buf, &mask_area);
|
||||
|
||||
_vglite_draw_letter(&mask_area, glyph_draw_dsc->color, glyph_draw_dsc->opa);
|
||||
}
|
||||
break;
|
||||
case LV_FONT_GLYPH_FORMAT_IMAGE: {
|
||||
#if LV_USE_IMGFONT
|
||||
glyph_draw_dsc->glyph_data = lv_font_get_glyph_bitmap(glyph_draw_dsc->g, glyph_draw_dsc->_draw_buf);
|
||||
vglite_draw_task_t * vglite_task = lv_malloc_zeroed(sizeof(vglite_draw_task_t));
|
||||
LV_ASSERT_MALLOC(vglite_task);
|
||||
|
||||
lv_draw_image_dsc_t img_dsc;
|
||||
lv_draw_image_dsc_init(&img_dsc);
|
||||
img_dsc.opa = glyph_draw_dsc->opa;
|
||||
img_dsc.src = glyph_draw_dsc->glyph_data;
|
||||
|
||||
void * old_dsc = t->draw_dsc;
|
||||
lv_area_t old_area = t->area;
|
||||
|
||||
t->draw_dsc = &img_dsc;
|
||||
t->area = *glyph_draw_dsc->letter_coords;
|
||||
vglite_task->t = t;
|
||||
|
||||
lv_draw_vglite_img(vglite_task);
|
||||
|
||||
/** Cleanup for vglite_task */
|
||||
vg_lite_finish();
|
||||
if(vglite_task->path) {
|
||||
VGLITE_CHECK_ERROR(vg_lite_clear_path(vglite_task->path));
|
||||
lv_free(vglite_task->path_data);
|
||||
lv_free(vglite_task->path);
|
||||
}
|
||||
lv_free(vglite_task);
|
||||
|
||||
t->draw_dsc = old_dsc;
|
||||
t->area = old_area;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(fill_draw_dsc && fill_area) {
|
||||
vglite_draw_task_t * vglite_task = lv_malloc_zeroed(sizeof(vglite_draw_task_t));
|
||||
LV_ASSERT_MALLOC(vglite_task);
|
||||
|
||||
t->draw_dsc = fill_draw_dsc;
|
||||
t->area = *fill_area;
|
||||
vglite_task->t = t;
|
||||
|
||||
lv_draw_vglite_fill(vglite_task);
|
||||
|
||||
/** Cleanup for vglite_task */
|
||||
vg_lite_finish();
|
||||
if(vglite_task->path) {
|
||||
VGLITE_CHECK_ERROR(vg_lite_clear_path(vglite_task->path));
|
||||
lv_free(vglite_task->path_data);
|
||||
lv_free(vglite_task->path);
|
||||
}
|
||||
if(vglite_task->gradient) {
|
||||
VGLITE_CHECK_ERROR(vg_lite_clear_grad(vglite_task->gradient));
|
||||
lv_free(vglite_task->gradient);
|
||||
}
|
||||
lv_free(vglite_task);
|
||||
}
|
||||
}
|
||||
|
||||
static void _vglite_draw_letter(const lv_area_t * mask_area, lv_color_t color, lv_opa_t opa)
|
||||
{
|
||||
vg_lite_buffer_t * dest_buf = vglite_get_dest_buf();
|
||||
vg_lite_buffer_t * mask_buf = vglite_get_src_buf();
|
||||
|
||||
mask_buf->image_mode = VG_LITE_MULTIPLY_IMAGE_MODE;
|
||||
mask_buf->transparency_mode = VG_LITE_IMAGE_TRANSPARENT;
|
||||
|
||||
vg_lite_rectangle_t rect = {
|
||||
.x = (vg_lite_int32_t)mask_area->x1,
|
||||
.y = (vg_lite_int32_t)mask_area->y1,
|
||||
.width = (vg_lite_int32_t)lv_area_get_width(mask_area),
|
||||
.height = (vg_lite_int32_t)lv_area_get_height(mask_area)
|
||||
};
|
||||
|
||||
lv_color32_t col32 = lv_color_to_32(color, opa);
|
||||
vg_lite_color_t vgcol = vglite_get_color(col32, false);
|
||||
|
||||
vg_lite_matrix_t * matrix = vglite_get_matrix();
|
||||
|
||||
/*Blit with font color as paint color*/
|
||||
VGLITE_CHECK_ERROR(vg_lite_blit_rect(dest_buf, mask_buf, &rect, matrix, VG_LITE_BLEND_SRC_OVER, vgcol,
|
||||
VG_LITE_FILTER_POINT));
|
||||
|
||||
vglite_run();
|
||||
}
|
||||
|
||||
#endif /*LV_USE_DRAW_VGLITE*/
|
||||
@@ -0,0 +1,156 @@
|
||||
/**
|
||||
* @file lv_draw_vglite_layer.c
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2023-2024 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_vglite.h"
|
||||
|
||||
#if LV_USE_DRAW_VGLITE
|
||||
|
||||
#include "../../../stdlib/lv_string.h"
|
||||
#include "../../../core/lv_global.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
#define _draw_info LV_GLOBAL_DEFAULT()->draw_info
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_vglite_layer(vglite_draw_task_t * vglite_task)
|
||||
{
|
||||
lv_draw_image_dsc_t * draw_dsc = vglite_task->t->draw_dsc;
|
||||
|
||||
lv_layer_t * layer_to_draw = (lv_layer_t *)draw_dsc->src;
|
||||
const lv_draw_buf_t * draw_buf = layer_to_draw->draw_buf;
|
||||
|
||||
/* It can happen that nothing was draw on a layer and therefore its buffer is not allocated.
|
||||
* In this case just return.
|
||||
*/
|
||||
if(draw_buf == NULL)
|
||||
return;
|
||||
|
||||
if(_draw_info.unit_cnt > 1) {
|
||||
const lv_area_t area_to_draw = {
|
||||
.x1 = 0,
|
||||
.y1 = 0,
|
||||
.x2 = draw_buf->header.w - 1,
|
||||
.y2 = draw_buf->header.h - 1
|
||||
};
|
||||
lv_draw_buf_invalidate_cache(draw_buf, &area_to_draw);
|
||||
}
|
||||
|
||||
lv_draw_image_dsc_t new_draw_dsc = *draw_dsc;
|
||||
new_draw_dsc.src = draw_buf;
|
||||
vglite_task->t->draw_dsc = &new_draw_dsc;
|
||||
lv_draw_vglite_img(vglite_task);
|
||||
vglite_task->t->draw_dsc = draw_dsc;
|
||||
|
||||
#if LV_USE_LAYER_DEBUG || LV_USE_PARALLEL_DRAW_DEBUG
|
||||
const lv_area_t * coords = &vglite_task->t->area;
|
||||
lv_area_t area_rot;
|
||||
lv_area_copy(&area_rot, coords);
|
||||
bool has_transform = (draw_dsc->rotation != 0 || draw_dsc->scale_x != LV_SCALE_NONE ||
|
||||
draw_dsc->scale_y != LV_SCALE_NONE);
|
||||
|
||||
if(has_transform) {
|
||||
int32_t w = lv_area_get_width(coords);
|
||||
int32_t h = lv_area_get_height(coords);
|
||||
|
||||
lv_image_buf_get_transformed_area(&area_rot, w, h, draw_dsc->rotation, draw_dsc->scale_x, draw_dsc->scale_y,
|
||||
&draw_dsc->pivot);
|
||||
|
||||
area_rot.x1 += coords->x1;
|
||||
area_rot.y1 += coords->y1;
|
||||
area_rot.x2 += coords->x1;
|
||||
area_rot.y2 += coords->y1;
|
||||
}
|
||||
lv_area_t draw_area;
|
||||
if(!lv_area_intersect(&draw_area, &area_rot, &vglite_task->t->clip_area)) return;
|
||||
#endif
|
||||
|
||||
#if LV_USE_LAYER_DEBUG
|
||||
lv_draw_fill_dsc_t fill_dsc;
|
||||
lv_draw_fill_dsc_init(&fill_dsc);
|
||||
fill_dsc.color = lv_color_hex(layer_to_draw->color_format == LV_COLOR_FORMAT_ARGB8888 ? 0xff0000 : 0x00ff00);
|
||||
fill_dsc.opa = LV_OPA_20;
|
||||
lv_draw_sw_fill(vglite_task->t, &fill_dsc, &area_rot);
|
||||
|
||||
lv_draw_border_dsc_t border_dsc;
|
||||
lv_draw_border_dsc_init(&border_dsc);
|
||||
border_dsc.color = fill_dsc.color;
|
||||
border_dsc.opa = LV_OPA_60;
|
||||
border_dsc.width = 2;
|
||||
lv_draw_sw_border(vglite_task->t, &border_dsc, &area_rot);
|
||||
|
||||
#endif
|
||||
|
||||
#if LV_USE_PARALLEL_DRAW_DEBUG
|
||||
int32_t idx = vglite_task->t->draw_unit->idx;
|
||||
|
||||
lv_draw_fill_dsc_t fill_dsc;
|
||||
lv_draw_rect_dsc_init(&fill_dsc);
|
||||
fill_dsc.color = lv_palette_main(idx % LV_PALETTE_LAST);
|
||||
fill_dsc.opa = LV_OPA_10;
|
||||
lv_draw_sw_fill(vglite_task->t, &fill_dsc, &area_rot);
|
||||
|
||||
lv_draw_border_dsc_t border_dsc;
|
||||
lv_draw_border_dsc_init(&border_dsc);
|
||||
border_dsc.color = lv_palette_main(idx % LV_PALETTE_LAST);
|
||||
border_dsc.opa = LV_OPA_100;
|
||||
border_dsc.width = 2;
|
||||
lv_draw_sw_border(vglite_task->t, &border_dsc, &area_rot);
|
||||
|
||||
lv_point_t txt_size;
|
||||
lv_text_get_size(&txt_size, "W", LV_FONT_DEFAULT, 0, 0, 100, LV_TEXT_FLAG_NONE);
|
||||
|
||||
lv_area_t txt_area;
|
||||
txt_area.x1 = draw_area.x1;
|
||||
txt_area.x2 = draw_area.x1 + txt_size.x - 1;
|
||||
txt_area.y2 = draw_area.y2;
|
||||
txt_area.y1 = draw_area.y2 - txt_size.y + 1;
|
||||
|
||||
lv_draw_fill_dsc_init(&fill_dsc);
|
||||
fill_dsc.color = lv_color_black();
|
||||
lv_draw_sw_fill(vglite_task->t, &fill_dsc, &txt_area);
|
||||
|
||||
char buf[8];
|
||||
lv_snprintf(buf, sizeof(buf), "%d", idx);
|
||||
lv_draw_label_dsc_t label_dsc;
|
||||
lv_draw_label_dsc_init(&label_dsc);
|
||||
label_dsc.color = lv_color_white();
|
||||
label_dsc.text = buf;
|
||||
lv_draw_sw_label(vglite_task->t, &label_dsc, &txt_area);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /*LV_USE_DRAW_VGLITE*/
|
||||
@@ -0,0 +1,169 @@
|
||||
/**
|
||||
* @file lv_draw_vglite_line.c
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2022-2024 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_vglite.h"
|
||||
|
||||
#if LV_USE_DRAW_VGLITE
|
||||
#include "lv_vglite_buf.h"
|
||||
#include "lv_vglite_utils.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Set line path data
|
||||
*
|
||||
* @param[in/out] line_path Coordinates of the line
|
||||
* @param[in/out] path_data_size Size of path_data (bytes)
|
||||
* @param[in] p1 First point of the line
|
||||
* @patam[in] p2 Second point of the line
|
||||
*
|
||||
*/
|
||||
static void _vglite_set_line(int32_t * line_path, uint32_t * path_data_size,
|
||||
const lv_point_t * point1, const lv_point_t * point2);
|
||||
|
||||
/**
|
||||
* Draw line shape with effects
|
||||
*
|
||||
* @param[in] point1 Starting point with relative coordinates
|
||||
* @param[in] point2 Ending point with relative coordinates
|
||||
* @param[in] clip_area Clip area with relative coordinates to dest buff
|
||||
* @param[in] dsc Line description structure (width, rounded ending, opacity, ...)
|
||||
*
|
||||
*/
|
||||
static void _vglite_draw_line(vglite_draw_task_t * vglite_task, const lv_point_t * point1, const lv_point_t * point2,
|
||||
const lv_area_t * clip_area, const lv_draw_line_dsc_t * dsc);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_vglite_line(vglite_draw_task_t * vglite_task)
|
||||
{
|
||||
const lv_draw_line_dsc_t * dsc = vglite_task->t->draw_dsc;
|
||||
|
||||
if(dsc->width == 0)
|
||||
return;
|
||||
if(dsc->opa <= (lv_opa_t)LV_OPA_MIN)
|
||||
return;
|
||||
if(dsc->p1.x == dsc->p2.x && dsc->p1.y == dsc->p2.y)
|
||||
return;
|
||||
|
||||
lv_layer_t * layer = vglite_task->t->target_layer;
|
||||
lv_area_t clip_area;
|
||||
clip_area.x1 = LV_MIN(dsc->p1.x, dsc->p2.x) - dsc->width / 2;
|
||||
clip_area.x2 = LV_MAX(dsc->p1.x, dsc->p2.x) + dsc->width / 2;
|
||||
clip_area.y1 = LV_MIN(dsc->p1.y, dsc->p2.y) - dsc->width / 2;
|
||||
clip_area.y2 = LV_MAX(dsc->p1.y, dsc->p2.y) + dsc->width / 2;
|
||||
|
||||
if(!lv_area_intersect(&clip_area, &clip_area, &vglite_task->t->clip_area))
|
||||
return; /*Fully clipped, nothing to do*/
|
||||
|
||||
lv_area_move(&clip_area, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
lv_point_t point1 = {dsc->p1.x - layer->buf_area.x1, dsc->p1.y - layer->buf_area.y1};
|
||||
lv_point_t point2 = {dsc->p2.x - layer->buf_area.x1, dsc->p2.y - layer->buf_area.y1};
|
||||
|
||||
_vglite_draw_line(vglite_task, &point1, &point2, &clip_area, dsc);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void _vglite_set_line(int32_t * line_path, uint32_t * path_data_size, const lv_point_t * point1,
|
||||
const lv_point_t * point2)
|
||||
{
|
||||
uint32_t pidx = 0;
|
||||
line_path[pidx++] = VLC_OP_MOVE;
|
||||
line_path[pidx++] = point1->x;
|
||||
line_path[pidx++] = point1->y;
|
||||
line_path[pidx++] = VLC_OP_LINE;
|
||||
line_path[pidx++] = point2->x;
|
||||
line_path[pidx++] = point2->y;
|
||||
line_path[pidx++] = VLC_OP_END;
|
||||
|
||||
*path_data_size = pidx * sizeof(int32_t);
|
||||
}
|
||||
|
||||
static void _vglite_draw_line(vglite_draw_task_t * vglite_task, const lv_point_t * point1, const lv_point_t * point2,
|
||||
const lv_area_t * clip_area, const lv_draw_line_dsc_t * dsc)
|
||||
{
|
||||
vg_lite_path_t * path = lv_malloc_zeroed(sizeof(vg_lite_path_t));
|
||||
LV_ASSERT_MALLOC(path);
|
||||
vglite_task->path = path;
|
||||
vg_lite_buffer_t * dest_buf = vglite_get_dest_buf();
|
||||
vg_lite_cap_style_t cap_style = (dsc->round_start || dsc->round_end) ? VG_LITE_CAP_ROUND : VG_LITE_CAP_BUTT;
|
||||
vg_lite_join_style_t join_style = (dsc->round_start || dsc->round_end) ? VG_LITE_JOIN_ROUND : VG_LITE_JOIN_MITER;
|
||||
|
||||
bool is_dashed = (dsc->dash_width && dsc->dash_gap);
|
||||
|
||||
vg_lite_float_t stroke_dash_pattern[2] = {0, 0};
|
||||
uint32_t stroke_dash_count = 0;
|
||||
vg_lite_float_t stroke_dash_phase = 0;
|
||||
if(is_dashed) {
|
||||
stroke_dash_pattern[0] = (vg_lite_float_t)dsc->dash_width;
|
||||
stroke_dash_pattern[1] = (vg_lite_float_t)dsc->dash_gap;
|
||||
stroke_dash_count = sizeof(stroke_dash_pattern) / sizeof(vg_lite_float_t);
|
||||
stroke_dash_phase = (vg_lite_float_t)dsc->dash_width / 2;
|
||||
}
|
||||
|
||||
/*** Init path ***/
|
||||
int32_t width = dsc->width;
|
||||
|
||||
uint32_t path_data_size = 0;
|
||||
int32_t * line_path = lv_malloc_zeroed(7 * sizeof(int32_t));
|
||||
LV_ASSERT_MALLOC(line_path);
|
||||
vglite_task->path_data = line_path;
|
||||
_vglite_set_line(line_path, &path_data_size, point1, point2);
|
||||
|
||||
VGLITE_CHECK_ERROR(vg_lite_init_path(path, VG_LITE_S32, VG_LITE_HIGH, path_data_size, line_path,
|
||||
(vg_lite_float_t)clip_area->x1, (vg_lite_float_t)clip_area->y1,
|
||||
((vg_lite_float_t)clip_area->x2) + 1.0f, ((vg_lite_float_t)clip_area->y2) + 1.0f));
|
||||
|
||||
lv_color32_t col32 = lv_color_to_32(dsc->color, dsc->opa);
|
||||
vg_lite_color_t vgcol = vglite_get_color(col32, false);
|
||||
|
||||
/*** Draw line ***/
|
||||
VGLITE_CHECK_ERROR(vg_lite_set_draw_path_type(path, VG_LITE_DRAW_STROKE_PATH));
|
||||
|
||||
VGLITE_CHECK_ERROR(vg_lite_set_stroke(path, cap_style, join_style, width, 8, stroke_dash_pattern, stroke_dash_count,
|
||||
stroke_dash_phase, vgcol));
|
||||
|
||||
VGLITE_CHECK_ERROR(vg_lite_update_stroke(path));
|
||||
|
||||
VGLITE_CHECK_ERROR(vg_lite_draw(dest_buf, path, VG_LITE_FILL_NON_ZERO, NULL, VG_LITE_BLEND_SRC_OVER, vgcol));
|
||||
|
||||
vglite_run();
|
||||
}
|
||||
|
||||
#endif /*LV_USE_DRAW_VGLITE*/
|
||||
@@ -0,0 +1,214 @@
|
||||
/**
|
||||
* @file lv_draw_vglite_triangle.c
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2023-2024 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_vglite.h"
|
||||
|
||||
#if LV_USE_DRAW_VGLITE
|
||||
#include "lv_vglite_buf.h"
|
||||
#include "lv_vglite_path.h"
|
||||
#include "lv_vglite_utils.h"
|
||||
|
||||
#include "../../../stdlib/lv_string.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Set triangle path data
|
||||
*
|
||||
* @param[in/out] path_data Coordinates of the triangle
|
||||
* @param[in/out] path_data_size Size of path_data (bytes)
|
||||
* @param[in] p Points of the triangle
|
||||
*
|
||||
*/
|
||||
static void _vglite_set_triangle(int32_t * path_data, uint32_t * path_data_size,
|
||||
const lv_point_precise_t * p);
|
||||
|
||||
/**
|
||||
* Draw triangle shape with effects (opacity, gradient)
|
||||
*
|
||||
* @param[in] vglite_task The current vglite task
|
||||
* @param[in] coords Coordinates of the triangle (relative to dest buff)
|
||||
* @param[in] clip_area Clipping area with relative coordinates to dest buff
|
||||
* @param[in] dsc Description of the triangle
|
||||
*
|
||||
*/
|
||||
static void _vglite_draw_triangle(vglite_draw_task_t * vglite_task, const lv_area_t * coords,
|
||||
const lv_area_t * clip_area,
|
||||
const lv_draw_triangle_dsc_t * dsc);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_vglite_triangle(vglite_draw_task_t * vglite_task)
|
||||
{
|
||||
const lv_draw_triangle_dsc_t * dsc = vglite_task->t->draw_dsc;
|
||||
|
||||
if(dsc->opa <= (lv_opa_t)LV_OPA_MIN)
|
||||
return;
|
||||
|
||||
lv_layer_t * layer = vglite_task->t->target_layer;
|
||||
lv_area_t clip_area;
|
||||
lv_area_copy(&clip_area, &vglite_task->t->clip_area);
|
||||
lv_area_move(&clip_area, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
lv_area_t coords;
|
||||
coords.x1 = (int32_t)LV_MIN3(dsc->p[0].x, dsc->p[1].x, dsc->p[2].x);
|
||||
coords.y1 = (int32_t)LV_MIN3(dsc->p[0].y, dsc->p[1].y, dsc->p[2].y);
|
||||
coords.x2 = (int32_t)LV_MAX3(dsc->p[0].x, dsc->p[1].x, dsc->p[2].x);
|
||||
coords.y2 = (int32_t)LV_MAX3(dsc->p[0].y, dsc->p[1].y, dsc->p[2].y);
|
||||
|
||||
lv_area_move(&coords, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
lv_area_t clipped_coords;
|
||||
if(!lv_area_intersect(&clipped_coords, &coords, &clip_area))
|
||||
return; /* Fully clipped, nothing to do */
|
||||
|
||||
_vglite_draw_triangle(vglite_task, &coords, &clip_area, dsc);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void _vglite_set_triangle(int32_t * path_data, uint32_t * path_data_size, const lv_point_precise_t * p)
|
||||
{
|
||||
uint32_t pidx = 0;
|
||||
path_data[pidx++] = VLC_OP_MOVE;
|
||||
path_data[pidx++] = p[0].x;
|
||||
path_data[pidx++] = p[0].y;
|
||||
path_data[pidx++] = VLC_OP_LINE;
|
||||
path_data[pidx++] = p[1].x;
|
||||
path_data[pidx++] = p[1].y;
|
||||
path_data[pidx++] = VLC_OP_LINE;
|
||||
path_data[pidx++] = p[2].x;
|
||||
path_data[pidx++] = p[2].y;
|
||||
path_data[pidx++] = VLC_OP_LINE;
|
||||
path_data[pidx++] = p[0].x;
|
||||
path_data[pidx++] = p[0].y;
|
||||
path_data[pidx++] = VLC_OP_END;
|
||||
|
||||
*path_data_size = pidx * sizeof(int32_t);
|
||||
}
|
||||
|
||||
static void _vglite_draw_triangle(vglite_draw_task_t * vglite_task, const lv_area_t * coords,
|
||||
const lv_area_t * clip_area,
|
||||
const lv_draw_triangle_dsc_t * dsc)
|
||||
{
|
||||
vg_lite_buffer_t * dest_buf = vglite_get_dest_buf();
|
||||
|
||||
lv_area_t tri_area;
|
||||
tri_area.x1 = (int32_t)LV_MIN3(dsc->p[0].x, dsc->p[1].x, dsc->p[2].x);
|
||||
tri_area.y1 = (int32_t)LV_MIN3(dsc->p[0].y, dsc->p[1].y, dsc->p[2].y);
|
||||
tri_area.x2 = (int32_t)LV_MAX3(dsc->p[0].x, dsc->p[1].x, dsc->p[2].x);
|
||||
tri_area.y2 = (int32_t)LV_MAX3(dsc->p[0].y, dsc->p[1].y, dsc->p[2].y);
|
||||
|
||||
uint32_t width = lv_area_get_width(&tri_area);
|
||||
uint32_t height = lv_area_get_height(&tri_area);
|
||||
|
||||
/* Init path */
|
||||
uint32_t path_data_size;
|
||||
int32_t * triangle_path = lv_malloc_zeroed(13 * sizeof(int32_t));
|
||||
LV_ASSERT_MALLOC(triangle_path);
|
||||
vglite_task->path_data = triangle_path;
|
||||
_vglite_set_triangle(triangle_path, &path_data_size, dsc->p);
|
||||
|
||||
|
||||
vg_lite_path_t * path = lv_malloc_zeroed(sizeof(vg_lite_path_t));
|
||||
LV_ASSERT_MALLOC(path);
|
||||
vglite_task->path = path;
|
||||
VGLITE_CHECK_ERROR(vg_lite_init_path(path, VG_LITE_S32, VG_LITE_HIGH, path_data_size, triangle_path,
|
||||
(vg_lite_float_t)clip_area->x1, (vg_lite_float_t)clip_area->y1,
|
||||
((vg_lite_float_t)clip_area->x2) + 1.0f, ((vg_lite_float_t)clip_area->y2) + 1.0f));
|
||||
|
||||
/* Init Color */
|
||||
lv_color32_t col32 = lv_color_to_32(dsc->color, dsc->opa);
|
||||
vg_lite_color_t vgcol = vglite_get_color(col32, false);
|
||||
|
||||
vg_lite_linear_gradient_t * gradient;
|
||||
|
||||
bool has_gradient = (dsc->grad.dir != (lv_grad_dir_t)LV_GRAD_DIR_NONE);
|
||||
|
||||
/* Init Gradient*/
|
||||
if(has_gradient) {
|
||||
gradient = lv_malloc_zeroed(sizeof(vg_lite_linear_gradient_t));
|
||||
LV_ASSERT_MALLOC(gradient);
|
||||
vglite_task->gradient = gradient;
|
||||
|
||||
vg_lite_matrix_t * grad_matrix;
|
||||
|
||||
vg_lite_uint32_t colors[LV_GRADIENT_MAX_STOPS];
|
||||
vg_lite_uint32_t stops[LV_GRADIENT_MAX_STOPS];
|
||||
lv_color32_t col32[LV_GRADIENT_MAX_STOPS];
|
||||
|
||||
/* Gradient Setup */
|
||||
vg_lite_uint32_t cnt = LV_MIN(dsc->grad.stops_count, LV_GRADIENT_MAX_STOPS);
|
||||
lv_opa_t opa;
|
||||
|
||||
for(uint8_t i = 0; i < cnt; i++) {
|
||||
stops[i] = dsc->grad.stops[i].frac;
|
||||
opa = LV_OPA_MIX2(dsc->grad.stops[i].opa, dsc->opa);
|
||||
|
||||
col32[i] = lv_color_to_32(dsc->grad.stops[i].color, opa);
|
||||
colors[i] = vglite_get_color(col32[i], true);
|
||||
}
|
||||
|
||||
VGLITE_CHECK_ERROR(vg_lite_init_grad(gradient));
|
||||
|
||||
VGLITE_CHECK_ERROR(vg_lite_set_grad(gradient, cnt, colors, stops));
|
||||
|
||||
VGLITE_CHECK_ERROR(vg_lite_update_grad(gradient));
|
||||
|
||||
grad_matrix = vg_lite_get_grad_matrix(gradient);
|
||||
VGLITE_CHECK_ERROR(vg_lite_identity(grad_matrix));
|
||||
VGLITE_CHECK_ERROR(vg_lite_translate((float)coords->x1, (float)coords->y1, grad_matrix));
|
||||
|
||||
if(dsc->grad.dir == (lv_grad_dir_t)LV_GRAD_DIR_VER) {
|
||||
VGLITE_CHECK_ERROR(vg_lite_scale(1.0f, (float)height / 256.0f, grad_matrix));
|
||||
VGLITE_CHECK_ERROR(vg_lite_rotate(90.0f, grad_matrix));
|
||||
}
|
||||
else { /*LV_GRAD_DIR_HOR*/
|
||||
VGLITE_CHECK_ERROR(vg_lite_scale((float)width / 256.0f, 1.0f, grad_matrix));
|
||||
}
|
||||
|
||||
VGLITE_CHECK_ERROR(vg_lite_draw_gradient(dest_buf, path, VG_LITE_FILL_EVEN_ODD, NULL, gradient,
|
||||
VG_LITE_BLEND_SRC_OVER));
|
||||
}
|
||||
else {
|
||||
VGLITE_CHECK_ERROR(vg_lite_draw(dest_buf, path, VG_LITE_FILL_EVEN_ODD, NULL, VG_LITE_BLEND_SRC_OVER, vgcol));
|
||||
}
|
||||
|
||||
vglite_run();
|
||||
}
|
||||
|
||||
#endif /*LV_USE_DRAW_VGLITE*/
|
||||
@@ -0,0 +1,116 @@
|
||||
/**
|
||||
* @file lv_vglite_buf.c
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2023 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_vglite_buf.h"
|
||||
|
||||
#if LV_USE_DRAW_VGLITE
|
||||
#include "lv_vglite_utils.h"
|
||||
|
||||
#include "../../../stdlib/lv_string.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static inline void _set_vgbuf_ptr(vg_lite_buffer_t * vgbuf, void * buf);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
static vg_lite_buffer_t _dest_buf;
|
||||
static vg_lite_buffer_t _src_buf;
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
vg_lite_buffer_t * vglite_get_dest_buf(void)
|
||||
{
|
||||
return &_dest_buf;
|
||||
}
|
||||
|
||||
vg_lite_buffer_t * vglite_get_src_buf(void)
|
||||
{
|
||||
return &_src_buf;
|
||||
}
|
||||
|
||||
void vglite_set_dest_buf_ptr(void * buf)
|
||||
{
|
||||
_set_vgbuf_ptr(&_dest_buf, buf);
|
||||
}
|
||||
|
||||
void vglite_set_src_buf_ptr(const void * buf)
|
||||
{
|
||||
_set_vgbuf_ptr(&_src_buf, (void *)buf);
|
||||
}
|
||||
|
||||
void vglite_set_dest_buf(const void * buf, uint32_t width, uint32_t height, uint32_t stride,
|
||||
lv_color_format_t cf)
|
||||
{
|
||||
vglite_set_buf(&_dest_buf, (void *)buf, width, height, stride, cf);
|
||||
}
|
||||
|
||||
void vglite_set_src_buf(const void * buf, uint32_t width, uint32_t height, uint32_t stride,
|
||||
lv_color_format_t cf)
|
||||
{
|
||||
vglite_set_buf(&_src_buf, (void *)buf, width, height, stride, cf);
|
||||
}
|
||||
|
||||
void vglite_set_buf(vg_lite_buffer_t * vgbuf, void * buf,
|
||||
uint32_t width, uint32_t height, uint32_t stride,
|
||||
lv_color_format_t cf)
|
||||
{
|
||||
vg_lite_buffer_format_t vgformat = vglite_get_buf_format(cf);
|
||||
|
||||
vgbuf->format = vgformat;
|
||||
vgbuf->tiled = VG_LITE_LINEAR;
|
||||
vgbuf->image_mode = VG_LITE_NORMAL_IMAGE_MODE;
|
||||
vgbuf->transparency_mode = VG_LITE_IMAGE_OPAQUE;
|
||||
|
||||
vgbuf->width = (int32_t)width;
|
||||
vgbuf->height = (int32_t)height;
|
||||
vgbuf->stride = (int32_t)stride;
|
||||
|
||||
lv_memzero(&vgbuf->yuv, sizeof(vgbuf->yuv));
|
||||
|
||||
vgbuf->memory = buf;
|
||||
vgbuf->address = (uint32_t)vgbuf->memory;
|
||||
vgbuf->handle = NULL;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static inline void _set_vgbuf_ptr(vg_lite_buffer_t * vgbuf, void * buf)
|
||||
{
|
||||
vgbuf->memory = buf;
|
||||
vgbuf->address = (uint32_t)vgbuf->memory;
|
||||
}
|
||||
|
||||
#endif /*LV_USE_DRAW_VGLITE*/
|
||||
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* @file lv_vglite_buf.h
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2023 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef LV_VGLITE_BUF_H
|
||||
#define LV_VGLITE_BUF_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_DRAW_VGLITE
|
||||
#include "../../lv_draw.h"
|
||||
|
||||
#include "vg_lite.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Get vglite destination buffer pointer.
|
||||
*
|
||||
* @retval The vglite destination buffer
|
||||
*
|
||||
*/
|
||||
vg_lite_buffer_t * vglite_get_dest_buf(void);
|
||||
|
||||
/**
|
||||
* Get vglite source buffer pointer.
|
||||
*
|
||||
* @retval The vglite source buffer
|
||||
*
|
||||
*/
|
||||
vg_lite_buffer_t * vglite_get_src_buf(void);
|
||||
|
||||
/**
|
||||
* Set vglite destination buffer address only.
|
||||
*
|
||||
* @param[in] buf Destination buffer address (does not require alignment for VG_LITE_LINEAR mode)
|
||||
*
|
||||
*/
|
||||
void vglite_set_dest_buf_ptr(void * buf);
|
||||
|
||||
/**
|
||||
* Set vglite source buffer address only.
|
||||
*
|
||||
* @param[in] buf Source buffer address
|
||||
*
|
||||
*/
|
||||
void vglite_set_src_buf_ptr(const void * buf);
|
||||
|
||||
/**
|
||||
* Set vglite destination buffer.
|
||||
*
|
||||
* @param[in] buf Destination buffer address
|
||||
* @param[in] width Destination buffer width
|
||||
* @param[in] height Destination buffer height
|
||||
* @param[in] stride Destination buffer stride in bytes
|
||||
* @param[in] cf Destination buffer color format
|
||||
*
|
||||
*/
|
||||
void vglite_set_dest_buf(const void * buf, uint32_t width, uint32_t height, uint32_t stride,
|
||||
lv_color_format_t cf);
|
||||
|
||||
/**
|
||||
* Set vglite source buffer.
|
||||
*
|
||||
* @param[in] buf Source buffer address
|
||||
* @param[in] width Source buffer width
|
||||
* @param[in] height Source buffer height
|
||||
* @param[in] stride Source buffer stride in bytes
|
||||
* @param[in] cf Source buffer color format
|
||||
*
|
||||
*/
|
||||
void vglite_set_src_buf(const void * buf, uint32_t width, uint32_t height, uint32_t stride,
|
||||
lv_color_format_t cf);
|
||||
|
||||
/**
|
||||
* Set vglite buffer.
|
||||
*
|
||||
* @param[in] vgbuf Address of the VGLite buffer object
|
||||
* @param[in] buf Address of the memory for the VGLite buffer
|
||||
* @param[in] width Buffer width
|
||||
* @param[in] height Buffer height
|
||||
* @param[in] stride Buffer stride in bytes
|
||||
* @param[in] cf Buffer color format
|
||||
*
|
||||
*/
|
||||
void vglite_set_buf(vg_lite_buffer_t * vgbuf, void * buf,
|
||||
uint32_t width, uint32_t height, uint32_t stride,
|
||||
lv_color_format_t cf);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_DRAW_VGLITE*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_VGLITE_BUF_H*/
|
||||
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* @file lv_vglite_matrix.c
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2023 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_vglite_matrix.h"
|
||||
|
||||
#if LV_USE_DRAW_VGLITE
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
static vg_lite_matrix_t _matrix;
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
vg_lite_matrix_t * vglite_get_matrix(void)
|
||||
{
|
||||
return &_matrix;
|
||||
}
|
||||
|
||||
void vglite_set_translation_matrix(const lv_area_t * dest_area)
|
||||
{
|
||||
vg_lite_identity(&_matrix);
|
||||
vg_lite_translate((vg_lite_float_t)dest_area->x1, (vg_lite_float_t)dest_area->y1, &_matrix);
|
||||
}
|
||||
|
||||
void vglite_set_transformation_matrix(const lv_area_t * dest_area, const lv_draw_image_dsc_t * dsc)
|
||||
{
|
||||
vglite_set_translation_matrix(dest_area);
|
||||
|
||||
bool has_scale = (dsc->scale_x != LV_SCALE_NONE || dsc->scale_y != LV_SCALE_NONE);
|
||||
bool has_rotation = (dsc->rotation != 0);
|
||||
|
||||
if(has_scale || has_rotation) {
|
||||
vg_lite_translate(dsc->pivot.x, dsc->pivot.y, &_matrix);
|
||||
if(has_rotation)
|
||||
vg_lite_rotate(dsc->rotation / 10.0f, &_matrix); /* angle is 1/10 degree */
|
||||
if(has_scale) {
|
||||
vg_lite_float_t scale_x = 1.0f * dsc->scale_x / LV_SCALE_NONE;
|
||||
vg_lite_float_t scale_y = 1.0f * dsc->scale_y / LV_SCALE_NONE;
|
||||
vg_lite_scale(scale_x, scale_y, &_matrix);
|
||||
}
|
||||
vg_lite_translate(0.0f - dsc->pivot.x, 0.0f - dsc->pivot.y, &_matrix);
|
||||
}
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_DRAW_VGLITE*/
|
||||
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* @file lv_vglite_matrix.h
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2023 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef LV_VGLITE_MATRIX_H
|
||||
#define LV_VGLITE_MATRIX_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_DRAW_VGLITE
|
||||
|
||||
#include "../../lv_draw_image.h"
|
||||
#include "../../lv_draw.h"
|
||||
|
||||
#include "vg_lite.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
vg_lite_matrix_t * vglite_get_matrix(void);
|
||||
|
||||
/**
|
||||
* Creates matrix that translates to origin of given destination area.
|
||||
*
|
||||
* @param[in] dest_area Area with relative coordinates of destination buffer
|
||||
*
|
||||
*/
|
||||
void vglite_set_translation_matrix(const lv_area_t * dest_area);
|
||||
|
||||
/**
|
||||
* Creates matrix that translates to origin of given destination area with transformation (scale or rotate).
|
||||
*
|
||||
* @param[in] dest_area Area with relative coordinates of destination buffer
|
||||
* @param[in] dsc Image descriptor
|
||||
*
|
||||
*/
|
||||
void vglite_set_transformation_matrix(const lv_area_t * dest_area, const lv_draw_image_dsc_t * dsc);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_DRAW_VGLITE*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_VGLITE_MATRIX_H*/
|
||||
@@ -0,0 +1,217 @@
|
||||
/**
|
||||
* @file lv_vglite_path.c
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2023 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_vglite_path.h"
|
||||
|
||||
#if LV_USE_DRAW_VGLITE
|
||||
#include "vg_lite.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void vglite_create_rect_path_data(int32_t * path_data, uint32_t * path_data_size,
|
||||
int32_t radius,
|
||||
const lv_area_t * coords)
|
||||
{
|
||||
int32_t rect_width = lv_area_get_width(coords);
|
||||
int32_t rect_height = lv_area_get_height(coords);
|
||||
|
||||
/* Get the final radius. Can't be larger than the half of the shortest side */
|
||||
int32_t shortest_side = LV_MIN(rect_width, rect_height);
|
||||
int32_t final_radius = LV_MIN(radius, shortest_side / 2);
|
||||
|
||||
/* Path data element index */
|
||||
uint8_t pidx = 0;
|
||||
|
||||
if((radius == (int32_t)LV_RADIUS_CIRCLE) && (rect_width == rect_height)) {
|
||||
|
||||
/* Get the control point offset for rounded cases */
|
||||
int32_t cpoff = (int32_t)((float)final_radius * BEZIER_OPTIM_CIRCLE);
|
||||
|
||||
/* Circle case */
|
||||
/* Starting point */
|
||||
path_data[pidx++] = VLC_OP_MOVE;
|
||||
path_data[pidx++] = coords->x1 + final_radius;
|
||||
path_data[pidx++] = coords->y1;
|
||||
|
||||
/* Top-right arc */
|
||||
path_data[pidx++] = VLC_OP_CUBIC_REL;
|
||||
path_data[pidx++] = cpoff;
|
||||
path_data[pidx++] = 0;
|
||||
path_data[pidx++] = final_radius;
|
||||
path_data[pidx++] = final_radius - cpoff;
|
||||
path_data[pidx++] = final_radius;
|
||||
path_data[pidx++] = final_radius;
|
||||
|
||||
/* Bottom-right arc*/
|
||||
path_data[pidx++] = VLC_OP_CUBIC_REL;
|
||||
path_data[pidx++] = 0;
|
||||
path_data[pidx++] = cpoff;
|
||||
path_data[pidx++] = cpoff - final_radius;
|
||||
path_data[pidx++] = final_radius;
|
||||
path_data[pidx++] = 0 - final_radius;
|
||||
path_data[pidx++] = final_radius;
|
||||
|
||||
/* Bottom-left arc */
|
||||
path_data[pidx++] = VLC_OP_CUBIC_REL;
|
||||
path_data[pidx++] = 0 - cpoff;
|
||||
path_data[pidx++] = 0;
|
||||
path_data[pidx++] = 0 - final_radius;
|
||||
path_data[pidx++] = cpoff - final_radius;
|
||||
path_data[pidx++] = 0 - final_radius;
|
||||
path_data[pidx++] = 0 - final_radius;
|
||||
|
||||
/* Top-left arc*/
|
||||
path_data[pidx++] = VLC_OP_CUBIC_REL;
|
||||
path_data[pidx++] = 0;
|
||||
path_data[pidx++] = 0 - cpoff;
|
||||
path_data[pidx++] = final_radius - cpoff;
|
||||
path_data[pidx++] = 0 - final_radius;
|
||||
path_data[pidx++] = final_radius;
|
||||
path_data[pidx++] = 0 - final_radius;
|
||||
|
||||
/* Ending point */
|
||||
path_data[pidx++] = VLC_OP_END;
|
||||
}
|
||||
else if(radius > 0) {
|
||||
/* Get the control point offset for rounded cases */
|
||||
int32_t cpoff = (int32_t)((float)final_radius * BEZIER_OPTIM_CIRCLE);
|
||||
|
||||
/* Rounded rectangle case */
|
||||
/* Starting point */
|
||||
path_data[pidx++] = VLC_OP_MOVE;
|
||||
path_data[pidx++] = coords->x1 + final_radius;
|
||||
path_data[pidx++] = coords->y1;
|
||||
|
||||
/* Top side */
|
||||
path_data[pidx++] = VLC_OP_LINE;
|
||||
path_data[pidx++] = coords->x2 - final_radius + 1; /*Extended for VGLite*/
|
||||
path_data[pidx++] = coords->y1;
|
||||
|
||||
/* Top-right corner */
|
||||
path_data[pidx++] = VLC_OP_CUBIC_REL;
|
||||
path_data[pidx++] = cpoff;
|
||||
path_data[pidx++] = 0;
|
||||
path_data[pidx++] = final_radius;
|
||||
path_data[pidx++] = final_radius - cpoff;
|
||||
path_data[pidx++] = final_radius;
|
||||
path_data[pidx++] = final_radius;
|
||||
|
||||
/* Right side */
|
||||
path_data[pidx++] = VLC_OP_LINE;
|
||||
path_data[pidx++] = coords->x2 + 1; /*Extended for VGLite*/
|
||||
path_data[pidx++] = coords->y2 - final_radius + 1; /*Extended for VGLite*/
|
||||
|
||||
/* Bottom-right corner*/
|
||||
path_data[pidx++] = VLC_OP_CUBIC_REL;
|
||||
path_data[pidx++] = 0;
|
||||
path_data[pidx++] = cpoff;
|
||||
path_data[pidx++] = cpoff - final_radius;
|
||||
path_data[pidx++] = final_radius;
|
||||
path_data[pidx++] = 0 - final_radius;
|
||||
path_data[pidx++] = final_radius;
|
||||
|
||||
/* Bottom side */
|
||||
path_data[pidx++] = VLC_OP_LINE;
|
||||
path_data[pidx++] = coords->x1 + final_radius;
|
||||
path_data[pidx++] = coords->y2 + 1; /*Extended for VGLite*/
|
||||
|
||||
/* Bottom-left corner */
|
||||
path_data[pidx++] = VLC_OP_CUBIC_REL;
|
||||
path_data[pidx++] = 0 - cpoff;
|
||||
path_data[pidx++] = 0;
|
||||
path_data[pidx++] = 0 - final_radius;
|
||||
path_data[pidx++] = cpoff - final_radius;
|
||||
path_data[pidx++] = 0 - final_radius;
|
||||
path_data[pidx++] = 0 - final_radius;
|
||||
|
||||
/* Left side*/
|
||||
path_data[pidx++] = VLC_OP_LINE;
|
||||
path_data[pidx++] = coords->x1;
|
||||
path_data[pidx++] = coords->y1 + final_radius;
|
||||
|
||||
/* Top-left corner */
|
||||
path_data[pidx++] = VLC_OP_CUBIC_REL;
|
||||
path_data[pidx++] = 0;
|
||||
path_data[pidx++] = 0 - cpoff;
|
||||
path_data[pidx++] = final_radius - cpoff;
|
||||
path_data[pidx++] = 0 - final_radius;
|
||||
path_data[pidx++] = final_radius;
|
||||
path_data[pidx++] = 0 - final_radius;
|
||||
|
||||
/* Ending point */
|
||||
path_data[pidx++] = VLC_OP_END;
|
||||
}
|
||||
else {
|
||||
/* Non-rounded rectangle case */
|
||||
/* Starting point */
|
||||
path_data[pidx++] = VLC_OP_MOVE;
|
||||
path_data[pidx++] = coords->x1;
|
||||
path_data[pidx++] = coords->y1;
|
||||
|
||||
/* Top side */
|
||||
path_data[pidx++] = VLC_OP_LINE;
|
||||
path_data[pidx++] = coords->x2 + 1; /*Extended for VGLite*/
|
||||
path_data[pidx++] = coords->y1;
|
||||
|
||||
/* Right side */
|
||||
path_data[pidx++] = VLC_OP_LINE;
|
||||
path_data[pidx++] = coords->x2 + 1; /*Extended for VGLite*/
|
||||
path_data[pidx++] = coords->y2 + 1; /*Extended for VGLite*/
|
||||
|
||||
/* Bottom side */
|
||||
path_data[pidx++] = VLC_OP_LINE;
|
||||
path_data[pidx++] = coords->x1;
|
||||
path_data[pidx++] = coords->y2 + 1; /*Extended for VGLite*/
|
||||
|
||||
/* Left side*/
|
||||
path_data[pidx++] = VLC_OP_LINE;
|
||||
path_data[pidx++] = coords->x1;
|
||||
path_data[pidx++] = coords->y1;
|
||||
|
||||
/* Ending point */
|
||||
path_data[pidx++] = VLC_OP_END;
|
||||
}
|
||||
|
||||
/* Resulting path size */
|
||||
*path_data_size = pidx * sizeof(int32_t);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_DRAW_VGLITE*/
|
||||
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* @file lv_vglite_path.h
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2023 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef LV_VGLITE_PATH_H
|
||||
#define LV_VGLITE_PATH_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_DRAW_VGLITE
|
||||
#include "../../lv_draw.h"
|
||||
#include "../../lv_draw_triangle.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/* The optimal Bezier control point offset for radial unit
|
||||
* see: https://spencermortensen.com/articles/bezier-circle/
|
||||
**/
|
||||
#define BEZIER_OPTIM_CIRCLE 0.551915024494f
|
||||
|
||||
/* Draw lines for control points of Bezier curves */
|
||||
#define BEZIER_DBG_CONTROL_POINTS 0
|
||||
|
||||
/* Path data sizes for different elements */
|
||||
#define CUBIC_PATH_DATA_SIZE 7 /* 1 opcode, 6 arguments */
|
||||
#define LINE_PATH_DATA_SIZE 3 /* 1 opcode, 2 arguments */
|
||||
#define MOVE_PATH_DATA_SIZE 3 /* 1 opcode, 2 arguments */
|
||||
#define END_PATH_DATA_SIZE 1 /* 1 opcode, 0 arguments */
|
||||
/* Maximum possible rectangle path size
|
||||
* is in the rounded rectangle case:
|
||||
* - 1 move for the path start
|
||||
* - 4 cubics for the corners
|
||||
* - 4 lines for the sides
|
||||
* - 1 end for the path end */
|
||||
#define RECT_PATH_DATA_MAX_SIZE (1 * MOVE_PATH_DATA_SIZE + 4 * CUBIC_PATH_DATA_SIZE + 4 * LINE_PATH_DATA_SIZE + 1 * END_PATH_DATA_SIZE)
|
||||
|
||||
/* Maximum possible arc path size
|
||||
* is in the rounded arc case:
|
||||
* - 1 move for the path start
|
||||
* - 16 cubics for the arc (5 inner, 5 outer) and corners (3 per corner)
|
||||
* - 1 end for the path end */
|
||||
#define ARC_PATH_DATA_MAX_SIZE (1 * MOVE_PATH_DATA_SIZE + 16 * CUBIC_PATH_DATA_SIZE + 1 * END_PATH_DATA_SIZE)
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Generates path data for rectangle drawing.
|
||||
*
|
||||
* @param[in/out] path The path data to initialize
|
||||
* @param[in/out] path_size The resulting size of the created path data
|
||||
* @param[in] dsc The style descriptor for the rectangle to be drawn
|
||||
* @param[in] coords The coordinates of the rectangle to be drawn
|
||||
*
|
||||
*/
|
||||
void vglite_create_rect_path_data(int32_t * path_data, uint32_t * path_data_size,
|
||||
int32_t radius,
|
||||
const lv_area_t * coords);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_DRAW_VGLITE*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_VGLITE_PATH_H*/
|
||||
@@ -0,0 +1,286 @@
|
||||
/**
|
||||
* @file lv_vglite_utils.c
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2022-2024 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_vglite_utils.h"
|
||||
|
||||
#if LV_USE_DRAW_VGLITE
|
||||
#include "lv_vglite_buf.h"
|
||||
|
||||
#include "../../../core/lv_refr.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
#if LV_USE_VGLITE_DRAW_ASYNC
|
||||
static volatile bool _cmd_buf_flushed = false;
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
const char * vglite_error_to_string(vg_lite_error_t error)
|
||||
{
|
||||
switch(error) {
|
||||
ENUM_TO_STRING(VG_LITE_SUCCESS);
|
||||
ENUM_TO_STRING(VG_LITE_INVALID_ARGUMENT);
|
||||
ENUM_TO_STRING(VG_LITE_OUT_OF_MEMORY);
|
||||
ENUM_TO_STRING(VG_LITE_NO_CONTEXT);
|
||||
ENUM_TO_STRING(VG_LITE_TIMEOUT);
|
||||
ENUM_TO_STRING(VG_LITE_OUT_OF_RESOURCES);
|
||||
ENUM_TO_STRING(VG_LITE_GENERIC_IO);
|
||||
ENUM_TO_STRING(VG_LITE_NOT_SUPPORT);
|
||||
ENUM_TO_STRING(VG_LITE_ALREADY_EXISTS);
|
||||
ENUM_TO_STRING(VG_LITE_NOT_ALIGNED);
|
||||
ENUM_TO_STRING(VG_LITE_FLEXA_TIME_OUT);
|
||||
ENUM_TO_STRING(VG_LITE_FLEXA_HANDSHAKE_FAIL);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return "VG_LITE_UKNOWN_ERROR";
|
||||
}
|
||||
|
||||
#if LV_USE_VGLITE_DRAW_ASYNC
|
||||
bool vglite_cmd_buf_is_flushed(void)
|
||||
{
|
||||
return _cmd_buf_flushed;
|
||||
}
|
||||
#endif
|
||||
|
||||
void vglite_run(void)
|
||||
{
|
||||
#if LV_USE_VGLITE_DRAW_ASYNC
|
||||
vg_lite_uint32_t gpu_idle = 0;
|
||||
|
||||
VGLITE_CHECK_ERROR(vg_lite_get_parameter(VG_LITE_GPU_IDLE_STATE, 1, (vg_lite_pointer)&gpu_idle));
|
||||
|
||||
if(!gpu_idle) {
|
||||
_cmd_buf_flushed = false;
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If LV_USE_VGLITE_DRAW_ASYNC is enabled, simply flush the command buffer and the
|
||||
* vglite draw thread will signal asynchronous the dispatcher for completed tasks.
|
||||
* Without draw async, process the tasks and signal them as complete one by one.
|
||||
*/
|
||||
#if LV_USE_VGLITE_DRAW_ASYNC
|
||||
VGLITE_CHECK_ERROR(vg_lite_flush());
|
||||
_cmd_buf_flushed = true;
|
||||
#else
|
||||
VGLITE_CHECK_ERROR(vg_lite_finish());
|
||||
#endif
|
||||
}
|
||||
|
||||
#if LV_USE_VGLITE_DRAW_ASYNC
|
||||
void vglite_wait_for_finish(void)
|
||||
{
|
||||
VGLITE_CHECK_ERROR(vg_lite_finish());
|
||||
}
|
||||
#endif
|
||||
|
||||
vg_lite_color_t vglite_get_color(lv_color32_t lv_col32, bool gradient)
|
||||
{
|
||||
vg_lite_color_t vg_col32;
|
||||
|
||||
/* Pre-multiply alpha */
|
||||
lv_col32.red = LV_UDIV255(lv_col32.red * lv_col32.alpha);
|
||||
lv_col32.green = LV_UDIV255(lv_col32.green * lv_col32.alpha);
|
||||
lv_col32.blue = LV_UDIV255(lv_col32.blue * lv_col32.alpha);
|
||||
|
||||
if(!gradient)
|
||||
/* The color is in ABGR8888 format with red channel in the lower 8 bits. */
|
||||
vg_col32 = ((vg_lite_color_t)lv_col32.alpha << 24) | ((vg_lite_color_t)lv_col32.blue << 16) |
|
||||
((vg_lite_color_t)lv_col32.green << 8) | (vg_lite_color_t)lv_col32.red;
|
||||
else
|
||||
/* The gradient color is in ARGB8888 format with blue channel in the lower 8 bits. */
|
||||
vg_col32 = ((vg_lite_color_t)lv_col32.alpha << 24) | ((vg_lite_color_t)lv_col32.red << 16) |
|
||||
((vg_lite_color_t)lv_col32.green << 8) | (vg_lite_color_t)lv_col32.blue;
|
||||
|
||||
return vg_col32;
|
||||
}
|
||||
|
||||
vg_lite_blend_t vglite_get_blend_mode(lv_blend_mode_t lv_blend_mode)
|
||||
{
|
||||
vg_lite_blend_t vg_blend_mode = VG_LITE_BLEND_NONE;
|
||||
|
||||
if(vg_lite_query_feature(gcFEATURE_BIT_VG_LVGL_SUPPORT)) {
|
||||
switch(lv_blend_mode) {
|
||||
case LV_BLEND_MODE_NORMAL:
|
||||
vg_blend_mode = VG_LITE_BLEND_NORMAL_LVGL;
|
||||
break;
|
||||
case LV_BLEND_MODE_ADDITIVE:
|
||||
vg_blend_mode = VG_LITE_BLEND_ADDITIVE_LVGL;
|
||||
break;
|
||||
case LV_BLEND_MODE_SUBTRACTIVE:
|
||||
vg_blend_mode = VG_LITE_BLEND_SUBTRACT_LVGL;
|
||||
break;
|
||||
case LV_BLEND_MODE_MULTIPLY:
|
||||
vg_blend_mode = VG_LITE_BLEND_MULTIPLY_LVGL;
|
||||
break;
|
||||
default:
|
||||
VGLITE_ASSERT_MSG(false, "Unsupported blend mode.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch(lv_blend_mode) {
|
||||
case LV_BLEND_MODE_NORMAL:
|
||||
vg_blend_mode = VG_LITE_BLEND_SRC_OVER;
|
||||
break;
|
||||
case LV_BLEND_MODE_ADDITIVE:
|
||||
vg_blend_mode = VG_LITE_BLEND_ADDITIVE;
|
||||
break;
|
||||
case LV_BLEND_MODE_SUBTRACTIVE:
|
||||
vg_blend_mode = VG_LITE_BLEND_SUBTRACT;
|
||||
break;
|
||||
case LV_BLEND_MODE_MULTIPLY:
|
||||
vg_blend_mode = VG_LITE_BLEND_MULTIPLY;
|
||||
break;
|
||||
default:
|
||||
VGLITE_ASSERT_MSG(false, "Unsupported blend mode.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return vg_blend_mode;
|
||||
}
|
||||
|
||||
vg_lite_buffer_format_t vglite_get_buf_format(lv_color_format_t cf)
|
||||
{
|
||||
vg_lite_buffer_format_t vg_buffer_format = VG_LITE_BGR565;
|
||||
|
||||
switch(cf) {
|
||||
case LV_COLOR_FORMAT_L8:
|
||||
vg_buffer_format = VG_LITE_L8;
|
||||
break;
|
||||
case LV_COLOR_FORMAT_A4:
|
||||
vg_buffer_format = VG_LITE_A4;
|
||||
break;
|
||||
case LV_COLOR_FORMAT_A8:
|
||||
vg_buffer_format = VG_LITE_A8;
|
||||
break;
|
||||
case LV_COLOR_FORMAT_I1:
|
||||
vg_buffer_format = VG_LITE_INDEX_1;
|
||||
break;
|
||||
case LV_COLOR_FORMAT_I2:
|
||||
vg_buffer_format = VG_LITE_INDEX_2;
|
||||
break;
|
||||
case LV_COLOR_FORMAT_I4:
|
||||
vg_buffer_format = VG_LITE_INDEX_4;
|
||||
break;
|
||||
case LV_COLOR_FORMAT_I8:
|
||||
vg_buffer_format = VG_LITE_INDEX_8;
|
||||
break;
|
||||
case LV_COLOR_FORMAT_RGB565:
|
||||
vg_buffer_format = VG_LITE_BGR565;
|
||||
break;
|
||||
case LV_COLOR_FORMAT_ARGB8565:
|
||||
vg_buffer_format = VG_LITE_BGRA5658;
|
||||
break;
|
||||
case LV_COLOR_FORMAT_RGB888:
|
||||
vg_buffer_format = VG_LITE_BGR888;
|
||||
break;
|
||||
case LV_COLOR_FORMAT_ARGB8888:
|
||||
vg_buffer_format = VG_LITE_BGRA8888;
|
||||
break;
|
||||
case LV_COLOR_FORMAT_XRGB8888:
|
||||
vg_buffer_format = VG_LITE_BGRX8888;
|
||||
break;
|
||||
|
||||
default:
|
||||
VGLITE_ASSERT_MSG(false, "Unsupported color format.");
|
||||
break;
|
||||
}
|
||||
|
||||
return vg_buffer_format;
|
||||
}
|
||||
|
||||
uint8_t vglite_get_stride_alignment(lv_color_format_t cf)
|
||||
{
|
||||
uint8_t align_bytes = LV_COLOR_DEPTH / 8 * 16; /*16 pixels*/
|
||||
|
||||
switch(cf) {
|
||||
case LV_COLOR_FORMAT_I1:
|
||||
case LV_COLOR_FORMAT_I2:
|
||||
case LV_COLOR_FORMAT_I4:
|
||||
case LV_COLOR_FORMAT_A4:
|
||||
align_bytes = 8;
|
||||
break;
|
||||
case LV_COLOR_FORMAT_I8:
|
||||
case LV_COLOR_FORMAT_A8:
|
||||
case LV_COLOR_FORMAT_L8:
|
||||
align_bytes = 16;
|
||||
break;
|
||||
case LV_COLOR_FORMAT_RGB565:
|
||||
align_bytes = 32;
|
||||
break;
|
||||
case LV_COLOR_FORMAT_ARGB8565:
|
||||
case LV_COLOR_FORMAT_RGB888:
|
||||
align_bytes = 48;
|
||||
break;
|
||||
case LV_COLOR_FORMAT_ARGB8888:
|
||||
case LV_COLOR_FORMAT_XRGB8888:
|
||||
align_bytes = 64;
|
||||
break;
|
||||
|
||||
default:
|
||||
VGLITE_ASSERT_MSG(false, "Unsupported buffer format.");
|
||||
break;
|
||||
}
|
||||
|
||||
return align_bytes;
|
||||
}
|
||||
|
||||
bool vglite_src_buf_aligned(const void * buf, uint32_t stride, lv_color_format_t cf)
|
||||
{
|
||||
/* No alignment requirement for destination buffer when using mode VG_LITE_LINEAR */
|
||||
|
||||
/* Test for pointer alignment */
|
||||
if((uintptr_t)buf % LV_ATTRIBUTE_MEM_ALIGN_SIZE)
|
||||
return false;
|
||||
|
||||
/* Test for stride alignment */
|
||||
if(stride == 0 || stride % vglite_get_stride_alignment(cf))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_DRAW_VGLITE*/
|
||||
@@ -0,0 +1,183 @@
|
||||
/**
|
||||
* @file lv_vglite_utils.h
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2022-2024 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef LV_VGLITE_UTILS_H
|
||||
#define LV_VGLITE_UTILS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_DRAW_VGLITE
|
||||
#include "../../lv_draw.h"
|
||||
|
||||
#include "vg_lite.h"
|
||||
#include "vg_lite_options.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#define ENUM_TO_STRING(e) \
|
||||
case (e): \
|
||||
return #e
|
||||
|
||||
#if LV_USE_VGLITE_ASSERT
|
||||
#define VGLITE_ASSERT(expr) LV_ASSERT(expr)
|
||||
#else
|
||||
#define VGLITE_ASSERT(expr)
|
||||
#endif
|
||||
|
||||
#define VGLITE_ASSERT_MSG(expr, msg) \
|
||||
do { \
|
||||
if(!(expr)) { \
|
||||
LV_LOG_ERROR(msg); \
|
||||
VGLITE_ASSERT(false); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#if LV_USE_VGLITE_CHECK_ERROR
|
||||
#define VGLITE_CHECK_ERROR(function) \
|
||||
do { \
|
||||
vg_lite_error_t error = function; \
|
||||
if(error != VG_LITE_SUCCESS) { \
|
||||
LV_LOG_ERROR("Execute '" #function "' error(%d): %s", \
|
||||
(int)error, vglite_error_to_string(error)); \
|
||||
VGLITE_ASSERT(false); \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
#define VGLITE_CHECK_ERROR(function) function
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Set the clipping box.
|
||||
*
|
||||
* @param[in] clip_area Clip area with relative coordinates of destination buffer
|
||||
*
|
||||
*/
|
||||
static inline void vglite_set_scissor(const lv_area_t * clip_area);
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
const char * vglite_error_to_string(vg_lite_error_t error);
|
||||
|
||||
#if LV_USE_VGLITE_DRAW_ASYNC
|
||||
/**
|
||||
* Get VG-Lite command buffer flushed status.
|
||||
*
|
||||
*/
|
||||
bool vglite_cmd_buf_is_flushed(void);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Flush command to VG-Lite.
|
||||
*
|
||||
*/
|
||||
void vglite_run(void);
|
||||
|
||||
/**
|
||||
* Wait for VG-Lite finish.
|
||||
*
|
||||
*/
|
||||
#if LV_USE_VGLITE_DRAW_ASYNC
|
||||
void vglite_wait_for_finish(void);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Get vglite color. Premultiplies (if not hw already) and swizzles the given
|
||||
* LVGL 32bit color to obtain vglite color.
|
||||
*
|
||||
* @param[in] lv_col32 The initial LVGL 32bit color
|
||||
* @param[in] gradient True for gradient color
|
||||
*
|
||||
* @retval The vglite 32-bit color value:
|
||||
*
|
||||
*/
|
||||
vg_lite_color_t vglite_get_color(lv_color32_t lv_col32, bool gradient);
|
||||
|
||||
/**
|
||||
* Get vglite blend mode.
|
||||
*
|
||||
* @param[in] lv_blend_mode The LVGL blend mode
|
||||
*
|
||||
* @retval The vglite blend mode
|
||||
*
|
||||
*/
|
||||
vg_lite_blend_t vglite_get_blend_mode(lv_blend_mode_t lv_blend_mode);
|
||||
|
||||
/**
|
||||
* Get vglite buffer format.
|
||||
*
|
||||
* @param[in] cf Color format
|
||||
*
|
||||
* @retval The vglite buffer format
|
||||
*
|
||||
*/
|
||||
vg_lite_buffer_format_t vglite_get_buf_format(lv_color_format_t cf);
|
||||
|
||||
/**
|
||||
* Get vglite stride alignment.
|
||||
*
|
||||
* @param[in] cf Color format
|
||||
*
|
||||
* @retval Alignment requirement in bytes
|
||||
*
|
||||
*/
|
||||
uint8_t vglite_get_stride_alignment(lv_color_format_t cf);
|
||||
|
||||
/**
|
||||
* Check source start address and stride alignment.
|
||||
*
|
||||
* @param[in] buf Buffer address
|
||||
* @param[in] stride Stride of buffer in bytes
|
||||
* @param[in] cf Color format - to calculate the expected alignment
|
||||
*
|
||||
* @retval true Alignment OK
|
||||
*
|
||||
*/
|
||||
bool vglite_src_buf_aligned(const void * buf, uint32_t stride, lv_color_format_t cf);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static inline void vglite_set_scissor(const lv_area_t * clip_area)
|
||||
{
|
||||
vg_lite_set_scissor(clip_area->x1, clip_area->y1, clip_area->x2 + 1, clip_area->y2 + 1);
|
||||
}
|
||||
|
||||
#endif /*LV_USE_DRAW_VGLITE*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_VGLITE_UTILS_H*/
|
||||
@@ -0,0 +1,634 @@
|
||||
/**
|
||||
* @file lv_draw_opengles.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_opengles.h"
|
||||
#if LV_USE_DRAW_OPENGLES
|
||||
#include "../lv_draw_private.h"
|
||||
#include "../../misc/cache/lv_cache_entry_private.h"
|
||||
#include "../../drivers/glfw/lv_opengles_debug.h"
|
||||
#include "../../drivers/glfw/lv_opengles_texture.h"
|
||||
#include "../../drivers/glfw/lv_opengles_driver.h"
|
||||
#include <GL/glew.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
#include "../../draw/lv_draw_label.h"
|
||||
#include "../../draw/lv_draw_rect.h"
|
||||
#include "../../draw/lv_draw_arc.h"
|
||||
#include "../../draw/lv_draw_image.h"
|
||||
#include "../../draw/lv_draw_triangle.h"
|
||||
#include "../../draw/lv_draw_line.h"
|
||||
#include "../../draw/lv_draw_3d.h"
|
||||
#include "../../core/lv_obj.h"
|
||||
#include "../../core/lv_refr_private.h"
|
||||
#include "../../display/lv_display_private.h"
|
||||
#include "../../stdlib/lv_string.h"
|
||||
#include "../../misc/lv_area_private.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#define DRAW_UNIT_ID_OPENGLES 6
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct {
|
||||
lv_draw_unit_t base_unit;
|
||||
lv_draw_task_t * task_act;
|
||||
lv_cache_t * texture_cache;
|
||||
unsigned int framebuffer;
|
||||
lv_draw_buf_t render_draw_buf;
|
||||
} lv_draw_opengles_unit_t;
|
||||
|
||||
typedef struct {
|
||||
lv_draw_dsc_base_t * draw_dsc;
|
||||
int32_t w;
|
||||
int32_t h;
|
||||
unsigned int texture;
|
||||
} cache_data_t;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static bool opengles_texture_cache_create_cb(cache_data_t * cached_data, void * user_data);
|
||||
static void opengles_texture_cache_free_cb(cache_data_t * cached_data, void * user_data);
|
||||
static lv_cache_compare_res_t opengles_texture_cache_compare_cb(const cache_data_t * lhs, const cache_data_t * rhs);
|
||||
|
||||
static void blend_texture_layer(lv_draw_task_t * t);
|
||||
static void draw_from_cached_texture(lv_draw_task_t * t);
|
||||
|
||||
static void execute_drawing(lv_draw_opengles_unit_t * u);
|
||||
|
||||
static int32_t dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer);
|
||||
|
||||
static int32_t evaluate(lv_draw_unit_t * draw_unit, lv_draw_task_t * task);
|
||||
static bool draw_to_texture(lv_draw_opengles_unit_t * u, cache_data_t * cache_data);
|
||||
|
||||
static unsigned int layer_get_texture(lv_layer_t * layer);
|
||||
static unsigned int get_framebuffer(lv_draw_opengles_unit_t * u);
|
||||
static unsigned int create_texture(int32_t w, int32_t h, const void * data);
|
||||
|
||||
#if LV_USE_3DTEXTURE
|
||||
static void lv_draw_opengles_3d(lv_draw_task_t * t, const lv_draw_3d_dsc_t * dsc, const lv_area_t * coords);
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
static lv_draw_opengles_unit_t * g_unit;
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_opengles_init(void)
|
||||
{
|
||||
lv_draw_opengles_unit_t * draw_opengles_unit = lv_draw_create_unit(sizeof(lv_draw_opengles_unit_t));
|
||||
draw_opengles_unit->base_unit.dispatch_cb = dispatch;
|
||||
draw_opengles_unit->base_unit.evaluate_cb = evaluate;
|
||||
draw_opengles_unit->base_unit.name = "OPENGLES";
|
||||
draw_opengles_unit->texture_cache = lv_cache_create(&lv_cache_class_lru_rb_count,
|
||||
sizeof(cache_data_t), 128, (lv_cache_ops_t) {
|
||||
.compare_cb = (lv_cache_compare_cb_t)opengles_texture_cache_compare_cb,
|
||||
.create_cb = (lv_cache_create_cb_t)opengles_texture_cache_create_cb,
|
||||
.free_cb = (lv_cache_free_cb_t)opengles_texture_cache_free_cb,
|
||||
});
|
||||
lv_cache_set_name(draw_opengles_unit->texture_cache, "OPENGLES_TEXTURE");
|
||||
|
||||
lv_draw_buf_init(&draw_opengles_unit->render_draw_buf, 0, 0, LV_COLOR_FORMAT_ARGB8888, LV_STRIDE_AUTO, NULL, 0);
|
||||
|
||||
g_unit = draw_opengles_unit;
|
||||
}
|
||||
|
||||
void lv_draw_opengles_deinit(void)
|
||||
{
|
||||
lv_free(g_unit->render_draw_buf.unaligned_data);
|
||||
lv_cache_destroy(g_unit->texture_cache, g_unit);
|
||||
if(g_unit->framebuffer != 0) {
|
||||
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, 0));
|
||||
GL_CALL(glDeleteFramebuffers(1, &g_unit->framebuffer));
|
||||
}
|
||||
g_unit = NULL;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static bool opengles_texture_cache_create_cb(cache_data_t * cached_data, void * user_data)
|
||||
{
|
||||
return draw_to_texture((lv_draw_opengles_unit_t *)user_data, cached_data);
|
||||
}
|
||||
|
||||
static void opengles_texture_cache_free_cb(cache_data_t * cached_data, void * user_data)
|
||||
{
|
||||
LV_UNUSED(user_data);
|
||||
|
||||
lv_free(cached_data->draw_dsc);
|
||||
GL_CALL(glDeleteTextures(1, &cached_data->texture));
|
||||
cached_data->draw_dsc = NULL;
|
||||
cached_data->texture = 0;
|
||||
}
|
||||
|
||||
static lv_cache_compare_res_t opengles_texture_cache_compare_cb(const cache_data_t * lhs, const cache_data_t * rhs)
|
||||
{
|
||||
if(lhs == rhs) return 0;
|
||||
|
||||
if(lhs->w != rhs->w) {
|
||||
return lhs->w > rhs->w ? 1 : -1;
|
||||
}
|
||||
if(lhs->h != rhs->h) {
|
||||
return lhs->h > rhs->h ? 1 : -1;
|
||||
}
|
||||
|
||||
uint32_t lhs_dsc_size = lhs->draw_dsc->dsc_size;
|
||||
uint32_t rhs_dsc_size = rhs->draw_dsc->dsc_size;
|
||||
|
||||
if(lhs_dsc_size != rhs_dsc_size) {
|
||||
return lhs_dsc_size > rhs_dsc_size ? 1 : -1;
|
||||
}
|
||||
|
||||
const uint8_t * left_draw_dsc = (const uint8_t *)lhs->draw_dsc;
|
||||
const uint8_t * right_draw_dsc = (const uint8_t *)rhs->draw_dsc;
|
||||
left_draw_dsc += sizeof(lv_draw_dsc_base_t);
|
||||
right_draw_dsc += sizeof(lv_draw_dsc_base_t);
|
||||
|
||||
int cmp_res = lv_memcmp(left_draw_dsc, right_draw_dsc, lhs->draw_dsc->dsc_size - sizeof(lv_draw_dsc_base_t));
|
||||
|
||||
if(cmp_res != 0) {
|
||||
return cmp_res > 0 ? 1 : -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer)
|
||||
{
|
||||
lv_draw_opengles_unit_t * draw_opengles_unit = (lv_draw_opengles_unit_t *) draw_unit;
|
||||
|
||||
/*Return immediately if it's busy with a draw task*/
|
||||
if(draw_opengles_unit->task_act) return 0;
|
||||
|
||||
lv_draw_task_t * t = NULL;
|
||||
t = lv_draw_get_available_task(layer, NULL, DRAW_UNIT_ID_OPENGLES);
|
||||
if(t == NULL) return -1;
|
||||
|
||||
unsigned int texture = layer_get_texture(layer);
|
||||
if(texture == 0) {
|
||||
lv_display_t * disp = lv_refr_get_disp_refreshing();
|
||||
if(layer != disp->layer_head) {
|
||||
void * buf = lv_draw_layer_alloc_buf(layer);
|
||||
if(buf == NULL) return -1;
|
||||
|
||||
int32_t w = lv_area_get_width(&layer->buf_area);
|
||||
int32_t h = lv_area_get_height(&layer->buf_area);
|
||||
|
||||
texture = create_texture(w, h, NULL);
|
||||
|
||||
layer->user_data = (void *)(uintptr_t)texture;
|
||||
}
|
||||
else {
|
||||
layer->user_data = (void *)(uintptr_t)lv_opengles_texture_get_texture_id(disp);
|
||||
}
|
||||
}
|
||||
|
||||
t->state = LV_DRAW_TASK_STATE_IN_PROGRESS;
|
||||
draw_opengles_unit->task_act = t;
|
||||
|
||||
execute_drawing(draw_opengles_unit);
|
||||
|
||||
draw_opengles_unit->task_act->state = LV_DRAW_TASK_STATE_READY;
|
||||
draw_opengles_unit->task_act = NULL;
|
||||
|
||||
/*The draw unit is free now. Request a new dispatching as it can get a new task*/
|
||||
lv_draw_dispatch_request();
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int32_t evaluate(lv_draw_unit_t * draw_unit, lv_draw_task_t * task)
|
||||
{
|
||||
LV_UNUSED(draw_unit);
|
||||
|
||||
if(task->type == LV_DRAW_TASK_TYPE_IMAGE &&
|
||||
((lv_draw_image_dsc_t *)task->draw_dsc)->header.cf >= LV_COLOR_FORMAT_PROPRIETARY_START) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*If not refreshing the display probably it's a canvas rendering
|
||||
*which his not supported in OpenGL as it's not a texture.*/
|
||||
if(lv_refr_get_disp_refreshing() == NULL) return 0;
|
||||
|
||||
if(((lv_draw_dsc_base_t *)task->draw_dsc)->user_data == NULL) {
|
||||
task->preference_score = 0;
|
||||
task->preferred_draw_unit_id = DRAW_UNIT_ID_OPENGLES;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool draw_to_texture(lv_draw_opengles_unit_t * u, cache_data_t * cache_data)
|
||||
{
|
||||
lv_draw_task_t * task = u->task_act;
|
||||
|
||||
lv_layer_t dest_layer;
|
||||
lv_layer_init(&dest_layer);
|
||||
|
||||
int32_t texture_w = lv_area_get_width(&task->_real_area);
|
||||
int32_t texture_h = lv_area_get_height(&task->_real_area);
|
||||
|
||||
if(NULL == lv_draw_buf_reshape(&u->render_draw_buf, LV_COLOR_FORMAT_ARGB8888, texture_w, texture_h, LV_STRIDE_AUTO)) {
|
||||
uint8_t * data = u->render_draw_buf.unaligned_data;
|
||||
uint32_t data_size = LV_DRAW_BUF_SIZE(texture_w, texture_h, LV_COLOR_FORMAT_ARGB8888);
|
||||
data = lv_realloc(data, data_size);
|
||||
LV_ASSERT_MALLOC(data);
|
||||
lv_result_t init_result = lv_draw_buf_init(&u->render_draw_buf, texture_w, texture_h, LV_COLOR_FORMAT_ARGB8888,
|
||||
LV_STRIDE_AUTO, data, data_size);
|
||||
LV_ASSERT(init_result == LV_RESULT_OK);
|
||||
}
|
||||
|
||||
dest_layer.draw_buf = &u->render_draw_buf;
|
||||
dest_layer.color_format = LV_COLOR_FORMAT_ARGB8888;
|
||||
|
||||
dest_layer.buf_area = task->_real_area;
|
||||
dest_layer._clip_area = task->_real_area;
|
||||
dest_layer.phy_clip_area = task->_real_area;
|
||||
lv_memzero(u->render_draw_buf.data, lv_area_get_size(&task->_real_area) * 4);
|
||||
|
||||
lv_display_t * disp = lv_refr_get_disp_refreshing();
|
||||
|
||||
lv_obj_t * obj = ((lv_draw_dsc_base_t *)task->draw_dsc)->obj;
|
||||
bool original_send_draw_task_event = false;
|
||||
if(obj) {
|
||||
original_send_draw_task_event = lv_obj_has_flag(obj, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS);
|
||||
lv_obj_remove_flag(obj, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS);
|
||||
}
|
||||
|
||||
lv_draw_dsc_base_t * base_dsc = task->draw_dsc;
|
||||
cache_data->draw_dsc = lv_malloc(base_dsc->dsc_size);
|
||||
lv_memcpy((void *)cache_data->draw_dsc, base_dsc, base_dsc->dsc_size);
|
||||
|
||||
switch(task->type) {
|
||||
case LV_DRAW_TASK_TYPE_FILL: {
|
||||
lv_draw_fill_dsc_t * fill_dsc = task->draw_dsc;
|
||||
lv_draw_rect_dsc_t rect_dsc;
|
||||
lv_draw_rect_dsc_init(&rect_dsc);
|
||||
rect_dsc.base.user_data = (void *)(uintptr_t)1;
|
||||
rect_dsc.bg_color = fill_dsc->color;
|
||||
rect_dsc.bg_grad = fill_dsc->grad;
|
||||
rect_dsc.radius = fill_dsc->radius;
|
||||
rect_dsc.bg_opa = fill_dsc->opa;
|
||||
|
||||
lv_draw_rect(&dest_layer, &rect_dsc, &task->area);
|
||||
}
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_BORDER: {
|
||||
lv_draw_border_dsc_t * border_dsc = task->draw_dsc;
|
||||
lv_draw_rect_dsc_t rect_dsc;
|
||||
lv_draw_rect_dsc_init(&rect_dsc);
|
||||
rect_dsc.base.user_data = (void *)(uintptr_t)1;
|
||||
rect_dsc.bg_opa = LV_OPA_TRANSP;
|
||||
rect_dsc.radius = border_dsc->radius;
|
||||
rect_dsc.border_color = border_dsc->color;
|
||||
rect_dsc.border_opa = border_dsc->opa;
|
||||
rect_dsc.border_side = border_dsc->side;
|
||||
rect_dsc.border_width = border_dsc->width;
|
||||
lv_draw_rect(&dest_layer, &rect_dsc, &task->area);
|
||||
break;
|
||||
}
|
||||
case LV_DRAW_TASK_TYPE_BOX_SHADOW: {
|
||||
lv_draw_box_shadow_dsc_t * box_shadow_dsc = task->draw_dsc;
|
||||
lv_draw_rect_dsc_t rect_dsc;
|
||||
lv_draw_rect_dsc_init(&rect_dsc);
|
||||
rect_dsc.base.user_data = (void *)(uintptr_t)1;
|
||||
rect_dsc.bg_opa = LV_OPA_0;
|
||||
rect_dsc.radius = box_shadow_dsc->radius;
|
||||
rect_dsc.bg_color = box_shadow_dsc->color;
|
||||
rect_dsc.shadow_opa = box_shadow_dsc->opa;
|
||||
rect_dsc.shadow_width = box_shadow_dsc->width;
|
||||
rect_dsc.shadow_spread = box_shadow_dsc->spread;
|
||||
rect_dsc.shadow_offset_x = box_shadow_dsc->ofs_x;
|
||||
rect_dsc.shadow_offset_y = box_shadow_dsc->ofs_y;
|
||||
lv_draw_rect(&dest_layer, &rect_dsc, &task->area);
|
||||
break;
|
||||
}
|
||||
case LV_DRAW_TASK_TYPE_LABEL: {
|
||||
lv_draw_label_dsc_t label_dsc;
|
||||
lv_memcpy(&label_dsc, task->draw_dsc, sizeof(label_dsc));
|
||||
label_dsc.base.user_data = (void *)(uintptr_t)1;
|
||||
lv_draw_label(&dest_layer, &label_dsc, &task->area);
|
||||
}
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_ARC: {
|
||||
lv_draw_arc_dsc_t arc_dsc;
|
||||
lv_memcpy(&arc_dsc, task->draw_dsc, sizeof(arc_dsc));
|
||||
arc_dsc.base.user_data = (void *)(uintptr_t)1;
|
||||
lv_draw_arc(&dest_layer, &arc_dsc);
|
||||
}
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_LINE: {
|
||||
lv_draw_line_dsc_t line_dsc;
|
||||
lv_memcpy(&line_dsc, task->draw_dsc, sizeof(line_dsc));
|
||||
line_dsc.base.user_data = (void *)(uintptr_t)1;
|
||||
lv_draw_line(&dest_layer, &line_dsc);
|
||||
}
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_TRIANGLE: {
|
||||
lv_draw_triangle_dsc_t triangle_dsc;
|
||||
lv_memcpy(&triangle_dsc, task->draw_dsc, sizeof(triangle_dsc));
|
||||
triangle_dsc.base.user_data = (void *)(uintptr_t)1;
|
||||
lv_draw_triangle(&dest_layer, &triangle_dsc);
|
||||
}
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_IMAGE: {
|
||||
lv_draw_image_dsc_t image_dsc;
|
||||
lv_memcpy(&image_dsc, task->draw_dsc, sizeof(image_dsc));
|
||||
image_dsc.base.user_data = (void *)(uintptr_t)1;
|
||||
lv_draw_image(&dest_layer, &image_dsc, &task->area);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
/*The malloced cache_data->draw_dsc will be freed automatically on failure
|
||||
*in opengles_texture_cache_free_cb*/
|
||||
return false;
|
||||
}
|
||||
|
||||
while(dest_layer.draw_task_head) {
|
||||
lv_draw_dispatch_layer(disp, &dest_layer);
|
||||
if(dest_layer.draw_task_head) {
|
||||
lv_draw_dispatch_wait_for_request();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int texture = create_texture(texture_w, texture_h, u->render_draw_buf.data);
|
||||
|
||||
cache_data->w = texture_w;
|
||||
cache_data->h = texture_h;
|
||||
cache_data->texture = texture;
|
||||
|
||||
if(obj) {
|
||||
lv_obj_set_flag(obj, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS, original_send_draw_task_event);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void blend_texture_layer(lv_draw_task_t * t)
|
||||
{
|
||||
lv_draw_image_dsc_t * draw_dsc = t->draw_dsc;
|
||||
lv_draw_opengles_unit_t * u = (lv_draw_opengles_unit_t *)t->draw_unit;
|
||||
lv_area_t area;
|
||||
area.x1 = -draw_dsc->pivot.x;
|
||||
area.y1 = -draw_dsc->pivot.y;
|
||||
area.x1 = (area.x1 * draw_dsc->scale_x) / 256;
|
||||
area.y1 = (area.y1 * draw_dsc->scale_y) / 256;
|
||||
area.x1 += t->area.x1 + draw_dsc->pivot.x;
|
||||
area.y1 += t->area.y1 + draw_dsc->pivot.y;
|
||||
lv_area_set_width(&area, lv_area_get_width(&t->area) * draw_dsc->scale_x / 256);
|
||||
lv_area_set_height(&area, lv_area_get_height(&t->area) * draw_dsc->scale_y / 256);
|
||||
|
||||
lv_layer_t * src_layer = (lv_layer_t *)draw_dsc->src;
|
||||
unsigned int src_texture = layer_get_texture(src_layer);
|
||||
|
||||
|
||||
lv_layer_t * dest_layer = t->target_layer;
|
||||
unsigned int target_texture = layer_get_texture(dest_layer);
|
||||
LV_ASSERT(target_texture != 0);
|
||||
int32_t targ_tex_w = lv_area_get_width(&dest_layer->buf_area);
|
||||
int32_t targ_tex_h = lv_area_get_height(&dest_layer->buf_area);
|
||||
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_2D, target_texture));
|
||||
|
||||
unsigned int framebuffer = get_framebuffer(u);
|
||||
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, framebuffer));
|
||||
GL_CALL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, target_texture, 0));
|
||||
|
||||
lv_opengles_viewport(0, 0, targ_tex_w, targ_tex_h);
|
||||
// TODO rotation
|
||||
lv_opengles_render_texture(src_texture, &area, draw_dsc->opa, targ_tex_w, targ_tex_h, &t->clip_area, false);
|
||||
|
||||
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, 0));
|
||||
|
||||
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_2D, 0));
|
||||
GL_CALL(glDeleteTextures(1, &src_texture));
|
||||
}
|
||||
|
||||
static void draw_from_cached_texture(lv_draw_task_t * t)
|
||||
{
|
||||
lv_draw_opengles_unit_t * u = (lv_draw_opengles_unit_t *)t->draw_unit;
|
||||
cache_data_t data_to_find;
|
||||
data_to_find.draw_dsc = (lv_draw_dsc_base_t *)t->draw_dsc;
|
||||
|
||||
data_to_find.w = lv_area_get_width(&t->_real_area);
|
||||
data_to_find.h = lv_area_get_height(&t->_real_area);
|
||||
data_to_find.texture = 0;
|
||||
|
||||
/*user_data stores the renderer to differentiate it from SW rendered tasks.
|
||||
*However the cached texture is independent from the renderer so use NULL user_data*/
|
||||
void * user_data_saved = data_to_find.draw_dsc->user_data;
|
||||
data_to_find.draw_dsc->user_data = NULL;
|
||||
|
||||
/*img_dsc->image_area is an absolute coordinate so it's different
|
||||
*for the same image on a different position. So make it relative before using for cache. */
|
||||
lv_area_t a = t->area;
|
||||
if(t->type == LV_DRAW_TASK_TYPE_IMAGE) {
|
||||
lv_draw_image_dsc_t * img_dsc = (lv_draw_image_dsc_t *)data_to_find.draw_dsc;
|
||||
lv_area_move(&img_dsc->image_area, -t->area.x1, -t->area.y1);
|
||||
}
|
||||
else if(t->type == LV_DRAW_TASK_TYPE_TRIANGLE) {
|
||||
lv_draw_triangle_dsc_t * tri_dsc = (lv_draw_triangle_dsc_t *)data_to_find.draw_dsc;
|
||||
tri_dsc->p[0].x -= t->area.x1;
|
||||
tri_dsc->p[0].y -= t->area.y1;
|
||||
tri_dsc->p[1].x -= t->area.x1;
|
||||
tri_dsc->p[1].y -= t->area.y1;
|
||||
tri_dsc->p[2].x -= t->area.x1;
|
||||
tri_dsc->p[2].y -= t->area.y1;
|
||||
}
|
||||
else if(t->type == LV_DRAW_TASK_TYPE_LINE) {
|
||||
lv_draw_line_dsc_t * line_dsc = (lv_draw_line_dsc_t *)data_to_find.draw_dsc;
|
||||
line_dsc->p1.x -= t->area.x1;
|
||||
line_dsc->p1.y -= t->area.y1;
|
||||
line_dsc->p2.x -= t->area.x1;
|
||||
line_dsc->p2.y -= t->area.y1;
|
||||
}
|
||||
else if(t->type == LV_DRAW_TASK_TYPE_ARC) {
|
||||
lv_draw_arc_dsc_t * arc_dsc = (lv_draw_arc_dsc_t *)data_to_find.draw_dsc;
|
||||
arc_dsc->center.x -= t->area.x1;
|
||||
arc_dsc->center.y -= t->area.y1;
|
||||
}
|
||||
|
||||
lv_area_move(&t->area, -a.x1, -a.y1);
|
||||
lv_area_move(&t->_real_area, -a.x1, -a.y1);
|
||||
|
||||
lv_cache_entry_t * entry_cached = lv_cache_acquire_or_create(u->texture_cache, &data_to_find, u);
|
||||
|
||||
lv_area_move(&t->area, a.x1, a.y1);
|
||||
lv_area_move(&t->_real_area, a.x1, a.y1);
|
||||
|
||||
if(!entry_cached) {
|
||||
return;
|
||||
}
|
||||
|
||||
data_to_find.draw_dsc->user_data = user_data_saved;
|
||||
|
||||
cache_data_t * data_cached = lv_cache_entry_get_data(entry_cached);
|
||||
unsigned int texture = data_cached->texture;
|
||||
|
||||
lv_layer_t * dest_layer = t->target_layer;
|
||||
|
||||
unsigned int target_texture = layer_get_texture(dest_layer);
|
||||
LV_ASSERT(target_texture != 0);
|
||||
int32_t targ_tex_w = lv_area_get_width(&dest_layer->buf_area);
|
||||
int32_t targ_tex_h = lv_area_get_height(&dest_layer->buf_area);
|
||||
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_2D, target_texture));
|
||||
|
||||
unsigned int framebuffer = get_framebuffer(u);
|
||||
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, framebuffer));
|
||||
GL_CALL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, target_texture, 0));
|
||||
|
||||
lv_opengles_viewport(0, 0, targ_tex_w, targ_tex_h);
|
||||
lv_area_move(&t->clip_area, -dest_layer->buf_area.x1, -dest_layer->buf_area.y1);
|
||||
lv_area_t render_area = t->_real_area;
|
||||
lv_area_move(&render_area, -dest_layer->buf_area.x1, -dest_layer->buf_area.y1);
|
||||
lv_opengles_render_texture(texture, &render_area, 0xff, targ_tex_w, targ_tex_h, &t->clip_area, true);
|
||||
|
||||
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, 0));
|
||||
|
||||
lv_cache_release(u->texture_cache, entry_cached, u);
|
||||
|
||||
/*Do not cache non static (const) texts as the text's pointer can be freed/reallocated
|
||||
*at any time resulting in a wild pointer in the cached draw dsc. */
|
||||
if(t->type == LV_DRAW_TASK_TYPE_LABEL) {
|
||||
lv_draw_label_dsc_t * label_dsc = t->draw_dsc;
|
||||
if(!label_dsc->text_static) {
|
||||
lv_cache_drop(u->texture_cache, &data_to_find, u);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void execute_drawing(lv_draw_opengles_unit_t * u)
|
||||
{
|
||||
lv_draw_task_t * t = u->task_act;
|
||||
t->draw_unit = (lv_draw_unit_t *)u;
|
||||
|
||||
if(t->type == LV_DRAW_TASK_TYPE_FILL) {
|
||||
lv_draw_fill_dsc_t * fill_dsc = t->draw_dsc;
|
||||
if(fill_dsc->radius == 0 && fill_dsc->grad.dir == LV_GRAD_DIR_NONE) {
|
||||
lv_layer_t * layer = t->target_layer;
|
||||
lv_area_t fill_area = t->area;
|
||||
lv_area_intersect(&fill_area, &fill_area, &t->clip_area);
|
||||
lv_area_move(&fill_area, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
unsigned int target_texture = layer_get_texture(layer);
|
||||
LV_ASSERT(target_texture != 0);
|
||||
int32_t targ_tex_w = lv_area_get_width(&layer->buf_area);
|
||||
int32_t targ_tex_h = lv_area_get_height(&layer->buf_area);
|
||||
|
||||
unsigned int framebuffer = get_framebuffer(u);
|
||||
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, framebuffer));
|
||||
GL_CALL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, target_texture, 0));
|
||||
|
||||
lv_opengles_viewport(0, 0, targ_tex_w, targ_tex_h);
|
||||
lv_opengles_render_fill(fill_dsc->color, &fill_area, fill_dsc->opa, targ_tex_w, targ_tex_h);
|
||||
|
||||
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, 0));
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(t->type == LV_DRAW_TASK_TYPE_LAYER) {
|
||||
blend_texture_layer(t);
|
||||
return;
|
||||
}
|
||||
|
||||
#if LV_USE_3DTEXTURE
|
||||
if(t->type == LV_DRAW_TASK_TYPE_3D) {
|
||||
lv_draw_opengles_3d(t, t->draw_dsc, &t->area);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
draw_from_cached_texture(t);
|
||||
}
|
||||
|
||||
static unsigned int layer_get_texture(lv_layer_t * layer)
|
||||
{
|
||||
return (unsigned int)(uintptr_t)layer->user_data;
|
||||
}
|
||||
|
||||
static unsigned int get_framebuffer(lv_draw_opengles_unit_t * u)
|
||||
{
|
||||
if(u->framebuffer == 0) {
|
||||
GL_CALL(glGenFramebuffers(1, &u->framebuffer));
|
||||
}
|
||||
return u->framebuffer;
|
||||
}
|
||||
|
||||
static unsigned int create_texture(int32_t w, int32_t h, const void * data)
|
||||
{
|
||||
unsigned int texture;
|
||||
|
||||
GL_CALL(glGenTextures(1, &texture));
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_2D, texture));
|
||||
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
|
||||
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
|
||||
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
|
||||
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
|
||||
GL_CALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
|
||||
|
||||
/* LV_COLOR_DEPTH 32, 24, 16 are supported but the cached textures will always
|
||||
* have full ARGB pixels since the alpha channel is required for blending.
|
||||
*/
|
||||
GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, data));
|
||||
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 20);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
#if LV_USE_3DTEXTURE
|
||||
static void lv_draw_opengles_3d(lv_draw_task_t * t, const lv_draw_3d_dsc_t * dsc, const lv_area_t * coords)
|
||||
{
|
||||
lv_draw_opengles_unit_t * u = (lv_draw_opengles_unit_t *) t->draw_unit;
|
||||
|
||||
lv_layer_t * dest_layer = t->target_layer;
|
||||
unsigned int target_texture = layer_get_texture(dest_layer);
|
||||
LV_ASSERT(target_texture != 0);
|
||||
int32_t targ_tex_w = lv_area_get_width(&dest_layer->buf_area);
|
||||
int32_t targ_tex_h = lv_area_get_height(&dest_layer->buf_area);
|
||||
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_2D, target_texture));
|
||||
|
||||
unsigned int framebuffer = get_framebuffer(u);
|
||||
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, framebuffer));
|
||||
GL_CALL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, target_texture, 0));
|
||||
|
||||
lv_opengles_viewport(0, 0, targ_tex_w, targ_tex_h);
|
||||
lv_area_t clip_area = t->clip_area;
|
||||
lv_area_move(&clip_area, -dest_layer->buf_area.x1, -dest_layer->buf_area.y1);
|
||||
|
||||
lv_opengles_render_texture(dsc->tex_id, coords, dsc->opa, targ_tex_w, targ_tex_h, &clip_area, true);
|
||||
|
||||
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, 0));
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_2D, 0));
|
||||
}
|
||||
#endif /*LV_USE_3DTEXTURE*/
|
||||
|
||||
#endif /*LV_USE_DRAW_OPENGLES*/
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* @file lv_draw_opengles.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_OPENGLES_H
|
||||
#define LV_DRAW_OPENGLES_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../lv_conf_internal.h"
|
||||
#if LV_USE_DRAW_OPENGLES
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
void lv_draw_opengles_init(void);
|
||||
void lv_draw_opengles_deinit(void);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_DRAW_OPENGLES*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_OPENGLES_H*/
|
||||
@@ -0,0 +1,616 @@
|
||||
/**
|
||||
* @file lv_draw_dave2d.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_dave2d.h"
|
||||
#if LV_USE_DRAW_DAVE2D
|
||||
#include "../../lv_draw_buf_private.h"
|
||||
#include "../../../misc/lv_area_private.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define DRAW_UNIT_ID_DAVE2D 4
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
#if LV_USE_OS
|
||||
static void _dave2d_render_thread_cb(void * ptr);
|
||||
#endif
|
||||
|
||||
static void execute_drawing(lv_draw_dave2d_unit_t * u);
|
||||
|
||||
#if defined(RENESAS_CORTEX_M85)
|
||||
#if (BSP_CFG_DCACHE_ENABLED)
|
||||
static void _dave2d_buf_invalidate_cache_cb(const lv_draw_buf_t * draw_buf, const lv_area_t * area);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static int32_t _dave2d_evaluate(lv_draw_unit_t * draw_unit, lv_draw_task_t * task);
|
||||
|
||||
static int32_t lv_draw_dave2d_dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer);
|
||||
|
||||
static d2_s32 lv_dave2d_init(void);
|
||||
|
||||
static void lv_draw_buf_dave2d_init_handlers(void);
|
||||
|
||||
void dave2d_execute_dlist_and_flush(void);
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
d2_device * _d2_handle;
|
||||
d2_renderbuffer * _renderbuffer;
|
||||
d2_renderbuffer * _blit_renderbuffer;
|
||||
|
||||
lv_ll_t _ll_Dave2D_Tasks;
|
||||
|
||||
#if LV_USE_OS
|
||||
lv_mutex_t xd2Semaphore;
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_dave2d_init(void)
|
||||
{
|
||||
d2_s32 result = D2_OK;
|
||||
|
||||
lv_draw_buf_dave2d_init_handlers();
|
||||
|
||||
lv_draw_dave2d_unit_t * draw_dave2d_unit = lv_draw_create_unit(sizeof(lv_draw_dave2d_unit_t));
|
||||
draw_dave2d_unit->base_unit.dispatch_cb = lv_draw_dave2d_dispatch;
|
||||
draw_dave2d_unit->base_unit.evaluate_cb = _dave2d_evaluate;
|
||||
draw_dave2d_unit->base_unit.name = "DAVE2D";
|
||||
draw_dave2d_unit->idx = DRAW_UNIT_ID_DAVE2D;
|
||||
|
||||
result = lv_dave2d_init();
|
||||
LV_ASSERT(D2_OK == result);
|
||||
|
||||
#if LV_USE_OS
|
||||
lv_result_t res;
|
||||
res = lv_mutex_init(&xd2Semaphore);
|
||||
LV_ASSERT(LV_RESULT_OK == res);
|
||||
|
||||
draw_dave2d_unit->pd2Mutex = &xd2Semaphore;
|
||||
#endif
|
||||
|
||||
draw_dave2d_unit->d2_handle = _d2_handle;
|
||||
draw_dave2d_unit->renderbuffer = _renderbuffer;
|
||||
lv_ll_init(&_ll_Dave2D_Tasks, 4);
|
||||
|
||||
#if LV_USE_OS
|
||||
lv_thread_init(&draw_dave2d_unit->thread, "dave2d", LV_DRAW_THREAD_PRIO, _dave2d_render_thread_cb, 8 * 1024,
|
||||
draw_dave2d_unit);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void lv_draw_buf_dave2d_init_handlers(void)
|
||||
{
|
||||
|
||||
#if defined(RENESAS_CORTEX_M85)
|
||||
#if (BSP_CFG_DCACHE_ENABLED)
|
||||
lv_draw_buf_handlers_t * handlers = lv_draw_buf_get_handlers();
|
||||
handlers->invalidate_cache_cb = _dave2d_buf_invalidate_cache_cb;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(RENESAS_CORTEX_M85)
|
||||
#if (BSP_CFG_DCACHE_ENABLED)
|
||||
static void _dave2d_buf_invalidate_cache_cb(const lv_draw_buf_t * draw_buf, const lv_area_t * area)
|
||||
{
|
||||
const lv_image_header_t * header = &draw_buf->header;
|
||||
uint32_t stride = header->stride;
|
||||
lv_color_format_t cf = header->cf;
|
||||
|
||||
uint8_t * address = draw_buf->data;
|
||||
int32_t i = 0;
|
||||
uint32_t bytes_per_pixel = lv_color_format_get_size(cf);
|
||||
int32_t width = lv_area_get_width(area);
|
||||
int32_t lines = lv_area_get_height(area);
|
||||
int32_t bytes_to_flush_per_line = (int32_t)width * (int32_t)bytes_per_pixel;
|
||||
|
||||
/* Stride is in bytes, not pixels */
|
||||
address = address + (area->x1 * (int32_t)bytes_per_pixel) + (stride * (uint32_t)area->y1);
|
||||
|
||||
for(i = 0; i < lines; i++) {
|
||||
SCB_CleanInvalidateDCache_by_Addr(address, bytes_to_flush_per_line);
|
||||
address += stride;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @todo
|
||||
* LVGL needs to use hardware acceleration for buf_copy and do not affect GPU rendering.
|
||||
*/
|
||||
#if 0
|
||||
static void _dave2d_buf_copy(void * dest_buf, uint32_t dest_w, uint32_t dest_h, const lv_area_t * dest_area,
|
||||
void * src_buf, uint32_t src_w, uint32_t src_h, const lv_area_t * src_area, lv_color_format_t color_format)
|
||||
{
|
||||
d2_s32 result;
|
||||
|
||||
#if LV_USE_OS
|
||||
lv_result_t status;
|
||||
|
||||
status = lv_mutex_lock(&xd2Semaphore);
|
||||
LV_ASSERT(LV_RESULT_OK == status);
|
||||
#endif
|
||||
|
||||
d2_u32 src_blend_mode = d2_getblendmodesrc(_d2_handle);
|
||||
d2_u32 dst_blend_mode = d2_getblendmodedst(_d2_handle);
|
||||
|
||||
result = d2_selectrenderbuffer(_d2_handle, _blit_renderbuffer);
|
||||
LV_ASSERT(D2_OK == result);
|
||||
|
||||
result = d2_setblendmode(_d2_handle, d2_bm_one, d2_bm_zero);
|
||||
LV_ASSERT(D2_OK == result);
|
||||
|
||||
// Generate render operations
|
||||
result = d2_framebuffer(_d2_handle, (uint16_t *)dest_buf, DISPLAY_HSIZE_INPUT0, DISPLAY_BUFFER_STRIDE_PIXELS_INPUT0,
|
||||
DISPLAY_VSIZE_INPUT0, lv_draw_dave2d_cf_fb_get());
|
||||
LV_ASSERT(D2_OK == result);
|
||||
|
||||
result = d2_cliprect(_d2_handle, (d2_border)dest_area->x1, (d2_border)dest_area->y1, (d2_border)dest_area->x2,
|
||||
(d2_border)dest_area->y2);
|
||||
LV_ASSERT(D2_OK == result);
|
||||
|
||||
result = d2_setblitsrc(_d2_handle, (void *) src_buf, (d2_s32)src_w, (d2_s32)src_w, (d2_s32)src_h,
|
||||
lv_draw_dave2d_lv_colour_fmt_to_d2_fmt(color_format));
|
||||
LV_ASSERT(D2_OK == result);
|
||||
|
||||
result = d2_blitcopy(_d2_handle, (d2_s32)src_w, (d2_s32)src_h, (d2_blitpos)src_area->x1, (d2_blitpos)src_area->y1,
|
||||
D2_FIX4(dest_w), D2_FIX4(dest_h),
|
||||
D2_FIX4(dest_area->x1), D2_FIX4(dest_area->y1), 0);
|
||||
LV_ASSERT(D2_OK == result);
|
||||
|
||||
// Execute render operations
|
||||
result = d2_executerenderbuffer(_d2_handle, _blit_renderbuffer, 0);
|
||||
LV_ASSERT(D2_OK == result) ;
|
||||
|
||||
result = d2_flushframe(_d2_handle);
|
||||
LV_ASSERT(D2_OK == result);
|
||||
|
||||
result = d2_selectrenderbuffer(_d2_handle, _renderbuffer);
|
||||
LV_ASSERT(D2_OK == result);
|
||||
|
||||
result = d2_setblendmode(_d2_handle, src_blend_mode, dst_blend_mode);
|
||||
LV_ASSERT(D2_OK != result);
|
||||
|
||||
#if LV_USE_OS
|
||||
status = lv_mutex_unlock(&xd2Semaphore);
|
||||
LV_ASSERT(LV_RESULT_OK == status);
|
||||
#endif
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
#define USE_D2 (1)
|
||||
|
||||
static int32_t _dave2d_evaluate(lv_draw_unit_t * u, lv_draw_task_t * t)
|
||||
{
|
||||
LV_UNUSED(u);
|
||||
int32_t ret = 0;
|
||||
|
||||
lv_draw_dsc_base_t * draw_dsc_base = (lv_draw_dsc_base_t *) t->draw_dsc;
|
||||
|
||||
if(!lv_draw_dave2d_is_dest_cf_supported(draw_dsc_base->layer->color_format))
|
||||
return 0;
|
||||
|
||||
switch(t->type) {
|
||||
case LV_DRAW_TASK_TYPE_FILL: {
|
||||
#if USE_D2
|
||||
lv_draw_fill_dsc_t * dsc = t->draw_dsc;
|
||||
if(dsc->grad.dir == LV_GRAD_DIR_NONE
|
||||
|| ((dsc->grad.dir != LV_GRAD_DIR_NONE)
|
||||
&& ((dsc->grad.stops[0].color.blue == dsc->grad.stops[dsc->grad.stops_count - 1].color.blue)
|
||||
&& (dsc->grad.stops[0].color.red == dsc->grad.stops[dsc->grad.stops_count - 1].color.red)
|
||||
&& (dsc->grad.stops[0].color.green == dsc->grad.stops[dsc->grad.stops_count - 1].color.green)))) {
|
||||
|
||||
t->preferred_draw_unit_id = DRAW_UNIT_ID_DAVE2D;
|
||||
t->preference_score = 0;
|
||||
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
}
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
case LV_DRAW_TASK_TYPE_LAYER: {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case LV_DRAW_TASK_TYPE_IMAGE: {
|
||||
lv_draw_image_dsc_t * dsc = t->draw_dsc;
|
||||
if((dsc->header.cf >= LV_COLOR_FORMAT_PROPRIETARY_START) || (dsc->header.cf == LV_COLOR_FORMAT_RGB888) ||
|
||||
(dsc->header.cf == LV_COLOR_FORMAT_RGB565A8)) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
#if USE_D2
|
||||
t->preferred_draw_unit_id = DRAW_UNIT_ID_DAVE2D;
|
||||
t->preference_score = 0;
|
||||
#endif
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case LV_DRAW_TASK_TYPE_BORDER: {
|
||||
#if USE_D2
|
||||
t->preferred_draw_unit_id = DRAW_UNIT_ID_DAVE2D;
|
||||
t->preference_score = 0;
|
||||
#endif
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case LV_DRAW_TASK_TYPE_BOX_SHADOW: {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case LV_DRAW_TASK_TYPE_LABEL: {
|
||||
#if USE_D2
|
||||
t->preferred_draw_unit_id = DRAW_UNIT_ID_DAVE2D;
|
||||
t->preference_score = 0;
|
||||
#endif
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case LV_DRAW_TASK_TYPE_LINE: {
|
||||
#if USE_D2
|
||||
t->preferred_draw_unit_id = DRAW_UNIT_ID_DAVE2D;
|
||||
t->preference_score = 0;
|
||||
#endif
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case LV_DRAW_TASK_TYPE_ARC: {
|
||||
#if USE_D2
|
||||
t->preferred_draw_unit_id = DRAW_UNIT_ID_DAVE2D;
|
||||
t->preference_score = 0;
|
||||
#endif
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case LV_DRAW_TASK_TYPE_TRIANGLE: {
|
||||
#if USE_D2
|
||||
lv_draw_fill_dsc_t * dsc = t->draw_dsc;
|
||||
if(dsc->grad.dir == LV_GRAD_DIR_NONE
|
||||
|| ((dsc->grad.dir != LV_GRAD_DIR_NONE)
|
||||
&& ((dsc->grad.stops[0].color.blue == dsc->grad.stops[dsc->grad.stops_count - 1].color.blue)
|
||||
&& (dsc->grad.stops[0].color.red == dsc->grad.stops[dsc->grad.stops_count - 1].color.red)
|
||||
&& (dsc->grad.stops[0].color.green == dsc->grad.stops[dsc->grad.stops_count - 1].color.green)))) {
|
||||
t->preferred_draw_unit_id = DRAW_UNIT_ID_DAVE2D;
|
||||
t->preference_score = 0;
|
||||
}
|
||||
else {
|
||||
}
|
||||
#endif
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case LV_DRAW_TASK_TYPE_MASK_RECTANGLE: {
|
||||
#if 0//USE_D2
|
||||
t->preferred_draw_unit_id = DRAW_UNIT_ID_DAVE2D;
|
||||
t->preference_score = 0;
|
||||
#endif
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case LV_DRAW_TASK_TYPE_MASK_BITMAP: {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define DAVE2D_REFERRING_WATERMARK 10
|
||||
|
||||
static int32_t lv_draw_dave2d_dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer)
|
||||
{
|
||||
lv_draw_dave2d_unit_t * draw_dave2d_unit = (lv_draw_dave2d_unit_t *) draw_unit;
|
||||
#if (0 == D2_RENDER_EACH_OPERATION)
|
||||
static uint32_t ref_count = 0;
|
||||
#endif
|
||||
|
||||
/*Return immediately if it's busy with draw task*/
|
||||
if(draw_dave2d_unit->task_act) return 0;
|
||||
|
||||
lv_draw_task_t * t = NULL;
|
||||
t = lv_draw_get_available_task(layer, NULL, DRAW_UNIT_ID_DAVE2D);
|
||||
while(t && t->preferred_draw_unit_id != DRAW_UNIT_ID_DAVE2D) {
|
||||
t->state = LV_DRAW_TASK_STATE_READY;
|
||||
t = lv_draw_get_available_task(layer, NULL, DRAW_UNIT_ID_DAVE2D);
|
||||
}
|
||||
|
||||
if(t == NULL) {
|
||||
#if (0 == D2_RENDER_EACH_OPERATION)
|
||||
if(false == lv_ll_is_empty(&_ll_Dave2D_Tasks)) {
|
||||
ref_count = 0;
|
||||
dave2d_execute_dlist_and_flush();
|
||||
}
|
||||
#endif
|
||||
return LV_DRAW_UNIT_IDLE; /*Couldn't start rendering*/
|
||||
}
|
||||
|
||||
/* Return if target buffer format is not supported. */
|
||||
if(!lv_draw_dave2d_is_dest_cf_supported(layer->color_format)) {
|
||||
return LV_DRAW_UNIT_IDLE; /*Couldn't start rendering*/
|
||||
}
|
||||
|
||||
void * buf = lv_draw_layer_alloc_buf(layer);
|
||||
if(buf == NULL) {
|
||||
return LV_DRAW_UNIT_IDLE; /*Couldn't start rendering*/
|
||||
}
|
||||
|
||||
#if (0 == D2_RENDER_EACH_OPERATION)
|
||||
ref_count += lv_draw_get_dependent_count(t);
|
||||
|
||||
if(DAVE2D_REFERRING_WATERMARK < ref_count) {
|
||||
ref_count = 0;
|
||||
dave2d_execute_dlist_and_flush();
|
||||
}
|
||||
|
||||
lv_draw_task_t ** p_new_list_entry;
|
||||
p_new_list_entry = lv_ll_ins_tail(&_ll_Dave2D_Tasks);
|
||||
*p_new_list_entry = t;
|
||||
#endif
|
||||
|
||||
t->state = LV_DRAW_TASK_STATE_IN_PROGRESS;
|
||||
draw_dave2d_unit->task_act = t;
|
||||
|
||||
#if LV_USE_OS
|
||||
/*Let the render thread work*/
|
||||
lv_thread_sync_signal(&draw_dave2d_unit->sync);
|
||||
#else
|
||||
execute_drawing(draw_dave2d_unit);
|
||||
#if (D2_RENDER_EACH_OPERATION)
|
||||
draw_dave2d_unit->task_act->state = LV_DRAW_TASK_STATE_READY;
|
||||
#endif
|
||||
draw_dave2d_unit->task_act = NULL;
|
||||
|
||||
/*The draw unit is free now. Request a new dispatching as it can get a new task*/
|
||||
lv_draw_dispatch_request();
|
||||
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if LV_USE_OS
|
||||
static void _dave2d_render_thread_cb(void * ptr)
|
||||
{
|
||||
lv_draw_dave2d_unit_t * u = ptr;
|
||||
|
||||
lv_thread_sync_init(&u->sync);
|
||||
|
||||
while(1) {
|
||||
while(u->task_act == NULL) {
|
||||
lv_thread_sync_wait(&u->sync);
|
||||
}
|
||||
|
||||
execute_drawing(u);
|
||||
|
||||
/*Cleanup*/
|
||||
#if (D2_RENDER_EACH_OPERATION)
|
||||
u->task_act->state = LV_DRAW_TASK_STATE_READY;
|
||||
#endif
|
||||
u->task_act = NULL;
|
||||
|
||||
/*The draw unit is free now. Request a new dispatching as it can get a new task*/
|
||||
lv_draw_dispatch_request();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void execute_drawing(lv_draw_dave2d_unit_t * u)
|
||||
{
|
||||
/*Render the draw task*/
|
||||
lv_draw_task_t * t = u->task_act;
|
||||
|
||||
/* remember draw unit for access to unit's context */
|
||||
t->draw_unit = (lv_draw_unit_t *)u;
|
||||
|
||||
#if defined(RENESAS_CORTEX_M85)
|
||||
#if (BSP_CFG_DCACHE_ENABLED)
|
||||
lv_layer_t * layer = t->target_layer;
|
||||
lv_area_t clipped_area;
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
|
||||
lv_area_intersect(&clipped_area, &t->area, &t->clip_area);
|
||||
|
||||
x = 0 - t->target_layer->buf_area.x1;
|
||||
y = 0 - t->target_layer->buf_area.y1;
|
||||
|
||||
lv_area_move(&clipped_area, x, y);
|
||||
|
||||
/* Invalidate cache */
|
||||
lv_draw_buf_invalidate_cache(layer->draw_buf, &clipped_area);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
switch(t->type) {
|
||||
case LV_DRAW_TASK_TYPE_FILL:
|
||||
lv_draw_dave2d_fill(t, t->draw_dsc, &t->area);
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_BORDER:
|
||||
lv_draw_dave2d_border(t, t->draw_dsc, &t->area);
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_BOX_SHADOW:
|
||||
//lv_draw_dave2d_box_shadow(t, t->draw_dsc, &t->area);
|
||||
break;
|
||||
#if 0
|
||||
case LV_DRAW_TASK_TYPE_BG_IMG:
|
||||
//lv_draw_dave2d_bg_image(t, t->draw_dsc, &t->area);
|
||||
break;
|
||||
#endif
|
||||
case LV_DRAW_TASK_TYPE_LABEL:
|
||||
lv_draw_dave2d_label(t, t->draw_dsc, &t->area);
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_IMAGE:
|
||||
lv_draw_dave2d_image(t, t->draw_dsc, &t->area);
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_LINE:
|
||||
lv_draw_dave2d_line(t, t->draw_dsc);
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_ARC:
|
||||
lv_draw_dave2d_arc(t, t->draw_dsc, &t->area);
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_TRIANGLE:
|
||||
lv_draw_dave2d_triangle(t, t->draw_dsc);
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_LAYER:
|
||||
//lv_draw_dave2d_layer(t, t->draw_dsc, &t->area);
|
||||
break;
|
||||
case LV_DRAW_TASK_TYPE_MASK_RECTANGLE:
|
||||
//lv_draw_dave2d_mask_rect(t, t->draw_dsc, &t->area);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static d2_s32 lv_dave2d_init(void)
|
||||
{
|
||||
d2_s32 result = D2_OK;
|
||||
|
||||
if(_d2_handle != NULL) {
|
||||
return D2_NOMEMORY;
|
||||
}
|
||||
|
||||
_d2_handle = d2_opendevice(0);
|
||||
if(_d2_handle == NULL) {
|
||||
return D2_NOMEMORY;
|
||||
}
|
||||
|
||||
/* bind the hardware */
|
||||
result = d2_inithw(_d2_handle, 0);
|
||||
if(result != D2_OK) {
|
||||
LV_LOG_ERROR("Could NOT d2_inithw");
|
||||
d2_closedevice(_d2_handle);
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
// Set various D2 parameters
|
||||
//
|
||||
result = d2_setblendmode(_d2_handle, d2_bm_alpha, d2_bm_one_minus_alpha);
|
||||
result = d2_setalphamode(_d2_handle, d2_am_constant);
|
||||
result = d2_setalpha(_d2_handle, UINT8_MAX);
|
||||
result = d2_setantialiasing(_d2_handle, 1);
|
||||
result = d2_setlinecap(_d2_handle, d2_lc_butt);
|
||||
result = d2_setlinejoin(_d2_handle, d2_lj_miter);
|
||||
|
||||
/* set blocksize for default displaylist */
|
||||
result = d2_setdlistblocksize(_d2_handle, 25);
|
||||
if(D2_OK != result) {
|
||||
LV_LOG_ERROR("Could NOT d2_setdlistblocksize");
|
||||
d2_closedevice(_d2_handle);
|
||||
return result;
|
||||
}
|
||||
|
||||
_blit_renderbuffer = d2_newrenderbuffer(_d2_handle, 20, 20);
|
||||
if(!_blit_renderbuffer) {
|
||||
LV_LOG_ERROR("NO renderbuffer");
|
||||
d2_closedevice(_d2_handle);
|
||||
|
||||
return D2_NOMEMORY;
|
||||
}
|
||||
|
||||
_renderbuffer = d2_newrenderbuffer(_d2_handle, 20, 20);
|
||||
if(!_renderbuffer) {
|
||||
LV_LOG_ERROR("NO renderbuffer");
|
||||
d2_closedevice(_d2_handle);
|
||||
|
||||
return D2_NOMEMORY;
|
||||
}
|
||||
|
||||
result = d2_selectrenderbuffer(_d2_handle, _renderbuffer);
|
||||
if(D2_OK != result) {
|
||||
LV_LOG_ERROR("Could NOT d2_selectrenderbuffer");
|
||||
d2_closedevice(_d2_handle);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void dave2d_execute_dlist_and_flush(void)
|
||||
{
|
||||
#if LV_USE_OS
|
||||
lv_result_t status;
|
||||
|
||||
status = lv_mutex_lock(&xd2Semaphore);
|
||||
LV_ASSERT(LV_RESULT_OK == status);
|
||||
#endif
|
||||
|
||||
d2_s32 result;
|
||||
lv_draw_task_t ** p_list_entry;
|
||||
lv_draw_task_t * p_list_entry1;
|
||||
|
||||
// Execute render operations
|
||||
result = d2_executerenderbuffer(_d2_handle, _renderbuffer, 0);
|
||||
LV_ASSERT(D2_OK == result);
|
||||
|
||||
result = d2_flushframe(_d2_handle);
|
||||
LV_ASSERT(D2_OK == result);
|
||||
|
||||
result = d2_selectrenderbuffer(_d2_handle, _renderbuffer);
|
||||
LV_ASSERT(D2_OK == result);
|
||||
|
||||
while(false == lv_ll_is_empty(&_ll_Dave2D_Tasks)) {
|
||||
p_list_entry = lv_ll_get_tail(&_ll_Dave2D_Tasks);
|
||||
p_list_entry1 = *p_list_entry;
|
||||
p_list_entry1->state = LV_DRAW_TASK_STATE_READY;
|
||||
lv_ll_remove(&_ll_Dave2D_Tasks, p_list_entry);
|
||||
lv_free(p_list_entry);
|
||||
}
|
||||
|
||||
#if LV_USE_OS
|
||||
status = lv_mutex_unlock(&xd2Semaphore);
|
||||
LV_ASSERT(LV_RESULT_OK == status);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /*LV_USE_DRAW_DAVE2D*/
|
||||
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* @file lv_draw_dave2d.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_DAVE2D_H
|
||||
#define LV_DRAW_DAVE2D_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../../../lv_conf_internal.h"
|
||||
#if LV_USE_DRAW_DAVE2D
|
||||
#include "../../lv_draw.h"
|
||||
#include "../../lv_draw_private.h"
|
||||
#include "hal_data.h"
|
||||
#include "lv_draw_dave2d_utils.h"
|
||||
#include "../../lv_draw_rect.h"
|
||||
#include "../../lv_draw_line.h"
|
||||
#include "../../lv_draw_arc.h"
|
||||
#include "../../lv_draw_label.h"
|
||||
#include "../../lv_draw_image.h"
|
||||
#include "../../lv_draw_triangle.h"
|
||||
#include "../../lv_draw_buf.h"
|
||||
|
||||
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#define D2_RENDER_EACH_OPERATION (1)
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct {
|
||||
lv_draw_unit_t base_unit;
|
||||
lv_draw_task_t * task_act;
|
||||
#if LV_USE_OS
|
||||
lv_thread_sync_t sync;
|
||||
lv_thread_t thread;
|
||||
#endif
|
||||
uint32_t idx;
|
||||
d2_device * d2_handle;
|
||||
d2_renderbuffer * renderbuffer;
|
||||
#if LV_USE_OS
|
||||
lv_mutex_t * pd2Mutex;
|
||||
#endif
|
||||
} lv_draw_dave2d_unit_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
void lv_draw_dave2d_init(void);
|
||||
|
||||
void lv_draw_dave2d_image(lv_draw_task_t * t, const lv_draw_image_dsc_t * draw_dsc,
|
||||
const lv_area_t * coords);
|
||||
|
||||
void lv_draw_dave2d_fill(lv_draw_task_t * t, const lv_draw_fill_dsc_t * dsc, const lv_area_t * coords);
|
||||
|
||||
void lv_draw_dave2d_border(lv_draw_task_t * t, const lv_draw_border_dsc_t * dsc,
|
||||
const lv_area_t * coords);
|
||||
|
||||
void lv_draw_dave2d_box_shadow(lv_draw_task_t * t, const lv_draw_box_shadow_dsc_t * dsc,
|
||||
const lv_area_t * coords);
|
||||
|
||||
void lv_draw_dave2d_label(lv_draw_task_t * t, const lv_draw_label_dsc_t * dsc, const lv_area_t * coords);
|
||||
|
||||
void lv_draw_dave2d_arc(lv_draw_task_t * t, const lv_draw_arc_dsc_t * dsc, const lv_area_t * coords);
|
||||
|
||||
void lv_draw_dave2d_line(lv_draw_task_t * t, const lv_draw_line_dsc_t * dsc);
|
||||
|
||||
void lv_draw_dave2d_layer(lv_draw_task_t * t, const lv_draw_image_dsc_t * draw_dsc,
|
||||
const lv_area_t * coords);
|
||||
|
||||
void lv_draw_dave2d_triangle(lv_draw_task_t * t, const lv_draw_triangle_dsc_t * dsc);
|
||||
|
||||
void lv_draw_dave2d_mask_rect(lv_draw_task_t * t, const lv_draw_mask_rect_dsc_t * dsc,
|
||||
const lv_area_t * coords);
|
||||
|
||||
void lv_draw_dave2d_transform(lv_draw_task_t * t, const lv_area_t * dest_area, const void * src_buf,
|
||||
int32_t src_w, int32_t src_h, int32_t src_stride,
|
||||
const lv_draw_image_dsc_t * draw_dsc, const lv_draw_image_sup_t * sup, lv_color_format_t cf, void * dest_buf);
|
||||
|
||||
/***********************
|
||||
* GLOBAL VARIABLES
|
||||
***********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_DRAW_DAVE2D*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_USE_DRAW_DAVE2D*/
|
||||
@@ -0,0 +1,189 @@
|
||||
#include "lv_draw_dave2d.h"
|
||||
#if LV_USE_DRAW_DAVE2D
|
||||
|
||||
#include "../../../misc/lv_area_private.h"
|
||||
|
||||
void lv_draw_dave2d_arc(lv_draw_task_t * t, const lv_draw_arc_dsc_t * dsc, const lv_area_t * coords)
|
||||
{
|
||||
|
||||
uint32_t flags = 0;
|
||||
int32_t sin_start;
|
||||
int32_t cos_start;
|
||||
int32_t sin_end;
|
||||
int32_t cos_end;
|
||||
d2_s32 result;
|
||||
lv_area_t clipped_area;
|
||||
lv_area_t buffer_area;
|
||||
lv_point_t arc_centre;
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
lv_draw_dave2d_unit_t * u = (lv_draw_dave2d_unit_t *)t->draw_unit;
|
||||
|
||||
if(!lv_area_intersect(&clipped_area, coords, &t->clip_area)) return;
|
||||
|
||||
x = 0 - t->target_layer->buf_area.x1;
|
||||
y = 0 - t->target_layer->buf_area.y1;
|
||||
|
||||
buffer_area = t->target_layer->buf_area;
|
||||
|
||||
arc_centre = dsc->center;
|
||||
arc_centre.x = arc_centre.x - buffer_area.x1;
|
||||
arc_centre.y = arc_centre.y - buffer_area.y1;
|
||||
|
||||
lv_area_move(&clipped_area, x, y);
|
||||
lv_area_move(&buffer_area, x, y);
|
||||
|
||||
//
|
||||
// If both angles are equal (e.g. 0 and 0 or 180 and 180) nothing has to be done
|
||||
//
|
||||
if(dsc->start_angle == dsc->end_angle) {
|
||||
return; // Nothing to do, no angle - no arc
|
||||
}
|
||||
|
||||
#if LV_USE_OS
|
||||
lv_result_t status;
|
||||
status = lv_mutex_lock(u->pd2Mutex);
|
||||
LV_ASSERT(LV_RESULT_OK == status);
|
||||
#endif
|
||||
|
||||
#if D2_RENDER_EACH_OPERATION
|
||||
d2_selectrenderbuffer(u->d2_handle, u->renderbuffer);
|
||||
#endif
|
||||
|
||||
//
|
||||
// Generate render operations
|
||||
//
|
||||
d2_framebuffer_from_layer(u->d2_handle, t->target_layer);
|
||||
|
||||
d2_setalpha(u->d2_handle, dsc->opa);
|
||||
|
||||
d2_setcolor(u->d2_handle, 0, lv_draw_dave2d_lv_colour_to_d2_colour(dsc->color));
|
||||
|
||||
result = d2_cliprect(u->d2_handle, (d2_border)clipped_area.x1, (d2_border)clipped_area.y1, (d2_border)clipped_area.x2,
|
||||
(d2_border)clipped_area.y2);
|
||||
LV_ASSERT(D2_OK == result);
|
||||
|
||||
if(360 <= LV_ABS(dsc->start_angle - dsc->end_angle)) {
|
||||
d2_rendercircle(u->d2_handle,
|
||||
(d2_point)D2_FIX4(arc_centre.x),
|
||||
(d2_point) D2_FIX4(arc_centre.y),
|
||||
(d2_width) D2_FIX4(dsc->radius - dsc->width / 2),
|
||||
(d2_width) D2_FIX4(dsc->width));
|
||||
}
|
||||
else { //An ARC, not a full circle
|
||||
//
|
||||
// If the difference between both is larger than 180 degrees we must use the concave flag
|
||||
//
|
||||
/** Set d2_wf_concave flag if the pie object to draw is concave shape. */
|
||||
if((LV_ABS(dsc->start_angle - dsc->end_angle) > 180) || ((dsc->end_angle < dsc->start_angle) &&
|
||||
(LV_ABS(dsc->start_angle - (dsc->end_angle + 360)) > 180))) {
|
||||
flags = d2_wf_concave;
|
||||
}
|
||||
else {
|
||||
flags = 0;
|
||||
}
|
||||
|
||||
sin_start = lv_trigo_sin((int16_t)dsc->start_angle);
|
||||
cos_start = lv_trigo_cos((int16_t)dsc->start_angle);
|
||||
|
||||
sin_end = lv_trigo_sin((int16_t)dsc->end_angle);
|
||||
cos_end = lv_trigo_cos((int16_t)dsc->end_angle);
|
||||
|
||||
bool draw_arc;
|
||||
lv_area_t arc_area;
|
||||
lv_area_t clip_arc;
|
||||
lv_point_t start_point;
|
||||
lv_point_t end_point;
|
||||
|
||||
start_point.x = arc_centre.x + (int16_t)(((dsc->radius) * cos_start) >> LV_TRIGO_SHIFT);
|
||||
start_point.y = arc_centre.y + (int16_t)(((dsc->radius) * sin_start) >> LV_TRIGO_SHIFT);
|
||||
|
||||
end_point.x = arc_centre.x + (int16_t)(((dsc->radius) * cos_end) >> LV_TRIGO_SHIFT);
|
||||
end_point.y = arc_centre.y + (int16_t)(((dsc->radius) * sin_end) >> LV_TRIGO_SHIFT);
|
||||
|
||||
arc_area.x1 = LV_MIN3(start_point.x, end_point.x, arc_centre.x);
|
||||
arc_area.y1 = LV_MIN3(start_point.y, end_point.y, arc_centre.y);
|
||||
|
||||
arc_area.x2 = LV_MAX3(start_point.x, end_point.x, arc_centre.x);
|
||||
arc_area.y2 = LV_MAX3(start_point.y, end_point.y, arc_centre.y);
|
||||
|
||||
/* 0 degrees */
|
||||
if((dsc->end_angle < dsc->start_angle) || ((dsc->start_angle < 360) && (dsc->end_angle > 360))) {
|
||||
arc_area.x2 = arc_centre.x + dsc->radius;
|
||||
}
|
||||
|
||||
/* 90 degrees */
|
||||
if(((dsc->end_angle > 90) && (dsc->start_angle < 90)) || ((dsc->start_angle < 90) &&
|
||||
(dsc->end_angle < dsc->start_angle))) {
|
||||
arc_area.y2 = arc_centre.y + dsc->radius;
|
||||
}
|
||||
|
||||
/* 180 degrees */
|
||||
if(((dsc->end_angle > 180) && (dsc->start_angle < 180)) || ((dsc->start_angle < 180) &&
|
||||
(dsc->end_angle < dsc->start_angle))) {
|
||||
arc_area.x1 = arc_centre.x - dsc->radius;
|
||||
}
|
||||
|
||||
/* 270 degrees */
|
||||
if(((dsc->end_angle > 270) && (dsc->start_angle < 270)) || ((dsc->start_angle < 270) &&
|
||||
(dsc->end_angle < dsc->start_angle))) {
|
||||
arc_area.y1 = arc_centre.y - dsc->radius;
|
||||
}
|
||||
|
||||
draw_arc = lv_area_intersect(&clip_arc, &arc_area, &clipped_area);
|
||||
|
||||
if(draw_arc) {
|
||||
|
||||
result = d2_renderwedge(u->d2_handle,
|
||||
(d2_point)D2_FIX4(arc_centre.x),
|
||||
(d2_point) D2_FIX4(arc_centre.y),
|
||||
(d2_width) D2_FIX4(dsc->radius - dsc->width / 2),
|
||||
(d2_width) D2_FIX4(dsc->width),
|
||||
-(d2_s32)(sin_start << 1),
|
||||
(d2_s32)(cos_start << 1),
|
||||
(d2_s32)(sin_end << 1),
|
||||
-(d2_s32)(cos_end << 1),
|
||||
flags);
|
||||
LV_ASSERT(D2_OK == result);
|
||||
|
||||
if(dsc->rounded) {
|
||||
lv_point_t start_coord;
|
||||
lv_point_t end_coord;
|
||||
|
||||
start_coord.x = arc_centre.x + (int16_t)(((dsc->radius - dsc->width / 2) * cos_start) >> LV_TRIGO_SHIFT);
|
||||
start_coord.y = arc_centre.y + (int16_t)(((dsc->radius - dsc->width / 2) * sin_start) >> LV_TRIGO_SHIFT);
|
||||
|
||||
/** Render a circle. */
|
||||
d2_rendercircle(u->d2_handle,
|
||||
(d2_point) D2_FIX4((uint16_t)(start_coord.x)),
|
||||
(d2_point) D2_FIX4((uint16_t)(start_coord.y)),
|
||||
(d2_width) D2_FIX4(dsc->width / 2), 0);
|
||||
|
||||
end_coord.x = arc_centre.x + (int16_t)(((dsc->radius - dsc->width / 2) * cos_end) >> LV_TRIGO_SHIFT);
|
||||
end_coord.y = arc_centre.y + (int16_t)(((dsc->radius - dsc->width / 2) * sin_end) >> LV_TRIGO_SHIFT);
|
||||
|
||||
/** Render a circle. */
|
||||
d2_rendercircle(u->d2_handle,
|
||||
(d2_point) D2_FIX4((uint16_t)(end_coord.x)),
|
||||
(d2_point) D2_FIX4((uint16_t)(end_coord.y)),
|
||||
(d2_width) D2_FIX4(dsc->width / 2), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Execute render operations
|
||||
//
|
||||
|
||||
#if D2_RENDER_EACH_OPERATION
|
||||
d2_executerenderbuffer(u->d2_handle, u->renderbuffer, 0);
|
||||
d2_flushframe(u->d2_handle);
|
||||
#endif
|
||||
|
||||
#if LV_USE_OS
|
||||
status = lv_mutex_unlock(u->pd2Mutex);
|
||||
LV_ASSERT(LV_RESULT_OK == status);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /*LV_USE_DRAW_DAVE2D*/
|
||||
@@ -0,0 +1,420 @@
|
||||
#include "lv_draw_dave2d.h"
|
||||
#if LV_USE_DRAW_DAVE2D
|
||||
|
||||
#include "../../../misc/lv_area_private.h"
|
||||
|
||||
static void dave2d_draw_border_complex(lv_draw_task_t * t, const lv_area_t * outer_area,
|
||||
const lv_area_t * inner_area,
|
||||
int32_t rout, int32_t rin, lv_color_t color, lv_opa_t opa);
|
||||
|
||||
static void dave2d_draw_border_simple(lv_draw_task_t * t, const lv_area_t * outer_area,
|
||||
const lv_area_t * inner_area,
|
||||
lv_color_t color, lv_opa_t opa);
|
||||
|
||||
void lv_draw_dave2d_border(lv_draw_task_t * t, const lv_draw_border_dsc_t * dsc,
|
||||
const lv_area_t * coords)
|
||||
{
|
||||
if(dsc->opa <= LV_OPA_MIN) return;
|
||||
if(dsc->width == 0) return;
|
||||
if(dsc->side == LV_BORDER_SIDE_NONE) return;
|
||||
|
||||
int32_t coords_w = lv_area_get_width(coords);
|
||||
int32_t coords_h = lv_area_get_height(coords);
|
||||
int32_t rout = dsc->radius;
|
||||
int32_t short_side = LV_MIN(coords_w, coords_h);
|
||||
if(rout > short_side >> 1) rout = short_side >> 1;
|
||||
|
||||
/*Get the inner area*/
|
||||
lv_area_t area_inner;
|
||||
lv_area_copy(&area_inner, coords);
|
||||
area_inner.x1 += ((dsc->side & LV_BORDER_SIDE_LEFT) ? dsc->width : - (dsc->width + rout));
|
||||
area_inner.x2 -= ((dsc->side & LV_BORDER_SIDE_RIGHT) ? dsc->width : - (dsc->width + rout));
|
||||
area_inner.y1 += ((dsc->side & LV_BORDER_SIDE_TOP) ? dsc->width : - (dsc->width + rout));
|
||||
area_inner.y2 -= ((dsc->side & LV_BORDER_SIDE_BOTTOM) ? dsc->width : - (dsc->width + rout));
|
||||
|
||||
int32_t rin = rout - dsc->width;
|
||||
if(rin < 0) rin = 0;
|
||||
|
||||
if(rout == 0 && rin == 0) {
|
||||
dave2d_draw_border_simple(t, coords, &area_inner, dsc->color, dsc->opa);
|
||||
}
|
||||
else {
|
||||
dave2d_draw_border_complex(t, coords, &area_inner, rout, rin, dsc->color, dsc->opa);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void dave2d_draw_border_simple(lv_draw_task_t * t, const lv_area_t * outer_area,
|
||||
const lv_area_t * inner_area,
|
||||
lv_color_t color, lv_opa_t opa)
|
||||
|
||||
{
|
||||
|
||||
lv_area_t clip_area;
|
||||
lv_area_t local_outer_area;
|
||||
lv_area_t local_inner_area;
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
bool is_common;
|
||||
|
||||
is_common = lv_area_intersect(&clip_area, outer_area, &t->clip_area);
|
||||
if(!is_common) return;
|
||||
|
||||
lv_draw_dave2d_unit_t * u = (lv_draw_dave2d_unit_t *)t->draw_unit;
|
||||
|
||||
#if LV_USE_OS
|
||||
lv_result_t status;
|
||||
status = lv_mutex_lock(u->pd2Mutex);
|
||||
LV_ASSERT(LV_RESULT_OK == status);
|
||||
#endif
|
||||
|
||||
local_outer_area = *outer_area;
|
||||
local_inner_area = *inner_area;
|
||||
|
||||
x = 0 - t->target_layer->buf_area.x1;
|
||||
y = 0 - t->target_layer->buf_area.y1;
|
||||
|
||||
lv_area_move(&clip_area, x, y);
|
||||
lv_area_move(&local_outer_area, x, y);
|
||||
lv_area_move(&local_inner_area, x, y);
|
||||
|
||||
#if D2_RENDER_EACH_OPERATION
|
||||
d2_selectrenderbuffer(u->d2_handle, u->renderbuffer);
|
||||
#endif
|
||||
//
|
||||
// Generate render operations
|
||||
//
|
||||
|
||||
d2_framebuffer_from_layer(u->d2_handle, t->target_layer);
|
||||
|
||||
d2_setcolor(u->d2_handle, 0, lv_draw_dave2d_lv_colour_to_d2_colour(color));
|
||||
d2_setalpha(u->d2_handle, opa);
|
||||
d2_cliprect(u->d2_handle, (d2_border)clip_area.x1, (d2_border)clip_area.y1, (d2_border)clip_area.x2,
|
||||
(d2_border)clip_area.y2);
|
||||
|
||||
lv_area_t a;
|
||||
|
||||
bool top_side = local_outer_area.y1 <= local_inner_area.y1;
|
||||
bool bottom_side = local_outer_area.y2 >= local_inner_area.y2;
|
||||
bool left_side = local_outer_area.x1 <= local_inner_area.x1;
|
||||
bool right_side = local_outer_area.x2 >= local_inner_area.x2;
|
||||
|
||||
/*Top*/
|
||||
a.x1 = local_outer_area.x1;
|
||||
a.x2 = local_outer_area.x2;
|
||||
a.y1 = local_outer_area.y1;
|
||||
a.y2 = local_inner_area.y1 - 1;
|
||||
if(top_side) {
|
||||
d2_renderbox(u->d2_handle, (d2_point)D2_FIX4(a.x1),
|
||||
(d2_point)D2_FIX4(a.y1),
|
||||
(d2_point)D2_FIX4(lv_area_get_width(&a)),
|
||||
(d2_point)D2_FIX4(lv_area_get_height(&a)));
|
||||
}
|
||||
|
||||
/*Bottom*/
|
||||
a.y1 = local_inner_area.y2 + 1;
|
||||
a.y2 = local_outer_area.y2;
|
||||
if(bottom_side) {
|
||||
d2_renderbox(u->d2_handle, (d2_point)D2_FIX4(a.x1),
|
||||
(d2_point)D2_FIX4(a.y1),
|
||||
(d2_point)D2_FIX4(lv_area_get_width(&a)),
|
||||
(d2_point)D2_FIX4(lv_area_get_height(&a)));
|
||||
}
|
||||
|
||||
/*Left*/
|
||||
a.x1 = local_outer_area.x1;
|
||||
a.x2 = local_inner_area.x1 - 1;
|
||||
a.y1 = (top_side) ? local_inner_area.y1 : local_outer_area.y1;
|
||||
a.y2 = (bottom_side) ? local_inner_area.y2 : local_outer_area.y2;
|
||||
if(left_side) {
|
||||
d2_renderbox(u->d2_handle, (d2_point)D2_FIX4(a.x1),
|
||||
(d2_point)D2_FIX4(a.y1),
|
||||
(d2_point)D2_FIX4(lv_area_get_width(&a)),
|
||||
(d2_point)D2_FIX4(lv_area_get_height(&a)));
|
||||
}
|
||||
|
||||
/*Right*/
|
||||
a.x1 = local_inner_area.x2 + 1;
|
||||
a.x2 = local_outer_area.x2;
|
||||
if(right_side) {
|
||||
d2_renderbox(u->d2_handle, (d2_point)D2_FIX4(a.x1),
|
||||
(d2_point)D2_FIX4(a.y1),
|
||||
(d2_point)D2_FIX4(lv_area_get_width(&a)),
|
||||
(d2_point)D2_FIX4(lv_area_get_height(&a)));
|
||||
}
|
||||
|
||||
//
|
||||
// Execute render operations
|
||||
//
|
||||
#if D2_RENDER_EACH_OPERATION
|
||||
d2_executerenderbuffer(u->d2_handle, u->renderbuffer, 0);
|
||||
d2_flushframe(u->d2_handle);
|
||||
#endif
|
||||
|
||||
#if LV_USE_OS
|
||||
status = lv_mutex_unlock(u->pd2Mutex);
|
||||
LV_ASSERT(LV_RESULT_OK == status);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void dave2d_draw_border_complex(lv_draw_task_t * t, const lv_area_t * orig_outer_area,
|
||||
const lv_area_t * orig_inner_area,
|
||||
int32_t rout, int32_t rin, lv_color_t color, lv_opa_t opa)
|
||||
{
|
||||
/*Get clipped draw area which is the real draw area.
|
||||
*It is always the same or inside `coords`*/
|
||||
lv_area_t draw_area;
|
||||
lv_area_t outer_area;
|
||||
lv_area_t inner_area;
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
d2_s32 result;
|
||||
d2_u32 flags = 0;
|
||||
|
||||
outer_area = *orig_outer_area;
|
||||
inner_area = *orig_inner_area;
|
||||
lv_draw_dave2d_unit_t * u = (lv_draw_dave2d_unit_t *)t->draw_unit;
|
||||
|
||||
if(!lv_area_intersect(&draw_area, &outer_area, &t->clip_area)) return;
|
||||
|
||||
#if LV_USE_OS
|
||||
lv_result_t status;
|
||||
status = lv_mutex_lock(u->pd2Mutex);
|
||||
LV_ASSERT(LV_RESULT_OK == status);
|
||||
#endif
|
||||
|
||||
x = 0 - t->target_layer->buf_area.x1;
|
||||
y = 0 - t->target_layer->buf_area.y1;
|
||||
|
||||
lv_area_move(&draw_area, x, y);
|
||||
lv_area_move(&outer_area, x, y);
|
||||
lv_area_move(&inner_area, x, y);
|
||||
|
||||
#if D2_RENDER_EACH_OPERATION
|
||||
d2_selectrenderbuffer(u->d2_handle, u->renderbuffer);
|
||||
#endif
|
||||
//
|
||||
// Generate render operations
|
||||
//
|
||||
|
||||
d2_framebuffer_from_layer(u->d2_handle, t->target_layer);
|
||||
|
||||
d2_setcolor(u->d2_handle, 0, lv_draw_dave2d_lv_colour_to_d2_colour(color));
|
||||
d2_setalpha(u->d2_handle, opa);
|
||||
d2_cliprect(u->d2_handle, (d2_border)draw_area.x1, (d2_border)draw_area.y1, (d2_border)draw_area.x2,
|
||||
(d2_border)draw_area.y2);
|
||||
|
||||
lv_area_t blend_area;
|
||||
/*Calculate the x and y coordinates where the straight parts area are */
|
||||
lv_area_t core_area;
|
||||
core_area.x1 = LV_MAX(outer_area.x1 + rout, inner_area.x1);
|
||||
core_area.x2 = LV_MIN(outer_area.x2 - rout, inner_area.x2);
|
||||
core_area.y1 = LV_MAX(outer_area.y1 + rout, inner_area.y1);
|
||||
core_area.y2 = LV_MIN(outer_area.y2 - rout, inner_area.y2);
|
||||
|
||||
bool top_side = outer_area.y1 <= inner_area.y1;
|
||||
bool bottom_side = outer_area.y2 >= inner_area.y2;
|
||||
|
||||
/*No masks*/
|
||||
bool left_side = outer_area.x1 <= inner_area.x1;
|
||||
bool right_side = outer_area.x2 >= inner_area.x2;
|
||||
|
||||
/*Draw the straight lines first */
|
||||
if(top_side) {
|
||||
blend_area.x1 = core_area.x1;
|
||||
blend_area.x2 = core_area.x2;
|
||||
blend_area.y1 = outer_area.y1;
|
||||
blend_area.y2 = inner_area.y1 - 1;
|
||||
d2_renderbox(u->d2_handle,
|
||||
(d2_point)D2_FIX4(blend_area.x1),
|
||||
(d2_point)D2_FIX4(blend_area.y1),
|
||||
(d2_point)D2_FIX4(lv_area_get_width(&blend_area)),
|
||||
(d2_point)D2_FIX4(lv_area_get_height(&blend_area)));
|
||||
}
|
||||
|
||||
if(bottom_side) {
|
||||
blend_area.x1 = core_area.x1;
|
||||
blend_area.x2 = core_area.x2;
|
||||
blend_area.y1 = inner_area.y2 + 1;
|
||||
blend_area.y2 = outer_area.y2;
|
||||
d2_renderbox(u->d2_handle,
|
||||
(d2_point)D2_FIX4(blend_area.x1),
|
||||
(d2_point)D2_FIX4(blend_area.y1),
|
||||
(d2_point)D2_FIX4(lv_area_get_width(&blend_area)),
|
||||
(d2_point)D2_FIX4(lv_area_get_height(&blend_area)));
|
||||
}
|
||||
|
||||
if(left_side) {
|
||||
blend_area.x1 = outer_area.x1;
|
||||
blend_area.x2 = inner_area.x1 - 1;
|
||||
blend_area.y1 = core_area.y1;
|
||||
blend_area.y2 = core_area.y2;
|
||||
d2_renderbox(u->d2_handle,
|
||||
(d2_point)D2_FIX4(blend_area.x1),
|
||||
(d2_point)D2_FIX4(blend_area.y1),
|
||||
(d2_point)D2_FIX4(lv_area_get_width(&blend_area)),
|
||||
(d2_point)D2_FIX4(lv_area_get_height(&blend_area)));
|
||||
}
|
||||
|
||||
if(right_side) {
|
||||
blend_area.x1 = inner_area.x2 + 1;
|
||||
blend_area.x2 = outer_area.x2;
|
||||
blend_area.y1 = core_area.y1;
|
||||
blend_area.y2 = core_area.y2;
|
||||
d2_renderbox(u->d2_handle,
|
||||
(d2_point)D2_FIX4(blend_area.x1),
|
||||
(d2_point)D2_FIX4(blend_area.y1),
|
||||
(d2_point)D2_FIX4(lv_area_get_width(&blend_area)),
|
||||
(d2_point)D2_FIX4(lv_area_get_height(&blend_area)));
|
||||
}
|
||||
|
||||
/*Draw the corners*/
|
||||
int32_t blend_w;
|
||||
/*Left corners*/
|
||||
blend_area.x1 = draw_area.x1;
|
||||
blend_area.x2 = LV_MIN(draw_area.x2, core_area.x1 - 1);
|
||||
|
||||
blend_w = lv_area_get_width(&blend_area);
|
||||
|
||||
if(blend_w > 0) {
|
||||
d2_s32 aa;
|
||||
aa = d2_getantialiasing(u->d2_handle);
|
||||
d2_setantialiasing(u->d2_handle, 0); //Don't blend with the background according to coverage value
|
||||
|
||||
if(left_side || top_side) {
|
||||
lv_area_t arc_area;
|
||||
lv_area_t clip_arc;
|
||||
|
||||
arc_area.x1 = core_area.x1 - rout;
|
||||
arc_area.y1 = core_area.y1 - rout;
|
||||
arc_area.x2 = core_area.x1;
|
||||
arc_area.y2 = core_area.y1;
|
||||
|
||||
if(lv_area_intersect(&clip_arc, &arc_area, &draw_area)) {
|
||||
d2_cliprect(u->d2_handle, (d2_border)clip_arc.x1, (d2_border)clip_arc.y1, (d2_border)clip_arc.x2,
|
||||
(d2_border)clip_arc.y2);
|
||||
result = d2_renderwedge(u->d2_handle,
|
||||
(d2_point)D2_FIX4(core_area.x1),
|
||||
(d2_point) D2_FIX4(core_area.y1),
|
||||
(d2_width) D2_FIX4(rout),
|
||||
(d2_width) D2_FIX4((rout - rin)),
|
||||
(d2_s32) D2_FIX16(0), // 180 Degrees
|
||||
(d2_s32) D2_FIX16((int16_t) -1),
|
||||
(d2_s32) D2_FIX16((int16_t) -1),//( 270 Degrees
|
||||
(d2_s32) D2_FIX16(0),
|
||||
flags);
|
||||
LV_ASSERT(D2_OK == result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(left_side || bottom_side) {
|
||||
lv_area_t arc_area;
|
||||
lv_area_t clip_arc;
|
||||
|
||||
arc_area.x1 = core_area.x1 - rout;
|
||||
arc_area.y1 = core_area.y2;
|
||||
arc_area.x2 = core_area.x1;
|
||||
arc_area.y2 = core_area.y2 + rout;
|
||||
|
||||
if(lv_area_intersect(&clip_arc, &arc_area, &draw_area)) {
|
||||
|
||||
d2_cliprect(u->d2_handle, (d2_border)clip_arc.x1, (d2_border)clip_arc.y1, (d2_border)clip_arc.x2,
|
||||
(d2_border)clip_arc.y2);
|
||||
result = d2_renderwedge(u->d2_handle,
|
||||
(d2_point)D2_FIX4(core_area.x1),
|
||||
(d2_point) D2_FIX4(core_area.y2),
|
||||
(d2_width) D2_FIX4(rout),
|
||||
(d2_width) D2_FIX4((rout - rin)),
|
||||
(d2_s32) D2_FIX16((int16_t) -1), //90 degrees
|
||||
(d2_s32) D2_FIX16(0),
|
||||
(d2_s32) D2_FIX16(0), //180 degrees
|
||||
(d2_s32) D2_FIX16(1),
|
||||
flags);
|
||||
LV_ASSERT(D2_OK == result);
|
||||
}
|
||||
}
|
||||
|
||||
/*Right corners*/
|
||||
blend_area.x1 = LV_MAX(draw_area.x1, blend_area.x2 + 1); /*To not overlap with the left side*/
|
||||
blend_area.x1 = LV_MAX(draw_area.x1, core_area.x2 + 1);
|
||||
|
||||
blend_area.x2 = draw_area.x2;
|
||||
blend_w = lv_area_get_width(&blend_area);
|
||||
|
||||
if(blend_w > 0) {
|
||||
if(right_side || top_side) {
|
||||
|
||||
lv_area_t arc_area;
|
||||
lv_area_t clip_arc;
|
||||
|
||||
arc_area.x1 = core_area.x2;
|
||||
arc_area.y1 = core_area.y1 - rout;
|
||||
arc_area.x2 = core_area.x2 + rout;
|
||||
arc_area.y2 = core_area.y1;
|
||||
|
||||
if(lv_area_intersect(&clip_arc, &arc_area, &draw_area)) {
|
||||
|
||||
d2_cliprect(u->d2_handle, (d2_border)clip_arc.x1, (d2_border)clip_arc.y1, (d2_border)clip_arc.x2,
|
||||
(d2_border)clip_arc.y2);
|
||||
result = d2_renderwedge(u->d2_handle,
|
||||
(d2_point)D2_FIX4(core_area.x2),
|
||||
(d2_point) D2_FIX4(core_area.y1),
|
||||
(d2_width) D2_FIX4(rout),
|
||||
(d2_width) D2_FIX4((rout - rin)),
|
||||
(d2_s32) D2_FIX16((int16_t)1), // 270 Degrees
|
||||
(d2_s32) D2_FIX16(0),
|
||||
(d2_s32) D2_FIX16(0),// 0 degrees
|
||||
(d2_s32) D2_FIX16(-1),
|
||||
flags);
|
||||
LV_ASSERT(D2_OK == result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(right_side || bottom_side) {
|
||||
lv_area_t arc_area;
|
||||
lv_area_t clip_arc;
|
||||
|
||||
arc_area.x1 = core_area.x2;
|
||||
arc_area.y1 = core_area.y2;
|
||||
arc_area.x2 = core_area.x2 + rout;
|
||||
arc_area.y2 = core_area.y2 + rout;
|
||||
|
||||
if(lv_area_intersect(&clip_arc, &arc_area, &draw_area)) {
|
||||
|
||||
d2_cliprect(u->d2_handle, (d2_border)clip_arc.x1, (d2_border)clip_arc.y1, (d2_border)clip_arc.x2,
|
||||
(d2_border)clip_arc.y2);
|
||||
result = d2_renderwedge(u->d2_handle,
|
||||
(d2_point)D2_FIX4(core_area.x2),
|
||||
(d2_point) D2_FIX4(core_area.y2),
|
||||
(d2_width) D2_FIX4(rout),
|
||||
(d2_width) D2_FIX4((rout - rin)),
|
||||
(d2_s32) D2_FIX16(0),// 0 degrees
|
||||
(d2_s32) D2_FIX16(1),
|
||||
(d2_s32) D2_FIX16(1),// 90 degrees
|
||||
(d2_s32) D2_FIX16(0),
|
||||
flags);
|
||||
LV_ASSERT(D2_OK == result);
|
||||
}
|
||||
}
|
||||
}
|
||||
d2_setantialiasing(u->d2_handle, aa); //restore original setting
|
||||
}
|
||||
|
||||
//
|
||||
// Execute render operations
|
||||
//
|
||||
#if D2_RENDER_EACH_OPERATION
|
||||
d2_executerenderbuffer(u->d2_handle, u->renderbuffer, 0);
|
||||
d2_flushframe(u->d2_handle);
|
||||
#endif
|
||||
|
||||
#if LV_USE_OS
|
||||
status = lv_mutex_unlock(u->pd2Mutex);
|
||||
LV_ASSERT(LV_RESULT_OK == status);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif /*LV_USE_DRAW_DAVE2D*/
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user