X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fcore%2Fmodule.cpp;h=ed5f02823f0bf34671a7ee4a31e7dad4035f0dc9;hp=406b4739d1c765f981ddd992081411f5203b4123;hb=3a1b9cbe2441ae670a97541dc8ccb0a2860c8302;hpb=dccad64b2ec82249d850b9745614042171499972 diff --git a/source/core/module.cpp b/source/core/module.cpp index 406b4739..ed5f0282 100644 --- a/source/core/module.cpp +++ b/source/core/module.cpp @@ -1,36 +1,574 @@ +#include +#include #include "module.h" #include "resources.h" -#include "glsl/compiler.h" using namespace std; +enum SpirVConstants +{ + SPIRV_MAGIC = 0x07230203, + SPIRV_MAGIC_REVERSED = 0x03022307, + + OP_NAME = 5, + OP_MEMBER_NAME = 6, + OP_ENTRY_POINT = 15, + OP_TYPE_VOID = 19, + OP_TYPE_BOOL = 20, + OP_TYPE_INT = 21, + OP_TYPE_FLOAT = 22, + OP_TYPE_VECTOR = 23, + OP_TYPE_MATRIX = 24, + OP_TYPE_IMAGE = 25, + OP_TYPE_SAMPLED_IMAGE = 27, + OP_TYPE_ARRAY = 28, + OP_TYPE_STRUCT = 30, + OP_TYPE_POINTER = 32, + OP_CONSTANT_TRUE = 41, + OP_CONSTANT_FALSE = 42, + OP_CONSTANT = 43, + OP_SPEC_CONSTANT_TRUE = 48, + OP_SPEC_CONSTANT_FALSE = 49, + OP_SPEC_CONSTANT = 50, + OP_VARIABLE = 59, + OP_DECORATE = 71, + OP_MEMBER_DECORATE = 72, + + DECO_SPEC_ID = 1, + DECO_ARRAY_STRIDE = 6, + DECO_MATRIX_STRIDE = 7, + DECO_LOCATION = 30, + DECO_BINDING = 33, + DECO_DESCRIPTOR_SET = 34, + DECO_OFFSET = 35 +}; + namespace Msp { namespace GL { -Module::Module() -{ } - void Module::set_source(const string &src) { SL::Compiler compiler; compiler.set_source(src); - compiler.compile(SL::Compiler::MODULE); - prepared_source = compiler.get_combined_glsl(); - source_map = compiler.get_source_map(); + compile(compiler); } void Module::load_source(IO::Base &io, Resources *res, const string &name) { SL::Compiler compiler; compiler.load_source(io, res, name); + compile(compiler); +} + +void Module::load_source(IO::Base &io, const string &name) +{ + load_source(io, 0, name); +} + + +void GlslModule::compile(SL::Compiler &compiler) +{ compiler.compile(SL::Compiler::MODULE); prepared_source = compiler.get_combined_glsl(); source_map = compiler.get_source_map(); + +#ifdef DEBUG + string diagnostics = compiler.get_diagnostics(); + if(!diagnostics.empty()) + IO::print("Module diagnostics:\n%s\n", diagnostics); +#endif } -void Module::load_source(IO::Base &io, const string &name) + +SpirVModule::SpirVModule(const SpirVModule &other): + code(other.code), + entry_points(other.entry_points), + structs(other.structs), + variables(other.variables) { - load_source(io, 0, name); + remap_pointers_from(other); +} + +SpirVModule &SpirVModule::operator=(const SpirVModule &other) +{ + code = other.code; + entry_points = other.entry_points; + structs = other.structs; + variables = other.variables; + remap_pointers_from(other); + return *this; +} + +void SpirVModule::remap_pointers_from(const SpirVModule &other) +{ + for(EntryPoint &e: entry_points) + for(const Variable *&v: e.globals) + v = &variables[v-&other.variables.front()]; + + for(Variable &v: variables) + if(v.struct_type) + v.struct_type = &structs[v.struct_type-&other.structs.front()]; + + for(Structure &s: structs) + for(StructMember &m: s.members) + if(m.struct_type) + m.struct_type = &structs[m.struct_type-&other.structs.front()]; +} + +void SpirVModule::load_code(IO::Base &io) +{ + uint32_t buffer[1024]; + while(1) + { + unsigned len = io.read(reinterpret_cast(buffer), sizeof(buffer)); + if(!len) + break; + len /= 4; + code.reserve(code.size()+len); + code.insert(code.end(), buffer, buffer+len); + } + + reflect(); +} + +void SpirVModule::compile(SL::Compiler &compiler) +{ + compiler.compile(SL::Compiler::SPIRV); + code = compiler.get_combined_spirv(); + reflect(); +} + +void SpirVModule::reflect() +{ + if(code.empty()) + throw invalid_module("Empty SPIR-V code"); + + if(code[0]==SPIRV_MAGIC_REVERSED) + { + for(uint32_t &c: code) + c = ((c&0xFF)<<24) || ((c&0xFF00)<<8) | ((c>>8)&0xFF00) | ((c>>24)&0xFF); + } + else if(code[0]!=SPIRV_MAGIC) + throw invalid_module("SPIR-V magic number not found"); + + Reflection reflection; + reflection.reflect_code(code); + + map spec_indices; + for(const auto &kvp: reflection.constants) + if(kvp.second.constant_id>=0) + { + spec_indices[&kvp.second] = spec_constants.size(); + spec_constants.push_back(kvp.second); + } + + map struct_indices; + structs.reserve(reflection.structs.size()); + for(const auto &kvp: reflection.structs) + { + struct_indices[&kvp.second] = structs.size(); + structs.push_back(kvp.second); + } + + for(Structure &s: structs) + { + for(StructMember &m: s.members) + { + if(m.struct_type) + { + auto i = struct_indices.find(m.struct_type); + m.struct_type = (i!=struct_indices.end() ? &structs[i->second] : 0); + } + if(m.array_size_spec) + { + auto i = spec_indices.find(m.array_size_spec); + m.array_size_spec = (i!=spec_indices.end() ? &spec_constants[i->second] : 0); + } + } + + const StructMember *last_member = &s.members.back(); + unsigned last_offset = last_member->offset; + while(last_member->struct_type) + { + const StructMember *lm = &last_member->struct_type->members.back(); + if(last_member->array_size) + last_offset += last_member->array_stride*(last_member->array_size-1); + else if(last_member->array_size_spec) + last_offset += last_member->array_stride*(last_member->array_size_spec->i_value-1); + last_offset += lm->offset; + last_member = lm; + } + + s.size = last_offset+get_type_size(last_member->type); + s.size = (s.size+15)&~15; + } + + map var_indices; + variables.reserve(reflection.variables.size()); + for(const auto &kvp: reflection.variables) + { + auto i = find_if(variables, [&kvp](const Variable &v){ return v==kvp.second; }); + if(i!=variables.end()) + var_indices[&kvp.second] = i-variables.begin(); + else + { + var_indices[&kvp.second] = variables.size(); + variables.push_back(kvp.second); + } + } + + for(Variable &v: variables) + { + if(v.struct_type) + { + auto i = struct_indices.find(v.struct_type); + v.struct_type = (i!=struct_indices.end() ? &structs[i->second] : 0); + } + if(v.array_size_spec) + { + auto i = spec_indices.find(v.array_size_spec); + v.array_size_spec = (i!=spec_indices.end() ? &spec_constants[i->second] : 0); + } + } + + entry_points.reserve(reflection.entry_points.size()); + for(const auto &kvp: reflection.entry_points) + { + entry_points.push_back(kvp.second); + EntryPoint &entry = entry_points.back(); + for(const Variable *&v: entry.globals) + { + auto i = var_indices.find(v); + v = (i!=var_indices.end() ? &variables[i->second] : 0); + } + } +} + + +SpirVModule::EntryPoint::EntryPoint(): + stage(VERTEX) +{ } + + +SpirVModule::StructMember::StructMember(): + type(VOID), + struct_type(0), + offset(0), + array_size(0), + array_size_spec(0), + array_stride(0), + matrix_stride(0) +{ } + + +SpirVModule::Variable::Variable(): + type(VOID), + struct_type(0), + location(-1), + descriptor_set(-1), + binding(-1) +{ } + +bool SpirVModule::Variable::operator==(const Variable &other) const +{ + if(storage!=UNIFORM_CONSTANT && storage!=UNIFORM) + return false; + if(storage!=other.storage || type!=other.type || struct_type!=other.struct_type) + return false; + if(location!=other.location || descriptor_set!=other.descriptor_set || binding!=other.binding) + return false; + return true; +} + + +SpirVModule::TypeInfo::TypeInfo(): + type(VOID), + struct_type(0), + array_size_spec(0), + array_size(0), + array_stride(0), + storage(static_cast(-1)) +{ } + + +uint32_t SpirVModule::Reflection::get_opcode(uint32_t op) +{ + return op&0xFFFF; +} + +SpirVModule::Reflection::CodeIterator SpirVModule::Reflection::get_op_end(const CodeIterator &op) +{ + return op+(*op>>16); +} + +string SpirVModule::Reflection::read_string(CodeIterator &op, const CodeIterator &op_end) +{ + string result; + for(; op!=op_end; ++op) + { + unsigned word = *op; + for(unsigned i=0; i<4; ++i) + { + char c = word&0xFF; + if(!c) + { + ++op; + return result; + } + result += c; + word >>= 8; + } + } + + throw invalid_module("Unterminated SPIR-V string literal"); +} + +void SpirVModule::Reflection::reflect_code(const vector &code) +{ + for(CodeIterator op=code.begin()+5; op!=code.end(); ) + { + unsigned word_count = *op>>16; + if(word_count>static_cast(code.end()-op)) + throw invalid_module("Truncated SPIR-V instruction"); + + switch(get_opcode(*op)) + { + case OP_NAME: reflect_name(op); break; + case OP_MEMBER_NAME: reflect_member_name(op); break; + case OP_ENTRY_POINT: reflect_entry_point(op); break; + case OP_TYPE_VOID: reflect_void_type(op); break; + case OP_TYPE_BOOL: reflect_bool_type(op); break; + case OP_TYPE_INT: reflect_int_type(op); break; + case OP_TYPE_FLOAT: reflect_float_type(op); break; + case OP_TYPE_VECTOR: reflect_vector_type(op); break; + case OP_TYPE_MATRIX: reflect_vector_type(op); break; + case OP_TYPE_IMAGE: reflect_image_type(op); break; + case OP_TYPE_SAMPLED_IMAGE: reflect_sampled_image_type(op); break; + case OP_TYPE_ARRAY: reflect_array_type(op); break; + case OP_TYPE_STRUCT: reflect_struct_type(op); break; + case OP_TYPE_POINTER: reflect_pointer_type(op); break; + case OP_CONSTANT_TRUE: + case OP_CONSTANT_FALSE: + case OP_CONSTANT: + case OP_SPEC_CONSTANT_TRUE: + case OP_SPEC_CONSTANT_FALSE: + case OP_SPEC_CONSTANT: reflect_constant(op); break; + case OP_VARIABLE: reflect_variable(op); break; + case OP_DECORATE: reflect_decorate(op); break; + case OP_MEMBER_DECORATE: reflect_member_decorate(op); break; + } + + op += word_count; + } +} + +void SpirVModule::Reflection::reflect_name(CodeIterator op) +{ + CodeIterator op_end = get_op_end(op); + string &name = names[*(op+1)]; + op += 2; + name = read_string(op, op_end); +} + +void SpirVModule::Reflection::reflect_member_name(CodeIterator op) +{ + CodeIterator op_end = get_op_end(op); + Structure &strct = structs[*(op+1)]; + unsigned index = *(op+2); + if(index>=strct.members.size()) + strct.members.resize(index+1); + op += 3; + strct.members[index].name = read_string(op, op_end); +} + +void SpirVModule::Reflection::reflect_entry_point(CodeIterator op) +{ + CodeIterator op_end = get_op_end(op); + EntryPoint &entry = entry_points[*(op+2)]; + entry.stage = static_cast(*(op+1)); // Execution model in SPIR-V spec + op += 3; + entry.name = read_string(op, op_end); + + entry.globals.reserve(op_end-op); + for(; op!=op_end; ++op) + entry.globals.push_back(&variables[*op]); +} + +void SpirVModule::Reflection::reflect_void_type(CodeIterator op) +{ + types[*(op+1)].type = VOID; +} + +void SpirVModule::Reflection::reflect_bool_type(CodeIterator op) +{ + types[*(op+1)].type = BOOL; +} + +void SpirVModule::Reflection::reflect_int_type(CodeIterator op) +{ + TypeInfo &type = types[*(op+1)]; + unsigned size = *(op+2); + bool sign = *(op+3); + type.type = static_cast(size/8 | sign*0x100); +} + +void SpirVModule::Reflection::reflect_float_type(CodeIterator op) +{ + TypeInfo &type = types[*(op+1)]; + unsigned size = *(op+2); + type.type = static_cast(size/8 | 0x300); +} + +void SpirVModule::Reflection::reflect_vector_type(CodeIterator op) +{ + TypeInfo &type = types[*(op+1)]; + DataType component = types[*(op+2)].type; + unsigned count = *(op+3); + type.type = static_cast((count<<12) | (component&0xF00) | ((component&0xFF)*count)); +} + +void SpirVModule::Reflection::reflect_matrix_type(CodeIterator op) +{ + TypeInfo &type = types[*(op+1)]; + DataType column = types[*(op+2)].type; + unsigned count = *(op+3); + type.type = static_cast((count<<16) | (column&0xF00) | ((column&0xFF)*count)); +} + +void SpirVModule::Reflection::reflect_image_type(CodeIterator op) +{ + TypeInfo &type = types[*(op+1)]; + DataType sample = types[*(op+2)].type; + unsigned dimensions = *(op+3); + bool depth = *(op+4)==1; + bool array = *(op+5); + type.type = static_cast((depth*0x200000) | (array*0x80000) | (dimensions+1) | sample); +} + +void SpirVModule::Reflection::reflect_sampled_image_type(CodeIterator op) +{ + TypeInfo &type = types[*(op+1)]; + DataType image = types[*(op+2)].type; + type.type = static_cast(image | 0x100000); +} + +void SpirVModule::Reflection::reflect_array_type(CodeIterator op) +{ + TypeInfo &type = types[*(op+1)]; + const TypeInfo &elem = types[*(op+2)]; + type.type = elem.type; + type.struct_type = elem.struct_type; + + const Constant &size = constants[*(op+3)]; + if(size.constant_id>=0) + type.array_size_spec = &size; + else if(size.type==INT || size.type==UNSIGNED_INT) + type.array_size = size.i_value; +} + +void SpirVModule::Reflection::reflect_struct_type(CodeIterator op) +{ + CodeIterator op_end = get_op_end(op); + unsigned id = *(op+1); + Structure &strct = structs[id]; + strct.name = names[id]; + types[id].struct_type = &strct; + op += 2; + + strct.members.resize(op_end-op); + auto mem = strct.members.begin(); + for(; op!=op_end; ++op, ++mem) + { + TypeInfo &type = types[*op]; + mem->type = type.type; + mem->struct_type = type.struct_type; + mem->array_size = type.array_size; + mem->array_size_spec = type.array_size_spec; + mem->array_stride = type.array_stride; + } +} + +void SpirVModule::Reflection::reflect_pointer_type(CodeIterator op) +{ + TypeInfo &type = types[*(op+1)]; + type = types[*(op+3)]; + type.storage = static_cast(*(op+2)); +} + +void SpirVModule::Reflection::reflect_constant(CodeIterator op) +{ + unsigned id = *(op+2); + Constant &cnst = constants[id]; + cnst.name = names[id]; + cnst.type = types[*(op+1)].type; + if(*op==OP_CONSTANT_TRUE || *op==OP_SPEC_CONSTANT_TRUE) + cnst.i_value = true; + else if(*op==OP_CONSTANT_FALSE || *op==OP_SPEC_CONSTANT_FALSE) + cnst.i_value = false; + else if(cnst.type==INT || cnst.type==UNSIGNED_INT) + cnst.i_value = *(op+3); + else if(cnst.type==FLOAT) + cnst.f_value = *reinterpret_cast(&*(op+3)); +} + +void SpirVModule::Reflection::reflect_variable(CodeIterator op) +{ + unsigned id = *(op+2); + Variable &var = variables[id]; + var.name = names[id]; + const TypeInfo &type = types[*(op+1)]; + var.storage = type.storage; + var.type = type.type; + var.struct_type = type.struct_type; + var.array_size = type.array_size; + var.array_size_spec = type.array_size_spec; +} + +void SpirVModule::Reflection::reflect_decorate(CodeIterator op) +{ + unsigned id = *(op+1); + unsigned decoration = *(op+2); + op += 3; + + switch(decoration) + { + case DECO_SPEC_ID: + constants[id].constant_id = *op; + break; + case DECO_ARRAY_STRIDE: + types[id].array_stride = *op; + break; + case DECO_LOCATION: + variables[id].location = *op; + break; + case DECO_BINDING: + variables[id].binding = *op; + break; + case DECO_DESCRIPTOR_SET: + variables[id].descriptor_set = *op; + break; + } +} + +void SpirVModule::Reflection::reflect_member_decorate(CodeIterator op) +{ + Structure &strct = structs[*(op+1)]; + unsigned index = *(op+2); + if(index>=strct.members.size()) + strct.members.resize(index+1); + unsigned decoration = *(op+3); + op += 4; + + StructMember &member = strct.members[index]; + switch(decoration) + { + case DECO_MATRIX_STRIDE: + member.matrix_stride = *op; + break; + case DECO_OFFSET: + member.offset = *op; + break; + } } } // namespace GL