// JoeyLib lifecycle: init, shutdown, error reporting. // // jlInit stores configuration, allocates the library-owned screen // surface, and asks the port HAL to set up the display mode. // jlShutdown tears those down in reverse order. #include #include #include #include "joey/core.h" #include "codegenArenaInternal.h" #include "hal.h" #include "surfaceInternal.h" // 8 KB fits the largest typical sprite working set (~3-4 KB per // 32x32 sprite at all opaque) and keeps malloc requests small enough // for the IIgs heap to satisfy them. #define DEFAULT_CODEGEN_BYTES (8u * 1024u) // ----- Prototypes ----- static void clearError(void); // coreSetError is the shared error setter (declared in surfaceInternal.h // and called by surface.c etc.); its definition lives here next to the // rest of the error-reporting state. // ----- Module state ----- static jlConfigT gConfig; static bool gInitialized = false; static const char *gLastError = NULL; // ----- Internal helpers (alphabetical) ----- static void clearError(void) { gLastError = NULL; } void coreSetError(const char *message) { gLastError = message; } // ----- Default large-allocation backing ----- // // jlAlloc / jlFree route through halBigAlloc / halBigFree. Most ports // have a normal heap, so the default below (plain malloc / free) serves // them and they do NOT need to implement the hook themselves. Only ports // whose C heap is too small or per-allocation-capped to satisfy a large // request -- currently just the IIgs -- provide their own halBigAlloc / // halBigFree (src/port/iigs/hal.c) and compile out this default. #ifndef JOEYLIB_PLATFORM_IIGS void *halBigAlloc(uint32_t bytes) { return malloc((size_t)bytes); } void halBigFree(void *p) { free(p); } #endif // ----- Public API (alphabetical) ----- void *jlAlloc(uint32_t bytes) { return halBigAlloc(bytes); } void jlFree(void *p) { halBigFree(p); } bool jlInit(const jlConfigT *config) { clearError(); if (gInitialized) { coreSetError("jlInit called while already initialized"); return false; } if (config == NULL) { coreSetError("jlInit called with NULL config"); return false; } memcpy(&gConfig, config, sizeof(gConfig)); // halInit must run before stageAlloc: on IIgs the stage's pixel // buffer comes from halStageAllocPixels, which depends on shadow / // SHR setup that halInit performs. if (!halInit(&gConfig)) { const char *halMsg = halLastError(); coreSetError(halMsg != NULL ? halMsg : "halInit failed"); return false; } if (!stageAlloc()) { coreSetError("failed to allocate stage surface"); halShutdown(); return false; } if (!codegenArenaInit(gConfig.codegenBytes != 0 ? gConfig.codegenBytes : DEFAULT_CODEGEN_BYTES)) { coreSetError("failed to allocate codegen arena"); stageFree(); halShutdown(); return false; } halInputInit(); gInitialized = true; return true; } const char *jlLastError(void) { return gLastError; } const char *jlPlatformName(void) { return JOEYLIB_PLATFORM_NAME; } void jlShutdown(void) { if (!gInitialized) { return; } halInputShutdown(); codegenArenaShutdown(); stageFree(); halShutdown(); gInitialized = false; clearError(); } const char *jlVersionString(void) { return JOEYLIB_VERSION_STRING; } void jlWaitVBL(void) { halWaitVBL(); } uint16_t jlFrameCount(void) { return halFrameCount(); } uint16_t jlFrameHz(void) { return halFrameHz(); } uint32_t jlMillisElapsed(void) { return halMillisElapsed(); }