VRAM buffers!

This commit is contained in:
IonutParau 2025-07-24 19:09:16 +02:00
parent 9320a19d1c
commit 0d9a59bfc7
6 changed files with 441 additions and 29 deletions

View File

@ -43,7 +43,7 @@
# Internal changes # Internal changes
- rework some interfaces to account for possibility of errors - make sure OOMs are recoverable
- rework some interfaces to use pre-allocated or stack-allocated memory more
- use dynamic arrays for signals (and maybe components), but still keep the maximums to prevent memory hogging - use dynamic arrays for signals (and maybe components), but still keep the maximums to prevent memory hogging
- setup an extensive testing system to find bugs easier - setup an extensive testing system to find bugs easier
- check if ports are open in `nn_pushNetworkMessage`

View File

@ -55,6 +55,17 @@ nn_bool_t nni_inBounds(nni_gpu *gpu, int x, int y) {
true; true;
} }
nn_size_t nni_vramNeededForSize(int w, int h) {
return w * h;
}
nn_size_t nni_vramNeededForScreen(nn_screen *screen) {
if(screen == NULL) return 0;
int w, h;
nn_maxResolution(screen, &w, &h);
return nni_vramNeededForSize(w, h);
}
// VRAM // VRAM
nni_buffer *nni_vram_newBuffer(nn_Alloc *alloc, int width, int height) { nni_buffer *nni_vram_newBuffer(nn_Alloc *alloc, int width, int height) {
@ -66,6 +77,15 @@ nni_buffer *nni_vram_newBuffer(nn_Alloc *alloc, int width, int height) {
buf->width = width; buf->width = width;
buf->height = height; buf->height = height;
buf->data = nn_alloc(alloc, sizeof(nn_scrchr_t) * area); buf->data = nn_alloc(alloc, sizeof(nn_scrchr_t) * area);
for(int i = 0; i < area; i++) {
buf->data[i] = (nn_scrchr_t) {
.codepoint = ' ',
.fg = 0xFFFFFF,
.bg = 0x000000,
.isFgPalette = false,
.isBgPalette = false,
};
}
if(buf->data == NULL) { if(buf->data == NULL) {
nn_dealloc(alloc, buf, sizeof(nni_buffer)); nn_dealloc(alloc, buf, sizeof(nni_buffer));
} }
@ -123,6 +143,55 @@ void nni_vram_set(nni_gpu *gpu, int x, int y, const char *s, nn_bool_t vertical)
} }
} }
void nni_vram_fill(nni_gpu *gpu, int x, int y, int w, int h, const char *s) {
nni_buffer *buffer = gpu->buffers[gpu->activeBuffer - 1];
// DoS mitigation
if(x < 0) x = 0;
if(y < 0) y = 0;
if(w > buffer->width) w = buffer->width - x;
if(h > buffer->height) h = buffer->height - y;
nn_scrchr_t p = nni_gpu_makePixel(gpu, s);
for(int py = 0; py < h; py++) {
for(int px = 0; px < w; px++) {
nni_vram_setPixel(buffer, px, py, p);
}
}
}
void nni_vram_copy(nni_gpu *gpu, int x, int y, int w, int h, int tx, int ty, nn_errorbuf_t err) {
nni_buffer *buffer = gpu->buffers[gpu->activeBuffer - 1];
// DoS mitigation
if(x < 0) x = 0;
if(y < 0) y = 0;
if(w > buffer->width) w = buffer->width - x;
if(h > buffer->height) h = buffer->height - y;
nn_size_t tmpBufSize = sizeof(nn_scrchr_t) * w * h;
nn_scrchr_t *tmpBuf = nn_alloc(&gpu->alloc, tmpBufSize);
if(tmpBuf == NULL) {
nn_error_write(err, "out of memory");
return;
}
// copy
for(int iy = 0; iy < h; iy++) {
for(int ix = 0; ix < w; ix++) {
tmpBuf[ix + iy * w] = nni_vram_getPixel(buffer, x, y);
}
}
for(int iy = 0; iy < h; iy++) {
for(int ix = 0; ix < w; ix++) {
nn_scrchr_t p = tmpBuf[ix + iy * w];
nni_vram_setPixel(buffer, x + ix + tx, y + iy + ty, p);
}
}
nn_dealloc(&gpu->alloc, tmpBuf, tmpBufSize);
}
// GPU stuff // GPU stuff
nni_gpu *nni_newGPU(nn_Alloc *alloc, nn_gpuControl *ctrl) { nni_gpu *nni_newGPU(nn_Alloc *alloc, nn_gpuControl *ctrl) {
@ -200,11 +269,22 @@ void nni_gpu_bind(nni_gpu *gpu, void *_, nn_component *component, nn_computer *c
return; return;
} }
nn_screen *oldScreen = gpu->currentScreen;
nn_size_t oldScreenVRAM = nni_vramNeededForScreen(oldScreen);
nn_screen *screen = nn_getComponentUserdata(c); nn_screen *screen = nn_getComponentUserdata(c);
nn_retainScreen(screen); nn_size_t screenVRAM = nni_vramNeededForScreen(screen);
if(gpu->currentScreen != NULL) nn_destroyScreen(gpu->currentScreen);
gpu->currentScreen = screen;
if(gpu->usedVRAM - oldScreenVRAM + screenVRAM > gpu->ctrl.totalVRAM) {
nn_setCError(computer, "out of vram");
return;
}
gpu->usedVRAM -= oldScreenVRAM;
gpu->usedVRAM += screenVRAM;
nn_retainScreen(screen);
if(oldScreen != NULL) nn_destroyScreen(oldScreen);
gpu->currentScreen = screen;
if(reset) { if(reset) {
for(nn_size_t i = 0; i < screen->width; i++) { for(nn_size_t i = 0; i < screen->width; i++) {
@ -222,13 +302,13 @@ void nni_gpu_bind(nni_gpu *gpu, void *_, nn_component *component, nn_computer *c
if(gpu->screenAddress != NULL) { if(gpu->screenAddress != NULL) {
nn_deallocStr(&gpu->alloc, gpu->screenAddress); nn_deallocStr(&gpu->alloc, gpu->screenAddress);
} }
// TODO: fix OOM here
gpu->screenAddress = nn_strdup(&gpu->alloc, addr); gpu->screenAddress = nn_strdup(&gpu->alloc, addr);
nn_return(computer, nn_values_boolean(true)); nn_return(computer, nn_values_boolean(true));
} }
void nni_gpu_set(nni_gpu *gpu, void *_, nn_component *component, nn_computer *computer) { 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)) - 1; int x = nn_toInt(nn_getArgument(computer, 0)) - 1;
int y = nn_toInt(nn_getArgument(computer, 1)) - 1; int y = nn_toInt(nn_getArgument(computer, 1)) - 1;
const char *s = nn_toCString(nn_getArgument(computer, 2)); const char *s = nn_toCString(nn_getArgument(computer, 2));
@ -239,6 +319,14 @@ void nni_gpu_set(nni_gpu *gpu, void *_, nn_component *component, nn_computer *co
return; return;
} }
if(gpu->activeBuffer != 0) {
nni_buffer *buffer = gpu->buffers[gpu->activeBuffer - 1];
nni_vram_set(gpu, x, y, s, isVertical);
return;
}
if(gpu->currentScreen == NULL) return;
nn_size_t current = 0; nn_size_t current = 0;
while(s[current] != 0) { while(s[current] != 0) {
unsigned int codepoint = nn_unicode_nextCodepointPermissive(s, &current); unsigned int codepoint = nn_unicode_nextCodepointPermissive(s, &current);
@ -343,8 +431,6 @@ void nni_gpu_setBackground(nni_gpu *gpu, void *_, nn_component *component, nn_co
gpu->currentBg = color; gpu->currentBg = color;
gpu->isBgPalette = isPalette; gpu->isBgPalette = isPalette;
nn_simulateBufferedIndirect(component, 1, gpu->ctrl.screenColorChangesPerTick);
nn_return(computer, nn_values_integer(old)); nn_return(computer, nn_values_integer(old));
if(idx != -1) { if(idx != -1) {
nn_return(computer, nn_values_integer(idx)); nn_return(computer, nn_values_integer(idx));
@ -375,8 +461,6 @@ void nni_gpu_setForeground(nni_gpu *gpu, void *_, nn_component *component, nn_co
gpu->currentFg = color; gpu->currentFg = color;
gpu->isFgPalette = isPalette; gpu->isFgPalette = isPalette;
nn_simulateBufferedIndirect(component, 1, gpu->ctrl.screenColorChangesPerTick);
nn_return(computer, nn_values_integer(old)); nn_return(computer, nn_values_integer(old));
if(idx != -1) { if(idx != -1) {
nn_return(computer, nn_values_integer(idx)); nn_return(computer, nn_values_integer(idx));
@ -388,7 +472,6 @@ void nni_gpu_getForeground(nni_gpu *gpu, void *_, nn_component *component, nn_co
} }
void nni_gpu_fill(nni_gpu *gpu, void *_, nn_component *component, nn_computer *computer) { 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)) - 1; int x = nn_toInt(nn_getArgument(computer, 0)) - 1;
int y = nn_toInt(nn_getArgument(computer, 1)) - 1; int y = nn_toInt(nn_getArgument(computer, 1)) - 1;
int w = nn_toInt(nn_getArgument(computer, 2)); int w = nn_toInt(nn_getArgument(computer, 2));
@ -399,6 +482,13 @@ void nni_gpu_fill(nni_gpu *gpu, void *_, nn_component *component, nn_computer *c
return; return;
} }
if(gpu->activeBuffer != 0) {
nni_vram_fill(gpu, x, y, w, h, s);
return;
}
if(gpu->currentScreen == NULL) return;
nn_size_t startIdx = 0; nn_size_t startIdx = 0;
int codepoint = nn_unicode_nextCodepointPermissive(s, &startIdx); int codepoint = nn_unicode_nextCodepointPermissive(s, &startIdx);
@ -436,7 +526,6 @@ void nni_gpu_fill(nni_gpu *gpu, void *_, nn_component *component, nn_computer *c
} }
void nni_gpu_copy(nni_gpu *gpu, void *_, nn_component *component, nn_computer *computer) { void nni_gpu_copy(nni_gpu *gpu, void *_, nn_component *component, nn_computer *computer) {
if(gpu->currentScreen == NULL) return;
int x = nn_toInt(nn_getArgument(computer, 0)) - 1; int x = nn_toInt(nn_getArgument(computer, 0)) - 1;
int y = nn_toInt(nn_getArgument(computer, 1)) - 1; int y = nn_toInt(nn_getArgument(computer, 1)) - 1;
int w = nn_toInt(nn_getArgument(computer, 2)); int w = nn_toInt(nn_getArgument(computer, 2));
@ -444,6 +533,17 @@ void nni_gpu_copy(nni_gpu *gpu, void *_, nn_component *component, nn_computer *c
int tx = nn_toInt(nn_getArgument(computer, 4)); int tx = nn_toInt(nn_getArgument(computer, 4));
int ty = nn_toInt(nn_getArgument(computer, 5)); int ty = nn_toInt(nn_getArgument(computer, 5));
if(gpu->activeBuffer != 0) {
nn_errorbuf_t err = "";
nni_vram_copy(gpu, x, y, w, h, tx, ty, err);
if(!nn_error_isEmpty(err)) {
nn_setError(computer, err);
}
return;
}
if(gpu->currentScreen == NULL) return;
// prevent DoS // prevent DoS
if(x < 0) x = 0; if(x < 0) x = 0;
if(y < 0) y = 0; if(y < 0) y = 0;
@ -539,8 +639,284 @@ void nni_gpu_maxDepth(nni_gpu *gpu, void *_, nn_component *component, nn_compute
nn_return(computer, nn_values_integer(gpu->currentScreen->maxDepth)); nn_return(computer, nn_values_integer(gpu->currentScreen->maxDepth));
} }
void nni_gpu_useless(nni_gpu *gpu, void *_, nn_component *component, nn_computer *computer) { void nni_gpu_totalMemory(nni_gpu *gpu, void *_, nn_component *component, nn_computer *computer) {
nn_return_boolean(computer, true); nn_return_integer(computer, gpu->ctrl.totalVRAM);
}
void nni_gpu_usedMemory(nni_gpu *gpu, void *_, nn_component *component, nn_computer *computer) {
nn_return_integer(computer, gpu->usedVRAM);
}
void nni_gpu_freeMemory(nni_gpu *gpu, void *_, nn_component *component, nn_computer *computer) {
nn_return_integer(computer, gpu->ctrl.totalVRAM - gpu->usedVRAM);
}
void nni_gpu_getActiveBuffer(nni_gpu *gpu, void *_, nn_component *component, nn_computer *computer) {
nn_return_integer(computer, gpu->activeBuffer);
}
void nni_gpu_setActiveBuffer(nni_gpu *gpu, void *_, nn_component *component, nn_computer *computer) {
int buf = nn_toInt(nn_getArgument(computer, 0));
if(!nni_gpu_validActiveScreen(gpu, buf)) {
nn_setCError(computer, "invalid buffer");
return;
}
gpu->activeBuffer = buf;
nn_return_integer(computer, buf);
}
void nni_gpu_buffers(nni_gpu *gpu, void *_, nn_component *component, nn_computer *computer) {
int bufCount = 0;
for(int i = 0; i < gpu->ctrl.maximumBufferCount; i++) {
if(gpu->buffers[i] != NULL) {
gpu->vramIDBuf[bufCount] = i + 1;
bufCount++;
}
}
nn_value arr = nn_return_array(computer, bufCount);
for(int i = 0; i < bufCount; i++) {
nn_values_set(arr, i, nn_values_integer(gpu->vramIDBuf[i]));
}
}
void nni_gpu_allocateBuffer(nni_gpu *gpu, void *_, nn_component *component, nn_computer *computer) {
int width = gpu->ctrl.defaultBufferWidth;
int height = gpu->ctrl.defaultBufferHeight;
nn_value widthVal = nn_getArgument(computer, 0);
nn_value heightVal = nn_getArgument(computer, 1);
if(widthVal.tag != NN_VALUE_NIL) {
width = nn_toInt(widthVal);
}
if(heightVal.tag != NN_VALUE_NIL) {
height = nn_toInt(heightVal);
}
if(width < 0 || height < 0) {
nn_setCError(computer, "invalid size");
return;
}
nn_size_t vramNeeded = nni_vramNeededForSize(width, height);
if(gpu->usedVRAM + vramNeeded > gpu->ctrl.totalVRAM) {
nn_setCError(computer, "out of vram");
return;
}
nn_size_t idx = 0;
for(nn_size_t i = 0; i < gpu->ctrl.maximumBufferCount; i++) {
if(gpu->buffers[i] == NULL) {
idx = i + 1;
break;
}
}
if(idx == 0) {
nn_setCError(computer, "too many buffers");
return;
}
nni_buffer *buf = nni_vram_newBuffer(&gpu->alloc, width, height);
if(buf == NULL) {
nn_setCError(computer, "out of memory");
return;
}
gpu->buffers[idx - 1] = buf;
gpu->usedVRAM += vramNeeded;
nn_return_integer(computer, idx);
}
void nni_gpu_freeBuffer(nni_gpu *gpu, void *_, nn_component *component, nn_computer *computer) {
int bufidx = gpu->activeBuffer;
nn_value bufVal = nn_getArgument(computer, 0);
if(bufVal.tag != NN_VALUE_NIL) {
bufidx = nn_toInt(bufVal);
}
if(!nni_gpu_validActiveScreen(gpu, bufidx) || bufidx == 0) {
nn_setCError(computer, "invalid buffer");
return;
}
nni_buffer *buf = gpu->buffers[bufidx - 1];
if(buf == NULL) {
nn_setCError(computer, "invalid buffer");
return;
}
int vramUsed = buf->width * buf->height;
nni_vram_deinit(&gpu->alloc, buf);
gpu->buffers[bufidx - 1] = NULL;
if(bufidx == gpu->activeBuffer) gpu->activeBuffer = 0;
gpu->usedVRAM -= vramUsed;
}
void nni_gpu_freeAllBuffers(nni_gpu *gpu, void *_, nn_component *component, nn_computer *computer) {
gpu->activeBuffer = 0;
for(nn_size_t i = 0; i < gpu->ctrl.maximumBufferCount; i++) {
if(gpu->buffers[i] != NULL) {
int vramUsed = gpu->buffers[i]->width * gpu->buffers[i]->height;
nni_vram_deinit(&gpu->alloc, gpu->buffers[i]);
gpu->buffers[i] = NULL;
gpu->usedVRAM -= vramUsed;
}
}
}
void nni_gpu_getBufferSize(nni_gpu *gpu, void *_, nn_component *component, nn_computer *computer) {
int bufidx = gpu->activeBuffer;
nn_value bufVal = nn_getArgument(computer, 0);
if(bufVal.tag != NN_VALUE_NIL) {
bufidx = nn_toInt(bufVal);
}
if(!nni_gpu_validActiveScreen(gpu, bufidx)) {
nn_setCError(computer, "invalid buffer");
return;
}
if(bufidx == 0) {
if(gpu->currentScreen == NULL) {
nn_setCError(computer, "invalid buffer");
return;
}
int w, h;
nn_getResolution(gpu->currentScreen, &w, &h);
nn_return_integer(computer, w);
nn_return_integer(computer, h);
return;
}
nni_buffer *buf = gpu->buffers[bufidx - 1];
if(buf == NULL) {
nn_setCError(computer, "invalid buffer");
return;
}
nn_return_integer(computer, buf->width);
nn_return_integer(computer, buf->height);
}
void nni_gpu_bitblt(nni_gpu *gpu, void *_, nn_component *component, nn_computer *computer) {
// I will kill OC creators for this
int dst = nn_toIntOr(nn_getArgument(computer, 0), 0);
int x = nn_toIntOr(nn_getArgument(computer, 1), 1);
int y = nn_toIntOr(nn_getArgument(computer, 2), 1);
int width = nn_toIntOr(nn_getArgument(computer, 3), 0);
int height = nn_toIntOr(nn_getArgument(computer, 4), 0);
int src = nn_toIntOr(nn_getArgument(computer, 5), gpu->activeBuffer);
int fromCol = nn_toIntOr(nn_getArgument(computer, 6), 1);
int fromRow = nn_toIntOr(nn_getArgument(computer, 7), 1);
if(x < 1) x = 1;
if(y < 1) y = 1;
if(fromCol < 1) fromCol = 1;
if(fromRow < 1) fromRow = 1;
if(!nni_gpu_validActiveScreen(gpu, dst)) {
nn_setCError(computer, "invalid destination buffer");
return;
}
if(!nni_gpu_validActiveScreen(gpu, src)) {
nn_setCError(computer, "invalid source buffer");
return;
}
// such great parsing
if(dst == 0) {
if(gpu->currentScreen == NULL) return;
int w, h;
nn_getResolution(gpu->currentScreen, &w, &h);
width = width == 0 ? w : width;
height = height == 0 ? h : height;
} else {
nni_buffer *buffer = gpu->buffers[dst - 1];
if(buffer == NULL) return;
width = width == 0 ? buffer->width : width;
height = height == 0 ? buffer->height : height;
}
if(dst == src) {
nn_setCError(computer, "invalid operation, use copy() instead");
return;
}
// from buffer to screen
if(dst == 0 && src != 0) {
nn_screen *screen = gpu->currentScreen;
nni_buffer *buf = gpu->buffers[src - 1];
if(buf == NULL) {
nn_setCError(computer, "invalid source buffer");
return;
}
int w, h;
nn_getResolution(gpu->currentScreen, &w, &h);
if(width > w) width = w;
if(height > h) height = h;
for(int j = 0; j < height; j++) {
for(int i = 0; i < width; i++) {
nn_scrchr_t src = nni_vram_getPixel(buf, i + fromCol - 1, j + fromRow - 1);
nn_setPixel(screen, i + x - 1, j + y - 1, src);
}
}
return;
}
// from screen to buffer
if(dst != 0 && src == 0) {
nn_screen *screen = gpu->currentScreen;
nni_buffer *buf = gpu->buffers[dst - 1];
if(buf == NULL) {
nn_setCError(computer, "invalid destination buffer");
return;
}
if(width > buf->width) width = buf->width;
if(height > buf->height) height = buf->height;
for(int j = 0; j < height; j++) {
for(int i = 0; i < width; i++) {
nn_scrchr_t src = nn_getPixel(screen, i + fromCol - 1, j + fromRow - 1);
nni_vram_setPixel(buf, i + x - 1, j + y - 1, src);
}
}
return;
}
// from buffer to buffer
if(dst != 0 && src != 0) {
nni_buffer *srcBuf = gpu->buffers[src - 1];
if(srcBuf == NULL) {
nn_setCError(computer, "invalid destination buffer");
return;
}
nni_buffer *destBuf = gpu->buffers[dst - 1];
if(destBuf == NULL) {
nn_setCError(computer, "invalid destination buffer");
return;
}
if(width > destBuf->width) width = destBuf->width;
if(height > destBuf->height) height = destBuf->height;
for(int j = 0; j < height; j++) {
for(int i = 0; i < width; i++) {
nn_scrchr_t src = nni_vram_getPixel(srcBuf, i + fromCol - 1, j + fromRow - 1);
nni_vram_setPixel(destBuf, i + x - 1, j + y - 1, src);
}
}
return;
}
} }
void nn_loadGraphicsCardTable(nn_universe *universe) { void nn_loadGraphicsCardTable(nn_universe *universe) {
@ -570,7 +946,17 @@ void nn_loadGraphicsCardTable(nn_universe *universe) {
nn_defineMethod(gpuTable, "getViewport", (nn_componentMethod *)nni_gpu_getViewport, "getViewport(): integer, integer - Gets the current viewport resolution"); nn_defineMethod(gpuTable, "getViewport", (nn_componentMethod *)nni_gpu_getViewport, "getViewport(): integer, integer - Gets the current viewport resolution");
// VRAM buffers // VRAM buffers
nn_defineMethod(gpuTable, "freeAllBuffers", (nn_componentMethod *)nni_gpu_useless, "dummy for now"); nn_defineMethod(gpuTable, "totalMemory", (nn_componentMethod *)nni_gpu_totalMemory, "totalMemory(): integer - Returns the VRAM capacity of the card");
nn_defineMethod(gpuTable, "usedMemory", (nn_componentMethod *)nni_gpu_usedMemory, "usedMemory(): integer - Returns the amount of used VRAM");
nn_defineMethod(gpuTable, "freeMemory", (nn_componentMethod *)nni_gpu_freeMemory, "freeMemory(): integer - Returns the amount of unused VRAM");
nn_defineMethod(gpuTable, "buffers", (nn_componentMethod *)nni_gpu_buffers, "buffers(): integer[] - Returns the VRAM buffers allocated (not including the screen)");
nn_defineMethod(gpuTable, "setActiveBuffer", (nn_componentMethod *)nni_gpu_setActiveBuffer, "setActiveBuffer(buffer: integer): integer - Changes the current buffer");
nn_defineMethod(gpuTable, "getActiveBuffer", (nn_componentMethod *)nni_gpu_getActiveBuffer, "getActiveBuffer(): integer - Returns the current buffer");
nn_defineMethod(gpuTable, "allocateBuffer", (nn_componentMethod *)nni_gpu_allocateBuffer, "allocateBuffer([width: integer, height: integer]): integer - Allocates a new VRAM buffer. Default size depends on GPU.");
nn_defineMethod(gpuTable, "freeBuffer", (nn_componentMethod *)nni_gpu_freeBuffer, "freeBuffer([buffer: integer]): boolean - Frees a buffer. By default, the current buffer. If the current buffer is freed, it will switch back to the screen.");
nn_defineMethod(gpuTable, "freeAllBuffers", (nn_componentMethod *)nni_gpu_freeAllBuffers, "freeAllBuffers() - Frees every VRAM buffer (if any). Also switches back to the screen.");
nn_defineMethod(gpuTable, "getBufferSize", (nn_componentMethod *)nni_gpu_getBufferSize, "getBufferSize(buffer: integer): integer, integer - Returns the size of the specified buffer.");
nn_defineMethod(gpuTable, "bitblt", (nn_componentMethod *)nni_gpu_bitblt, "dummy func");
} }
nn_component *nn_addGPU(nn_computer *computer, nn_address address, int slot, nn_gpuControl *control) { nn_component *nn_addGPU(nn_computer *computer, nn_address address, int slot, nn_gpuControl *control) {

View File

@ -1,4 +1,5 @@
#include <assert.h> #include <assert.h>
#include <time.h>
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
@ -12,8 +13,6 @@
#ifdef NN_POSIX #ifdef NN_POSIX
#include <time.h>
static double nni_realTime() { static double nni_realTime() {
struct timespec time; struct timespec time;
if(clock_gettime(CLOCK_MONOTONIC, &time) < 0) return 0; // oh no if(clock_gettime(CLOCK_MONOTONIC, &time) < 0) return 0; // oh no
@ -621,7 +620,7 @@ int main() {
// 1MB of RAM, 16 components max // 1MB of RAM, 16 components max
nn_computer *computer = nn_newComputer(universe, "testMachine", arch, NULL, 1*1024*1024, 16); nn_computer *computer = nn_newComputer(universe, "testMachine", arch, NULL, 1*1024*1024, 16);
nn_setEnergyInfo(computer, 5000, 5000); nn_setEnergyInfo(computer, 5000, 5000);
//nn_setCallBudget(computer, 18000); nn_setCallBudget(computer, 1*1024*1024);
nn_addSupportedArchitecture(computer, arch); nn_addSupportedArchitecture(computer, arch);
nn_eepromTable genericEEPROMTable = { nn_eepromTable genericEEPROMTable = {
@ -645,7 +644,7 @@ int main() {
nn_addEEPROM(computer, NULL, 0, genericEEPROM); nn_addEEPROM(computer, NULL, 0, genericEEPROM);
nn_address fsFolder = "OpenOS"; nn_address fsFolder = "Halyde";
nn_filesystemTable genericFSTable = { nn_filesystemTable genericFSTable = {
.userdata = fsFolder, .userdata = fsFolder,
.deinit = NULL, .deinit = NULL,
@ -716,7 +715,7 @@ int main() {
nn_drive *genericDrive = nn_volatileDrive(&ctx, vdriveOpts, vdriveCtrl); nn_drive *genericDrive = nn_volatileDrive(&ctx, vdriveOpts, vdriveCtrl);
nn_addDrive(computer, NULL, 4, genericDrive); nn_addDrive(computer, NULL, 4, genericDrive);
int maxWidth = 160, maxHeight = 48; int maxWidth = 80, maxHeight = 32;
nn_screen *s = nn_newScreen(&ctx, maxWidth, maxHeight, 24, 16, 256); nn_screen *s = nn_newScreen(&ctx, maxWidth, maxHeight, 24, 16, 256);
nn_setDepth(s, 4); // looks cool nn_setDepth(s, 4); // looks cool
@ -729,11 +728,12 @@ int main() {
nn_gpuControl gpuCtrl = { nn_gpuControl gpuCtrl = {
.totalVRAM = 16*1024, .totalVRAM = 16*1024,
.maximumBufferCount = 64, // probably too many .maximumBufferCount = 64, // probably too many
.defaultBufferWidth = maxWidth,
.defaultBufferHeight = maxHeight,
.screenCopyPerTick = 8, .screenCopyPerTick = 8,
.screenFillPerTick = 16, .screenFillPerTick = 16,
.screenSetsPerTick = 32, .screenSetsPerTick = 32,
.screenColorChangesPerTick = 64,
.heatPerPixelChange = 0.00005, .heatPerPixelChange = 0.00005,
.heatPerPixelReset = 0.00001, .heatPerPixelReset = 0.00001,
@ -782,6 +782,7 @@ int main() {
double idleTime = 0; double idleTime = 0;
int tps = 20; // mc TPS int tps = 20; // mc TPS
double interval = 1.0/tps; double interval = 1.0/tps;
double totalTime = 0;
while(true) { while(true) {
if(WindowShouldClose()) break; if(WindowShouldClose()) break;
@ -789,6 +790,8 @@ int main() {
double dt = GetFrameTime(); double dt = GetFrameTime();
totalTime += dt;
double heat = nn_getTemperature(computer); double heat = nn_getTemperature(computer);
double roomHeat = nn_getRoomTemperature(computer); double roomHeat = nn_getRoomTemperature(computer);
@ -797,6 +800,7 @@ int main() {
// remove some heat per second // remove some heat per second
nn_removeHeat(computer, dt * (rand() % 3) * tx * (heat - roomHeat)); nn_removeHeat(computer, dt * (rand() % 3) * tx * (heat - roomHeat));
if(nn_isOverheating(computer)) { if(nn_isOverheating(computer)) {
TraceLog(LOG_WARNING, "%3.2lf OVERHEATING", totalTime);
goto render; goto render;
} }

View File

@ -592,6 +592,10 @@ nn_bool_t nn_toBoolean(nn_value val);
const char *nn_toCString(nn_value val); const char *nn_toCString(nn_value val);
const char *nn_toString(nn_value val, nn_size_t *len); const char *nn_toString(nn_value val, nn_size_t *len);
nn_intptr_t nn_toIntOr(nn_value val, nn_intptr_t defaultVal);
double nn_toNumberOr(nn_value val, double defaultVal);
nn_bool_t nn_toBooleanOr(nn_value val, nn_bool_t defaultVal);
/* /*
* Computes the "packet size" of the values, using the same algorithm as OC. * Computes the "packet size" of the values, using the same algorithm as OC.
* This is used by pushSignal to check the size * This is used by pushSignal to check the size
@ -884,12 +888,13 @@ typedef struct nn_gpuControl {
// VRAM Buffers // VRAM Buffers
int totalVRAM; int totalVRAM;
int maximumBufferCount; int maximumBufferCount;
int defaultBufferWidth;
int defaultBufferHeight;
// Calls per tick, only applicable to screens // Calls per tick, only applicable to screens
double screenCopyPerTick; double screenCopyPerTick;
double screenFillPerTick; double screenFillPerTick;
double screenSetsPerTick; double screenSetsPerTick;
double screenColorChangesPerTick;
double bitbltPerTick; // for bitblit double bitbltPerTick; // for bitblit
// Heat // Heat

View File

@ -205,6 +205,23 @@ const char *nn_toString(nn_value val, nn_size_t *len) {
return c; return c;
} }
nn_intptr_t nn_toIntOr(nn_value val, nn_intptr_t defaultVal) {
if(val.tag == NN_VALUE_INT) return val.integer;
if(val.tag == NN_VALUE_NUMBER) return val.number;
return defaultVal;
}
double nn_toNumberOr(nn_value val, double defaultVal) {
if(val.tag == NN_VALUE_INT) return val.integer;
if(val.tag == NN_VALUE_NUMBER) return val.number;
return defaultVal;
}
nn_bool_t nn_toBooleanOr(nn_value val, nn_bool_t defaultVal) {
if(val.tag == NN_VALUE_BOOL) return val.boolean;
return defaultVal;
}
nn_size_t nn_measurePacketSize(nn_value *vals, nn_size_t len) { nn_size_t nn_measurePacketSize(nn_value *vals, nn_size_t len) {
nn_size_t size = 0; nn_size_t size = 0;
for(nn_size_t i = 0; i < len; i++) { for(nn_size_t i = 0; i < len; i++) {