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;
}