ref: 8b6238bf263ac5d1f357c0f4a4d0e113b83f1570
dir: /vm.c/
#include <u.h> #include <libc.h> #include <String.h> #include "objects.h" #include "ops.h" #include "vm.h" extern int debug; u32int magic = 0x07230203; static char *Einvalid = "invalid id %lld"; static char *Ewrongtype = "wrong object type %lld != %s"; #define IDVALID(c) (c < numobjects) Frame *stack = nil; u32int runinst(u32int *ptr) { u32int len, opcode; void (*func)(Frame*,u32int); opcode = (*ptr) & 0x0000ffff; len = ((*ptr) & 0xffff0000) >> 16; if (oplookup(opcode, &func)) { func(stack, len); // if (func) changes pc, ignore it if (ptr == stack->pc) { stack->pc += len; } return len; } fprint(2, "error: %r\n"); return 0; } void runstack(u32int *ptr) { Frame *n = malloc(sizeof(Frame)); n->next = stack; stack = n; stack->pc = ptr; while (runinst(stack->pc)) { ; } } void retstack(void) { Frame *p, *c; p = stack->next; c = stack; if (!p) goto fin; stack = p; fin: free(c); } void vmrun(u32int *ptr) { stack = nil; // TODO clean stack runstack(ptr); } typedef struct Object Object; struct Object { int id; char type; char *info; union { Shader s; Buffer b; }; }; Object objects[256]; int numobjects = 0; DescPool descpools[8]; int numdescpools = 0; static char* typenames[] = { "BUFFER", "SHADER", }; int validate(vlong id, int type) { if (!IDVALID(id)) { werrstr(Einvalid, id); return 0; } if (objects[id].type != type) { werrstr(Ewrongtype, id, typenames[type]); return 0; } return 1; } int runshader(vlong id, char *entrypoint) { Shader *s; EntryPoint *ep; if (!validate(id, SHADER)) return 0; s = &objects[id].s; if (!s->compiled) { werrstr("Shader %lld not compiled", id); return 0; } for (ep = s->entrypoints; ep; ep = ep->next) { if (strcmp(ep->name, entrypoint) == 0) break; } if (!ep) { werrstr("entry point %s not found", entrypoint); return 0; } for (int i = 0; i < s->nitems; i++) { fprint(2, "%d → %d\n", i, s->items[i].type); } if (s->items[ep->func].type != TFUNCTION) { werrstr("entry point function not found (object %ld type %d)", ep->func, s->items[ep->func].type); return 0; } long label = s->items[ep->func].f.label; if (label < 0) { werrstr("entry point function has no label"); return 0; } if (s->items[label].type != TLABEL) { werrstr("entry point function label is not valid"); return 0; } u32int *ptr = s->items[label].l.ptr; werrstr("passed tests, but not implemented yet"); return 0; } String* getentrypointlist(Shader *sh) { String *s; EntryPoint *ep; s = s_new(); for (ep = sh->entrypoints; ep; ep = ep->next) { s_append(s, "\nEntryPoint "); s_append(s, ep->name); } return s; } void updateinfostring(vlong id) { String *s; switch (objects[id].type) { case SHADER: if (objects[id].info) free(objects[id].info); s = getentrypointlist(&objects[id].s); objects[id].info = smprint( "DescriptorPool %d\n" "Compiled %s" "%s\n", objects[id].s.descpool, objects[id].s.compiled ? "yes" : "no", s_to_c(s) ); s_free(s); break; case BUFFER: if (objects[id].info) free(objects[id].info); objects[id].info = smprint( "Length %ld\n", objects[id].b.len ); break; } } vlong genshader(void) { vlong id; if (numobjects >= 256) { werrstr("not enough free objects!"); return -1; } id = numobjects++; objects[id].id = id; objects[id].type = SHADER; objects[id].s.buffer = nil; objects[id].s.len = -1; objects[id].s.descpool = -1; objects[id].s.compiled = 0; objects[id].s.items = nil; objects[id].s.nitems = -1; objects[id].s.maxitems = -1; objects[id].s.entrypoints = nil; objects[id].s.lastfunction = -1; updateinfostring(id); return id; } vlong genbuffer(long size) { vlong id; if (numobjects >= 256) { werrstr("not enough free objects!"); return -1; } id = numobjects++; objects[id].id = id; objects[id].type = BUFFER; objects[id].b.len = size; objects[id].b.buffer = malloc(size); if (!objects[id].b.buffer) { werrstr("cannot allocate memory: %r"); return -1; } updateinfostring(id); return id; } vlong getnumobjects() { return numobjects; } long getbufferlength(vlong id) { if (objects[id].type != BUFFER) { werrstr("invalid object type!"); return -1; } return objects[id].b.len; } long getshaderlength(vlong id) { long len; if (objects[id].type != SHADER) { werrstr("invalid object type!"); return -1; } len = objects[id].s.len; return len < 0 ? 0 : len; } int getobjecttype(vlong id) { return objects[id].type; } vlong getobjectid(vlong num) { if (num >= numobjects) { werrstr("invalid object number: %lld", num); return -1; } return objects[num].id; } int writeshader(vlong id, void *data, long n, long offset) { char *buf; if (!validate(id, SHADER)) { return 0; } buf = (char*)objects[id].s.buffer; if (!buf) { objects[id].s.len = n+offset; objects[id].s.buffer = malloc(objects[id].s.len); buf = (char*)objects[id].s.buffer; } if (!buf) { sysfatal("out of memory"); return 0; } if (offset+n > objects[id].s.len) { objects[id].s.len = n+offset; objects[id].s.buffer = realloc(objects[id].s.buffer, objects[id].s.len); buf = (char*)objects[id].s.buffer; } if (!buf) { sysfatal("out of memory!"); return 0; } buf += offset; memcpy(buf, data, n); updateinfostring(id); return n; } int writebuffer(vlong id, void *data, long n, long offset) { char *buf; if (!validate(id, BUFFER)) { return 0; } if (offset+n > objects[id].b.len) { return -1; } buf = &objects[id].b.buffer[offset]; memcpy(buf, data, n); updateinfostring(id); return n; } int compileshader(vlong id) { Shader *sh; Frame f; u32int *lastbuf; if (!validate(id, SHADER)) { return 0; } sh = &objects[id].s; if (!sh->buffer || sh->len <= 0) { werrstr("shader is empty"); return 0; } if (sh->descpool < 0) { werrstr("shader is not bound to a descriptor pool"); return 0; } if (sh->compiled) { werrstr("shader is already compiled"); return 0; } if (*sh->buffer != magic) { werrstr("invalid shader format"); return 0; } sh->maxitems = 100; sh->items = malloc(sh->maxitems*sizeof(Item)); sh->nitems = 0; f.pc = &sh->buffer[1]; // ignore magic number f.next = nil; f.ctxt.type = COMPILE; f.ctxt.c.shader = sh; lastbuf = &sh->buffer[sh->len-1]; while (f.pc < lastbuf) { u32int len, opcode; u32int *oldpc = f.pc; void (*func)(Frame*,u32int); opcode = (*f.pc) & 0x0000ffff; len = ((*f.pc) & 0xffff0000) >> 16; if (!len) break; if (oplookup(opcode, &func)) { func(&f, len); } if (oldpc == f.pc) { f.pc += len; } } updateinfostring(id); return sh->compiled = 1; } int readshader(vlong id, void *data, long n, long offset) { char *buf; if (!validate(id, SHADER)) { return 0; } buf = (char*)objects[id].s.buffer; if (!buf) { werrstr("shader is empty"); return 0; } if (offset+n > objects[id].b.len) { n = objects[id].s.len - offset; } if (n <= 0) return 0; buf = &buf[offset]; memcpy(data, buf, n); return n; } int readbuffer(vlong id, void *data, long n, long offset) { char *buf; if (!validate(id, BUFFER)) { return 0; } if (offset+n > objects[id].b.len) { n = objects[id].b.len - offset; } if (n <= 0) return 0; buf = &objects[id].b.buffer[offset]; memcpy(data, buf, n); return n; } int gendescpool(int numsets) { int id; if (numdescpools >= 8) { werrstr("not enough pools reserved"); return -1; } id = numdescpools++; descpools[id].sets = malloc(sizeof(DescSet)*numsets); if (!descpools[id].sets) { sysfatal("out of memory"); return -1; } descpools[id].numsets = numsets; memset(descpools[id].sets, 0, sizeof(DescSet)*numsets); return id; } int getnumdescpools(void) { return numdescpools; } char* getpoolinfo(void) { String* ret = s_new(); char s[128]; for (int i = 0; i < numdescpools; i++) { snprint(s, 128, "DescPool %d\n", i); ret = s_append(ret, s); for (int j = 0; j < descpools[i].numsets; j++) { snprint(s, 128, "\tSet %d\n", j); s_append(ret, s); for (int k = 0; k < descpools[i].sets[j].numbindings; k++) { snprint(s, 128, "\t\t%5d %5lld\n", k, descpools[i].sets[j].bindings[k]); s_append(ret, s); } } } return s_to_c(ret); } int allocdescset(int pool, int set, int numbindings) { if (pool >= numdescpools) { werrstr("invalid pool id %d", pool); return 0; } if (set >= descpools[pool].numsets) { werrstr("invalid set id %d", pool); return 0; } descpools[pool].sets[set].bindings = malloc(sizeof(vlong)*numbindings); if (!descpools[pool].sets[set].bindings) { sysfatal("out of memory"); return 0; } for (int i = 0; i < numbindings; i++) { descpools[pool].sets[set].bindings[i] = -1; } descpools[pool].sets[set].numbindings = numbindings; return 1; } int binduniform(vlong id, int pool, int set, int binding) { if (!validate(id, BUFFER)) { return 0; } if (pool >= numdescpools) { werrstr("invalid pool id %d", pool); return 0; } if (set >= descpools[pool].numsets) { werrstr("pool has not enough sets"); return 0; } if (binding >= descpools[pool].sets[set].numbindings) { werrstr("set has not enough bindings"); return 0; } descpools[pool].sets[set].bindings[binding] = id; return 1; } int bindshader(vlong id, int pool) { if (!validate(id, SHADER)) { return 0; } objects[id].s.descpool = pool; updateinfostring(id); return 1; } char* getobjectinfo(vlong id) { if (!IDVALID(id)) { werrstr(Einvalid, id); return nil; } return objects[id].info; }