From e2bc6bd4694d7036625d78004ded448101b19400 Mon Sep 17 00:00:00 2001 From: IonutParau Date: Wed, 25 Jun 2025 00:35:33 +0200 Subject: [PATCH] made stuff kind of work TODO: fix some issues in the GPU code --- src/components/gpu.c | 155 ++++++++++++++++++++++++++++++++++++++++ src/components/screen.c | 15 ++++ src/emulator.c | 42 +++++++++-- src/neonucleus.h | 2 +- src/sandbox.lua | 8 +-- 5 files changed, 210 insertions(+), 12 deletions(-) diff --git a/src/components/gpu.c b/src/components/gpu.c index 772a90c..12599a9 100644 --- a/src/components/gpu.c +++ b/src/components/gpu.c @@ -1,5 +1,6 @@ #include "../neonucleus.h" #include "screen.h" +#include typedef struct nni_gpu { nn_screen *currentScreen; @@ -12,6 +13,16 @@ typedef struct nni_gpu { // TODO: think about buffers and stuff } nni_gpu; +bool nni_samePixel(nn_scrchr_t a, nn_scrchr_t b) { + return + a.codepoint == b.codepoint && + a.fg == b.fg && + a.bg == b.bg && + a.isFgPalette == b.isFgPalette && + a.isBgPalette == b.isBgPalette + ; +} + nni_gpu *nni_newGPU(nn_gpuControl *ctrl) { nni_gpu *gpu = nn_malloc(sizeof(nni_gpu)); gpu->currentScreen = NULL; @@ -101,11 +112,41 @@ void nni_gpu_bind(nni_gpu *gpu, void *_, nn_component *component, nn_computer *c } void nni_gpu_set(nni_gpu *gpu, void *_, nn_component *component, nn_computer *computer) { + if(gpu->currentScreen == NULL) return; + int x = nn_toInt(nn_getArgument(computer, 0)); + int y = nn_toInt(nn_getArgument(computer, 1)); + const char *s = nn_toCString(nn_getArgument(computer, 2)); + bool isVertical = nn_toBoolean(nn_getArgument(computer, 3)); + if(s == NULL) { + nn_setCError(computer, "bad argument #4 (string expected)"); + return; + } + + int current = 0; + while(s[current]) { + int codepoint = nn_unicode_codepointAt(s, current); + nn_setPixel(gpu->currentScreen, x, y, nni_gpu_makePixel(gpu, s + current)); + if(isVertical) + y++; + else + x++; + current += nn_unicode_codepointSize(codepoint); + } } void nni_gpu_get(nni_gpu *gpu, void *_, nn_component *component, nn_computer *computer) { + if(gpu->screenAddress == NULL) return; + int x = nn_toInt(nn_getArgument(computer, 0)); + int y = nn_toInt(nn_getArgument(computer, 1)); + nn_scrchr_t pxl = nn_getPixel(gpu->currentScreen, x, y); + size_t l; + const char *chr = nn_unicode_codepointToChar(pxl.codepoint, &l); + + nn_return(computer, nn_values_cstring(chr)); + nn_return(computer, nn_values_integer(pxl.fg)); + nn_return(computer, nn_values_integer(pxl.bg)); } void nni_gpu_getScreen(nni_gpu *gpu, void *_, nn_component *component, nn_computer *computer) { @@ -133,6 +174,117 @@ void nni_gpu_setResolution(nni_gpu *gpu, void *_, nn_component *component, nn_co if(gpu->currentScreen == NULL) return; } +void nni_gpu_setBackground(nni_gpu *gpu, void *_, nn_component *component, nn_computer *computer) { + if(gpu->currentScreen == NULL) return; + int color = nn_toInt(nn_getArgument(computer, 0)); + bool isPalette = nn_toBoolean(nn_getArgument(computer, 1)); + + if(isPalette && (color < 0 || color >= gpu->currentScreen->paletteColors)) { + nn_setCError(computer, "invalid palette index"); + return; + } + + int old = gpu->currentBg; + int idx = -1; + if(gpu->isBgPalette) { + idx = old; + old = gpu->currentScreen->palette[old]; + } + + gpu->currentBg = color; + gpu->isBgPalette = isPalette; + + nn_addHeat(computer, gpu->ctrl.colorChangeHeat); + nn_callCost(computer, gpu->ctrl.colorChangeCost); + nn_removeEnergy(computer, gpu->ctrl.colorChangeEnergy); + nn_busySleep(gpu->ctrl.colorChangeLatency); + + nn_return(computer, nn_values_integer(old)); + if(idx != -1) { + nn_return(computer, nn_values_integer(idx)); + } +} + +void nni_gpu_setForeground(nni_gpu *gpu, void *_, nn_component *component, nn_computer *computer) { + if(gpu->currentScreen == NULL) return; + int color = nn_toInt(nn_getArgument(computer, 0)); + bool isPalette = nn_toBoolean(nn_getArgument(computer, 1)); + + if(isPalette && (color < 0 || color >= gpu->currentScreen->paletteColors)) { + nn_setCError(computer, "invalid palette index"); + return; + } + + int old = gpu->currentFg; + int idx = -1; + if(gpu->isFgPalette) { + idx = old; + old = gpu->currentScreen->palette[old]; + } + + gpu->currentFg = color; + gpu->isFgPalette = isPalette; + + nn_addHeat(computer, gpu->ctrl.colorChangeHeat); + nn_callCost(computer, gpu->ctrl.colorChangeCost); + nn_removeEnergy(computer, gpu->ctrl.colorChangeEnergy); + nn_busySleep(gpu->ctrl.colorChangeLatency); + + nn_return(computer, nn_values_integer(old)); + if(idx != -1) { + nn_return(computer, nn_values_integer(idx)); + } +} + +void nni_gpu_fill(nni_gpu *gpu, void *_, nn_component *component, nn_computer *computer) { + if(gpu->currentScreen == NULL) return; + int x = nn_toInt(nn_getArgument(computer, 0)); + int y = nn_toInt(nn_getArgument(computer, 1)); + int w = nn_toInt(nn_getArgument(computer, 2)); + int h = nn_toInt(nn_getArgument(computer, 3)); + const char *s = nn_toCString(nn_getArgument(computer, 4)); + if(s == NULL) { + nn_setCError(computer, "bad argument #5 (character expected)"); + return; + } + + int codepoint = nn_unicode_codepointAt(s, 0); + + // prevent DoS + if(x < 0) x = 0; + if(y < 0) y = 0; + if(w > gpu->currentScreen->width - x) w = gpu->currentScreen->width - x; + if(h > gpu->currentScreen->height - y) y = gpu->currentScreen->height - y; + + int changes = 0, clears = 0; + + nn_scrchr_t new = nni_gpu_makePixel(gpu, s); + + for(int cx = x; cx < x + w; cx++) { + for(int cy = y; cy < y + h; cy++) { + nn_scrchr_t old = nn_getPixel(gpu->currentScreen, cx, cy); + if(!nni_samePixel(old, new)) { + nn_setPixel(gpu->currentScreen, cx, cy, new); + if(codepoint == ' ') + clears++; + else changes++; + } + } + } + + nn_addHeat(computer, gpu->ctrl.pixelChangeHeat * changes); + nn_callCost(computer, gpu->ctrl.pixelChangeCost * changes); + nn_removeEnergy(computer, gpu->ctrl.pixelChangeEnergy * changes); + nn_busySleep(gpu->ctrl.pixelChangeLatency * changes); + + nn_addHeat(computer, gpu->ctrl.pixelChangeHeat * clears); + nn_callCost(computer, gpu->ctrl.pixelChangeCost * clears); + nn_removeEnergy(computer, gpu->ctrl.pixelChangeEnergy * clears); + nn_busySleep(gpu->ctrl.pixelChangeLatency * clears); + + nn_return(computer, nn_values_boolean(true)); +} + void nn_loadGraphicsCardTable(nn_universe *universe) { nn_componentTable *gpuTable = nn_newComponentTable("gpu", NULL, NULL, (void *)nni_gpuDeinit); nn_storeUserdata(universe, "NN:GPU", gpuTable); @@ -144,6 +296,9 @@ void nn_loadGraphicsCardTable(nn_universe *universe) { nn_defineMethod(gpuTable, "maxResolution", true, (void *)nni_gpu_maxResolution, NULL, "maxResolution(): integer, integer - Gets the maximum resolution supported by the bound screen."); nn_defineMethod(gpuTable, "getResolution", true, (void *)nni_gpu_getResolution, NULL, "getResolution(): integer, integer - Gets the current resolution of the bound screen."); nn_defineMethod(gpuTable, "setResolution", true, (void *)nni_gpu_setResolution, NULL, "maxResolution(): integer, integer - Changes the resolution of the bound screen."); + nn_defineMethod(gpuTable, "setBackground", true, (void *)nni_gpu_setBackground, NULL, "setBackground(color: integer, isPalette: boolean): integer, integer? - Sets the current background color. Returns the old one and palette index if applicable."); + nn_defineMethod(gpuTable, "setForeground", true, (void *)nni_gpu_setForeground, NULL, "setForeground(color: integer, isPalette: boolean): integer, integer? - Sets the current foreground color. Returns the old one and palette index if applicable."); + nn_defineMethod(gpuTable, "fill", true, (void *)nni_gpu_fill, NULL, "fill(x: integer, y: integer, w: integer, h: integer, s: string)"); } nn_component *nn_addGPU(nn_computer *computer, nn_address address, int slot, nn_gpuControl *control) { diff --git a/src/components/screen.c b/src/components/screen.c index 14f13ad..e2cbd26 100644 --- a/src/components/screen.c +++ b/src/components/screen.c @@ -146,10 +146,25 @@ void nn_setDepth(nn_screen *screen, int depth) { } void nn_setPixel(nn_screen *screen, int x, int y, nn_scrchr_t pixel) { + if(x < 0) return; + if(y < 0) return; + if(x >= screen->width) return; + if(y >= screen->height) return; screen->buffer[x + y * screen->maxWidth] = pixel; } nn_scrchr_t nn_getPixel(nn_screen *screen, int x, int y) { + nn_scrchr_t blank = { + .codepoint = ' ', + .fg = 0xFFFFFF, + .bg = 0x000000, + .isFgPalette = false, + .isBgPalette = false, + }; + if(x < 0) return blank; + if(y < 0) return blank; + if(x >= screen->width) return blank; + if(x >= screen->height) return blank; return screen->buffer[x + y * screen->maxWidth]; } diff --git a/src/emulator.c b/src/emulator.c index 8ef0d3a..50a5dae 100644 --- a/src/emulator.c +++ b/src/emulator.c @@ -7,8 +7,10 @@ #include "testLuaArch.h" #include -Color ne_processColor(int color) { - return GetColor(color * 0x100 + 0xFF); +Color ne_processColor(unsigned int color) { + color <<= 8; + color |= 0xFF; + return GetColor(color); } nn_eepromControl ne_eeprom_getControl(nn_component *component, void *_) { @@ -136,6 +138,7 @@ size_t ne_fs_open(nn_component *component, ne_fs *fs, const char *path, const ch } const char *p = ne_fs_diskPath(component, path); + if(p[0] == '/') p++; FILE *f = fopen(p, trueMode); if(f == NULL) { @@ -175,6 +178,7 @@ size_t ne_fs_read(nn_component *component, ne_fs *fs, int fd, char *buf, size_t char **ne_fs_list(nn_component *component, ne_fs *fs, const char *path, size_t *len) { const char *p = ne_fs_diskPath(component, path); + if(p[0] == '/') p++; FilePathList files = LoadDirectoryFiles(p); *len = files.count; @@ -191,18 +195,21 @@ char **ne_fs_list(nn_component *component, ne_fs *fs, const char *path, size_t * bool ne_fs_isDirectory(nn_component *component, ne_fs *fs, const char *path) { const char *p = ne_fs_diskPath(component, path); + if(p[0] == '/') p++; return DirectoryExists(p); } bool ne_fs_makeDirectory(nn_component *component, ne_fs *fs, const char *path) { const char *p = ne_fs_diskPath(component, path); + if(p[0] == '/') p++; return MakeDirectory(p) == 0; } bool ne_fs_exists(nn_component *component, ne_fs *fs, const char *path) { const char *p = ne_fs_diskPath(component, path); + if(p[0] == '/') p++; return FileExists(p) || DirectoryExists(p); } @@ -271,19 +278,40 @@ int main() { }; nn_addFileSystem(computer, "OpenOS", 1, &genericFS); - nn_screen *s = nn_newScreen(240, 80, 16, 16, 256); - + nn_screen *s = nn_newScreen(80, 32, 16, 16, 256); + nn_addKeyboard(s, "shitty keyboard"); nn_addScreen(computer, "Main Screen", 2, s); nn_gpuControl gpuCtrl = { .maxWidth = 240, .maxHeight = 80, .maxDepth = 16, - // fuck the rest, to be decided later + + .totalVRAM = 32*1024, + .vramByteChangeCost = 0, + .vramByteChangeEnergy = 0, + .vramByteChangeHeat = 0, + .vramByteChangeLatency = 0, + + .pixelChangeCost = 0, + .pixelChangeEnergy = 0, + .pixelChangeHeat = 0, + .pixelChangeLatency = 0, + + .pixelResetCost = 0, + .pixelResetEnergy = 0, + .pixelResetHeat = 0, + .pixelResetLatency = 0, + + .colorChangeLatency = 0, + .colorChangeCost = 0, + .colorChangeEnergy = 0, + .colorChangeHeat = 0, }; nn_addGPU(computer, "RTX 6090", 3, &gpuCtrl); + SetWindowState(FLAG_WINDOW_RESIZABLE); InitWindow(800, 600, "emulator"); double lastTime = nn_realTime(); @@ -344,14 +372,14 @@ render: Color fgColor = ne_processColor(p.fg); Color bgColor = ne_processColor(p.bg); DrawRectangle(x * pixelWidth, y * pixelHeight, pixelWidth, pixelHeight, bgColor); - DrawText(s, x * pixelWidth, y * pixelHeight, pixelHeight, fgColor); + DrawText(s, x * pixelWidth, y * pixelHeight, pixelHeight - 5, fgColor); } } Color heatColor = GREEN; if(heat > 60) heatColor = YELLOW; if(heat > 80) heatColor = RED; - DrawText(TextFormat("Heat: %lf\n", heat), 10, 10, 20, heatColor); + DrawText(TextFormat("Heat: %lf\n", heat), 10, GetScreenHeight() - 30, 20, heatColor); EndDrawing(); } diff --git a/src/neonucleus.h b/src/neonucleus.h index 87a42c8..1982adf 100644 --- a/src/neonucleus.h +++ b/src/neonucleus.h @@ -65,7 +65,7 @@ #define NN_CALL_HEAT 0.05 #define NN_CALL_COST 1 #define NN_LABEL_SIZE 128 -#define NN_INDIRECT_CALL_LATENCY 0.05 +#define NN_INDIRECT_CALL_LATENCY 0.005 typedef struct nn_guard nn_guard; typedef atomic_size_t nn_refc; diff --git a/src/sandbox.lua b/src/sandbox.lua index 2fd1f99..b23344d 100644 --- a/src/sandbox.lua +++ b/src/sandbox.lua @@ -48,7 +48,7 @@ debug.sethook(function() bubbleYield = true error(tooLongWithoutYielding) -- here it is an actual string end -end, "c", 20000) -- no bogo mips, the check is cheap anyways +end, "c", 100000) -- no bogo mips, the check is cheap anyways local function resume(co, val1, ...) while true do @@ -222,7 +222,7 @@ local libcomputer = { repeat yield() -- give executor a chance to give us stuff - local s = table.pack(computer.pullSignal()) + local s = table.pack(computer.popSignal()) if s.n > 0 then return table.unpack(s) end @@ -396,7 +396,7 @@ sandbox = { checkArg = checkArg, component = libcomponent, computer = libcomputer, - print = print, + debugprint = print, } sandbox._G = sandbox @@ -419,7 +419,7 @@ while true do timeout = nextDeadline() bubbleYield = false - local ok, err = resume(co) + local ok, err = coroutine.resume(co) if not ok then error(debug.traceback(co, err), 0)