Branimir Karadžić před 9 roky
rodič
revize
e14c5b1c3e
8 změnil soubory, kde provedl 891 přidání a 595 odebrání
  1. 2 1
      src/renderer_d3d11.cpp
  2. 4 3
      src/renderer_d3d12.cpp
  3. 48 44
      src/shader_dx9bc.cpp
  4. 8 8
      src/shader_dx9bc.h
  5. 120 117
      src/shader_dxbc.cpp
  6. 10 10
      src/shader_dxbc.h
  7. 577 374
      src/shader_spirv.cpp
  8. 122 38
      src/shader_spirv.h

+ 2 - 1
src/renderer_d3d11.cpp

@@ -3728,8 +3728,9 @@ BX_PRAGMA_DIAGNOSTIC_POP();
 	{
 		bx::MemoryReader rd(_code, _size);
 
+		bx::Error err;
 		DxbcContext dxbc;
-		read(&rd, dxbc);
+		read(&rd, dxbc, &err);
 
 		struct FindDepthOp
 		{

+ 4 - 3
src/renderer_d3d12.cpp

@@ -2238,7 +2238,8 @@ data.NumQualityLevels = 0;
  			bx::StaticMemoryBlockWriter wr(temp->data, temp->size);
 
 			DxbcContext dxbc;
-			read(&rd, dxbc);
+			bx::Error err;
+			read(&rd, dxbc, &err);
 
 			bool patchShader = true;
 			if (BX_ENABLED(BGFX_CONFIG_DEBUG) )
@@ -2246,7 +2247,7 @@ data.NumQualityLevels = 0;
 				union { uint32_t offset; void* ptr; } cast = { 0 };
 				filter(dxbc.shader, dxbc.shader, patchCb0, cast.ptr);
 
-				write(&wr, dxbc);
+				write(&wr, dxbc, &err);
 
 				dxbcHash(temp->data + 20, temp->size - 20, temp->data + 4);
 
@@ -2280,7 +2281,7 @@ data.NumQualityLevels = 0;
 					uint32_t(program.m_vsh->m_size)/16
 				};
 				filter(dxbc.shader, dxbc.shader, patchCb0, cast.ptr);
-				write(&wr, dxbc);
+				write(&wr, dxbc, &err);
 				dxbcHash(temp->data + 20, temp->size - 20, temp->data + 4);
 
 				desc.PS.pShaderBytecode = temp->data;

+ 48 - 44
src/shader_dx9bc.cpp

@@ -274,12 +274,12 @@ namespace bgfx
 	};
 	BX_STATIC_ASSERT(BX_COUNTOF(s_dx9bcDeclUsage) == Dx9bcDeclUsage::Count);
 
-	int32_t read(bx::ReaderI* _reader, Dx9bcSubOperand& _subOperand)
+	int32_t read(bx::ReaderI* _reader, Dx9bcSubOperand& _subOperand, bx::Error* _err)
 	{
 		int32_t size = 0;
 
 		uint32_t token;
-		size += bx::read(_reader, token);
+		size += bx::read(_reader, token, _err);
 
 		_subOperand.type        =   Dx9bcOperandType::Enum( ( (token & UINT32_C(0x70000000) ) >> 28)
 														  | ( (token & UINT32_C(0x00001800) ) >>  8) );
@@ -289,7 +289,7 @@ namespace bgfx
 		return size;
 	}
 
-	int32_t write(bx::WriterI* _writer, const Dx9bcSubOperand& _subOperand)
+	int32_t write(bx::WriterI* _writer, const Dx9bcSubOperand& _subOperand, bx::Error* _err)
 	{
 		int32_t size = 0;
 
@@ -298,17 +298,17 @@ namespace bgfx
 		token |= (_subOperand.type        <<  8) & UINT32_C(0x00001800);
 		token |=  _subOperand.regIndex           & UINT32_C(0x000007ff);
 		token |= (_subOperand.swizzleBits << 16) & UINT32_C(0x00ff0000);
-		size += bx::write(_writer, token);
+		size += bx::write(_writer, token, _err);
 
 		return size;
 	}
 
-	int32_t read(bx::ReaderI* _reader, Dx9bcOperand& _operand)
+	int32_t read(bx::ReaderI* _reader, Dx9bcOperand& _operand, bx::Error* _err)
 	{
 		int32_t size = 0;
 
 		uint32_t token;
-		size += bx::read(_reader, token);
+		size += bx::read(_reader, token, _err);
 
 		_operand.type     =   Dx9bcOperandType::Enum( ( (token & UINT32_C(0x70000000) ) >> 28)
 													| ( (token & UINT32_C(0x00001800) ) >>  8) );
@@ -339,13 +339,13 @@ namespace bgfx
 
 		if (Dx9bcOperandAddrMode::Relative == _operand.addrMode)
 		{
-			size += read(_reader, _operand.subOperand);
+			size += read(_reader, _operand.subOperand, _err);
 		}
 
 		return size;
 	}
 
-	int32_t write(bx::WriterI* _writer, const Dx9bcOperand& _operand)
+	int32_t write(bx::WriterI* _writer, const Dx9bcOperand& _operand, bx::Error* _err)
 	{
 		int32_t size = 0;
 
@@ -354,22 +354,22 @@ namespace bgfx
 		token |= (_operand.type     <<  8) & UINT32_C(0x00001800);
 		token |=  _operand.regIndex        & UINT32_C(0x000007ff);
 		token |= (_operand.addrMode << 13) & UINT32_C(0x00002000);
-		size += bx::write(_writer, token);
+		size += bx::write(_writer, token, _err);
 
 		if (Dx9bcOperandAddrMode::Relative == _operand.addrMode)
 		{
-			size += write(_writer, _operand.subOperand);
+			size += write(_writer, _operand.subOperand, _err);
 		}
 
 		return size;
 	}
 
-	int32_t read(bx::ReaderI* _reader, Dx9bcInstruction& _instruction)
+	int32_t read(bx::ReaderI* _reader, Dx9bcInstruction& _instruction, bx::Error* _err)
 	{
 		int32_t size = 0;
 
 		uint32_t token;
-		size += bx::read(_reader, token);
+		size += bx::read(_reader, token, _err);
 
 		_instruction.opcode = Dx9bcOpcode::Enum( (token & UINT32_C(0x0000ffff) ) );
 
@@ -395,7 +395,7 @@ namespace bgfx
 				for (int32_t ii = 0, num = _instruction.length-1; ii < num; ++ii)
 				{
 					uint32_t tmp;
-					size += bx::read(_reader, tmp);
+					size += bx::read(_reader, tmp, _err);
 				}
 			}
 
@@ -436,24 +436,24 @@ namespace bgfx
 		if (valuesBeforeOpcode
 		&&  0 < info.numValues)
 		{
-			size += read(_reader, _instruction.value, info.numValues*sizeof(uint32_t) );
+			size += read(_reader, _instruction.value, info.numValues*sizeof(uint32_t), _err);
 		}
 
 		_instruction.operand[0].destination = true;
 
 		switch (_instruction.numOperands)
 		{
-		case 6: size += read(_reader, _instruction.operand[currOp++]);
-		case 5: size += read(_reader, _instruction.operand[currOp++]);
-		case 4: size += read(_reader, _instruction.operand[currOp++]);
-		case 3: size += read(_reader, _instruction.operand[currOp++]);
-		case 2: size += read(_reader, _instruction.operand[currOp++]);
-		case 1: size += read(_reader, _instruction.operand[currOp++]);
+		case 6: size += read(_reader, _instruction.operand[currOp++], _err);
+		case 5: size += read(_reader, _instruction.operand[currOp++], _err);
+		case 4: size += read(_reader, _instruction.operand[currOp++], _err);
+		case 3: size += read(_reader, _instruction.operand[currOp++], _err);
+		case 2: size += read(_reader, _instruction.operand[currOp++], _err);
+		case 1: size += read(_reader, _instruction.operand[currOp++], _err);
 		case 0:
 			if (!valuesBeforeOpcode
 			&&  0 < info.numValues)
 			{
-				size += read(_reader, _instruction.value, info.numValues*sizeof(uint32_t) );
+				size += read(_reader, _instruction.value, info.numValues*sizeof(uint32_t), _err);
 			}
 			break;
 
@@ -469,7 +469,7 @@ namespace bgfx
 		return size;
 	}
 
-	int32_t write(bx::WriterI* _writer, const Dx9bcInstruction& _instruction)
+	int32_t write(bx::WriterI* _writer, const Dx9bcInstruction& _instruction, bx::Error* _err)
 	{
 		int32_t size = 0;
 
@@ -477,17 +477,17 @@ namespace bgfx
 		token |=    _instruction.opcode             & UINT32_C(0x0000ffff);
 		token |=   (_instruction.specific    << 16) & UINT32_C(0x00ff0000);
 		token |= ( (_instruction.length - 1) << 24) & UINT32_C(0x0f000000);
-		size += bx::write(_writer, token);
+		size += bx::write(_writer, token, _err);
 
 		uint32_t currOp = 0;
 		switch (_instruction.numOperands)
 		{
-		case 6: size += write(_writer, _instruction.operand[currOp++]);
-		case 5: size += write(_writer, _instruction.operand[currOp++]);
-		case 4: size += write(_writer, _instruction.operand[currOp++]);
-		case 3: size += write(_writer, _instruction.operand[currOp++]);
-		case 2: size += write(_writer, _instruction.operand[currOp++]);
-		case 1: size += write(_writer, _instruction.operand[currOp++]);
+		case 6: size += write(_writer, _instruction.operand[currOp++], _err);
+		case 5: size += write(_writer, _instruction.operand[currOp++], _err);
+		case 4: size += write(_writer, _instruction.operand[currOp++], _err);
+		case 3: size += write(_writer, _instruction.operand[currOp++], _err);
+		case 2: size += write(_writer, _instruction.operand[currOp++], _err);
+		case 1: size += write(_writer, _instruction.operand[currOp++], _err);
 		case 0:
 			break;
 		}
@@ -626,7 +626,7 @@ namespace bgfx
 		return size;
 	}
 
-	int32_t read(bx::ReaderSeekerI* _reader, Dx9bcShader& _shader)
+	int32_t read(bx::ReaderSeekerI* _reader, Dx9bcShader& _shader, bx::Error* _err)
 	{
 		int32_t size = 0;
 		int64_t offset = bx::seek(_reader);
@@ -634,7 +634,7 @@ namespace bgfx
 		for (;;)
 		{
 			Dx9bcInstruction instruction;
-			int32_t length = read(_reader, instruction);
+			int32_t length = read(_reader, instruction, _err);
 			size += length;
 
 			if (Dx9bcOpcode::Count > instruction.opcode)
@@ -662,22 +662,22 @@ namespace bgfx
 		bx::seek(_reader, offset, bx::Whence::Begin);
 
 		_shader.byteCode.resize(size);
-		bx::read(_reader, _shader.byteCode.data(), size);
+		bx::read(_reader, _shader.byteCode.data(), size, _err);
 
 		return size;
 	}
 
-	int32_t write(bx::WriterI* _writer, const Dx9bcShader& _shader)
+	int32_t write(bx::WriterI* _writer, const Dx9bcShader& _shader, bx::Error* _err)
 	{
-		BX_UNUSED(_writer, _shader);
+		BX_UNUSED(_writer, _shader, _err);
 		return 0;
 	}
 
-	int32_t read(bx::ReaderSeekerI* _reader, Dx9bc& _bc)
+	int32_t read(bx::ReaderSeekerI* _reader, Dx9bc& _bc, bx::Error* _err)
 	{
 		int32_t size = 0;
 
-		size += bx::read(_reader, _bc.version);
+		size += bx::read(_reader, _bc.version, _err);
 
 		bool pixelShader = (0xffff0000 == (_bc.version & 0xffff0000) );
 		uint32_t versionMajor = (_bc.version>>8)&0xff;
@@ -689,27 +689,29 @@ namespace bgfx
 			, versionMinor
 			);
 
-		size += read(_reader, _bc.shader);
+		size += read(_reader, _bc.shader, _err);
 
 		return size;
 	}
 
-	int32_t write(bx::WriterSeekerI* _writer, const Dx9bc& _dxbc)
+	int32_t write(bx::WriterSeekerI* _writer, const Dx9bc& _dxbc, bx::Error* _err)
 	{
-		BX_UNUSED(_writer, _dxbc);
+		BX_UNUSED(_writer, _dxbc, _err);
 		return 0;
 	}
 
-	void parse(const Dx9bcShader& _src, Dx9bcParseFn _fn, void* _userData)
+	void parse(const Dx9bcShader& _src, Dx9bcParseFn _fn, void* _userData, bx::Error* _err)
 	{
+		BX_ERROR_SCOPE(_err);
+
 		bx::MemoryReader reader(_src.byteCode.data(), uint32_t(_src.byteCode.size() ) );
 
-//BX_TRACE("parse %d", _src.byteCode.size());
+		bx::Error err;
 
 		for (uint32_t token = 0, numTokens = uint32_t(_src.byteCode.size() / sizeof(uint32_t) ); token < numTokens;)
 		{
 			Dx9bcInstruction instruction;
-			uint32_t size = read(&reader, instruction);
+			uint32_t size = read(&reader, instruction, _err);
 			BX_CHECK(size/4 == instruction.length, "read %d, expected %d", size/4, instruction.length); BX_UNUSED(size);
 
 			bool cont = _fn(token * sizeof(uint32_t), instruction, _userData);
@@ -722,8 +724,10 @@ namespace bgfx
 		}
 	}
 
-	void filter(Dx9bcShader& _dst, const Dx9bcShader& _src, Dx9bcFilterFn _fn, void* _userData)
+	void filter(Dx9bcShader& _dst, const Dx9bcShader& _src, Dx9bcFilterFn _fn, void* _userData, bx::Error* _err)
 	{
+		BX_ERROR_SCOPE(_err);
+
 		bx::MemoryReader reader(_src.byteCode.data(), uint32_t(_src.byteCode.size() ) );
 
 		bx::MemoryBlock mb(g_allocator);
@@ -732,7 +736,7 @@ namespace bgfx
 		for (uint32_t token = 0, numTokens = uint32_t(_src.byteCode.size() / sizeof(uint32_t) ); token < numTokens;)
 		{
 			Dx9bcInstruction instruction;
-			uint32_t size = read(&reader, instruction);
+			uint32_t size = read(&reader, instruction, _err);
 			BX_CHECK(size/4 == instruction.length, "read %d, expected %d", size/4, instruction.length); BX_UNUSED(size);
 
 			_fn(instruction, _userData);

+ 8 - 8
src/shader_dx9bc.h

@@ -226,8 +226,8 @@ namespace bgfx
 		int32_t value[4];
 	};
 
-	int32_t read(bx::ReaderI* _reader, Dx9bcInstruction& _instruction);
-	int32_t write(bx::WriterI* _writer, const Dx9bcInstruction& _instruction);
+	int32_t read(bx::ReaderI* _reader, Dx9bcInstruction& _instruction, bx::Error* _err);
+	int32_t write(bx::WriterI* _writer, const Dx9bcInstruction& _instruction, bx::Error* _err);
 	int32_t toString(char* _out, int32_t _size, const Dx9bcInstruction& _instruction);
 
 	struct Dx9bcShader
@@ -235,8 +235,8 @@ namespace bgfx
 		stl::vector<uint8_t> byteCode;
 	};
 
-	int32_t read(bx::ReaderSeekerI* _reader, Dx9bcShader& _shader);
-	int32_t write(bx::WriterI* _writer, const Dx9bcShader& _shader);
+	int32_t read(bx::ReaderSeekerI* _reader, Dx9bcShader& _shader, bx::Error* _err);
+	int32_t write(bx::WriterI* _writer, const Dx9bcShader& _shader, bx::Error* _err);
 
 	struct Dx9bc
 	{
@@ -244,14 +244,14 @@ namespace bgfx
 		Dx9bcShader shader;
 	};
 
-	int32_t read(bx::ReaderSeekerI* _reader, Dx9bc& _dx9bc);
-	int32_t write(bx::WriterSeekerI* _writer, const Dx9bc& _dx9bc);
+	int32_t read(bx::ReaderSeekerI* _reader, Dx9bc& _dx9bc, bx::Error* _err);
+	int32_t write(bx::WriterSeekerI* _writer, const Dx9bc& _dx9bc, bx::Error* _err);
 
 	typedef bool (*Dx9bcParseFn)(uint32_t _offset, const Dx9bcInstruction& _instruction, void* _userData);
