perf(lcd): precompose emote updates and smooth closed eyes
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
from pathlib import Path
|
||||
import re,subprocess,tempfile
|
||||
src=(Path(__file__).resolve().parents[1]/'components/platform/src/lcd_direct.c').read_text()
|
||||
def extract(name):
|
||||
m=re.search(r'static [^;{}]+\b'+name+r'\([^;{}]*\)\s*\{',src)
|
||||
a=m.start(); b=src.index('{',a)+1; depth=1
|
||||
while depth:
|
||||
if src[b]=='{': depth+=1
|
||||
if src[b]=='}': depth-=1
|
||||
b+=1
|
||||
return src[a:b]
|
||||
prefix='''#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#define LCD_DIRECT_WIDTH 320
|
||||
#define LCD_DIRECT_EMOTE_DMA_ROWS 16
|
||||
#define LCD_DIRECT_TRANSFER_TIMEOUT_MS 100
|
||||
#define portENTER_CRITICAL(x) ((void)0)
|
||||
#define portEXIT_CRITICAL(x) ((void)0)
|
||||
#define pdMS_TO_TICKS(x) (x)
|
||||
#define ESP_LOGE(...) ((void)0)
|
||||
#define ESP_OK 0
|
||||
#define ESP_ERR_INVALID_SIZE 1
|
||||
#define ESP_ERR_TIMEOUT 2
|
||||
#define pdTRUE 1
|
||||
typedef int esp_err_t;
|
||||
typedef int gfx_disp_t;
|
||||
static bool s_emote_active, s_emote_transfer_fault;
|
||||
static int s_emote_flush_error, s_panel, s_transfer_done_sem;
|
||||
static uint16_t dma[5120];
|
||||
static uint16_t *s_emote_dma_pixels=dma;
|
||||
static uint16_t capture[320*240];
|
||||
static int calls,ready,fail_call,timeout_call,origin_y,width;
|
||||
static bool gfx_disp_flush_ready(gfx_disp_t *d,bool swap) {++ready;return true;}
|
||||
static int xSemaphoreTake(int sem,int ticks) {return ticks && calls!=timeout_call;}
|
||||
static int esp_lcd_panel_draw_bitmap(int panel,int x1,int y1,int x2,int y2,const void *data) {
|
||||
++calls; assert(ready==0); assert((x2-x1)*(y2-y1)<=5120); assert(data==dma);
|
||||
if(calls==fail_call) return 3;
|
||||
memcpy(capture+(y1-origin_y)*width,data,(x2-x1)*(y2-y1)*2);
|
||||
return 0;
|
||||
}
|
||||
'''
|
||||
test='''int main(void) {
|
||||
uint16_t source[320*240];
|
||||
for(int i=0;i<320*240;++i) source[i]=(uint16_t)i;
|
||||
for(width=1;width<=320;++width) {
|
||||
calls=ready=fail_call=timeout_call=0;origin_y=65;s_emote_active=true;
|
||||
s_emote_transfer_fault=false;s_emote_flush_error=0;
|
||||
lcd_direct_emote_flush(NULL,0,65,width,158,source);
|
||||
assert(ready==1 && s_emote_flush_error==0);
|
||||
assert(memcmp(source,capture,width*93*2)==0);
|
||||
assert(calls==(93+5120/width-1)/(5120/width));
|
||||
}
|
||||
width=238;calls=ready=0;timeout_call=2;s_emote_flush_error=0;
|
||||
lcd_direct_emote_flush(NULL,41,65,279,158,source);
|
||||
assert(ready==1 && s_emote_transfer_fault && s_emote_flush_error==2 && calls==2);
|
||||
lcd_direct_emote_flush(NULL,41,65,279,158,source);
|
||||
assert(calls==2 && ready==2);
|
||||
s_emote_transfer_fault=false;timeout_call=0;fail_call=1;calls=ready=0;
|
||||
lcd_direct_emote_flush(NULL,41,65,279,158,source);
|
||||
assert(calls==1 && ready==1 && s_emote_flush_error==3);
|
||||
calls=ready=0;s_emote_active=false;
|
||||
lcd_direct_emote_flush(NULL,41,65,279,158,source);assert(calls==0 && ready==1);
|
||||
uint8_t eyes[238*14*3+2];memset(eyes,123,sizeof(eyes));
|
||||
lcd_direct_emote_draw_closed_eyes(eyes+1,238,14,0xffe0);
|
||||
assert(eyes[0]==123 && eyes[sizeof(eyes)-1]==123);
|
||||
const uint8_t *alpha=eyes+1+238*14*2;
|
||||
for(int y=0;y<14;++y) for(int x=3;x<=95;++x)
|
||||
assert(alpha[y*238+x]==alpha[y*238+x+140]);
|
||||
assert(alpha[3*238+49]==255 && alpha[11*238+3]==255);
|
||||
puts("PASS: 320 transfer widths, DMA bounds/order, timeout latch, inactive/error completion and symmetric closed-eye raster");
|
||||
}'''
|
||||
with tempfile.TemporaryDirectory(prefix='emote-transport-') as tmp:
|
||||
c=Path(tmp)/'test.c';exe=Path(tmp)/'test'
|
||||
c.write_text(prefix+extract('lcd_direct_emote_flush')+'\n'+extract('lcd_direct_emote_draw_closed_eyes')+'\n'+test)
|
||||
subprocess.run(['clang','-std=c11','-fsanitize=address,undefined',str(c),'-o',str(exe)],check=True)
|
||||
subprocess.run([str(exe)],check=True)
|
||||
Reference in New Issue
Block a user