#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