diff --git a/src/main.c b/src/main.c index b2838dd..d319480 100644 --- a/src/main.c +++ b/src/main.c @@ -414,7 +414,7 @@ int main(int argc, char **argv) { double wattage = 0; nn_Component *screen = ncl_createScreen(u, NULL, &nn_defaultScreens[3]); - //nn_Component *gpu = ncl_createGPU(u, NULL, &nn_defaultGPUs[3]); + nn_Component *gpuCard = ncl_createGPU(u, NULL, &nn_defaultGPUs[3]); { // draw test @@ -444,6 +444,7 @@ restart:; nn_mountComponent(c, ocelotCard, -1); nn_mountComponent(c, eepromCard, 0); nn_mountComponent(c, managedfs, 1); + nn_mountComponent(c, gpuCard, 2); while(true) { if(WindowShouldClose()) break; @@ -578,6 +579,7 @@ cleanup:; nn_dropComponent(eepromCard); nn_dropComponent(managedfs); nn_dropComponent(screen); + nn_dropComponent(gpuCard); // rip the universe nn_destroyUniverse(u); UnloadFont(font); diff --git a/src/ncomplib.c b/src/ncomplib.c index a2e8a4f..918c724 100644 --- a/src/ncomplib.c +++ b/src/ncomplib.c @@ -438,6 +438,30 @@ static ncl_VRAMBuf *ncl_allocVRAM(nn_Context *ctx, int width, int height) { return buf; } +static ncl_ScreenPixel *ncl_vramPtr(ncl_VRAMBuf *buf, int x, int y) { + x--; + y--; + if(x < 0 || y < 0 || x >= buf->width || y >= buf->height) return NULL; + return &buf->pixels[x + y * buf->width]; +} + +static ncl_ScreenPixel ncl_vramGet(ncl_VRAMBuf *buf, int x, int y) { + ncl_ScreenPixel *ptr = ncl_vramPtr(buf, x, y); + if(ptr != NULL) return *ptr; + return (ncl_ScreenPixel) { + .codepoint = ' ', + .storedFg = 0xFFFFFF, + .storedBg = 0x000000, + .realFg = 0xFFFFFF, + .realBg = 0x000000, + }; +} + +static void ncl_vramSet(ncl_VRAMBuf *buf, int x, int y, ncl_ScreenPixel pixel) { + ncl_ScreenPixel *ptr = ncl_vramPtr(buf, x, y); + if(ptr != NULL) *ptr = pixel; +} + typedef struct ncl_FSState { nn_Context *ctx; nn_Lock *lock; @@ -590,6 +614,11 @@ static nn_Exit ncl_fsHandler(nn_FSRequest *req) { } state->fds[fd] = file; req->fd = fd; + if(mode[0] == 'w') { + // file cleared + state->spaceUsed = 0; + state->realSpaceUsed = 0; + } nn_unlock(ctx, state->lock); return NN_OK; } @@ -1008,7 +1037,88 @@ fail:; return NULL; } -nn_Component *ncl_createGPU(nn_Universe *universe, const char *address, const nn_GPU *gpu); +static ncl_ScreenState *ncl_getBoundScreen(ncl_GPUState *gpu, nn_Computer *C) { + if(gpu->screenAddress == NULL) return NULL; + nn_Component *c = nn_getComponent(C, gpu->screenAddress); + if(c == NULL) return NULL; + return nn_getComponentState(c); +} + +static void ncl_getGPULimits(ncl_GPUState *gpu, nn_Computer *C, int *maxWidth, int *maxHeight, char *maxDepth) { + int w = gpu->conf.maxWidth, h = gpu->conf.maxHeight; + char d = gpu->conf.maxDepth; + + ncl_ScreenState *screen = ncl_getBoundScreen(gpu, C); + + if(screen != NULL) { + if(w > screen->conf.maxWidth) w = screen->conf.maxWidth; + if(h > screen->conf.maxHeight) h = screen->conf.maxHeight; + if(d > screen->conf.maxDepth) d = screen->conf.maxDepth; + } + + *maxWidth = w; + *maxHeight = h; + *maxDepth = d; +} + +static nn_Exit ncl_gpuHandler(nn_GPURequest *req) { + nn_Context *ctx = req->ctx; + nn_Computer *C = req->computer; + ncl_GPUState *state = req->state; + const nn_GPU *gpu = req->gpu; + if(req->action == NN_GPU_DROP) { + for(size_t i = 0; i < NCL_MAX_VRAMBUF; i++) { + if(state->vram[i] != NULL) ncl_freeVRAM(ctx, state->vram[i]); + } + if(state->screenAddress != NULL) nn_strfree(ctx, state->screenAddress); + nn_free(ctx, state, sizeof(*state)); + return NN_OK; + } + if(C != NULL) nn_setError(C, "ncl-gpu: not implemented yet"); + return NN_EBADCALL; +} + +nn_Component *ncl_createGPU(nn_Universe *universe, const char *address, const nn_GPU *gpu) { + nn_Context *ctx = nn_getUniverseContext(universe); + nn_Lock *lock = NULL; + ncl_GPUState *state = NULL; + nn_Component *c = NULL; + + lock = nn_createLock(ctx); + if(lock == NULL) goto fail; + + state = nn_alloc(ctx, sizeof(*state)); + if(state == NULL) goto fail; + + state->ctx = ctx; + state->lock = lock; + state->conf = *gpu; + state->vramFree = gpu->totalVRAM; + state->screenAddress = NULL; + state->currentFg = 0xFFFFFF; + state->currentBg = 0x000000; + state->activeBuffer = 0; + state->isFgPalette = false; + state->isBgPalette = false; + for(size_t i = 0; i < NCL_MAX_VRAMBUF; i++) { + state->vram[i] = NULL; + } + + c = nn_createGPU(universe, address, gpu, state, ncl_gpuHandler); + if(c == NULL) goto fail; + + if(nn_setComponentTypeID(c, NCL_GPU)) goto fail; + + return c; +fail: + if(c != NULL) { + nn_dropComponent(c); + return NULL; + } + if(lock != NULL) nn_destroyLock(ctx, lock); + nn_free(ctx, state, sizeof(*state)); + return NULL; +} void ncl_lockScreen(ncl_ScreenState *state) { nn_lock(state->ctx, state->lock); diff --git a/src/neonucleus.c b/src/neonucleus.c index 14568a1..0f7a93c 100644 --- a/src/neonucleus.c +++ b/src/neonucleus.c @@ -1821,6 +1821,8 @@ bool nn_costComponent(nn_Computer *computer, const char *address, double perTick } bool nn_costComponentN(nn_Computer *computer, const char *address, double amount, double perTick) { + // this means 0 per tick means free + if(perTick == 0) return false; nn_ComponentEntry *c = nn_getInternalComponent(computer, address); if(c == NULL) return false; c->budgetUsed += (NN_COMPONENT_CALLBUDGET * amount) / perTick; @@ -3825,3 +3827,51 @@ nn_Component *nn_createScreen(nn_Universe *universe, const char *address, const nn_setComponentHandler(c, nn_screenHandler); return c; } + +typedef struct nn_GPUState { + nn_Context *ctx; + nn_GPU gpu; + nn_GPUHandler *handler; +} nn_GPUState; + +static nn_Exit nn_gpuHandler(nn_ComponentRequest *req) { + if(req->action == NN_COMP_CHECKMETHOD) return NN_OK; + if(req->action == NN_COMP_SIGNAL) return NN_OK; + nn_Context *ctx = req->ctx; + nn_GPUState *state = req->classState; + nn_Computer *C = req->computer; + nn_GPURequest greq; + greq.ctx = ctx; + greq.state = req->state; + greq.computer = C; + greq.gpu = &state->gpu; + + if(req->action == NN_COMP_DROP) { + greq.action = NN_GPU_DROP; + state->handler(&greq); + nn_free(ctx, state, sizeof(*state)); + return NN_OK; + } + + nn_setError(C, "gpu: not yet implemented"); + return NN_EBADCALL; +} + +nn_Component *nn_createGPU(nn_Universe *universe, const char *address, const nn_GPU *gpu, void *state, nn_GPUHandler *handler) { + nn_Component *c = nn_createComponent(universe, address, "gpu"); + if(c == NULL) return NULL; + // TODO: methods + nn_Context *ctx = &universe->ctx; + nn_GPUState *gpustate = nn_alloc(ctx, sizeof(*gpustate)); + if(gpustate == NULL) { + nn_dropComponent(c); + return NULL; + } + gpustate->ctx = ctx; + gpustate->gpu = *gpu; + gpustate->handler = handler; + nn_setComponentState(c, state); + nn_setComponentClassState(c, gpustate); + nn_setComponentHandler(c, nn_gpuHandler); + return c; +} diff --git a/src/neonucleus.h b/src/neonucleus.h index db9d965..c6db470 100644 --- a/src/neonucleus.h +++ b/src/neonucleus.h @@ -1220,6 +1220,22 @@ typedef struct nn_GPU { // 1 GPU tier for every screen. extern const nn_GPU nn_defaultGPUs[4]; +typedef enum nn_GPUAction { + NN_GPU_DROP, +} nn_GPUAction; + +typedef struct nn_GPURequest { + nn_Context *ctx; + nn_Computer *computer; + void *state; + const nn_GPU *gpu; + nn_GPUAction action; +} nn_GPURequest; + +typedef nn_Exit (nn_GPUHandler)(nn_GPURequest *req); + +nn_Component *nn_createGPU(nn_Universe *universe, const char *address, const nn_GPU *gpu, void *state, nn_GPUHandler *handler); + // Colors and palettes. // Do note that the