-	void parse(const Dx9bcShader& _src, Dx9bcParseFn _fn, void* _userData);
+	void parse(const Dx9bcShader& _src, Dx9bcParseFn _fn, void* _userData, bx::Error* _err = NULL);
 
 	typedef void (*Dx9bcFilterFn)(Dx9bcInstruction& _instruction, void* _userData);
-	void filter(Dx9bcShader& _dst, const Dx9bcShader& _src, Dx9bcFilterFn _fn, void* _userData);
+	void filter(Dx9bcShader& _dst, const Dx9bcShader& _src, Dx9bcFilterFn _fn, void* _userData, bx::Error* _err = NULL);
 
 } // namespace bgfx
 

+ 120 - 117
src/shader_dxbc.cpp

@@ -552,7 +552,7 @@ namespace bgfx
 
 #define DXBC_MAX_NAME_STRING 512
 
-	int32_t readString(bx::ReaderSeekerI* _reader, int64_t _offset, char* _out, uint32_t _max = DXBC_MAX_NAME_STRING)
+	int32_t readString(bx::ReaderSeekerI* _reader, int64_t _offset, char* _out, uint32_t _max, bx::Error* _err)
 	{
 		int64_t oldOffset = bx::seek(_reader);
 		bx::seek(_reader, _offset, bx::Whence::Begin);
@@ -562,7 +562,7 @@ namespace bgfx
 		for (uint32_t ii = 0; ii < _max-1; ++ii)
 		{
 			char ch;
-			size += bx::read(_reader, ch);
+			size += bx::read(_reader, ch, _err);
 			*_out++ = ch;
 
 			if ('\0' == ch)
@@ -755,7 +755,7 @@ namespace bgfx
 		memcpy(_digest, hash, 16);
 	}
 
-	int32_t read(bx::ReaderI* _reader, DxbcSubOperand& _subOperand)
+	int32_t read(bx::ReaderI* _reader, DxbcSubOperand& _subOperand, bx::Error* _err)
 	{
 		uint32_t token;
 		int32_t size = 0;
@@ -773,7 +773,7 @@ namespace bgfx
 		// |+------------------------------- addressing mode 2
 		// +-------------------------------- extended
 
-		size += bx::read(_reader, token);
+		size += bx::read(_reader, token, _err);
 		_subOperand.type         = DxbcOperandType::Enum( (token & UINT32_C(0x000ff000) ) >> 12);
 		_subOperand.numAddrModes =               uint8_t( (token & UINT32_C(0x00300000) ) >> 20);
 		_subOperand.addrMode     =               uint8_t( (token & UINT32_C(0x01c00000) ) >> 22);
@@ -784,7 +784,7 @@ namespace bgfx
 		switch (_subOperand.addrMode)
 		{
 		case DxbcOperandAddrMode::Imm32:
-			size += bx::read(_reader, _subOperand.regIndex);
+			size += bx::read(_reader, _subOperand.regIndex, _err);
 			break;
 
 		case DxbcOperandAddrMode::Reg:
@@ -796,7 +796,7 @@ namespace bgfx
 
 		case DxbcOperandAddrMode::RegImm32:
 			{
-				size += bx::read(_reader, _subOperand.regIndex);
+				size += bx::read(_reader, _subOperand.regIndex, _err);
 
 				DxbcSubOperand subOperand;
 				size += read(_reader, subOperand);
@@ -805,8 +805,8 @@ namespace bgfx
 
 		case DxbcOperandAddrMode::RegImm64:
 			{
-				size += bx::read(_reader, _subOperand.regIndex);
-				size += bx::read(_reader, _subOperand.regIndex);
+				size += bx::read(_reader, _subOperand.regIndex, _err);
+				size += bx::read(_reader, _subOperand.regIndex, _err);
 
 				DxbcSubOperand subOperand;
 				size += read(_reader, subOperand);
@@ -821,7 +821,7 @@ namespace bgfx
 		return size;
 	}
 
-	int32_t write(bx::WriterI* _writer, const DxbcSubOperand& _subOperand)
+	int32_t write(bx::WriterI* _writer, const DxbcSubOperand& _subOperand, bx::Error* _err)
 	{
 		int32_t size = 0;
 
@@ -832,12 +832,12 @@ namespace bgfx
 		token |= (_subOperand.mode         <<  2) & UINT32_C(0x0000000c);
 		token |= (_subOperand.modeBits     <<  4) & UINT32_C(0x00000ff0);
 		token |=  _subOperand.num                 & UINT32_C(0x00000003);
-		size += bx::write(_writer, token);
+		size += bx::write(_writer, token, _err);
 
 		switch (_subOperand.addrMode)
 		{
 		case DxbcOperandAddrMode::Imm32:
-			size += bx::write(_writer, _subOperand.regIndex);
+			size += bx::write(_writer, _subOperand.regIndex, _err);
 			break;
 
 		case DxbcOperandAddrMode::Reg:
@@ -849,7 +849,7 @@ namespace bgfx
 
 		case DxbcOperandAddrMode::RegImm32:
 			{
-				size += bx::write(_writer, _subOperand.regIndex);
+				size += bx::write(_writer, _subOperand.regIndex, _err);
 
 				DxbcSubOperand subOperand;
 				size += write(_writer, subOperand);
@@ -858,8 +858,8 @@ namespace bgfx
 
 		case DxbcOperandAddrMode::RegImm64:
 			{
-				size += bx::write(_writer, _subOperand.regIndex);
-				size += bx::write(_writer, _subOperand.regIndex);
+				size += bx::write(_writer, _subOperand.regIndex, _err);
+				size += bx::write(_writer, _subOperand.regIndex, _err);
 
 				DxbcSubOperand subOperand;
 				size += write(_writer, subOperand);
@@ -874,12 +874,12 @@ namespace bgfx
 		return size;
 	}
 
-	int32_t read(bx::ReaderI* _reader, DxbcOperand& _operand)
+	int32_t read(bx::ReaderI* _reader, DxbcOperand& _operand, bx::Error* _err)
 	{
 		int32_t size = 0;
 
 		uint32_t token;
-		size += bx::read(_reader, token);
+		size += bx::read(_reader, token, _err);
 
 		// 0       1       2       3
 		// 76543210765432107654321076543210
@@ -906,7 +906,7 @@ namespace bgfx
 
 		if (_operand.extended)
 		{
-			size += bx::read(_reader, _operand.extBits);
+			size += bx::read(_reader, _operand.extBits, _err);
 		}
 
 		switch (_operand.type)
@@ -915,7 +915,7 @@ namespace bgfx
 			_operand.num = 2 == _operand.num ? 4 : _operand.num;
 			for (uint32_t ii = 0; ii < _operand.num; ++ii)
 			{
-				size += bx::read(_reader, _operand.un.imm32[ii]);
+				size += bx::read(_reader, _operand.un.imm32[ii], _err);
 			}
 			break;
 
@@ -923,7 +923,7 @@ namespace bgfx
 			_operand.num = 2 == _operand.num ? 4 : _operand.num;
 			for (uint32_t ii = 0; ii < _operand.num; ++ii)
 			{
-				size += bx::read(_reader, _operand.un.imm64[ii]);
+				size += bx::read(_reader, _operand.un.imm64[ii], _err);
 			}
 			break;
 
@@ -936,16 +936,16 @@ namespace bgfx
 			switch (_operand.addrMode[ii])
 			{
 			case DxbcOperandAddrMode::Imm32:
-				size += bx::read(_reader, _operand.regIndex[ii]);
+				size += bx::read(_reader, _operand.regIndex[ii], _err);
 				break;
 
 			case DxbcOperandAddrMode::Reg:
-				size += read(_reader, _operand.subOperand[ii]);
+				size += read(_reader, _operand.subOperand[ii], _err);
 				break;
 
 			case DxbcOperandAddrMode::RegImm32:
-				size += bx::read(_reader, _operand.regIndex[ii]);
-				size += read(_reader, _operand.subOperand[ii]);
+				size += bx::read(_reader, _operand.regIndex[ii], _err);
+				size += read(_reader, _operand.subOperand[ii], _err);
 				break;
 
 			default:
@@ -957,7 +957,7 @@ namespace bgfx
 		return size;
 	}
 
-	int32_t write(bx::WriterI* _writer, const DxbcOperand& _operand)
+	int32_t write(bx::WriterI* _writer, const DxbcOperand& _operand, bx::Error* _err)
 	{
 		int32_t size = 0;
 
@@ -973,7 +973,7 @@ namespace bgfx
 		token |= (4 == _operand.num ? 2 : _operand.num) & UINT32_C(0x00000003);
 		token |= ( (_operand.modeBits & "\x0f\xff\x03\x00"[_operand.mode]) << 4) & UINT32_C(0x00000ff0);
 
-		size += bx::write(_writer, token);
+		size += bx::write(_writer, token, _err);
 
 		if (_operand.extended)
 		{
@@ -985,14 +985,14 @@ namespace bgfx
 		case DxbcOperandType::Imm32:
 			for (uint32_t ii = 0; ii < _operand.num; ++ii)
 			{
-				size += bx::write(_writer, _operand.un.imm32[ii]);
+				size += bx::write(_writer, _operand.un.imm32[ii], _err);
 			}
 			break;
 
 		case DxbcOperandType::Imm64:
 			for (uint32_t ii = 0; ii < _operand.num; ++ii)
 			{
-				size += bx::write(_writer, _operand.un.imm64[ii]);
+				size += bx::write(_writer, _operand.un.imm64[ii], _err);
 			}
 			break;
 
@@ -1005,16 +1005,16 @@ namespace bgfx
 			switch (_operand.addrMode[ii])
 			{
 			case DxbcOperandAddrMode::Imm32:
-				size += bx::write(_writer, _operand.regIndex[ii]);
+				size += bx::write(_writer, _operand.regIndex[ii], _err);
 				break;
 
 			case DxbcOperandAddrMode::Reg:
-				size += write(_writer, _operand.subOperand[ii]);
+				size += write(_writer, _operand.subOperand[ii], _err);
 				break;
 
 			case DxbcOperandAddrMode::RegImm32:
-				size += bx::write(_writer, _operand.regIndex[ii]);
-				size += write(_writer, _operand.subOperand[ii]);
+				size += bx::write(_writer, _operand.regIndex[ii], _err);
+				size += write(_writer, _operand.subOperand[ii], _err);
 				break;
 
 			default:
@@ -1026,12 +1026,12 @@ namespace bgfx
 		return size;
 	}
 
-	int32_t read(bx::ReaderI* _reader, DxbcInstruction& _instruction)
+	int32_t read(bx::ReaderI* _reader, DxbcInstruction& _instruction, bx::Error* _err)
 	{
 		uint32_t size = 0;
 
 		uint32_t token;
-		size += bx::read(_reader, token);
+		size += bx::read(_reader, token, _err);
 
 		// 0       1       2       3
 		// 76543210765432107654321076543210
@@ -1077,7 +1077,7 @@ namespace bgfx
 					for (uint32_t ii = 0, num = (_instruction.length-2)/4; ii < num; ++ii)
 					{
 						char temp[16];
-						size += bx::read(_reader, temp, 16);
+						size += bx::read(_reader, temp, 16, _err);
 					}
 
 				}
@@ -1190,7 +1190,7 @@ namespace bgfx
 			uint32_t extBits;
 			size += bx::read(_reader, extBits);
 			extended = 0 != (extBits & UINT32_C(0x80000000) );
-			_instruction.extended[ii] = DxbcInstruction::ExtendedType::Enum(extBits & UINT32_C(0x0000001f) );
+			_instruction.extended[ii  ] = DxbcInstruction::ExtendedType::Enum(extBits & UINT32_C(0x0000001f) );
 			_instruction.extended[ii+1] = DxbcInstruction::ExtendedType::Count;
 
 			switch (_instruction.extended[ii])
@@ -1244,7 +1244,7 @@ namespace bgfx
 			case DxbcOpcode::DCL_FUNCTION_TABLE:
 				{
 					uint32_t tableId;
-					size += read(_reader, tableId);
+					size += read(_reader, tableId, _err);
 
 					uint32_t num;
 					size += read(_reader, num);
@@ -1252,7 +1252,7 @@ namespace bgfx
 					for (uint32_t ii = 0; ii < num; ++ii)
 					{
 						uint32_t bodyId;
-						size += read(_reader, bodyId);
+						size += read(_reader, bodyId, _err);
 					}
 				}
 				break;
@@ -1260,10 +1260,10 @@ namespace bgfx
 			case DxbcOpcode::DCL_INTERFACE:
 				{
 					uint32_t interfaceId;
-					size += read(_reader, interfaceId);
+					size += read(_reader, interfaceId, _err);
 
 					uint32_t num;
-					size += read(_reader, num);
+					size += read(_reader, num, _err);
 
 					BX_CHECK(false, "not implemented.");
 				}
@@ -1279,16 +1279,16 @@ namespace bgfx
 		_instruction.numOperands = info.numOperands;
 		switch (info.numOperands)
 		{
-		case 6: size += read(_reader, _instruction.operand[currOp++]);
-		case 5: size += read(_reader, _instruction.operand[currOp++]);
-		case 4: size += read(_reader, _instruction.operand[currOp++]);
-		case 3: size += read(_reader, _instruction.operand[currOp++]);
-		case 2: size += read(_reader, _instruction.operand[currOp++]);
-		case 1: size += read(_reader, _instruction.operand[currOp++]);
+		case 6: size += read(_reader, _instruction.operand[currOp++], _err);
+		case 5: size += read(_reader, _instruction.operand[currOp++], _err);
+		case 4: size += read(_reader, _instruction.operand[currOp++], _err);
+		case 3: size += read(_reader, _instruction.operand[currOp++], _err);
+		case 2: size += read(_reader, _instruction.operand[currOp++], _err);
+		case 1: size += read(_reader, _instruction.operand[currOp++], _err);
 		case 0:
 			if (0 < info.numValues)
 			{
-				size += read(_reader, _instruction.value, info.numValues*sizeof(uint32_t) );
+				size += read(_reader, _instruction.value, info.numValues*sizeof(uint32_t), _err);
 			}
 			break;
 
@@ -1304,7 +1304,7 @@ namespace bgfx
 		return size;
 	}
 
-	int32_t write(bx::WriterI* _writer, const DxbcInstruction& _instruction)
+	int32_t write(bx::WriterI* _writer, const DxbcInstruction& _instruction, bx::Error* _err)
 	{
 		uint32_t token = 0;
 		token |= (_instruction.opcode        ) & UINT32_C(0x000007ff);
@@ -1366,7 +1366,7 @@ namespace bgfx
 
 		uint32_t size =0;
 		size += bx::write(_writer, token);
-;
+
 		for (uint32_t ii = 0; _instruction.extended[ii] != DxbcInstruction::ExtendedType::Count; ++ii)
 		{
 			// 0       1       2       3
@@ -1427,18 +1427,18 @@ namespace bgfx
 				break;
 			}
 
-			size += bx::write(_writer, token);
+			size += bx::write(_writer, token, _err);
 		}
 
 		for (uint32_t ii = 0; ii < _instruction.numOperands; ++ii)
 		{
-			size += write(_writer, _instruction.operand[ii]);
+			size += write(_writer, _instruction.operand[ii], _err);
 		}
 
 		const DxbcOpcodeInfo& info = s_dxbcOpcodeInfo[_instruction.opcode];
 		if (0 < info.numValues)
 		{
-			size += bx::write(_writer, _instruction.value, info.numValues*sizeof(uint32_t) );
+			size += bx::write(_writer, _instruction.value, info.numValues*sizeof(uint32_t), _err);
 		}
 
 		return size;
@@ -1609,15 +1609,15 @@ namespace bgfx
 		return size;
 	}
 
-	int32_t read(bx::ReaderSeekerI* _reader, DxbcSignature& _signature)
+	int32_t read(bx::ReaderSeekerI* _reader, DxbcSignature& _signature, bx::Error* _err)
 	{
 		int32_t size = 0;
 
 		int64_t offset = bx::seek(_reader);
 
 		uint32_t num;
-		size += bx::read(_reader, num);
-		size += bx::read(_reader, _signature.key);
+		size += bx::read(_reader, num, _err);
+		size += bx::read(_reader, _signature.key, _err);
 
 		for (uint32_t ii = 0; ii < num; ++ii)
 		{
@@ -1627,20 +1627,20 @@ namespace bgfx
 			size += bx::read(_reader, nameOffset);
 
 			char name[DXBC_MAX_NAME_STRING];
-			readString(_reader, offset + nameOffset, name);
+			readString(_reader, offset + nameOffset, name, DXBC_MAX_NAME_STRING, _err);
 			element.name = name;
 
-			size += bx::read(_reader, element.semanticIndex);
-			size += bx::read(_reader, element.valueType);
-			size += bx::read(_reader, element.componentType);
-			size += bx::read(_reader, element.registerIndex);
-			size += bx::read(_reader, element.mask);
-			size += bx::read(_reader, element.readWriteMask);
-			size += bx::read(_reader, element.stream);
+			size += bx::read(_reader, element.semanticIndex, _err);
+			size += bx::read(_reader, element.valueType, _err);
+			size += bx::read(_reader, element.componentType, _err);
+			size += bx::read(_reader, element.registerIndex, _err);
+			size += bx::read(_reader, element.mask, _err);
+			size += bx::read(_reader, element.readWriteMask, _err);
+			size += bx::read(_reader, element.stream, _err);
 
 			// padding
 			uint8_t padding;
-			size += bx::read(_reader, padding);
+			size += bx::read(_reader, padding, _err);
 
 			_signature.elements.push_back(element);
 		}
@@ -1648,13 +1648,13 @@ namespace bgfx
 		return size;
 	}
 
-	int32_t write(bx::WriterI* _writer, const DxbcSignature& _signature)
+	int32_t write(bx::WriterI* _writer, const DxbcSignature& _signature, bx::Error* _err)
 	{
 		int32_t size = 0;
 
 		const uint32_t num = uint32_t(_signature.elements.size() );
-		size += bx::write(_writer, num);
-		size += bx::write(_writer, _signature.key);
+		size += bx::write(_writer, num, _err);
+		size += bx::write(_writer, _signature.key, _err);
 
 		typedef stl::unordered_map<stl::string, uint32_t> NameOffsetMap;
 		NameOffsetMap nom;
@@ -1669,7 +1669,7 @@ namespace bgfx
 			if (it == nom.end() )
 			{
 				nom.insert(stl::make_pair(element.name, nameOffset) );
-				size += bx::write(_writer, nameOffset);
+				size += bx::write(_writer, nameOffset, _err);
 				nameOffset += uint32_t(element.name.size() + 1);
 			}
 			else
@@ -1677,15 +1677,14 @@ namespace bgfx
 				size += bx::write(_writer, it->second);
 			}
 
-			size += bx::write(_writer, element.semanticIndex);
-			size += bx::write(_writer, element.valueType);
-			size += bx::write(_writer, element.componentType);
-			size += bx::write(_writer, element.registerIndex);
-			size += bx::write(_writer, element.mask);
-			size += bx::write(_writer, element.readWriteMask);
-			size += bx::write(_writer, element.stream);
-			size += bx::write(_writer, pad);
-
+			size += bx::write(_writer, element.semanticIndex, _err);
+			size += bx::write(_writer, element.valueType, _err);
+			size += bx::write(_writer, element.componentType, _err);
+			size += bx::write(_writer, element.registerIndex, _err);
+			size += bx::write(_writer, element.mask, _err);
+			size += bx::write(_writer, element.readWriteMask, _err);
+			size += bx::write(_writer, element.stream, _err);
+			size += bx::write(_writer, pad, _err);
 		}
 
 		uint32_t len = 0;
@@ -1696,42 +1695,42 @@ namespace bgfx
 			if (it != nom.end() )
 			{
 				nom.erase(it);
-				size += bx::write(_writer, element.name.c_str(), uint32_t(element.name.size() + 1) );
+				size += bx::write(_writer, element.name.c_str(), uint32_t(element.name.size() + 1), _err);
 				len  += uint32_t(element.name.size() + 1);
 			}
 		}
 
 		// align 4 bytes
-		size += bx::writeRep(_writer, 0xab, (len+3)/4*4 - len);
+		size += bx::writeRep(_writer, 0xab, (len+3)/4*4 - len, _err);
 
 		return size;
 	}
 
-	int32_t read(bx::ReaderSeekerI* _reader, DxbcShader& _shader)
+	int32_t read(bx::ReaderSeekerI* _reader, DxbcShader& _shader, bx::Error* _err)
 	{
 		int32_t size = 0;
 
-		size += bx::read(_reader, _shader.version);
+		size += bx::read(_reader, _shader.version, _err);
 
 		uint32_t bcLength;
-		size += bx::read(_reader, bcLength);
+		size += bx::read(_reader, bcLength, _err);
 
 		uint32_t len = (bcLength-2)*sizeof(uint32_t);
 		_shader.byteCode.resize(len);
-		size += bx::read(_reader, _shader.byteCode.data(), len);
+		size += bx::read(_reader, _shader.byteCode.data(), len, _err);
 
 		return size;
 	}
 
-	int32_t write(bx::WriterI* _writer, const DxbcShader& _shader)
+	int32_t write(bx::WriterI* _writer, const DxbcShader& _shader, bx::Error* _err)
 	{
 		const uint32_t len = uint32_t(_shader.byteCode.size() );
 		const uint32_t bcLength = len / sizeof(uint32_t) + 2;
 
 		int32_t size = 0;
-		size += bx::write(_writer, _shader.version);
-		size += bx::write(_writer, bcLength);
-		size += bx::write(_writer, _shader.byteCode.data(), len);
+		size += bx::write(_writer, _shader.version, _err);
+		size += bx::write(_writer, bcLength, _err);
+		size += bx::write(_writer, _shader.byteCode.data(), len, _err);
 
 		return size;
 	}
@@ -1743,10 +1742,10 @@ namespace bgfx
 #define DXBC_CHUNK_INPUT_SIGNATURE  BX_MAKEFOURCC('I', 'S', 'G', 'N')
 #define DXBC_CHUNK_OUTPUT_SIGNATURE BX_MAKEFOURCC('O', 'S', 'G', 'N')
 
-	int32_t read(bx::ReaderSeekerI* _reader, DxbcContext& _dxbc)
+	int32_t read(bx::ReaderSeekerI* _reader, DxbcContext& _dxbc, bx::Error* _err)
 	{
 		int32_t size = 0;
-		size += bx::read(_reader, _dxbc.header);
+		size += bx::read(_reader, _dxbc.header, _err);
 		_dxbc.shader.shex = false;
 
 		for (uint32_t ii = 0; ii < _dxbc.header.numChunks; ++ii)
@@ -1754,15 +1753,15 @@ namespace bgfx
 			bx::seek(_reader, sizeof(DxbcContext::Header) + ii*sizeof(uint32_t), bx::Whence::Begin);
 
 			uint32_t chunkOffset;
-			size += bx::read(_reader, chunkOffset);
+			size += bx::read(_reader, chunkOffset, _err);
 
 			bx::seek(_reader, chunkOffset, bx::Whence::Begin);
 
 			uint32_t fourcc;
-			size += bx::read(_reader, fourcc);
+			size += bx::read(_reader, fourcc, _err);
 
 			uint32_t chunkSize;
-			size += bx::read(_reader, chunkSize);
+			size += bx::read(_reader, chunkSize, _err);
 
 			switch (fourcc)
 			{
@@ -1771,18 +1770,18 @@ namespace bgfx
 				// fallthrough
 
 			case DXBC_CHUNK_SHADER:
-				size += read(_reader, _dxbc.shader);
+				size += read(_reader, _dxbc.shader, _err);
 				break;
 
 			case BX_MAKEFOURCC('I', 'S', 'G', '1'):
 			case DXBC_CHUNK_INPUT_SIGNATURE:
-				size += read(_reader, _dxbc.inputSignature);
+				size += read(_reader, _dxbc.inputSignature, _err);
 				break;
 
 			case BX_MAKEFOURCC('O', 'S', 'G', '1'):
 			case BX_MAKEFOURCC('O', 'S', 'G', '5'):
 			case DXBC_CHUNK_OUTPUT_SIGNATURE:
-				size += read(_reader, _dxbc.outputSignature);
+				size += read(_reader, _dxbc.outputSignature, _err);
 				break;
 
 			case BX_MAKEFOURCC('A', 'o', 'n', '9'): // Contains DX9BC for feature level 9.x (*s_4_0_level_9_*) shaders.
@@ -1816,43 +1815,43 @@ namespace bgfx
 		return size;
 	}
 
-	int32_t write(bx::WriterSeekerI* _writer, const DxbcContext& _dxbc)
+	int32_t write(bx::WriterSeekerI* _writer, const DxbcContext& _dxbc, bx::Error* _err)
 	{
 		int32_t size = 0;
 
 		int64_t dxbcOffset = bx::seek(_writer);
 		size += bx::write(_writer, DXBC_CHUNK_HEADER);
 
-		size += bx::writeRep(_writer, 0, 16);
+		size += bx::writeRep(_writer, 0, 16, _err);
 
-		size += bx::write(_writer, UINT32_C(1) );
+		size += bx::write(_writer, UINT32_C(1), _err);
 
 		int64_t sizeOffset = bx::seek(_writer);
-		size += bx::writeRep(_writer, 0, 4);
+		size += bx::writeRep(_writer, 0, 4, _err);
 
 		uint32_t numChunks = 3;
-		size += bx::write(_writer, numChunks);
+		size += bx::write(_writer, numChunks, _err);
 
 		int64_t chunksOffsets = bx::seek(_writer);
-		size += bx::writeRep(_writer, 0, numChunks*sizeof(uint32_t) );
+		size += bx::writeRep(_writer, 0, numChunks*sizeof(uint32_t), _err);
 
 		uint32_t chunkOffset[3];
 		uint32_t chunkSize[3];
 
 		chunkOffset[0] = uint32_t(bx::seek(_writer) - dxbcOffset);
-		size += write(_writer, DXBC_CHUNK_INPUT_SIGNATURE);
-		size += write(_writer, UINT32_C(0) );
-		chunkSize[0] = write(_writer, _dxbc.inputSignature);
+		size += write(_writer, DXBC_CHUNK_INPUT_SIGNATURE, _err);
+		size += write(_writer, UINT32_C(0), _err);
+		chunkSize[0] = write(_writer, _dxbc.inputSignature, _err);
 
 		chunkOffset[1] = uint32_t(bx::seek(_writer) - dxbcOffset);
-		size += write(_writer, DXBC_CHUNK_OUTPUT_SIGNATURE);
-		size += write(_writer, UINT32_C(0) );
-		chunkSize[1] = write(_writer, _dxbc.outputSignature);
+		size += write(_writer, DXBC_CHUNK_OUTPUT_SIGNATURE, _err);
+		size += write(_writer, UINT32_C(0), _err);
+		chunkSize[1] = write(_writer, _dxbc.outputSignature, _err);
 
 		chunkOffset[2] = uint32_t(bx::seek(_writer) - dxbcOffset);
-		size += write(_writer, _dxbc.shader.shex ? DXBC_CHUNK_SHADER_EX : DXBC_CHUNK_SHADER);
-		size += write(_writer, UINT32_C(0) );
-		chunkSize[2] = write(_writer, _dxbc.shader);
+		size += write(_writer, _dxbc.shader.shex ? DXBC_CHUNK_SHADER_EX : DXBC_CHUNK_SHADER, _err);
+		size += write(_writer, UINT32_C(0), _err);
+		chunkSize[2] = write(_writer, _dxbc.shader, _err);
 
 		size += 0
 			+ chunkSize[0]
@@ -1863,15 +1862,15 @@ namespace bgfx
 		int64_t eof = bx::seek(_writer);
 
 		bx::seek(_writer, sizeOffset, bx::Whence::Begin);
-		bx::write(_writer, size);
+		bx::write(_writer, size, _err);
 
 		bx::seek(_writer, chunksOffsets, bx::Whence::Begin);
-		bx::write(_writer, chunkOffset, sizeof(chunkOffset) );
+		bx::write(_writer, chunkOffset, sizeof(chunkOffset), _err);
 
 		for (uint32_t ii = 0; ii < BX_COUNTOF(chunkOffset); ++ii)
 		{
 			bx::seek(_writer, chunkOffset[ii]+4, bx::Whence::Begin);
-			bx::write(_writer, chunkSize[ii]);
+			bx::write(_writer, chunkSize[ii], _err);
 		}
 
 		bx::seek(_writer, eof, bx::Whence::Begin);
@@ -1879,14 +1878,16 @@ namespace bgfx
 		return size;
 	}
 
-	void parse(const DxbcShader& _src, DxbcParseFn _fn, void* _userData)
+	void parse(const DxbcShader& _src, DxbcParseFn _fn, void* _userData, bx::Error* _err)
 	{
+		BX_ERROR_SCOPE(_err);
+
 		bx::MemoryReader reader(_src.byteCode.data(), uint32_t(_src.byteCode.size() ) );
 
 		for (uint32_t token = 0, numTokens = uint32_t(_src.byteCode.size() / sizeof(uint32_t) ); token < numTokens;)
 		{
 			DxbcInstruction instruction;
-			uint32_t size = read(&reader, instruction);
+			uint32_t size = read(&reader, instruction, _err);
 			BX_CHECK(size/4 == instruction.length, "read %d, expected %d", size/4, instruction.length); BX_UNUSED(size);
 
 			bool cont = _fn(token * sizeof(uint32_t), instruction, _userData);
@@ -1899,8 +1900,10 @@ namespace bgfx
 		}
 	}
 
-	void filter(DxbcShader& _dst, const DxbcShader& _src, DxbcFilterFn _fn, void* _userData)
+	void filter(DxbcShader& _dst, const DxbcShader& _src, DxbcFilterFn _fn, void* _userData, bx::Error* _err)
 	{
+		BX_ERROR_SCOPE(_err);
+
 		bx::MemoryReader reader(_src.byteCode.data(), uint32_t(_src.byteCode.size() ) );
 
 		bx::MemoryBlock mb(g_allocator);
@@ -1909,12 +1912,12 @@ namespace bgfx
 		for (uint32_t token = 0, numTokens = uint32_t(_src.byteCode.size() / sizeof(uint32_t) ); token < numTokens;)
 		{
 			DxbcInstruction instruction;
-			uint32_t size = read(&reader, instruction);
+			uint32_t size = read(&reader, instruction, _err);
 			BX_CHECK(size/4 == instruction.length, "read %d, expected %d", size/4, instruction.length); BX_UNUSED(size);
 
 			_fn(instruction, _userData);
 
-			write(&writer, instruction);
+			write(&writer, instruction, _err);
 
 			token += instruction.length;
 		}

+ 10 - 10
src/shader_dxbc.h

@@ -540,8 +540,8 @@ namespace bgfx
 		DxbcOperand operand[6];
 	};
 
-	int32_t read(bx::ReaderI* _reader, DxbcInstruction& _instruction);
-	int32_t write(bx::WriterI* _writer, const DxbcInstruction& _instruction);
+	int32_t read(bx::ReaderI* _reader, DxbcInstruction& _instruction, bx::Error* _err);
+	int32_t write(bx::WriterI* _writer, const DxbcInstruction& _instruction, bx::Error* _err);
 	int32_t toString(char* _out, int32_t _size, const DxbcInstruction& _instruction);
 
 	struct DxbcSignature
@@ -562,8 +562,8 @@ namespace bgfx
 		stl::vector<Element> elements;
 	};
 
-	int32_t read(bx::ReaderSeekerI* _reader, DxbcSignature& _signature);
-	int32_t write(bx::WriterI* _writer, const DxbcSignature& _signature);
+	int32_t read(bx::ReaderSeekerI* _reader, DxbcSignature& _signature, bx::Error* _err);
+	int32_t write(bx::WriterI* _writer, const DxbcSignature& _signature, bx::Error* _err);
 
 	struct DxbcShader
 	{
@@ -572,14 +572,14 @@ namespace bgfx
 		bool shex;
 	};
 
-	int32_t read(bx::ReaderSeekerI* _reader, DxbcShader& _shader);
-	int32_t write(bx::WriterI* _writer, const DxbcShader& _shader);
+	int32_t read(bx::ReaderSeekerI* _reader, DxbcShader& _shader, bx::Error* _err);
+	int32_t write(bx::WriterI* _writer, const DxbcShader& _shader, bx::Error* _err);
 
 	typedef bool (*DxbcParseFn)(uint32_t _offset, const DxbcInstruction& _instruction, void* _userData);
-	void parse(const DxbcShader& _src, DxbcParseFn _fn, void* _userData);
+	void parse(const DxbcShader& _src, DxbcParseFn _fn, void* _userData, bx::Error* _err = NULL);
 
 	typedef void (*DxbcFilterFn)(DxbcInstruction& _instruction, void* _userData);
-	void filter(DxbcShader& _dst, const DxbcShader& _src, DxbcFilterFn _fn, void* _userData);
+	void filter(DxbcShader& _dst, const DxbcShader& _src, DxbcFilterFn _fn, void* _userData, bx::Error* _err = NULL);
 
 	struct DxbcContext
 	{
@@ -598,8 +598,8 @@ namespace bgfx
 		DxbcShader shader;
 	};
 
-	int32_t read(bx::ReaderSeekerI* _reader, DxbcContext& _dxbc);
-	int32_t write(bx::WriterSeekerI* _writer, const DxbcContext& _dxbc);
+	int32_t read(bx::ReaderSeekerI* _reader, DxbcContext& _dxbc, bx::Error* _err);
+	int32_t write(bx::WriterSeekerI* _writer, const DxbcContext& _dxbc, bx::Error* _err);
 
 	/// Calculate DXBC hash from data.
 	void dxbcHash(const void* _data, uint32_t _size, void* _digest);

+ 577 - 374
src/shader_spirv.cpp

@@ -8,313 +8,353 @@
 
 namespace bgfx
 {
-	struct SpirvOpcodeInfo
+	struct SpvOpcodeInfo
 	{
-		uint8_t numOperands;
-		uint8_t numValues;
-		bool    hasVariable;
+		bool hasType;
+		bool hasResult;
+		SpvOperand::Enum operands[8];
 	};
 
-	static const SpirvOpcodeInfo s_sprivOpcodeInfo[] =
+	static const SpvOpcodeInfo s_spvOpcodeInfo[] =
 	{
-		{ 0, 0, false }, // Nop,
-		{ 0, 0, false }, // Undef,
-		{ 0, 0, false }, // SourceContinued,
-		{ 0, 0, false }, // Source,
-		{ 0, 0, false }, // SourceExtension,
-		{ 0, 0, false }, // Name,
-		{ 0, 0, false }, // MemberName,
-		{ 0, 0, false }, // String,
-		{ 0, 0, false }, // Line,
-		{ 0, 0, false }, // Extension,
-		{ 0, 0, false }, // ExtInstImport,
-		{ 0, 0, false }, // ExtInst,
-		{ 0, 0, false }, // MemoryModel,
-		{ 0, 0, false }, // EntryPoint,
-		{ 0, 0, false }, // ExecutionMode,
-		{ 0, 0, false }, // Capability,
-		{ 0, 0, false }, // TypeVoid,
-		{ 0, 0, false }, // TypeBool,
-		{ 0, 0, false }, // TypeInt,
-		{ 0, 0, false }, // TypeFloat,
-		{ 0, 0, false }, // TypeVector,
-		{ 0, 0, false }, // TypeMatrix,
-		{ 0, 0, false }, // TypeImage,
-		{ 0, 0, false }, // TypeSampler,
-		{ 0, 0, false }, // TypeSampledImage,
-		{ 0, 0, false }, // TypeArray,
-		{ 0, 0, false }, // TypeRuntimeArray,
-		{ 0, 0, false }, // TypeStruct,
-		{ 0, 0, false }, // TypeOpaque,
-		{ 0, 0, false }, // TypePointer,
-		{ 0, 0, false }, // TypeFunction,
-		{ 0, 0, false }, // TypeEvent,
-		{ 0, 0, false }, // TypeDeviceEvent,
-		{ 0, 0, false }, // TypeReserveId,
-		{ 0, 0, false }, // TypeQueue,
-		{ 0, 0, false }, // TypePipe,
-		{ 0, 0, false }, // TypeForwardPointer,
-		{ 0, 0, false }, // ConstantTrue,
-		{ 0, 0, false }, // ConstantFalse,
-		{ 0, 0, false }, // Constant,
-		{ 0, 0, false }, // ConstantComposite,
-		{ 0, 0, false }, // ConstantSampler,
-		{ 0, 0, false }, // ConstantNull,
-		{ 0, 0, false }, // SpecConstantTrue,
-		{ 0, 0, false }, // SpecConstantFalse,
-		{ 0, 0, false }, // SpecConstant,
-		{ 0, 0, false }, // SpecConstantComposite,
-		{ 0, 0, false }, // SpecConstantOp,
-		{ 0, 0, false }, // Function,
-		{ 0, 0, false }, // FunctionParameter,
-		{ 0, 0, false }, // FunctionEnd,
-		{ 0, 0, false }, // FunctionCall,
-		{ 0, 0, false }, // Variable,
-		{ 0, 0, false }, // ImageTexelPointer,
-		{ 0, 0, false }, // Load,
-		{ 0, 0, false }, // Store,
-		{ 0, 0, false }, // CopyMemory,
-		{ 0, 0, false }, // CopyMemorySized,
-		{ 0, 0, false }, // AccessChain,
-		{ 0, 0, false }, // InBoundsAccessChain,
-		{ 0, 0, false }, // PtrAccessChain,
-		{ 0, 0, false }, // ArrayLength,
-		{ 0, 0, false }, // GenericPtrMemSemantics,
-		{ 0, 0, false }, // InBoundsPtrAccessChain,
-		{ 0, 0, false }, // Decorate,
-		{ 0, 0, false }, // MemberDecorate,
-		{ 0, 0, false }, // DecorationGroup,
-		{ 0, 0, false }, // GroupDecorate,
-		{ 0, 0, false }, // GroupMemberDecorate,
-		{ 0, 0, false }, // VectorExtractDynamic,
-		{ 0, 0, false }, // VectorInsertDynamic,
-		{ 0, 0, false }, // VectorShuffle,
-		{ 0, 0, false }, // CompositeConstruct,
-		{ 0, 0, false }, // CompositeExtract,
-		{ 0, 0, false }, // CompositeInsert,
-		{ 0, 0, false }, // CopyObject,
-		{ 0, 0, false }, // Transpose,
-		{ 0, 0, false }, // SampledImage,
-		{ 0, 0, false }, // ImageSampleImplicitLod,
-		{ 0, 0, false }, // ImageSampleExplicitLod,
-		{ 0, 0, false }, // ImageSampleDrefImplicitLod,
-		{ 0, 0, false }, // ImageSampleDrefExplicitLod,
-		{ 0, 0, false }, // ImageSampleProjImplicitLod,
-		{ 0, 0, false }, // ImageSampleProjExplicitLod,
-		{ 0, 0, false }, // ImageSampleProjDrefImplicitLod,
-		{ 0, 0, false }, // ImageSampleProjDrefExplicitLod,
-		{ 0, 0, false }, // ImageFetch,
-		{ 0, 0, false }, // ImageGather,
-		{ 0, 0, false }, // ImageDrefGather,
-		{ 0, 0, false }, // ImageRead,
-		{ 0, 0, false }, // ImageWrite,
-		{ 0, 0, false }, // Image,
-		{ 0, 0, false }, // ImageQueryFormat,
-		{ 0, 0, false }, // ImageQueryOrder,
-		{ 0, 0, false }, // ImageQuerySizeLod,
-		{ 0, 0, false }, // ImageQuerySize,
-		{ 0, 0, false }, // ImageQueryLod,
-		{ 0, 0, false }, // ImageQueryLevels,
-		{ 0, 0, false }, // ImageQuerySamples,
-		{ 0, 0, false }, // ConvertFToU,
-		{ 0, 0, false }, // ConvertFToS,
-		{ 0, 0, false }, // ConvertSToF,
-		{ 0, 0, false }, // ConvertUToF,
-		{ 0, 0, false }, // UConvert,
-		{ 0, 0, false }, // SConvert,
-		{ 0, 0, false }, // FConvert,
-		{ 0, 0, false }, // QuantizeToF16,
-		{ 0, 0, false }, // ConvertPtrToU,
-		{ 0, 0, false }, // SatConvertSToU,
-		{ 0, 0, false }, // SatConvertUToS,
-		{ 0, 0, false }, // ConvertUToPtr,
-		{ 0, 0, false }, // PtrCastToGeneric,
-		{ 0, 0, false }, // GenericCastToPtr,
-		{ 0, 0, false }, // GenericCastToPtrExplicit,
-		{ 0, 0, false }, // Bitcast,
-		{ 0, 0, false }, // SNegate,
-		{ 0, 0, false }, // FNegate,
-		{ 0, 0, false }, // IAdd,
-		{ 0, 0, false }, // FAdd,
-		{ 0, 0, false }, // ISub,
-		{ 0, 0, false }, // FSub,
-		{ 0, 0, false }, // IMul,
-		{ 0, 0, false }, // FMul,
-		{ 0, 0, false }, // UDiv,
-		{ 0, 0, false }, // SDiv,
-		{ 0, 0, false }, // FDiv,
-		{ 0, 0, false }, // UMod,
-		{ 0, 0, false }, // SRem,
-		{ 0, 0, false }, // SMod,
-		{ 0, 0, false }, // FRem,
-		{ 0, 0, false }, // FMod,
-		{ 0, 0, false }, // VectorTimesScalar,
-		{ 0, 0, false }, // MatrixTimesScalar,
-		{ 0, 0, false }, // VectorTimesMatrix,
-		{ 0, 0, false }, // MatrixTimesVector,
-		{ 0, 0, false }, // MatrixTimesMatrix,
-		{ 0, 0, false }, // OuterProduct,
-		{ 0, 0, false }, // Dot,
-		{ 0, 0, false }, // IAddCarry,
-		{ 0, 0, false }, // ISubBorrow,
-		{ 0, 0, false }, // UMulExtended,
-		{ 0, 0, false }, // SMulExtended,
-		{ 0, 0, false }, // Any,
-		{ 0, 0, false }, // All,
-		{ 0, 0, false }, // IsNan,
-		{ 0, 0, false }, // IsInf,
-		{ 0, 0, false }, // IsFinite,
-		{ 0, 0, false }, // IsNormal,
-		{ 0, 0, false }, // SignBitSet,
-		{ 0, 0, false }, // LessOrGreater,
-		{ 0, 0, false }, // Ordered,
-		{ 0, 0, false }, // Unordered,
-		{ 0, 0, false }, // LogicalEqual,
-		{ 0, 0, false }, // LogicalNotEqual,
-		{ 0, 0, false }, // LogicalOr,
-		{ 0, 0, false }, // LogicalAnd,
-		{ 0, 0, false }, // LogicalNot,
-		{ 0, 0, false }, // Select,
-		{ 0, 0, false }, // IEqual,
-		{ 0, 0, false }, // INotEqual,
-		{ 0, 0, false }, // UGreaterThan,
-		{ 0, 0, false }, // SGreaterThan,
-		{ 0, 0, false }, // UGreaterThanEqual,
-		{ 0, 0, false }, // SGreaterThanEqual,
-		{ 0, 0, false }, // ULessThan,
-		{ 0, 0, false }, // SLessThan,
-		{ 0, 0, false }, // ULessThanEqual,
-		{ 0, 0, false }, // SLessThanEqual,
-		{ 0, 0, false }, // FOrdEqual,
-		{ 0, 0, false }, // FUnordEqual,
-		{ 0, 0, false }, // FOrdNotEqual,
-		{ 0, 0, false }, // FUnordNotEqual,
-		{ 0, 0, false }, // FOrdLessThan,
-		{ 0, 0, false }, // FUnordLessThan,
-		{ 0, 0, false }, // FOrdGreaterThan,
-		{ 0, 0, false }, // FUnordGreaterThan,
-		{ 0, 0, false }, // FOrdLessThanEqual,
-		{ 0, 0, false }, // FUnordLessThanEqual,
-		{ 0, 0, false }, // FOrdGreaterThanEqual,
-		{ 0, 0, false }, // FUnordGreaterThanEqual,
-		{ 0, 0, false }, // ShiftRightLogical,
-		{ 0, 0, false }, // ShiftRightArithmetic,
-		{ 0, 0, false }, // ShiftLeftLogical,
-		{ 0, 0, false }, // BitwiseOr,
-		{ 0, 0, false }, // BitwiseXor,
-		{ 0, 0, false }, // BitwiseAnd,
-		{ 0, 0, false }, // Not,
-		{ 0, 0, false }, // BitFieldInsert,
-		{ 0, 0, false }, // BitFieldSExtract,
-		{ 0, 0, false }, // BitFieldUExtract,
-		{ 0, 0, false }, // BitReverse,
-		{ 0, 0, false }, // BitCount,
-		{ 0, 0, false }, // DPdx,
-		{ 0, 0, false }, // DPdy,
-		{ 0, 0, false }, // Fwidth,
-		{ 0, 0, false }, // DPdxFine,
-		{ 0, 0, false }, // DPdyFine,
-		{ 0, 0, false }, // FwidthFine,
-		{ 0, 0, false }, // DPdxCoarse,
-		{ 0, 0, false }, // DPdyCoarse,
-		{ 0, 0, false }, // FwidthCoarse,
-		{ 0, 0, false }, // EmitVertex,
-		{ 0, 0, false }, // EndPrimitive,
-		{ 0, 0, false }, // EmitStreamVertex,
-		{ 0, 0, false }, // EndStreamPrimitive,
-		{ 0, 0, false }, // ControlBarrier,
-		{ 0, 0, false }, // MemoryBarrier,
-		{ 0, 0, false }, // AtomicLoad,
-		{ 0, 0, false }, // AtomicStore,
-		{ 0, 0, false }, // AtomicExchange,
-		{ 0, 0, false }, // AtomicCompareExchange,
-		{ 0, 0, false }, // AtomicCompareExchangeWeak,
-		{ 0, 0, false }, // AtomicIIncrement,
-		{ 0, 0, false }, // AtomicIDecrement,
-		{ 0, 0, false }, // AtomicIAdd,
-		{ 0, 0, false }, // AtomicISub,
-		{ 0, 0, false }, // AtomicSMin,
-		{ 0, 0, false }, // AtomicUMin,
-		{ 0, 0, false }, // AtomicSMax,
-		{ 0, 0, false }, // AtomicUMax,
-		{ 0, 0, false }, // AtomicAnd,
-		{ 0, 0, false }, // AtomicOr,
-		{ 0, 0, false }, // AtomicXor,
-		{ 0, 0, false }, // Phi,
-		{ 0, 0, false }, // LoopMerge,
-		{ 0, 0, false }, // SelectionMerge,
-		{ 0, 0, false }, // Label,
-		{ 0, 0, false }, // Branch,
-		{ 0, 0, false }, // BranchConditional,
-		{ 0, 0, false }, // Switch,
-		{ 0, 0, false }, // Kill,
-		{ 0, 0, false }, // Return,
-		{ 0, 0, false }, // ReturnValue,
-		{ 0, 0, false }, // Unreachable,
-		{ 0, 0, false }, // LifetimeStart,
-		{ 0, 0, false }, // LifetimeStop,
-		{ 0, 0, false }, // GroupAsyncCopy,
-		{ 0, 0, false }, // GroupWaitEvents,
-		{ 0, 0, false }, // GroupAll,
-		{ 0, 0, false }, // GroupAny,
-		{ 0, 0, false }, // GroupBroadcast,
-		{ 0, 0, false }, // GroupIAdd,
-		{ 0, 0, false }, // GroupFAdd,
-		{ 0, 0, false }, // GroupFMin,
-		{ 0, 0, false }, // GroupUMin,
-		{ 0, 0, false }, // GroupSMin,
-		{ 0, 0, false }, // GroupFMax,
-		{ 0, 0, false }, // GroupUMax,
-		{ 0, 0, false }, // GroupSMax,
-		{ 0, 0, false }, // ReadPipe,
-		{ 0, 0, false }, // WritePipe,
-		{ 0, 0, false }, // ReservedReadPipe,
-		{ 0, 0, false }, // ReservedWritePipe,
-		{ 0, 0, false }, // ReserveReadPipePackets,
-		{ 0, 0, false }, // ReserveWritePipePackets,
-		{ 0, 0, false }, // CommitReadPipe,
-		{ 0, 0, false }, // CommitWritePipe,
-		{ 0, 0, false }, // IsValidReserveId,
-		{ 0, 0, false }, // GetNumPipePackets,
-		{ 0, 0, false }, // GetMaxPipePackets,
-		{ 0, 0, false }, // GroupReserveReadPipePackets,
-		{ 0, 0, false }, // GroupReserveWritePipePackets,
-		{ 0, 0, false }, // GroupCommitReadPipe,
-		{ 0, 0, false }, // GroupCommitWritePipe,
-		{ 0, 0, false }, // EnqueueMarker,
-		{ 0, 0, false }, // EnqueueKernel,
-		{ 0, 0, false }, // GetKernelNDrangeSubGroupCount,
-		{ 0, 0, false }, // GetKernelNDrangeMaxSubGroupSize,
-		{ 0, 0, false }, // GetKernelWorkGroupSize,
-		{ 0, 0, false }, // GetKernelPreferredWorkGroupSizeMultiple,
-		{ 0, 0, false }, // RetainEvent,
-		{ 0, 0, false }, // ReleaseEvent,
-		{ 0, 0, false }, // CreateUserEvent,
-		{ 0, 0, false }, // IsValidEvent,
-		{ 0, 0, false }, // SetUserEventStatus,
-		{ 0, 0, false }, // CaptureEventProfilingInfo,
-		{ 0, 0, false }, // GetDefaultQueue,
-		{ 0, 0, false }, // BuildNDRange,
-		{ 0, 0, false }, // ImageSparseSampleImplicitLod,
-		{ 0, 0, false }, // ImageSparseSampleExplicitLod,
-		{ 0, 0, false }, // ImageSparseSampleDrefImplicitLod,
-		{ 0, 0, false }, // ImageSparseSampleDrefExplicitLod,
-		{ 0, 0, false }, // ImageSparseSampleProjImplicitLod,
-		{ 0, 0, false }, // ImageSparseSampleProjExplicitLod,
-		{ 0, 0, false }, // ImageSparseSampleProjDrefImplicitLod,
-		{ 0, 0, false }, // ImageSparseSampleProjDrefExplicitLod,
-		{ 0, 0, false }, // ImageSparseFetch,
-		{ 0, 0, false }, // ImageSparseGather,
-		{ 0, 0, false }, // ImageSparseDrefGather,
-		{ 0, 0, false }, // ImageSparseTexelsResident,
-		{ 0, 0, false }, // NoLine,
-		{ 0, 0, false }, // AtomicFlagTestAndSet,
-		{ 0, 0, false }, // AtomicFlagClear,
-		{ 0, 0, false }, // ImageSparseRead,
+#define SPV_OPERAND_1(_a0) SpvOperand::_a0
+#define SPV_OPERAND_2(_a0, _a1) SPV_OPERAND_1(_a0), SPV_OPERAND_1(_a1)
+#define SPV_OPERAND_3(_a0, _a1, _a2) SPV_OPERAND_1(_a0), SPV_OPERAND_2(_a1, _a2)
+#define SPV_OPERAND_4(_a0, _a1, _a2, _a3) SPV_OPERAND_1(_a0), SPV_OPERAND_3(_a1, _a2, _a3)
+#define SPV_OPERAND_5(_a0, _a1, _a2, _a3, _a4) SPV_OPERAND_1(_a0), SPV_OPERAND_4(_a1, _a2, _a3, _a4)
+#define SPV_OPERAND_6(_a0, _a1, _a2, _a3, _a4, _a5) SPV_OPERAND_1(_a0), SPV_OPERAND_5(_a1, _a2, _a3, _a4, _a5)
+#define SPV_OPERAND_7(_a0, _a1, _a2, _a3, _a4, _a5, _a6) SPV_OPERAND_1(_a0), SPV_OPERAND_6(_a1, _a2, _a3, _a4, _a5, _a6)
+#define SPV_OPERAND_8(_a0, _a1, _a2, _a3, _a4, _a5, _a6, _a7) SPV_OPERAND_1(_a0), SPV_OPERAND_7(_a1, _a2, _a3, _a4, _a5, _a6, _a7)
+#define SPV_OPERAND_9(_a0, _a1, _a2, _a3, _a4, _a5, _a6, _a7, _a8) SPV_OPERAND_1(_a0), SPV_OPERAND_8(_a1, _a2, _a3, _a4, _a5, _a6, _a7, _a8)
+#define SPV_OPERAND(...) { BX_MACRO_DISPATCHER(SPV_OPERAND_, __VA_ARGS__) BX_VA_ARGS_PASS(__VA_ARGS__) }
+#define _ Count
+		{ false, false, /* Nop,                                     //   0 */ SPV_OPERAND(_) },
+		{ true,  true,  /* Undef,                                   //   1 */ SPV_OPERAND(_) },
+		{ false, false, /* SourceContinued,                         //   2 */ SPV_OPERAND(_) },
+		{ false, false, /* Source,                                  //   3 */ SPV_OPERAND(SourceLanguage, LiteralNumber, Id, LiteralString) },
+		{ false, false, /* SourceExtension,                         //   4 */ SPV_OPERAND(LiteralString) },
+		{ false, true,  /* Name,                                    //   5 */ SPV_OPERAND(LiteralString) },
+		{ false, true,  /* MemberName,                              //   6 */ SPV_OPERAND(LiteralNumber, LiteralString) },
+		{ false, false, /* String,                                  //   7 */ SPV_OPERAND(_) },
+		{ false, false, /* Line,                                    //   8 */ SPV_OPERAND(_) },
+		{ false, false, /* ------------------------------- Invalid9 //   9 */ SPV_OPERAND(_) },
+		{ false, false, /* Extension,                               //  10 */ SPV_OPERAND(LiteralString) },
+		{ false, true,  /* ExtInstImport,                           //  11 */ SPV_OPERAND(LiteralString) },
+		{ true,  true,  /* ExtInst,                                 //  12 */ SPV_OPERAND(LiteralNumber) },
+		{ false, false, /* ------------------------------ Invalid13 //  13 */ SPV_OPERAND(_) },
+		{ false, false, /* MemoryModel,                             //  14 */ SPV_OPERAND(AddressingModel, MemoryModel) },
+		{ false, false, /* EntryPoint,                              //  15 */ SPV_OPERAND(ExecutionModel, Id, LiteralString) },
+		{ true,  true,  /* ExecutionMode,                           //  16 */ SPV_OPERAND(_) },
+		{ false, false, /* Capability,                              //  17 */ SPV_OPERAND(Capability   ) },
+		{ false, false, /* ------------------------------ Invalid18 //  18 */ SPV_OPERAND(_) },
+		{ false, true,  /* TypeVoid,                                //  19 */ SPV_OPERAND(LiteralNumber) },
+		{ false, true,  /* TypeBool,                                //  20 */ SPV_OPERAND(LiteralNumber) },
+		{ false, true,  /* TypeInt,                                 //  21 */ SPV_OPERAND(LiteralNumber) },
+		{ false, true,  /* TypeFloat,                               //  22 */ SPV_OPERAND(LiteralNumber) },
+		{ false, true,  /* TypeVector,                              //  23 */ SPV_OPERAND(ComponentType, LiteralNumber) },
+		{ false, true,  /* TypeMatrix,                              //  24 */ SPV_OPERAND(LiteralNumber) },
+		{ false, true,  /* TypeImage,                               //  25 */ SPV_OPERAND(SampledType, Dim, LiteralNumber, LiteralNumber, LiteralNumber, LiteralNumber, ImageFormat, AccessQualifier) },
+		{ false, true,  /* TypeSampler,                             //  26 */ SPV_OPERAND(LiteralNumber) },
+		{ false, true,  /* TypeSampledImage,                        //  27 */ SPV_OPERAND(LiteralNumber) },
+		{ false, true,  /* TypeArray,                               //  28 */ SPV_OPERAND(LiteralNumber) },
+		{ false, true,  /* TypeRuntimeArray,                        //  29 */ SPV_OPERAND(_) },
+		{ false, true,  /* TypeStruct,                              //  30 */ SPV_OPERAND(_) },
+		{ false, true,  /* TypeOpaque,                              //  31 */ SPV_OPERAND(_) },
+		{ false, true,  /* TypePointer,                             //  32 */ SPV_OPERAND(StorageClass, Id) },
+		{ false, true,  /* TypeFunction,                            //  33 */ SPV_OPERAND(Id, Id, Id, Id, Id) },
+		{ false, true,  /* TypeEvent,                               //  34 */ SPV_OPERAND(_) },
+		{ false, true,  /* TypeDeviceEvent,                         //  35 */ SPV_OPERAND(_) },
+		{ false, true,  /* TypeReserveId,                           //  36 */ SPV_OPERAND(_) },
+		{ false, true,  /* TypeQueue,                               //  37 */ SPV_OPERAND(_) },
+		{ false, true,  /* TypePipe,                                //  38 */ SPV_OPERAND(_) },
+		{ false, true,  /* TypeForwardPointer,                      //  39 */ SPV_OPERAND(_) },
+		{ false, false, /* ------------------------------ Invalid40 //  40 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ConstantTrue,                            //  41 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ConstantFalse,                           //  42 */ SPV_OPERAND(_) },
+		{ true,  true,  /* Constant,                                //  43 */ SPV_OPERAND(LiteralRep) },
+		{ true,  true,  /* ConstantComposite,                       //  44 */ SPV_OPERAND(LiteralRep) },
+		{ true,  true,  /* ConstantSampler,                         //  45 */ SPV_OPERAND(SamplerAddressingMode, LiteralNumber, SamplerFilterMode) },
+		{ true,  true,  /* ConstantNull,                            //  46 */ SPV_OPERAND(_) },
+		{ false, false, /* ------------------------------ Invalid47 //  47 */ SPV_OPERAND(_) },
+		{ true,  true,  /* SpecConstantTrue,                        //  48 */ SPV_OPERAND(_) },
+		{ true,  true,  /* SpecConstantFalse,                       //  49 */ SPV_OPERAND(_) },
+		{ true,  true,  /* SpecConstant,                            //  50 */ SPV_OPERAND(_) },
+		{ true,  true,  /* SpecConstantComposite,                   //  51 */ SPV_OPERAND(_) },
+		{ true,  true,  /* SpecConstantOp,                          //  52 */ SPV_OPERAND(_) },
+		{ false, false, /* ------------------------------ Invalid53 //  53 */ SPV_OPERAND(_) },
+		{ true,  true,  /* Function,                                //  54 */ SPV_OPERAND(FunctionControl, Id) },
+		{ true,  true,  /* FunctionParameter,                       //  55 */ SPV_OPERAND(_) },
+		{ false, false, /* FunctionEnd,                             //  56 */ SPV_OPERAND(_) },
+		{ true,  true,  /* FunctionCall,                            //  57 */ SPV_OPERAND(Function, IdRep) },
+		{ false, false, /* ------------------------------ Invalid58 //  58 */ SPV_OPERAND(_) },
+		{ true,  true,  /* Variable,                                //  59 */ SPV_OPERAND(StorageClass, Id) },
+		{ true,  true,  /* ImageTexelPointer,                       //  60 */ SPV_OPERAND(_) },
+		{ true,  true,  /* Load,                                    //  61 */ SPV_OPERAND(Pointer, MemoryAccess) },
+		{ false, false, /* Store,                                   //  62 */ SPV_OPERAND(Pointer, Object, MemoryAccess) },
+		{ false, false, /* CopyMemory,                              //  63 */ SPV_OPERAND(_) },
+		{ false, false, /* CopyMemorySized,                         //  64 */ SPV_OPERAND(_) },
+		{ true,  true,  /* AccessChain,                             //  65 */ SPV_OPERAND(Base, IdRep) },
+		{ true,  true,  /* InBoundsAccessChain,                     //  66 */ SPV_OPERAND(Base, IdRep) },
+		{ true,  true,  /* PtrAccessChain,                          //  67 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ArrayLength,                             //  68 */ SPV_OPERAND(_) },
+		{ true,  true,  /* GenericPtrMemSemantics,                  //  69 */ SPV_OPERAND(_) },
+		{ true,  true,  /* InBoundsPtrAccessChain,                  //  70 */ SPV_OPERAND(_) },
+		{ false, false, /* Decorate,                                //  71 */ SPV_OPERAND(Id, Decoration, LiteralRep) },
+		{ false, false, /* MemberDecorate,                          //  72 */ SPV_OPERAND(StructureType, LiteralNumber, Decoration, LiteralRep) },
+		{ false, false, /* DecorationGroup,                         //  73 */ SPV_OPERAND(_) },
+		{ false, false, /* GroupDecorate,                           //  74 */ SPV_OPERAND(_) },
+		{ false, false, /* GroupMemberDecorate,                     //  75 */ SPV_OPERAND(_) },
+		{ false, false, /* ------------------------------ Invalid76 //  76 */ SPV_OPERAND(_) },
+		{ true,  true,  /* VectorExtractDynamic,                    //  77 */ SPV_OPERAND(_) },
+		{ true,  true,  /* VectorInsertDynamic,                     //  78 */ SPV_OPERAND(_) },
+		{ true,  true,  /* VectorShuffle,                           //  79 */ SPV_OPERAND(Id, Id, LiteralRep) },
+		{ true,  true,  /* CompositeConstruct,                      //  80 */ SPV_OPERAND(IdRep) },
+		{ true,  true,  /* CompositeExtract,                        //  81 */ SPV_OPERAND(Composite, LiteralRep) },
+		{ true,  true,  /* CompositeInsert,                         //  82 */ SPV_OPERAND(Id, Composite, LiteralRep) },
+		{ true,  true,  /* CopyObject,                              //  83 */ SPV_OPERAND(Id) },
+		{ true,  true,  /* Transpose,                               //  84 */ SPV_OPERAND(Matrix) },
+		{ false, false, /* ------------------------------ Invalid85 //  85 */ SPV_OPERAND(_) },
+		{ true,  true,  /* SampledImage,                            //  86 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ImageSampleImplicitLod,                  //  87 */ SPV_OPERAND(SampledImage, Coordinate, ImageOperands, IdRep) },
+		{ true,  true,  /* ImageSampleExplicitLod,                  //  88 */ SPV_OPERAND(SampledImage, Coordinate, ImageOperands, Id, IdRep) },
+		{ true,  true,  /* ImageSampleDrefImplicitLod,              //  89 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ImageSampleDrefExplicitLod,              //  90 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ImageSampleProjImplicitLod,              //  91 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ImageSampleProjExplicitLod,              //  92 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ImageSampleProjDrefImplicitLod,          //  93 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ImageSampleProjDrefExplicitLod,          //  94 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ImageFetch,                              //  95 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ImageGather,                             //  96 */ SPV_OPERAND(SampledImage, Coordinate, Component, ImageOperands, IdRep) },
+		{ true,  true,  /* ImageDrefGather,                         //  97 */ SPV_OPERAND(SampledImage, Coordinate, Dref, ImageOperands, IdRep) },
+		{ true,  true,  /* ImageRead,                               //  98 */ SPV_OPERAND(_) },
+		{ false, false, /* ImageWrite,                              //  99 */ SPV_OPERAND(_) },
+		{ true,  true,  /* Image,                                   // 100 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ImageQueryFormat,                        // 101 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ImageQueryOrder,                         // 102 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ImageQuerySizeLod,                       // 103 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ImageQuerySize,                          // 104 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ImageQueryLod,                           // 105 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ImageQueryLevels,                        // 106 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ImageQuerySamples,                       // 107 */ SPV_OPERAND(_) },
+		{ false, false, /* ----------------------------- Invalid108 // 108 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ConvertFToU,                             // 109 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ConvertFToS,                             // 110 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ConvertSToF,                             // 111 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ConvertUToF,                             // 112 */ SPV_OPERAND(_) },
+		{ true,  true,  /* UConvert,                                // 113 */ SPV_OPERAND(Id) },
+		{ true,  true,  /* SConvert,                                // 114 */ SPV_OPERAND(Id) },
+		{ true,  true,  /* FConvert,                                // 115 */ SPV_OPERAND(Id) },
+		{ true,  true,  /* QuantizeToF16,                           // 116 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ConvertPtrToU,                           // 117 */ SPV_OPERAND(_) },
+		{ true,  true,  /* SatConvertSToU,                          // 118 */ SPV_OPERAND(_) },
+		{ true,  true,  /* SatConvertUToS,                          // 119 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ConvertUToPtr,                           // 120 */ SPV_OPERAND(_) },
+		{ true,  true,  /* PtrCastToGeneric,                        // 121 */ SPV_OPERAND(_) },
+		{ true,  true,  /* GenericCastToPtr,                        // 122 */ SPV_OPERAND(_) },
+		{ true,  true,  /* GenericCastToPtrExplicit,                // 123 */ SPV_OPERAND(_) },
+		{ true,  true,  /* Bitcast,                                 // 124 */ SPV_OPERAND(_) },
+		{ false, false, /* ----------------------------- Invalid125 // 125 */ SPV_OPERAND(_) },
+		{ true,  true,  /* SNegate,                                 // 126 */ SPV_OPERAND(Id) },
+		{ true,  true,  /* FNegate,                                 // 127 */ SPV_OPERAND(Id) },
+		{ true,  true,  /* IAdd,                                    // 128 */ SPV_OPERAND(Id, Id) },
+		{ true,  true,  /* FAdd,                                    // 129 */ SPV_OPERAND(Id, Id) },
+		{ true,  true,  /* ISub,                                    // 130 */ SPV_OPERAND(Id, Id) },
+		{ true,  true,  /* FSub,                                    // 131 */ SPV_OPERAND(Id, Id) },
+		{ true,  true,  /* IMul,                                    // 132 */ SPV_OPERAND(Id, Id) },
+		{ true,  true,  /* FMul,                                    // 133 */ SPV_OPERAND(Id, Id) },
+		{ true,  true,  /* UDiv,                                    // 134 */ SPV_OPERAND(Id, Id) },
+		{ true,  true,  /* SDiv,                                    // 135 */ SPV_OPERAND(Id, Id) },
+		{ true,  true,  /* FDiv,                                    // 136 */ SPV_OPERAND(Id, Id) },
+		{ true,  true,  /* UMod,                                    // 137 */ SPV_OPERAND(Id, Id) },
+		{ true,  true,  /* SRem,                                    // 138 */ SPV_OPERAND(Id, Id) },
+		{ true,  true,  /* SMod,                                    // 139 */ SPV_OPERAND(Id, Id) },
+		{ true,  true,  /* FRem,                                    // 140 */ SPV_OPERAND(Id, Id) },
+		{ true,  true,  /* FMod,                                    // 141 */ SPV_OPERAND(Id, Id) },
+		{ true,  true,  /* VectorTimesScalar,                       // 142 */ SPV_OPERAND(Vector, Scalar) },
+		{ true,  true,  /* MatrixTimesScalar,                       // 143 */ SPV_OPERAND(Matrix, Scalar) },
+		{ true,  true,  /* VectorTimesMatrix,                       // 144 */ SPV_OPERAND(Vector, Matrix) },
+		{ true,  true,  /* MatrixTimesVector,                       // 145 */ SPV_OPERAND(Matrix, Vector) },
+		{ true,  true,  /* MatrixTimesMatrix,                       // 146 */ SPV_OPERAND(Matrix, Matrix) },
+		{ true,  true,  /* OuterProduct,                            // 147 */ SPV_OPERAND(Vector, Vector) },
+		{ true,  true,  /* Dot,                                     // 148 */ SPV_OPERAND(Vector, Vector) },
+		{ true,  true,  /* IAddCarry,                               // 149 */ SPV_OPERAND(Id, Id) },
+		{ true,  true,  /* ISubBorrow,                              // 150 */ SPV_OPERAND(Id, Id) },
+		{ true,  true,  /* UMulExtended,                            // 151 */ SPV_OPERAND(Id, Id) },
+		{ true,  true,  /* SMulExtended,                            // 152 */ SPV_OPERAND(Id, Id) },
+		{ false, false, /* ----------------------------- Invalid153 // 153 */ SPV_OPERAND(_) },
+		{ true,  true,  /* Any,                                     // 154 */ SPV_OPERAND(Vector) },
+		{ true,  true,  /* All,                                     // 155 */ SPV_OPERAND(Vector) },
+		{ true,  true,  /* IsNan,                                   // 156 */ SPV_OPERAND(Id) },
+		{ true,  true,  /* IsInf,                                   // 157 */ SPV_OPERAND(Id) },
+		{ true,  true,  /* IsFinite,                                // 158 */ SPV_OPERAND(Id) },
+		{ true,  true,  /* IsNormal,                                // 159 */ SPV_OPERAND(Id) },
+		{ true,  true,  /* SignBitSet,                              // 160 */ SPV_OPERAND(Id) },
+		{ true,  true,  /* LessOrGreater,                           // 161 */ SPV_OPERAND(Id, Id) },
+		{ true,  true,  /* Ordered,                                 // 162 */ SPV_OPERAND(Id, Id) },
+		{ true,  true,  /* Unordered,                               // 163 */ SPV_OPERAND(_) },
+		{ true,  true,  /* LogicalEqual,                            // 164 */ SPV_OPERAND(_) },
+		{ true,  true,  /* LogicalNotEqual,                         // 165 */ SPV_OPERAND(_) },
+		{ true,  true,  /* LogicalOr,                               // 166 */ SPV_OPERAND(_) },
+		{ true,  true,  /* LogicalAnd,                              // 167 */ SPV_OPERAND(_) },
+		{ true,  true,  /* LogicalNot,                              // 168 */ SPV_OPERAND(_) },
+		{ true,  true,  /* Select,                                  // 169 */ SPV_OPERAND(Condition, Id, Id) },
+		{ true,  true,  /* IEqual,                                  // 170 */ SPV_OPERAND(_) },
+		{ true,  true,  /* INotEqual,                               // 171 */ SPV_OPERAND(_) },
+		{ true,  true,  /* UGreaterThan,                            // 172 */ SPV_OPERAND(_) },
+		{ true,  true,  /* SGreaterThan,                            // 173 */ SPV_OPERAND(_) },
+		{ true,  true,  /* UGreaterThanEqual,                       // 174 */ SPV_OPERAND(_) },
+		{ true,  true,  /* SGreaterThanEqual,                       // 175 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ULessThan,                               // 176 */ SPV_OPERAND(_) },
+		{ true,  true,  /* SLessThan,                               // 177 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ULessThanEqual,                          // 178 */ SPV_OPERAND(_) },
+		{ true,  true,  /* SLessThanEqual,                          // 179 */ SPV_OPERAND(_) },
+		{ true,  true,  /* FOrdEqual,                               // 180 */ SPV_OPERAND(_) },
+		{ true,  true,  /* FUnordEqual,                             // 181 */ SPV_OPERAND(_) },
+		{ true,  true,  /* FOrdNotEqual,                            // 182 */ SPV_OPERAND(_) },
+		{ true,  true,  /* FUnordNotEqual,                          // 183 */ SPV_OPERAND(_) },
+		{ true,  true,  /* FOrdLessThan,                            // 184 */ SPV_OPERAND(_) },
+		{ true,  true,  /* FUnordLessThan,                          // 185 */ SPV_OPERAND(_) },
+		{ true,  true,  /* FOrdGreaterThan,                         // 186 */ SPV_OPERAND(_) },
+		{ true,  true,  /* FUnordGreaterThan,                       // 187 */ SPV_OPERAND(_) },
+		{ true,  true,  /* FOrdLessThanEqual,                       // 188 */ SPV_OPERAND(_) },
+		{ true,  true,  /* FUnordLessThanEqual,                     // 189 */ SPV_OPERAND(_) },
+		{ true,  true,  /* FOrdGreaterThanEqual,                    // 190 */ SPV_OPERAND(_) },
+		{ true,  true,  /* FUnordGreaterThanEqual,                  // 191 */ SPV_OPERAND(_) },
+		{ false, false, /* ----------------------------- Invalid192 // 192 */ SPV_OPERAND(_) },
+		{ false, false, /* ----------------------------- Invalid193 // 193 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ShiftRightLogical,                       // 194 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ShiftRightArithmetic,                    // 195 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ShiftLeftLogical,                        // 196 */ SPV_OPERAND(_) },
+		{ true,  true,  /* BitwiseOr,                               // 197 */ SPV_OPERAND(_) },
+		{ true,  true,  /* BitwiseXor,                              // 198 */ SPV_OPERAND(_) },
+		{ true,  true,  /* BitwiseAnd,                              // 199 */ SPV_OPERAND(_) },
+		{ true,  true,  /* Not,                                     // 200 */ SPV_OPERAND(_) },
+		{ true,  true,  /* BitFieldInsert,                          // 201 */ SPV_OPERAND(_) },
+		{ true,  true,  /* BitFieldSExtract,                        // 202 */ SPV_OPERAND(_) },
+		{ true,  true,  /* BitFieldUExtract,                        // 203 */ SPV_OPERAND(_) },
+		{ true,  true,  /* BitReverse,                              // 204 */ SPV_OPERAND(_) },
+		{ true,  true,  /* BitCount,                                // 205 */ SPV_OPERAND(_) },
+		{ false, false, /* ----------------------------- Invalid206 // 206 */ SPV_OPERAND(_) },
+		{ true,  true,  /* DPdx,                                    // 207 */ SPV_OPERAND(_) },
+		{ true,  true,  /* DPdy,                                    // 208 */ SPV_OPERAND(_) },
+		{ true,  true,  /* Fwidth,                                  // 209 */ SPV_OPERAND(_) },
+		{ true,  true,  /* DPdxFine,                                // 210 */ SPV_OPERAND(_) },
+		{ true,  true,  /* DPdyFine,                                // 211 */ SPV_OPERAND(_) },
+		{ true,  true,  /* FwidthFine,                              // 212 */ SPV_OPERAND(_) },
+		{ true,  true,  /* DPdxCoarse,                              // 213 */ SPV_OPERAND(_) },
+		{ true,  true,  /* DPdyCoarse,                              // 214 */ SPV_OPERAND(_) },
+		{ true,  true,  /* FwidthCoarse,                            // 215 */ SPV_OPERAND(_) },
+		{ false, false, /* ----------------------------- Invalid216 // 216 */ SPV_OPERAND(_) },
+		{ false, false, /* ----------------------------- Invalid217 // 217 */ SPV_OPERAND(_) },
+		{ false, false, /* EmitVertex,                              // 218 */ SPV_OPERAND(_) },
+		{ false, false, /* EndPrimitive,                            // 219 */ SPV_OPERAND(_) },
+		{ false, false, /* EmitStreamVertex,                        // 220 */ SPV_OPERAND(_) },
+		{ false, false, /* EndStreamPrimitive,                      // 221 */ SPV_OPERAND(_) },
+		{ false, false, /* ----------------------------- Invalid222 // 222 */ SPV_OPERAND(_) },
+		{ false, false, /* ----------------------------- Invalid223 // 223 */ SPV_OPERAND(_) },
+		{ false, false, /* ControlBarrier,                          // 224 */ SPV_OPERAND(_) },
+		{ false, false, /* MemoryBarrier,                           // 225 */ SPV_OPERAND(_) },
+		{ false, false, /* ----------------------------- Invalid226 // 226 */ SPV_OPERAND(_) },
+		{ true,  true,  /* AtomicLoad,                              // 227 */ SPV_OPERAND(_) },
+		{ false, false, /* AtomicStore,                             // 228 */ SPV_OPERAND(_) },
+		{ true,  true,  /* AtomicExchange,                          // 229 */ SPV_OPERAND(_) },
+		{ true,  true,  /* AtomicCompareExchange,                   // 230 */ SPV_OPERAND(_) },
+		{ true,  true,  /* AtomicCompareExchangeWeak,               // 231 */ SPV_OPERAND(_) },
+		{ true,  true,  /* AtomicIIncrement,                        // 232 */ SPV_OPERAND(_) },
+		{ true,  true,  /* AtomicIDecrement,                        // 233 */ SPV_OPERAND(_) },
+		{ true,  true,  /* AtomicIAdd,                              // 234 */ SPV_OPERAND(_) },
+		{ true,  true,  /* AtomicISub,                              // 235 */ SPV_OPERAND(_) },
+		{ true,  true,  /* AtomicSMin,                              // 236 */ SPV_OPERAND(_) },
+		{ true,  true,  /* AtomicUMin,                              // 237 */ SPV_OPERAND(_) },
+		{ true,  true,  /* AtomicSMax,                              // 238 */ SPV_OPERAND(_) },
+		{ true,  true,  /* AtomicUMax,                              // 239 */ SPV_OPERAND(_) },
+		{ true,  true,  /* AtomicAnd,                               // 240 */ SPV_OPERAND(_) },
+		{ true,  true,  /* AtomicOr,                                // 241 */ SPV_OPERAND(_) },
+		{ true,  true,  /* AtomicXor,                               // 242 */ SPV_OPERAND(_) },
+		{ false, false, /* ----------------------------- Invalid243 // 243 */ SPV_OPERAND(_) },
+		{ false, false, /* ----------------------------- Invalid244 // 244 */ SPV_OPERAND(_) },
+		{ true,  true,  /* Phi,                                     // 245 */ SPV_OPERAND(_) },
+		{ false, false, /* LoopMerge,                               // 246 */ SPV_OPERAND(_) },
+		{ false, false, /* SelectionMerge,                          // 247 */ SPV_OPERAND(_) },
+		{ false, true,  /* Label,                                   // 248 */ SPV_OPERAND(_) },
+		{ false, false, /* Branch,                                  // 249 */ SPV_OPERAND(Id) },
+		{ false, false, /* BranchConditional,                       // 250 */ SPV_OPERAND(Condition, Id, Id, LiteralRep) },
+		{ false, false, /* Switch,                                  // 251 */ SPV_OPERAND(_) },
+		{ false, false, /* Kill,                                    // 252 */ SPV_OPERAND(_) },
+		{ false, false, /* Return,                                  // 253 */ SPV_OPERAND(_) },
+		{ false, false, /* ReturnValue,                             // 254 */ SPV_OPERAND(Id) },
+		{ false, false, /* Unreachable,                             // 255 */ SPV_OPERAND(_) },
+		{ false, false, /* LifetimeStart,                           // 256 */ SPV_OPERAND(_) },
+		{ false, false, /* LifetimeStop,                            // 257 */ SPV_OPERAND(_) },
+		{ false, false, /* ----------------------------- Invalid258 // 258 */ SPV_OPERAND(_) },
+		{ true,  true,  /* GroupAsyncCopy,                          // 259 */ SPV_OPERAND(_) },
+		{ false, false, /* GroupWaitEvents,                         // 260 */ SPV_OPERAND(_) },
+		{ true,  true,  /* GroupAll,                                // 261 */ SPV_OPERAND(_) },
+		{ true,  true,  /* GroupAny,                                // 262 */ SPV_OPERAND(_) },
+		{ true,  true,  /* GroupBroadcast,                          // 263 */ SPV_OPERAND(_) },
+		{ true,  true,  /* GroupIAdd,                               // 264 */ SPV_OPERAND(_) },
+		{ true,  true,  /* GroupFAdd,                               // 265 */ SPV_OPERAND(_) },
+		{ true,  true,  /* GroupFMin,                               // 266 */ SPV_OPERAND(_) },
+		{ true,  true,  /* GroupUMin,                               // 267 */ SPV_OPERAND(_) },
+		{ true,  true,  /* GroupSMin,                               // 268 */ SPV_OPERAND(_) },
+		{ true,  true,  /* GroupFMax,                               // 269 */ SPV_OPERAND(_) },
+		{ true,  true,  /* GroupUMax,                               // 270 */ SPV_OPERAND(_) },
+		{ true,  true,  /* GroupSMax,                               // 271 */ SPV_OPERAND(_) },
+		{ false, false, /* ----------------------------- Invalid272 // 272 */ SPV_OPERAND(_) },
+		{ false, false, /* ----------------------------- Invalid273 // 273 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ReadPipe,                                // 274 */ SPV_OPERAND(_) },
+		{ true,  true,  /* WritePipe,                               // 275 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ReservedReadPipe,                        // 276 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ReservedWritePipe,                       // 277 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ReserveReadPipePackets,                  // 278 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ReserveWritePipePackets,                 // 279 */ SPV_OPERAND(_) },
+		{ false, false, /* CommitReadPipe,                          // 280 */ SPV_OPERAND(_) },
+		{ false, false, /* CommitWritePipe,                         // 281 */ SPV_OPERAND(_) },
+		{ true,  true,  /* IsValidReserveId,                        // 282 */ SPV_OPERAND(_) },
+		{ true,  true,  /* GetNumPipePackets,                       // 283 */ SPV_OPERAND(_) },
+		{ true,  true,  /* GetMaxPipePackets,                       // 284 */ SPV_OPERAND(_) },
+		{ true,  true,  /* GroupReserveReadPipePackets,             // 285 */ SPV_OPERAND(_) },
+		{ true,  true,  /* GroupReserveWritePipePackets,            // 286 */ SPV_OPERAND(_) },
+		{ false, false, /* GroupCommitReadPipe,                     // 287 */ SPV_OPERAND(_) },
+		{ false, false, /* GroupCommitWritePipe,                    // 288 */ SPV_OPERAND(_) },
+		{ false, false, /* ----------------------------- Invalid289 // 289 */ SPV_OPERAND(_) },
+		{ false, false, /* ----------------------------- Invalid290 // 290 */ SPV_OPERAND(_) },
+		{ true,  true,  /* EnqueueMarker,                           // 291 */ SPV_OPERAND(_) },
+		{ true,  true,  /* EnqueueKernel,                           // 292 */ SPV_OPERAND(_) },
+		{ true,  true,  /* GetKernelNDrangeSubGroupCount,           // 293 */ SPV_OPERAND(_) },
+		{ true,  true,  /* GetKernelNDrangeMaxSubGroupSize,         // 294 */ SPV_OPERAND(_) },
+		{ true,  true,  /* GetKernelWorkGroupSize,                  // 295 */ SPV_OPERAND(_) },
+		{ true,  true,  /* GetKernelPreferredWorkGroupSizeMultiple, // 296 */ SPV_OPERAND(_) },
+		{ false, false, /* RetainEvent,                             // 297 */ SPV_OPERAND(_) },
+		{ false, false, /* ReleaseEvent,                            // 298 */ SPV_OPERAND(_) },
+		{ true,  true,  /* CreateUserEvent,                         // 299 */ SPV_OPERAND(_) },
+		{ true,  true,  /* IsValidEvent,                            // 300 */ SPV_OPERAND(_) },
+		{ false, false, /* SetUserEventStatus,                      // 301 */ SPV_OPERAND(_) },
+		{ false, false, /* CaptureEventProfilingInfo,               // 302 */ SPV_OPERAND(_) },
+		{ true,  true,  /* GetDefaultQueue,                         // 303 */ SPV_OPERAND(_) },
+		{ true,  true,  /* BuildNDRange,                            // 304 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ImageSparseSampleImplicitLod,            // 305 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ImageSparseSampleExplicitLod,            // 306 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ImageSparseSampleDrefImplicitLod,        // 307 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ImageSparseSampleDrefExplicitLod,        // 308 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ImageSparseSampleProjImplicitLod,        // 309 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ImageSparseSampleProjExplicitLod,        // 310 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ImageSparseSampleProjDrefImplicitLod,    // 311 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ImageSparseSampleProjDrefExplicitLod,    // 312 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ImageSparseFetch,                        // 313 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ImageSparseGather,                       // 314 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ImageSparseDrefGather,                   // 315 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ImageSparseTexelsResident,               // 316 */ SPV_OPERAND(_) },
+		{ false, false, /* NoLine,                                  // 317 */ SPV_OPERAND(_) },
+		{ true,  true,  /* AtomicFlagTestAndSet,                    // 318 */ SPV_OPERAND(_) },
+		{ false, false, /* AtomicFlagClear,                         // 319 */ SPV_OPERAND(_) },
+		{ true,  true,  /* ImageSparseRead,                         // 320 */ SPV_OPERAND(_) },
+#undef _
+#undef SPV_OPERAND
 	};
-	BX_STATIC_ASSERT(BX_COUNTOF(s_sprivOpcodeInfo) == SpirvOpcode::Count);
+	BX_STATIC_ASSERT(BX_COUNTOF(s_spvOpcodeInfo) == SpvOpcode::Count);
 
-	const char* s_spirvOpcode[] =
+	const char* s_spvOpcode[] =
 	{
 		"Nop",
 		"Undef",
@@ -325,13 +365,16 @@ namespace bgfx
 		"MemberName",
 		"String",
 		"Line",
+		"Invalid9",
 		"Extension",
 		"ExtInstImport",
 		"ExtInst",
+		"Invalid13",
 		"MemoryModel",
 		"EntryPoint",
 		"ExecutionMode",
 		"Capability",
+		"Invalid18",
 		"TypeVoid",
 		"TypeBool",
 		"TypeInt",
@@ -353,21 +396,25 @@ namespace bgfx
 		"TypeQueue",
 		"TypePipe",
 		"TypeForwardPointer",
+		"Invalid40",
 		"ConstantTrue",
 		"ConstantFalse",
 		"Constant",
 		"ConstantComposite",
 		"ConstantSampler",
 		"ConstantNull",
+		"Invalid47",
 		"SpecConstantTrue",
 		"SpecConstantFalse",
 		"SpecConstant",
 		"SpecConstantComposite",
 		"SpecConstantOp",
+		"Invalid53",
 		"Function",
 		"FunctionParameter",
 		"FunctionEnd",
 		"FunctionCall",
+		"Invalid58",
 		"Variable",
 		"ImageTexelPointer",
 		"Load",
@@ -385,6 +432,7 @@ namespace bgfx
 		"DecorationGroup",
 		"GroupDecorate",
 		"GroupMemberDecorate",
+		"Invalid76",
 		"VectorExtractDynamic",
 		"VectorInsertDynamic",
 		"VectorShuffle",
@@ -393,6 +441,7 @@ namespace bgfx
 		"CompositeInsert",
 		"CopyObject",
 		"Transpose",
+		"Invalid85",
 		"SampledImage",
 		"ImageSampleImplicitLod",
 		"ImageSampleExplicitLod",
@@ -415,6 +464,7 @@ namespace bgfx
 		"ImageQueryLod",
 		"ImageQueryLevels",
 		"ImageQuerySamples",
+		"Invalid108",
 		"ConvertFToU",
 		"ConvertFToS",
 		"ConvertSToF",
@@ -431,6 +481,7 @@ namespace bgfx
 		"GenericCastToPtr",
 		"GenericCastToPtrExplicit",
 		"Bitcast",
+		"Invalid125",
 		"SNegate",
 		"FNegate",
 		"IAdd",
@@ -458,6 +509,7 @@ namespace bgfx
 		"ISubBorrow",
 		"UMulExtended",
 		"SMulExtended",
+		"Invalid153",
 		"Any",
 		"All",
 		"IsNan",
@@ -496,6 +548,8 @@ namespace bgfx
 		"FUnordLessThanEqual",
 		"FOrdGreaterThanEqual",
 		"FUnordGreaterThanEqual",
+		"Invalid192",
+		"Invalid193",
 		"ShiftRightLogical",
 		"ShiftRightArithmetic",
 		"ShiftLeftLogical",
@@ -508,6 +562,7 @@ namespace bgfx
 		"BitFieldUExtract",
 		"BitReverse",
 		"BitCount",
+		"Invalid206",
 		"DPdx",
 		"DPdy",
 		"Fwidth",
@@ -517,12 +572,17 @@ namespace bgfx
 		"DPdxCoarse",
 		"DPdyCoarse",
 		"FwidthCoarse",
+		"Invalid216",
+		"Invalid217",
 		"EmitVertex",
 		"EndPrimitive",
 		"EmitStreamVertex",
+		"Invalid222",
+		"Invalid223",
 		"EndStreamPrimitive",
 		"ControlBarrier",
 		"MemoryBarrier",
+		"Invalid226",
 		"AtomicLoad",
 		"AtomicStore",
 		"AtomicExchange",
@@ -539,6 +599,8 @@ namespace bgfx
 		"AtomicAnd",
 		"AtomicOr",
 		"AtomicXor",
+		"Invalid243",
+		"Invalid244",
 		"Phi",
 		"LoopMerge",
 		"SelectionMerge",
@@ -552,6 +614,7 @@ namespace bgfx
 		"Unreachable",
 		"LifetimeStart",
 		"LifetimeStop",
+		"Invalid258",
 		"GroupAsyncCopy",
 		"GroupWaitEvents",
 		"GroupAll",
@@ -565,6 +628,8 @@ namespace bgfx
 		"GroupFMax",
 		"GroupUMax",
 		"GroupSMax",
+		"Invalid272",
+		"Invalid273",
 		"ReadPipe",
 		"WritePipe",
 		"ReservedReadPipe",
@@ -580,6 +645,8 @@ namespace bgfx
 		"GroupReserveWritePipePackets",
 		"GroupCommitReadPipe",
 		"GroupCommitWritePipe",
+		"Invalid289",
+		"Invalid290",
 		"EnqueueMarker",
 		"EnqueueKernel",
 		"GetKernelNDrangeSubGroupCount",
@@ -611,165 +678,301 @@ namespace bgfx
 		"AtomicFlagClear",
 		"ImageSparseRead",
 	};
-	BX_STATIC_ASSERT(BX_COUNTOF(s_spirvOpcode) == SpirvOpcode::Count);
+	BX_STATIC_ASSERT(BX_COUNTOF(s_spvOpcode) == SpvOpcode::Count);
 
-	const char* getName(SpirvOpcode::Enum _opcode)
+	const char* getName(SpvOpcode::Enum _opcode)
 	{
-		BX_CHECK(_opcode < SpirvOpcode::Count, "Unknown opcode id %d.", _opcode);
-		return s_spirvOpcode[_opcode];
+		BX_WARN(_opcode < SpvOpcode::Count, "Unknown opcode id %d.", _opcode);
+		return _opcode < SpvOpcode::Count
+			?  s_spvOpcode[_opcode]
+			: "?SpvOpcode?"
+			;
 	}
 
-	int32_t read(bx::ReaderI* _reader, SpirvOperand& _operand)
+	static const char* s_spvStorageClass[] =
+	{
+		"UniformConstant",
+		"Input",
+		"Uniform",
+		"Output",
+		"Workgroup",
+		"CrossWorkgroup",
+		"Private",
+		"Function",
+		"Generic",
+		"PushConstant",
+		"AtomicCounter",
+		"Image",
+	};
+	BX_STATIC_ASSERT(BX_COUNTOF(s_spvStorageClass) == SpvStorageClass::Count);
+
+	const char* getName(SpvStorageClass::Enum _enum)
+	{
+		BX_CHECK(_enum < SpvStorageClass::Count, "Unknown storage class id %d.", _enum);
+		return _enum < SpvStorageClass::Count
+			?  s_spvStorageClass[_enum]
+			: "?SpvStorageClass?"
+			;
+	}
+
+	int32_t read(bx::ReaderI* _reader, SpvOperand& _operand, bx::Error* _err)
 	{
 		int32_t size = 0;
 
-		BX_UNUSED(_operand);
 		uint32_t token;
-		size += bx::read(_reader, token);
+		_operand.literalString = "";
+
+		switch (_operand.type)
+		{
+		case SpvOperand::LiteralString:
+			do
+			{
+				size += bx::read(_reader, token, _err);
+				_operand.literalString.append( (char*)&token, (char*)&token + sizeof(token) );
+			}
+			while (0 != (token & 0xff000000) && _err->isOk() );
+			break;
+
+		default:
+			size += bx::read(_reader, _operand.data[0], _err);
+			break;
+		}
 
 		return size;
 	}
 
-	int32_t read(bx::ReaderI* _reader, SpirvInstruction& _instruction)
+	int32_t read(bx::ReaderI* _reader, SpvInstruction& _instruction, bx::Error* _err)
 	{
 		int32_t size = 0;
 
 		uint32_t token;
-		size += bx::read(_reader, token);
+		size += bx::read(_reader, token, _err);
 
-		_instruction.opcode = SpirvOpcode::Enum( (token & UINT32_C(0x0000ffff) )      );
-		_instruction.length =          uint16_t( (token & UINT32_C(0xffff0000) ) >> 16);
+		_instruction.opcode = SpvOpcode::Enum( (token & UINT32_C(0x0000ffff) )      );
+		_instruction.length =        uint16_t( (token & UINT32_C(0xffff0000) ) >> 16);
 
-		uint32_t currOp = 0;
+		if (_instruction.opcode >= SpvOpcode::Count)
+		{
+			BX_ERROR_SET(_err, BGFX_SHADER_SPIRV_INVALID_INSTRUCTION, "SPIR-V: Invalid instruction.");
+			return size;
+		}
 
-		const SpirvOpcodeInfo& info = s_sprivOpcodeInfo[_instruction.opcode];
+		if (0 == _instruction.length)
+		{
+			return size;
+		}
+
+		const SpvOpcodeInfo& info = s_spvOpcodeInfo[_instruction.opcode];
+		_instruction.hasType   = info.hasType;
+		_instruction.hasResult = info.hasResult;
 
-		if (0 < info.numValues)
+		if (info.hasType)
 		{
-			size += read(_reader, _instruction.un.value, info.numValues*sizeof(uint32_t) );
+			size += read(_reader, _instruction.type, _err);
 		}
 
-		if (info.hasVariable)
+		if (info.hasResult)
 		{
-			while (size/4 != _instruction.length)
-			{
-				uint32_t tmp;
-				size += bx::read(_reader, tmp);
-			}
+			size += read(_reader, _instruction.result, _err);
 		}
-		else
+
+		uint32_t currOp = 0;
+		switch (_instruction.opcode)
 		{
-			_instruction.numOperands = info.numOperands;
-			switch (info.numOperands)
+		case SpvOpcode::EntryPoint:
+			_instruction.operand[currOp].type = info.operands[currOp];
+			size += read(_reader, _instruction.operand[currOp++], _err);
+			_instruction.operand[currOp].type = info.operands[currOp];
+			size += read(_reader, _instruction.operand[currOp++], _err);
+			_instruction.operand[currOp].type = info.operands[currOp];
+			size += read(_reader, _instruction.operand[currOp++], _err);
+
+			_instruction.operand[currOp].type = SpvOperand::Id;
+			for (uint32_t ii = 0, num = _instruction.length - size/4; ii < num; ++ii)
 			{
-			case 6: size += read(_reader, _instruction.operand[currOp++]);
-			case 5: size += read(_reader, _instruction.operand[currOp++]);
-			case 4: size += read(_reader, _instruction.operand[currOp++]);
-			case 3: size += read(_reader, _instruction.operand[currOp++]);
-			case 2: size += read(_reader, _instruction.operand[currOp++]);
-			case 1: size += read(_reader, _instruction.operand[currOp++]);
-			case 0:
-				break;
-
-			default:
-				BX_WARN(false, "Instruction %s with invalid number of operands %d (numValues %d)."
-						, getName(_instruction.opcode)
-						, info.numOperands
-						, info.numValues
-						);
-				break;
+				size += read(_reader, _instruction.operand[currOp], _err);
 			}
+			break;
 
-			BX_WARN(size/4 == _instruction.length, "read %d, expected %d, %s"
-					, size/4
-					, _instruction.length
-					, getName(_instruction.opcode)
-					);
-			while (size/4 != _instruction.length)
+		default:
+			for (;size/4 != _instruction.length && _err->isOk(); ++currOp)
 			{
-				uint32_t tmp;
-				size += bx::read(_reader, tmp);
+				_instruction.operand[currOp].type = info.operands[currOp];
+				size += read(_reader, _instruction.operand[currOp], _err);
 			}
+			break;
 		}
 
+		_instruction.numOperands = currOp;
+
 		return size;
 	}
 
-	int32_t write(bx::WriterI* _writer, const SpirvInstruction& _instruction)
+	int32_t write(bx::WriterI* _writer, const SpvInstruction& _instruction, bx::Error* _err)
 	{
 		int32_t size = 0;
-		BX_UNUSED(_writer, _instruction);
+		BX_UNUSED(_writer, _instruction, _err);
 		return size;
 	}
 
-	int32_t toString(char* _out, int32_t _size, const SpirvInstruction& _instruction)
+	int32_t toString(char* _out, int32_t _size, const SpvInstruction& _instruction)
 	{
 		int32_t size = 0;
+
+		if (_instruction.hasResult)
+		{
+			size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size)
+						, " %%%d = "
+						, _instruction.result
+						);
+		}
+
 		size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size)
-					, "%s %d (%d, %d)"
+					, "%s"
 					, getName(_instruction.opcode)
-					, _instruction.numOperands
-					, _instruction.un.value[0]
-					, _instruction.un.value[1]
 					);
 
+		for (uint32_t ii = 0, num = _instruction.numOperands; ii < num; ++ii)
+		{
+			const SpvOperand& operand = _instruction.operand[ii];
+			switch (operand.type)
+			{
+			case SpvOperand::AddressingModel:
+				size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size)
+							, "%sAddressingModel(%d)"
+							, 0 == ii ? " " : ", "
+							, operand.data[0]
+							);
+				break;
+
+			case SpvOperand::FunctionControl:
+				size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size)
+							, "%s0x%08x"
+							, 0 == ii ? " " : ", "
+							, operand.data[0]
+							);
+				break;
+
+			case SpvOperand::LiteralNumber:
+				size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size)
+							, "%s%d"
+							, 0 == ii ? " " : ", "
+							, operand.data[0]
+							);
+				break;
+
+			case SpvOperand::LiteralString:
+				size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size)
+							, "%s%s"
+							, 0 == ii ? " " : ", "
+							, operand.literalString.c_str()
+							);
+				break;
+
+			case SpvOperand::MemoryModel:
+				size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size)
+							, "%sMemoryModel(%d)"
+							, 0 == ii ? " " : ", "
+							, operand.data[0]
+							);
+				break;
+
+			case SpvOperand::StorageClass:
+				size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size)
+							, "%s%s"
+							, 0 == ii ? " " : ", "
+							, getName(SpvStorageClass::Enum(operand.data[0]) )
+							);
+				break;
+
+			case SpvOperand::Count:
+				size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size)
+							, "%s__%d__"
+							, 0 == ii ? " " : ", "
+							, operand.data[0]
+							);
+				break;
+
+			default:
+				size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size)
+							, "%s%%%d"
+							, 0 == ii ? " " : ", "
+							, operand.data[0]
+							);
+				break;
+
+			}
+		}
+
 		return size;
 	}
 
