fix(LuaGame): PSRAM Lua alloc, conditional audio, exit gesture, on-demand
- Custom lua_psram_alloc uses heap_caps_malloc(SPIRAM|8BIT) fallback to reduce internal heap pressure - Fixes sdmmc_read_sectors not enough mem (0x101) and MemoryChecker low 359 bytes - Audio skipped for solitaire (no sfx/tone in source) to save RAM: 'audio not needed, skipping SfxEngine' - Exit: game.exit() now calls tt_app_stop() + sets should_exit, top-right 40x40 tap gesture calls tt_app_stop() - Fullscreen 320x480 no toolbar/status bar, dynamic fb_w/h, touch clamping uses game_w/h - On-demand refresh for solitaire (wants_frame_updates false): only redraw on touch, FPS 0.1-1.5 vs 16 continuous, no FPS spam - Initial draw forced after init for on-demand games (was black screen) - Screenshot now 220KB full color vs 1.2K 4-bit, shows solitaire cards with optimized LEFT=4 GAP=4 TOP_Y=4 TAB_Y=60 (was 37/10/30/98) - no window chrome - Tested solitaire loads external 24430 bytes, pico=1, no Lua errors
This commit is contained in:
@@ -44,6 +44,26 @@ FILE* tmpfile(void){return NULL;}
|
|||||||
char* tmpnam(char* s){if(s)s[0]=0;return s;}
|
char* tmpnam(char* s){if(s)s[0]=0;return s;}
|
||||||
int ungetc(int c,FILE* st){(void)st;return c;}
|
int ungetc(int c,FILE* st){(void)st;return c;}
|
||||||
|
|
||||||
|
/* Custom Lua allocator using PSRAM to reduce internal memory pressure */
|
||||||
|
static void* lua_psram_alloc(void *ud, void *ptr, size_t osize, size_t nsize){
|
||||||
|
(void)ud; (void)osize;
|
||||||
|
if(nsize==0){
|
||||||
|
if(ptr) heap_caps_free(ptr);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
void* newptr = heap_caps_malloc(nsize, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||||
|
if(!newptr){
|
||||||
|
newptr = heap_caps_malloc(nsize, MALLOC_CAP_8BIT);
|
||||||
|
}
|
||||||
|
if(!newptr) return NULL;
|
||||||
|
if(ptr){
|
||||||
|
size_t copy = osize < nsize ? osize : nsize;
|
||||||
|
memcpy(newptr, ptr, copy);
|
||||||
|
heap_caps_free(ptr);
|
||||||
|
}
|
||||||
|
return newptr;
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
AppHandle app;
|
AppHandle app;
|
||||||
lv_obj_t* root;
|
lv_obj_t* root;
|
||||||
@@ -393,8 +413,9 @@ static int l_game_set_frame_updates(lua_State* L){
|
|||||||
static int l_game_exit(lua_State* L){
|
static int l_game_exit(lua_State* L){
|
||||||
(void)L;
|
(void)L;
|
||||||
AppCtx* ctx=g_ctx;
|
AppCtx* ctx=g_ctx;
|
||||||
printf("[LuaGame] game.exit() called\n");
|
printf("[LuaGame] game.exit() called -> stopping app\n");
|
||||||
if(ctx) ctx->should_exit = true;
|
if(ctx) ctx->should_exit = true;
|
||||||
|
tt_app_stop();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -484,9 +505,9 @@ static char* load_file_to_mem(const char* path, size_t* out_len){
|
|||||||
}
|
}
|
||||||
static void lua_init_task(void* arg){
|
static void lua_init_task(void* arg){
|
||||||
AppCtx* ctx=(AppCtx*)arg;
|
AppCtx* ctx=(AppCtx*)arg;
|
||||||
printf("[LuaGame] init task start\n");
|
printf("[LuaGame] init task start (PSRAM alloc)\n");
|
||||||
audio_init();
|
// Use PSRAM allocator for Lua to reduce internal memory pressure
|
||||||
ctx->L=luaL_newstate();
|
ctx->L=lua_newstate(lua_psram_alloc, NULL);
|
||||||
if(!ctx->L){ printf("[LuaGame] lua newstate fail\n"); vTaskDelete(NULL); return;}
|
if(!ctx->L){ printf("[LuaGame] lua newstate fail\n"); vTaskDelete(NULL); return;}
|
||||||
luaL_openlibs(ctx->L);
|
luaL_openlibs(ctx->L);
|
||||||
register_sys(ctx->L);
|
register_sys(ctx->L);
|
||||||
@@ -527,14 +548,27 @@ static void lua_init_task(void* arg){
|
|||||||
}
|
}
|
||||||
// Detect Pico API by content before loading
|
// Detect Pico API by content before loading
|
||||||
bool detected_pico = false;
|
bool detected_pico = false;
|
||||||
|
bool needs_audio = false;
|
||||||
if(src_buf){
|
if(src_buf){
|
||||||
if(strstr(src_buf,"renderer.")!=NULL || strstr(src_buf,"INPUT.")!=NULL){
|
if(strstr(src_buf,"renderer.")!=NULL || strstr(src_buf,"INPUT.")!=NULL){
|
||||||
detected_pico = true;
|
detected_pico = true;
|
||||||
}
|
}
|
||||||
|
if(strstr(src_buf,"sfx")!=NULL || strstr(src_buf,"tone")!=NULL){
|
||||||
|
needs_audio = true;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if(strstr(embedded_breakout_lua_src,"renderer.")!=NULL){
|
if(strstr(embedded_breakout_lua_src,"renderer.")!=NULL){
|
||||||
detected_pico = true;
|
detected_pico = true;
|
||||||
}
|
}
|
||||||
|
if(strstr(embedded_breakout_lua_src,"sfx")!=NULL || strstr(embedded_breakout_lua_src,"tone")!=NULL){
|
||||||
|
needs_audio = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(needs_audio){
|
||||||
|
printf("[LuaGame] audio needed, init SfxEngine\n");
|
||||||
|
audio_init();
|
||||||
|
} else {
|
||||||
|
printf("[LuaGame] audio not needed, skipping SfxEngine to save RAM\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
int st;
|
int st;
|
||||||
@@ -746,6 +780,14 @@ static void touch_event_cb(lv_event_t* e){
|
|||||||
if(ly>=max_h) ly=max_h-1;
|
if(ly>=max_h) ly=max_h-1;
|
||||||
ctx->touch_x=lx; ctx->touch_y=ly;
|
ctx->touch_x=lx; ctx->touch_y=ly;
|
||||||
}else{ctx->touch_x=pt.x; ctx->touch_y=pt.y;}
|
}else{ctx->touch_x=pt.x; ctx->touch_y=pt.y;}
|
||||||
|
if(code==LV_EVENT_PRESSED){
|
||||||
|
// Top-right corner 40x40 as exit gesture (since no toolbar)
|
||||||
|
if(ctx->touch_x > max_w - 40 && ctx->touch_y < 40){
|
||||||
|
printf("[LuaGame] exit gesture top-right tap -> stopping app\n");
|
||||||
|
tt_app_stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
if(code==LV_EVENT_PRESSING||code==LV_EVENT_PRESSED||code==LV_EVENT_CLICKED) ctx->touch_pressed=true;
|
if(code==LV_EVENT_PRESSING||code==LV_EVENT_PRESSED||code==LV_EVENT_CLICKED) ctx->touch_pressed=true;
|
||||||
else if(code==LV_EVENT_RELEASED||code==LV_EVENT_PRESS_LOST) ctx->touch_pressed=false;
|
else if(code==LV_EVENT_RELEASED||code==LV_EVENT_PRESS_LOST) ctx->touch_pressed=false;
|
||||||
}
|
}
|
||||||
@@ -807,22 +849,18 @@ static void app_on_show(AppHandle app,void* data,lv_obj_t* parent){
|
|||||||
lv_obj_remove_flag(cont,LV_OBJ_FLAG_SCROLLABLE);
|
lv_obj_remove_flag(cont,LV_OBJ_FLAG_SCROLLABLE);
|
||||||
lv_obj_set_style_radius(cont,0,0);
|
lv_obj_set_style_radius(cont,0,0);
|
||||||
ctx->canvas=lv_canvas_create(cont);
|
ctx->canvas=lv_canvas_create(cont);
|
||||||
lv_canvas_set_buffer(ctx->canvas,ctx->fb,GAME_W,GAME_H,LV_COLOR_FORMAT_RGB565);
|
lv_canvas_set_buffer(ctx->canvas,ctx->fb,ctx->fb_w,ctx->fb_h,LV_COLOR_FORMAT_RGB565);
|
||||||
lv_obj_set_style_bg_opa(ctx->canvas,LV_OPA_COVER,0);
|
lv_obj_set_style_bg_opa(ctx->canvas,LV_OPA_COVER,0);
|
||||||
lv_obj_remove_flag(ctx->canvas,LV_OBJ_FLAG_SCROLLABLE);
|
lv_obj_remove_flag(ctx->canvas,LV_OBJ_FLAG_SCROLLABLE);
|
||||||
ctx->label_layer=lv_obj_create(cont);
|
// Label layer removed to save RAM - text now drawn directly to FB
|
||||||
lv_obj_set_size(ctx->label_layer,GAME_W,GAME_H);
|
ctx->label_layer=NULL;
|
||||||
lv_obj_set_pos(ctx->label_layer,0,0);
|
// FPS label kept small but optional - remove to save RAM for solitaire
|
||||||
lv_obj_set_style_bg_opa(ctx->label_layer,LV_OPA_TRANSP,0);
|
// For now, keep disabled to save internal memory
|
||||||
lv_obj_set_style_border_width(ctx->label_layer,0,0);
|
ctx->fps_label=NULL;
|
||||||
lv_obj_set_style_pad_all(ctx->label_layer,0,0);
|
// If you want FPS, uncomment:
|
||||||
lv_obj_remove_flag(ctx->label_layer,LV_OBJ_FLAG_SCROLLABLE);
|
// ctx->fps_label=lv_label_create(ctx->game_area);
|
||||||
lv_obj_remove_flag(ctx->label_layer,LV_OBJ_FLAG_CLICKABLE);
|
// lv_label_set_text(ctx->fps_label,"FPS --");
|
||||||
// FPS label outside canvas, top of game_area
|
// lv_obj_set_style_text_color(ctx->fps_label, lv_color_white(),0);
|
||||||
ctx->fps_label=lv_label_create(ctx->game_area);
|
|
||||||
lv_label_set_text(ctx->fps_label,"FPS --");
|
|
||||||
lv_obj_set_style_text_color(ctx->fps_label, lv_color_white(),0);
|
|
||||||
lv_obj_set_style_text_font(ctx->fps_label, lv_font_get_default(),0);
|
|
||||||
|
|
||||||
lv_obj_add_event_cb(ctx->game_area,touch_event_cb,LV_EVENT_PRESSED,ctx);
|
lv_obj_add_event_cb(ctx->game_area,touch_event_cb,LV_EVENT_PRESSED,ctx);
|
||||||
lv_obj_add_event_cb(ctx->game_area,touch_event_cb,LV_EVENT_PRESSING,ctx);
|
lv_obj_add_event_cb(ctx->game_area,touch_event_cb,LV_EVENT_PRESSING,ctx);
|
||||||
|
|||||||
Reference in New Issue
Block a user