508 lines
11 KiB
C
508 lines
11 KiB
C
#ifndef MINI_SPIRV_H
|
|
#define MINI_SPIRV_H
|
|
#include "stdlib.h"
|
|
#include "stdint.h"
|
|
#include "stdio.h"
|
|
#include "string.h"
|
|
#include "unistd.h"
|
|
#define SPV_ENABLE_UTILITY_CODE
|
|
#include "spirv/unified1/spirv.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C"
|
|
{
|
|
#endif
|
|
|
|
/* arrays */
|
|
|
|
static inline uint32_t _mspvalign2( uint32_t x )
|
|
{
|
|
if (x <= 1) return 1;
|
|
x--;
|
|
x |= x >> 1;
|
|
x |= x >> 2;
|
|
x |= x >> 4;
|
|
x |= x >> 8;
|
|
x |= x >> 16;
|
|
x++;
|
|
return x;
|
|
}
|
|
|
|
#define mspv_array(T) \
|
|
struct \
|
|
{ \
|
|
size_t count; \
|
|
size_t capacity; \
|
|
T *data; \
|
|
}
|
|
|
|
#define mspv_array_zero(array) \
|
|
array.count = 0; \
|
|
array.capacity = 0; \
|
|
array.data = NULL;
|
|
|
|
#define mspv_array_create(array, count) \
|
|
array.count = count; \
|
|
array.capacity = _mspvalign2(count); \
|
|
array.data = malloc(array.capacity * sizeof(*array.data));
|
|
|
|
#define mspv_array_push(array, value) \
|
|
do { \
|
|
if (array.count >= array.capacity) { \
|
|
if (array.capacity == 0) array.capacity = 4; \
|
|
else array.capacity *= 2; \
|
|
array.data = (typeof(array.data))realloc(array.data, array.capacity * sizeof(*array.data)); \
|
|
} \
|
|
array.data[array.count++] = value;\
|
|
} while(0) \
|
|
|
|
#define mspv_array_destroy(array) \
|
|
if (array.data) free(array.data); \
|
|
mspv_array_zero(array)
|
|
|
|
/* strings views for simplicity */
|
|
typedef struct
|
|
{
|
|
const char *data;
|
|
size_t len;
|
|
} mspv_string_view;
|
|
|
|
typedef struct
|
|
{
|
|
uint32_t *data;
|
|
size_t len;
|
|
} mspv_data_view;
|
|
|
|
typedef struct
|
|
{
|
|
uint32_t id;
|
|
mspv_string_view name;
|
|
} mspv_ext_import;
|
|
|
|
typedef struct
|
|
{
|
|
SpvExecutionModel model;
|
|
uint32_t id;
|
|
mspv_string_view name;
|
|
mspv_array(uint32_t) params;
|
|
} mspv_entry_point;
|
|
|
|
typedef struct
|
|
{
|
|
uint32_t id;
|
|
SpvExecutionMode mode;
|
|
mspv_data_view dv;
|
|
} mspv_execution_mode;
|
|
|
|
typedef struct
|
|
{
|
|
uint32_t resulttype;
|
|
uint32_t result;
|
|
uint32_t functionctrl;
|
|
uint32_t functiontype;
|
|
mspv_data_view instructions;
|
|
} mspv_function;
|
|
|
|
typedef struct
|
|
{
|
|
uint32_t magic;
|
|
uint32_t reserved1;
|
|
uint32_t reserved2;
|
|
uint32_t reserved3;
|
|
uint32_t reserved4;
|
|
} mspv_header;
|
|
|
|
typedef struct
|
|
{
|
|
uint32_t id;
|
|
mspv_data_view dv;
|
|
} mspv_type;
|
|
|
|
typedef struct
|
|
{
|
|
uint32_t resulttype;
|
|
uint32_t result;
|
|
uint32_t storageclass;
|
|
uint32_t initializer;
|
|
} mspv_variable;
|
|
|
|
typedef struct
|
|
{
|
|
uint32_t id;
|
|
mspv_string_view name;
|
|
} mspv_name;
|
|
|
|
typedef struct
|
|
{
|
|
mspv_header header;
|
|
SpvMemoryModel memory_model;
|
|
SpvAddressingModel addressing_model;
|
|
mspv_array(SpvCapability) capabilities;
|
|
mspv_array(mspv_string_view) extensions;
|
|
mspv_array(mspv_ext_import) ext_instructions;
|
|
mspv_array(mspv_string_view) instruction_imports;
|
|
mspv_array(mspv_entry_point) entry_points;
|
|
mspv_array(mspv_execution_mode) execution_modes;
|
|
mspv_array(mspv_name) names;
|
|
mspv_array(mspv_type) types;
|
|
mspv_array(mspv_variable) variables;
|
|
mspv_array(mspv_function) functions;
|
|
|
|
uint32_t *data;
|
|
uint32_t count;
|
|
} mspv_module;
|
|
|
|
|
|
mspv_module *mspv_read_module( uint32_t count, uint32_t *data );
|
|
void mspv_close_module( mspv_module* module );
|
|
|
|
#define mspv_todo(str) printf("todo!!! " str "\n"); _exit(0)
|
|
|
|
#define mspv_sv_fmt "%.*s"
|
|
#define mspv_psv(sv) sv.len, sv.data
|
|
|
|
//#ifdef MINI_SPIRV_IMPLEMENTATION
|
|
static inline mspv_string_view mspv_sv_from_op( uint32_t *op )
|
|
{
|
|
return { (char*)op, strlen((char*)op)};
|
|
|
|
};
|
|
|
|
mspv_module *mspv_read_module( uint32_t count, uint32_t *data )
|
|
{
|
|
mspv_module m;
|
|
mspv_header *h;
|
|
int i;
|
|
uint32_t u;
|
|
SpvOp op;
|
|
uint16_t instruction_size;
|
|
uint16_t local_offset;
|
|
mspv_string_view sv;
|
|
mspv_data_view dv;
|
|
mspv_entry_point ep;
|
|
mspv_ext_import imp;
|
|
mspv_execution_mode em;
|
|
mspv_type type;
|
|
mspv_variable var;
|
|
mspv_function fn;
|
|
mspv_name nm;
|
|
int isfn;
|
|
|
|
if ( count == 0 || data == NULL)
|
|
return 0;
|
|
|
|
m = {};
|
|
m.data = data;
|
|
m.count = count;
|
|
|
|
h = (mspv_header*)data;
|
|
if ( h->magic != SpvMagicNumber )
|
|
return 0;
|
|
m.header = *h;
|
|
|
|
/* loop instrucitons */
|
|
isfn = 0;
|
|
|
|
for ( u = 5; u < count; )
|
|
{
|
|
instruction_size = data[u] >> 16;
|
|
op = (SpvOp)(data[u] & 0xFFFF);
|
|
switch (op)
|
|
{
|
|
case SpvOpCapability:
|
|
mspv_array_push(m.capabilities, (SpvCapability)data[u+1]);
|
|
break;
|
|
case SpvOpExtension:
|
|
sv.len = strlen((char*)(data + u + 1));
|
|
sv.data = (char*)&data[u+1];
|
|
mspv_array_push(m.extensions, sv);
|
|
break;
|
|
case SpvOpExtInstImport:
|
|
imp.id = data[u+1];
|
|
imp.name.len = strlen((char*)(data + u + 2));
|
|
imp.name.data = (char*)&data[u+2];
|
|
mspv_array_push(m.ext_instructions, imp);
|
|
break;
|
|
case SpvOpMemoryModel:
|
|
m.addressing_model = (SpvAddressingModel)data[u+1];
|
|
m.memory_model = (SpvMemoryModel)data[u+2];
|
|
break;
|
|
case SpvOpEntryPoint:
|
|
ep.model = (SpvExecutionModel)data[u+1];
|
|
ep.id = (SpvExecutionModel)data[u+2];
|
|
ep.name = mspv_sv_from_op(data+u+3);
|
|
ep.params = {};
|
|
for ( i = 4 + ep.name.len/4; i < instruction_size; i++ )
|
|
{
|
|
mspv_array_push(ep.params, data[u+i]);
|
|
}
|
|
mspv_array_push(m.entry_points, ep);
|
|
break;
|
|
case SpvOpExecutionMode:
|
|
em.id = data[u+1];
|
|
em.mode = (SpvExecutionMode)data[u+2];
|
|
em.dv.data = data + u;
|
|
em.dv.len = instruction_size - 1;
|
|
mspv_array_push(m.execution_modes, em);
|
|
break;
|
|
case SpvOpString:
|
|
case SpvOpSourceExtension:
|
|
case SpvOpSource:
|
|
case SpvOpSourceContinued:
|
|
case SpvOpMemberName:
|
|
case SpvOpModuleProcessed:
|
|
break;
|
|
case SpvOpName:
|
|
nm.id = data[u+1];
|
|
nm.name = mspv_sv_from_op(data+u+2);
|
|
mspv_array_push(m.names, nm);
|
|
|
|
break;
|
|
|
|
case SpvOpTypeVoid:
|
|
case SpvOpTypeBool:
|
|
case SpvOpTypeInt:
|
|
case SpvOpTypeFloat:
|
|
case SpvOpTypeVector:
|
|
case SpvOpTypeMatrix:
|
|
case SpvOpTypeImage:
|
|
case SpvOpTypeSampler:
|
|
case SpvOpTypeSampledImage:
|
|
case SpvOpTypeArray:
|
|
case SpvOpTypeRuntimeArray:
|
|
case SpvOpTypeStruct:
|
|
case SpvOpTypeOpaque:
|
|
case SpvOpTypePointer:
|
|
case SpvOpTypeFunction:
|
|
case SpvOpTypeEvent:
|
|
case SpvOpTypeDeviceEvent:
|
|
case SpvOpTypeReserveId:
|
|
case SpvOpTypeQueue:
|
|
case SpvOpTypePipe:
|
|
case SpvOpTypeForwardPointer:
|
|
type.dv.data = data+u;
|
|
type.dv.len = instruction_size;
|
|
type.id = data[u+1];
|
|
mspv_array_push(m.types, type);
|
|
break;
|
|
|
|
case SpvOpVariable:
|
|
var.resulttype = data[u+1];
|
|
var.result = data[u+2];
|
|
var.storageclass = data[u+3];
|
|
if (instruction_size > 4)
|
|
var.initializer = data[u+4];
|
|
else
|
|
var.initializer = 0;
|
|
if (!isfn)
|
|
mspv_array_push(m.variables, var);
|
|
else
|
|
fn.instructions.len += instruction_size;
|
|
break;
|
|
|
|
|
|
case SpvOpFunction:
|
|
fn = {};
|
|
fn.resulttype = data[u+1];
|
|
fn.result = data[u+2];
|
|
fn.functionctrl = data[u+3];
|
|
fn.functiontype = data[u+4];
|
|
fn.instructions.data = data+u+instruction_size;
|
|
fn.instructions.len = 0;
|
|
isfn = 1;
|
|
break;
|
|
case SpvOpFunctionEnd:
|
|
mspv_array_push(m.functions, fn);
|
|
isfn = 0;
|
|
break;
|
|
|
|
default:
|
|
fn.instructions.len += instruction_size;
|
|
break;
|
|
}
|
|
u += instruction_size;
|
|
|
|
};
|
|
return (mspv_module*)memcpy(malloc(sizeof(m)),&m, sizeof(m));
|
|
}
|
|
|
|
void mspv_close_module( mspv_module* m )
|
|
{
|
|
if (m == NULL)
|
|
return;
|
|
|
|
mspv_array_destroy(m->capabilities);
|
|
mspv_array_destroy(m->extensions);
|
|
mspv_array_destroy(m->execution_modes);
|
|
mspv_array_destroy(m->entry_points);
|
|
mspv_array_destroy(m->types);
|
|
mspv_array_destroy(m->functions);
|
|
free(m);
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
SpvOp op;
|
|
uint16_t size;
|
|
} mspv_op;
|
|
|
|
|
|
typedef mspv_array(uint32_t) mspv_spv;
|
|
static inline void mspv_write_op( mspv_spv *as, SpvOp op, uint16_t ops )
|
|
{
|
|
mspv_array_push((*as), op | (ops+1) << 16);
|
|
};
|
|
|
|
static inline void mspv_write_string( mspv_spv *as, mspv_string_view s )
|
|
{
|
|
uint32_t u;
|
|
uint32_t val;
|
|
char cval[4];
|
|
for ( u = 0; u < s.len/4; u++ )
|
|
{
|
|
mspv_array_push((*as), *(uint32_t*)(s.data+u*4));
|
|
}
|
|
if (!(s.len%4))
|
|
{
|
|
mspv_array_push((*as), 0);
|
|
}
|
|
else
|
|
{
|
|
cval[0] = 0;
|
|
cval[0] = 1;
|
|
cval[0] = 2;
|
|
cval[0] = 3;
|
|
|
|
for (u = 0; u < s.len%4; u++)
|
|
{
|
|
cval[u] = s.data[(s.len/4)*4+u];
|
|
}
|
|
mspv_array_push((*as), *(uint32_t*)cval);
|
|
}
|
|
};
|
|
|
|
static inline void mspv_write_dv( mspv_spv *as, mspv_data_view s )
|
|
{
|
|
uint32_t u;
|
|
for ( u = 0; u < s.len; u++ )
|
|
{
|
|
mspv_array_push((*as), *(s.data+u));
|
|
}
|
|
}
|
|
|
|
mspv_spv mspv_write_module( mspv_module *m )
|
|
{
|
|
mspv_spv as;
|
|
uint32_t u;
|
|
uint32_t n;
|
|
uint32_t il;
|
|
|
|
mspv_array_zero(as);
|
|
|
|
if (m == NULL)
|
|
return as;
|
|
|
|
mspv_array_push(as, m->header.magic);
|
|
mspv_array_push(as, m->header.reserved1);
|
|
mspv_array_push(as, m->header.reserved2);
|
|
mspv_array_push(as, m->header.reserved3);
|
|
mspv_array_push(as, m->header.reserved4);
|
|
|
|
for ( u = 0; u < m->capabilities.count; u++ )
|
|
{
|
|
mspv_write_op(&as, SpvOpCapability, 1);
|
|
mspv_array_push(as, m->capabilities.data[u]);
|
|
}
|
|
for ( u = 0; u < m->extensions.count; u++ )
|
|
{
|
|
il = 0;
|
|
if (m->extensions.data[u].len%4)
|
|
il = m->extensions.data[u].len/4+1;
|
|
else
|
|
il = m->extensions.data[u].len/4+2;
|
|
mspv_write_op(&as, SpvOpExtension, il);
|
|
mspv_write_string(&as, m->extensions.data[u]);
|
|
}
|
|
|
|
for ( u = 0; u < m->ext_instructions.count; u++ )
|
|
{
|
|
|
|
il = 0;
|
|
if (m->ext_instructions.data[u].name.len%4)
|
|
il = m->ext_instructions.data[u].name.len/4+2;
|
|
else
|
|
il = m->ext_instructions.data[u].name.len/4+3;
|
|
mspv_write_op(&as, SpvOpExtInstImport, il);
|
|
mspv_array_push(as, m->ext_instructions.data[u].id);
|
|
mspv_write_string(&as, m->ext_instructions.data[u].name);
|
|
}
|
|
for ( u = 0; u < m->entry_points.count; u++ )
|
|
{
|
|
il = 0;
|
|
if (m->entry_points.data[u].name.len%4)
|
|
il = m->entry_points.data[u].name.len/4+2;
|
|
else
|
|
il = m->entry_points.data[u].name.len/4+3;
|
|
il += m->entry_points.data[u].params.count;
|
|
mspv_write_op(&as, SpvOpEntryPoint, il);
|
|
mspv_array_push(as, m->entry_points.data[u].model);
|
|
mspv_array_push(as, m->entry_points.data[u].id);
|
|
mspv_write_string(&as, m->entry_points.data[u].name);
|
|
for ( n = 0; n < m->entry_points.data[u].params.count; n++ )
|
|
{
|
|
mspv_array_push(as, m->entry_points.data[u].params.data[n]);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
mspv_write_op(&as, SpvOpMemoryModel, 2);
|
|
mspv_array_push(as, m->addressing_model);
|
|
mspv_array_push(as, m->memory_model);
|
|
|
|
for ( u = 0; u < m->types.count; u++ )
|
|
{
|
|
mspv_write_op(&as, (SpvOp)m->types.data[u].dv.data[0], m->types.data[u].dv.len-1);
|
|
mspv_array_push(as, m->types.data[u].id);
|
|
if (m->types.data[u].dv.len-2)
|
|
mspv_write_dv(&as, {m->types.data[u].dv.data+2, m->types.data[u].dv.len-2});
|
|
}
|
|
for ( u = 0; u < m->variables.count; u++ )
|
|
{
|
|
mspv_write_op(&as, SpvOpVariable, m->variables.data[u].initializer ? 4 : 3);
|
|
mspv_array_push(as, m->variables.data[u].resulttype);
|
|
mspv_array_push(as, m->variables.data[u].result);
|
|
mspv_array_push(as, m->variables.data[u].storageclass);
|
|
if (m->variables.data[u].initializer)
|
|
{
|
|
mspv_array_push(as, m->variables.data[u].initializer);
|
|
|
|
}
|
|
}
|
|
|
|
for ( u = 0; u < m->functions.count; u++ )
|
|
{
|
|
mspv_write_op(&as, SpvOpFunction, 4);
|
|
mspv_array_push(as, m->functions.data[u].resulttype);
|
|
mspv_array_push(as, m->functions.data[u].result);
|
|
mspv_array_push(as, m->functions.data[u].functionctrl);
|
|
mspv_array_push(as, m->functions.data[u].functiontype);
|
|
|
|
mspv_write_dv(&as, m->functions.data[u].instructions);
|
|
|
|
mspv_write_op(&as, SpvOpFunctionEnd, 0);
|
|
}
|
|
|
|
|
|
|
|
return as;
|
|
|
|
}
|
|
|
|
//#endif
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif
|