-	int32_t read(bx::ReaderSeekerI* _reader, SpirvShader& _shader)
+	int32_t read(bx::ReaderSeekerI* _reader, SpvShader& _shader, bx::Error* _err)
 	{
 		int32_t size = 0;
 
-		uint32_t len = uint32_t(bx::getSize(_reader) - bx::seek(_reader) );
-		_shader.byteCode.resize(len);
-		size += bx::read(_reader, _shader.byteCode.data(), len);
+		uint32_t numBytes = uint32_t(bx::getSize(_reader) - bx::seek(_reader) );
+		_shader.byteCode.resize(numBytes);
+		size += bx::read(_reader, _shader.byteCode.data(), numBytes, _err);
 
 		return size;
 	}
 
-	int32_t write(bx::WriterI* _writer, const SpirvShader& _shader)
+	int32_t write(bx::WriterI* _writer, const SpvShader& _shader, bx::Error* _err)
 	{
 		int32_t size = 0;
-		BX_UNUSED(_writer, _shader);
+		BX_UNUSED(_writer, _shader, _err);
 		return size;
 	}
 
 #define SPIRV_MAGIC 0x07230203
 
-	int32_t read(bx::ReaderSeekerI* _reader, Spirv& _spirv)
+	int32_t read(bx::ReaderSeekerI* _reader, SpirV& _spirv, bx::Error* _err)
 	{
+		BX_ERROR_SCOPE(_err);
+
 		int32_t size = 0;
 
-		size += bx::read(_reader, _spirv.header);
+		size += bx::read(_reader, _spirv.header, _err);
 
-		if (size != sizeof(Spirv::Header)
+		if (!_err->isOk()
+		||  size != sizeof(SpirV::Header)
 		||  _spirv.header.magic != SPIRV_MAGIC
 		   )
 		{
-			// error
-			return -size;
+			BX_ERROR_SET(_err, BGFX_SHADER_SPIRV_INVALID_HEADER, "SPIR-V: Invalid header.");
+			return size;
 		}
 
-		size += read(_reader, _spirv.shader);
+		size += read(_reader, _spirv.shader, _err);
 
 		return size;
 	}
 
-	int32_t write(bx::WriterSeekerI* _writer, const Spirv& _spirv)
+	int32_t write(bx::WriterSeekerI* _writer, const SpirV& _spirv, bx::Error* _err)
 	{
 		int32_t size = 0;
-		BX_UNUSED(_writer, _spirv);
+		BX_UNUSED(_writer, _spirv, _err);
 		return size;
 	}
 
-	void parse(const SpirvShader& _src, SpirvParseFn _fn, void* _userData)
+	void parse(const SpvShader& _src, SpirvParseFn _fn, void* _userData, bx::Error* _err)
 	{
-		bx::MemoryReader reader(_src.byteCode.data(), uint32_t(_src.byteCode.size() ) );
+		BX_ERROR_SCOPE(_err);
+
+		uint32_t numBytes = uint32_t(_src.byteCode.size() );
+		bx::MemoryReader reader(_src.byteCode.data(), numBytes);
 
 		for (uint32_t token = 0, numTokens = uint32_t(_src.byteCode.size() / sizeof(uint32_t) ); token < numTokens;)
 		{
-			SpirvInstruction instruction;
-			uint32_t size = read(&reader, instruction);
+			SpvInstruction instruction;
+			uint32_t size = read(&reader, instruction, _err);
+
+			if (!_err->isOk() )
+			{
+				return;
+			}
+
 			BX_CHECK(size/4 == instruction.length, "read %d, expected %d, %s"
 					, size/4
 					, instruction.length

+ 122 - 38
src/shader_spirv.h

@@ -8,11 +8,14 @@
 
 #include <bx/readerwriter.h>
 
+BX_ERROR_RESULT(BGFX_SHADER_SPIRV_INVALID_HEADER,      BX_MAKEFOURCC('S', 'H', 0, 1) );
+BX_ERROR_RESULT(BGFX_SHADER_SPIRV_INVALID_INSTRUCTION, BX_MAKEFOURCC('S', 'H', 0, 2) );
+
 namespace bgfx
 {
 	// Reference: https://www.khronos.org/registry/spir-v/specs/1.0/SPIRV.html
 
-	struct SpirvOpcode
+	struct SpvOpcode
 	{
 		enum Enum
 		{
@@ -25,13 +28,16 @@ namespace bgfx
 			MemberName,
 			String,
 			Line,
+			Invalid9,
 			Extension,
 			ExtInstImport,
 			ExtInst,
+			Invalid13,
 			MemoryModel,
 			EntryPoint,
 			ExecutionMode,
 			Capability,
+			Invalid18,
 			TypeVoid,
 			TypeBool,
 			TypeInt,
@@ -53,21 +59,25 @@ namespace bgfx
 			TypeQueue,
 			TypePipe,
 			TypeForwardPointer,
+			Invalid40,
 			ConstantTrue,
 			ConstantFalse,
 			Constant,
 			ConstantComposite,
 			ConstantSampler,
 			ConstantNull,
+			Invalid47,
 			SpecConstantTrue,
 			SpecConstantFalse,
 			SpecConstant,
 			SpecConstantComposite,
 			SpecConstantOp,
+			Invalid53,
 			Function,
 			FunctionParameter,
 			FunctionEnd,
 			FunctionCall,
+			Invalid58,
 			Variable,
 			ImageTexelPointer,
 			Load,
@@ -85,6 +95,7 @@ namespace bgfx
 			DecorationGroup,
 			GroupDecorate,
 			GroupMemberDecorate,
+			Invalid76,
 			VectorExtractDynamic,
 			VectorInsertDynamic,
 			VectorShuffle,
@@ -93,6 +104,7 @@ namespace bgfx
 			CompositeInsert,
 			CopyObject,
 			Transpose,
+			Invalid85,
 			SampledImage,
 			ImageSampleImplicitLod,
 			ImageSampleExplicitLod,
@@ -115,6 +127,7 @@ namespace bgfx
 			ImageQueryLod,
 			ImageQueryLevels,
 			ImageQuerySamples,
+			Invalid108,
 			ConvertFToU,
 			ConvertFToS,
 			ConvertSToF,
@@ -131,6 +144,7 @@ namespace bgfx
 			GenericCastToPtr,
 			GenericCastToPtrExplicit,
 			Bitcast,
+			Invalid125,
 			SNegate,
 			FNegate,
 			IAdd,
@@ -158,6 +172,7 @@ namespace bgfx
 			ISubBorrow,
 			UMulExtended,
 			SMulExtended,
+			Invalid153,
 			Any,
 			All,
 			IsNan,
@@ -196,6 +211,8 @@ namespace bgfx
 			FUnordLessThanEqual,
 			FOrdGreaterThanEqual,
 			FUnordGreaterThanEqual,
+			Invalid192,
+			Invalid193,
 			ShiftRightLogical,
 			ShiftRightArithmetic,
 			ShiftLeftLogical,
@@ -208,6 +225,7 @@ namespace bgfx
 			BitFieldUExtract,
 			BitReverse,
 			BitCount,
+			Invalid206,
 			DPdx,
 			DPdy,
 			Fwidth,
@@ -217,12 +235,17 @@ namespace bgfx
 			DPdxCoarse,
 			DPdyCoarse,
 			FwidthCoarse,
+			Invalid216,
+			Invalid217,
 			EmitVertex,
 			EndPrimitive,
 			EmitStreamVertex,
 			EndStreamPrimitive,
+			Invalid222,
+			Invalid223,
 			ControlBarrier,
 			MemoryBarrier,
+			Invalid226,
 			AtomicLoad,
 			AtomicStore,
 			AtomicExchange,
@@ -239,6 +262,8 @@ namespace bgfx
 			AtomicAnd,
 			AtomicOr,
 			AtomicXor,
+			Invalid243,
+			Invalid244,
 			Phi,
 			LoopMerge,
 			SelectionMerge,
@@ -252,6 +277,7 @@ namespace bgfx
 			Unreachable,
 			LifetimeStart,
 			LifetimeStop,
+			Invalid258,
 			GroupAsyncCopy,
 			GroupWaitEvents,
 			GroupAll,
@@ -265,6 +291,8 @@ namespace bgfx
 			GroupFMax,
 			GroupUMax,
 			GroupSMax,
+			Invalid272,
+			Invalid273,
 			ReadPipe,
 			WritePipe,
 			ReservedReadPipe,
@@ -280,6 +308,8 @@ namespace bgfx
 			GroupReserveWritePipePackets,
 			GroupCommitReadPipe,
 			GroupCommitWritePipe,
+			Invalid289,
+			Invalid290,
 			EnqueueMarker,
 			EnqueueKernel,
 			GetKernelNDrangeSubGroupCount,
@@ -360,10 +390,12 @@ namespace bgfx
 			SubgroupLocalInvocationId,
 			VertexIndex,
 			InstanceIndex,
+
+			Count
 		};
 	};
 
-	struct SpirvExecutionModel
+	struct SpvExecutionModel
 	{
 		enum Enum
 		{
@@ -379,7 +411,19 @@ namespace bgfx
 		};
 	};
 
-	struct SpirvMemoryModel
+	struct SpvAddressingModel
+	{
+		enum Enum
+		{
+			Logical,
+			Physical32,
+			Physical64,
+
+			Count
+		};
+	};
+
+	struct SpvMemoryModel
 	{
 		enum Enum
 		{
@@ -391,7 +435,7 @@ namespace bgfx
 		};
 	};
 
-	struct SpirvStorageClass
+	struct SpvStorageClass
 	{
 		enum Enum
 		{
@@ -407,10 +451,12 @@ namespace bgfx
 			PushConstant,
 			AtomicCounter,
 			Image,
+
+			Count
 		};
 	};
 
-	struct SpirvResourceDim
+	struct SpvResourceDim
 	{
 		enum Enum
 		{
@@ -424,7 +470,7 @@ namespace bgfx
 		};
 	};
 
-	struct SpirvDecoration
+	struct SpvDecoration
 	{
 		enum Enum
 		{
@@ -476,52 +522,90 @@ namespace bgfx
 		};
 	};
 
-	struct SpirvOperand
+	struct SpvOperand
 	{
+		enum Enum
+		{
+			AccessQualifier,
+			AddressingModel,
+			Base,
+			Capability,
+			Component,
+			ComponentType,
+			Composite,
+			Condition,
+			Coordinate,
+			Decoration,
+			Dim,
+			Dref,
+			ExecutionModel,
+			Function,
+			FunctionControl,
+			Id,
+			IdRep,
+			ImageFormat,
+			ImageOperands,
+			LiteralNumber,
+			LiteralRep,
+			LiteralString,
+			Matrix,
+			MemoryAccess,
+			MemoryModel,
+			Object,
+			Pointer,
+			SampledType,
+			SampledImage,
+			SamplerAddressingMode,
+			SamplerFilterMode,
+			Scalar,
+			SourceLanguage,
+			StorageClass,
+			StructureType,
+			Vector,
+
+			Count
+		};
+
+		Enum type;
+		uint32_t data[4];
+
+		uint32_t target;
+		stl::string literalString;
 	};
 
-	struct SpirvInstruction
+	struct SpvInstruction
 	{
-		SpirvOpcode::Enum opcode;
+		SpvOpcode::Enum opcode;
 		uint16_t length;
+		uint16_t numOperands;
 
-		uint8_t numOperands;
-		SpirvOperand operand[6];
-
-		union
-		{
-			struct ResultTypeId
-			{
-				uint32_t resultType;
-				uint32_t id;
-			};
-
-			ResultTypeId constant;
-			ResultTypeId constantComposite;
+		uint32_t type;
+		uint32_t result;
+		bool hasType;
+		bool hasResult;
 
-			uint32_t value[8];
-		} un;
+		SpvOperand operand[8];
 	};
 
-	int32_t read(bx::ReaderI* _reader, SpirvInstruction& _instruction);
-	int32_t write(bx::WriterI* _writer, const SpirvInstruction& _instruction);
-	int32_t toString(char* _out, int32_t _size, const SpirvInstruction& _instruction);
+	int32_t read(bx::ReaderI* _reader, SpvInstruction& _instruction, bx::Error* _err);
+	int32_t write(bx::WriterI* _writer, const SpvInstruction& _instruction, bx::Error* _err);
+	int32_t toString(char* _out, int32_t _size, const SpvInstruction& _instruction);
 
-	struct SpirvShader
+	struct SpvShader
 	{
 		stl::vector<uint8_t> byteCode;
 	};
 
-	int32_t read(bx::ReaderSeekerI* _reader, SpirvShader& _shader);
-	int32_t write(bx::WriterI* _writer, const SpirvShader& _shader);
+	int32_t read(bx::ReaderSeekerI* _reader, SpvShader& _shader, bx::Error* _err);
+	int32_t write(bx::WriterI* _writer, const SpvShader& _shader, bx::Error* _err);
 
-	typedef bool (*SpirvParseFn)(uint32_t _offset, const SpirvInstruction& _instruction, void* _userData);
-	void parse(const SpirvShader& _src, SpirvParseFn _fn, void* _userData);
+	typedef bool (*SpirvParseFn)(uint32_t _offset, const SpvInstruction& _instruction, void* _userData);
+	void parse(const SpvShader& _src, SpirvParseFn _fn, void* _userData, bx::Error* _err = NULL);
 
-	typedef void (*SpirvFilterFn)(SpirvInstruction& _instruction, void* _userData);
-	void filter(SpirvShader& _dst, const SpirvShader& _src, SpirvFilterFn _fn, void* _userData);
+	typedef void (*SpirvFilterFn)(SpvInstruction& _instruction, void* _userData);
+	void filter(SpvShader& _dst, const SpvShader& _src, SpirvFilterFn _fn, void* _userData, bx::Error* _err = NULL);
 
-	struct Spirv
+	struct SpirV
 	{
 		struct Header
 		{
@@ -533,11 +617,11 @@ namespace bgfx
 		};
 
 		Header header;
-		SpirvShader shader;
+		SpvShader shader;
 	};
 
-	int32_t read(bx::ReaderSeekerI* _reader, Spirv& _spirv);
-	int32_t write(bx::WriterSeekerI* _writer, const Spirv& _spirv);
+	int32_t read(bx::ReaderSeekerI* _reader, SpirV& _spirv, bx::Error* _err);
+	int32_t write(bx::WriterSeekerI* _writer, const SpirV& _spirv, bx::Error* _err);
 
 } // namespace bgfx