]> git.tdb.fi Git - libs/gl.git/blobdiff - source/glsl/spirvwriter.cpp
Add a SPIR-V backend to the GLSL compiler
[libs/gl.git] / source / glsl / spirvwriter.cpp
diff --git a/source/glsl/spirvwriter.cpp b/source/glsl/spirvwriter.cpp
new file mode 100644 (file)
index 0000000..77ddbdb
--- /dev/null
@@ -0,0 +1,213 @@
+#include "glsl_error.h"
+#include "spirvwriter.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+namespace SL {
+
+SpirVWriter::SpirVWriter(SpirVContent &c):
+       content(c),
+       op_target(0),
+       op_head_pos(0),
+       current_block_id(0)
+{ }
+
+void SpirVWriter::append(vector<Word> &target, const vector<Word> &source)
+{
+       target.insert(target.end(), source.begin(), source.end());
+}
+
+void SpirVWriter::write(Word word)
+{
+       if(!op_target)
+               throw logic_error("write without begin_op");
+       op_target->push_back(word);
+}
+
+void SpirVWriter::write_float(float value)
+{
+       union
+       {
+               float fv;
+               Word word;
+       };
+       fv = value;
+       write(word);
+}
+
+void SpirVWriter::write_string(const string &str)
+{
+       for(unsigned i=0; i<=str.size(); i+=4)
+       {
+               Word word = 0;
+               for(unsigned j=0; (j<4 && i+j<str.size()); ++j)
+                       word |= static_cast<unsigned char>(str[i+j])<<(j*8);
+               write(word);
+       }
+}
+
+void SpirVWriter::begin_op(vector<Word> &target, Opcode opcode, unsigned size)
+{
+       if(op_target)
+               throw logic_error("begin_op without end_op");
+       if(&target==&content.function_body && !current_block_id)
+               throw logic_error("no open block in function");
+
+       op_head_pos = target.size();
+       op_target = &target;
+       write(opcode | (size<<16));
+
+       if(opcode==OP_BRANCH || opcode==OP_BRANCH_CONDITIONAL || opcode==OP_KILL ||
+               opcode==OP_RETURN || opcode==OP_RETURN_VALUE || opcode==OP_UNREACHABLE)
+               current_block_id = 0;
+}
+
+void SpirVWriter::end_op(Opcode opcode)
+{
+       if(!op_target)
+               throw logic_error("end_op without begin_op");
+       Word &op_head = (*op_target)[op_head_pos];
+       if(opcode!=(op_head&0xFFFF))
+               throw logic_error("opcode mismatch");
+
+       unsigned words = op_target->size()-op_head_pos;
+       unsigned op_size = op_head>>16;
+       if(op_size)
+       {
+               if(words!=op_size)
+                       throw logic_error("incorred number of words written");
+       }
+       else
+               op_head |= (words<<16);
+
+       op_target = 0;
+       op_head_pos = 0;
+}
+
+void SpirVWriter::write_op(vector<Word> &target, Opcode opcode)
+{
+       begin_op(target, opcode, 1);
+       end_op(opcode);
+}
+
+void SpirVWriter::write_op(vector<Word> &target, Opcode opcode, Word arg0)
+{
+       begin_op(target, opcode, 2);
+       write(arg0);
+       end_op(opcode);
+}
+
+void SpirVWriter::write_op(vector<Word> &target, Opcode opcode, Word arg0, Word arg1)
+{
+       begin_op(target, opcode, 3);
+       write(arg0);
+       write(arg1);
+       end_op(opcode);
+}
+
+void SpirVWriter::write_op(vector<Word> &target, Opcode opcode, Word arg0, Word arg1, Word arg2)
+{
+       begin_op(target, opcode, 4);
+       write(arg0);
+       write(arg1);
+       write(arg2);
+       end_op(opcode);
+}
+
+void SpirVWriter::write_op_name(Id id, const string &name)
+{
+       begin_op(content.names, OP_NAME);
+       write(id);
+       write_string(name);
+       end_op(OP_NAME);
+}
+
+void SpirVWriter::write_op_member_name(Id id, unsigned index, const string &name)
+{
+       begin_op(content.names, OP_MEMBER_NAME);
+       write(id);
+       write(index);
+       write_string(name);
+       end_op(OP_MEMBER_NAME);
+}
+
+void SpirVWriter::write_op_decorate(Id id, Decoration decoration)
+{
+       write_op(content.decorations, OP_DECORATE, id, decoration);
+}
+
+void SpirVWriter::write_op_decorate(Id id, Decoration decoration, Word value)
+{
+       write_op(content.decorations, OP_DECORATE, id, decoration, value);
+}
+
+void SpirVWriter::write_op_member_decorate(Id id, unsigned index, Decoration decoration)
+{
+       write_op(content.decorations, OP_MEMBER_DECORATE, id, index, decoration);
+}
+
+void SpirVWriter::write_op_member_decorate(Id id, unsigned index, Decoration decoration, Word value)
+{
+       begin_op(content.decorations, OP_MEMBER_DECORATE, 5);
+       write(id);
+       write(index);
+       write(decoration);
+       write(value);
+       end_op(OP_MEMBER_DECORATE);
+}
+
+void SpirVWriter::write_op_label(Id label_id)
+{
+       if(current_block_id)
+               write_op(content.function_body, OP_BRANCH, label_id);
+       current_block_id = label_id;
+       write_op(content.function_body, OP_LABEL, label_id);
+}
+
+void SpirVWriter::begin_function_body(Id first_block_id)
+{
+       if(!content.function_body.empty() || current_block_id)
+               throw internal_error("begin_function without end_function");
+
+       current_block_id = first_block_id;
+       write_op(content.functions, OP_LABEL, first_block_id);
+}
+
+void SpirVWriter::end_function_body()
+{
+       if(content.function_body.empty())
+               throw internal_error("end_function without begin_function");
+       if(current_block_id)
+               throw internal_error("end_function with open block");
+
+       append(content.functions, content.locals);
+       append(content.functions, content.function_body);
+       write_op(content.functions, OP_FUNCTION_END);
+
+       content.locals.clear();
+       content.function_body.clear();
+}
+
+void SpirVWriter::finalize(Id id_bound)
+{
+       content.code.push_back(SPIRV_MAGIC);
+       content.code.push_back(0x00010500);
+       content.code.push_back(0);  // Generator
+       content.code.push_back(id_bound);
+       content.code.push_back(0);  // Reserved
+       append(content.code, content.capabilities);
+       append(content.code, content.extensions);
+       write_op(content.code, OP_MEMORY_MODEL, 0, 1);  // Logical, GLSL450
+       append(content.code, content.entry_points);
+       append(content.code, content.exec_modes);
+       append(content.code, content.names);
+       append(content.code, content.decorations);
+       append(content.code, content.globals);
+       append(content.code, content.functions);
+}
+
+} // namespace SL
+} // namespace GL
+} // namespace Msp