joeylib2/src/core/init.c

172 lines
3.7 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 "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();
}