--- /dev/null
+#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 = ⌖
+ 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