181 lines
4.5 KiB
C
181 lines
4.5 KiB
C
// 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 <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "joey/core.h"
|
|
#include "codegenArenaInternal.h"
|
|
#include "port.h"
|
|
#include "spriteInternal.h"
|
|
#include "surfaceInternal.h"
|
|
|
|
|
|
// Default codegen arena size when jlConfigT.codegenBytes == 0.
|
|
// Per-platform because emitter code density differs ~4-8x across CPUs
|
|
// (PERF-AUDIT.md #39):
|
|
//
|
|
// IIgs (65816): ~3-4 KB per all-opaque 32x32 sprite, so 8 KB fits
|
|
// the typical working set and keeps the attrNoCross Memory Manager
|
|
// request small. Requests above one 64 KB bank are clamped in
|
|
// codegenArenaInit (#8).
|
|
//
|
|
// Amiga/ST/DOS: the 68k/x86 emitters are far less dense -- an
|
|
// all-opaque 32x32 costs ~6.4 KB on ST (both shifts) and a
|
|
// substantially-mixed one ~8-16 KB by itself, so an 8 KB default
|
|
// silently demoted sprites to the interpreter. 32 KB matches what
|
|
// the sprite-heavy examples (uber, sprite, spacetaxi) already pass
|
|
// explicitly, and these ports have real heaps.
|
|
#if defined(JOEYLIB_PLATFORM_IIGS)
|
|
#define DEFAULT_CODEGEN_BYTES (8UL * 1024UL)
|
|
#else
|
|
#define DEFAULT_CODEGEN_BYTES (32UL * 1024UL)
|
|
#endif
|
|
|
|
// ----- 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 jlpBigAlloc / jlpBigFree. Most ports have a
|
|
// normal heap, so the malloc/free generic default (src/generic/genericPort.c)
|
|
// serves them; only ports whose C heap is too small or per-allocation-capped
|
|
// (IIgs: bank-0 heap) define JL_HAS_BIG_ALLOC and override with their native
|
|
// allocator (IIgs Memory Manager NewHandle / DisposeHandle).
|
|
|
|
|
|
// ----- Public API (alphabetical) -----
|
|
|
|
void *jlAlloc(uint32_t bytes) {
|
|
return jlpBigAlloc(bytes);
|
|
}
|
|
|
|
|
|
void jlFree(void *p) {
|
|
jlpBigFree(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));
|
|
|
|
// jlpInit must run before stageAlloc: on IIgs the stage's pixel
|
|
// buffer comes from jlpStageAllocPixels, which depends on shadow /
|
|
// SHR setup that jlpInit performs.
|
|
if (!jlpInit(&gConfig)) {
|
|
const char *halMsg = jlpLastError();
|
|
coreSetError(halMsg != NULL ? halMsg : "jlpInit failed");
|
|
return false;
|
|
}
|
|
|
|
if (!stageAlloc()) {
|
|
coreSetError("failed to allocate stage surface");
|
|
jlpShutdown();
|
|
return false;
|
|
}
|
|
|
|
if (!codegenArenaInit(gConfig.codegenBytes != 0 ? gConfig.codegenBytes
|
|
: DEFAULT_CODEGEN_BYTES)) {
|
|
coreSetError("failed to allocate codegen arena");
|
|
stageFree();
|
|
jlpShutdown();
|
|
return false;
|
|
}
|
|
|
|
jlpInputInit();
|
|
|
|
gInitialized = true;
|
|
return true;
|
|
}
|
|
|
|
|
|
const char *jlLastError(void) {
|
|
return gLastError;
|
|
}
|
|
|
|
|
|
const char *jlPlatformName(void) {
|
|
return JOEYLIB_PLATFORM_NAME;
|
|
}
|
|
|
|
|
|
void jlShutdown(void) {
|
|
if (!gInitialized) {
|
|
return;
|
|
}
|
|
jlpInputShutdown();
|
|
// Reset compiled-sprite state (slot pointers, routine offsets, patch
|
|
// caches) in every registered sprite BEFORE the arena teardown frees
|
|
// the slot structs -- see spriteSystemShutdown in spriteInternal.h
|
|
// (PERF-AUDIT.md #34).
|
|
spriteSystemShutdown();
|
|
codegenArenaShutdown();
|
|
stageFree();
|
|
jlpShutdown();
|
|
gInitialized = false;
|
|
clearError();
|
|
}
|
|
|
|
|
|
const char *jlVersionString(void) {
|
|
return JOEYLIB_VERSION_STRING;
|
|
}
|
|
|
|
|
|
void jlWaitVBL(void) {
|
|
jlpWaitVBL();
|
|
}
|
|
|
|
|
|
uint16_t jlFrameCount(void) {
|
|
return jlpFrameCount();
|
|
}
|
|
|
|
|
|
uint16_t jlFrameHz(void) {
|
|
return jlpFrameHz();
|
|
}
|
|
|
|
|
|
uint32_t jlMillisElapsed(void) {
|
|
return jlpMillisElapsed();
|
|
}
|