1 /*
2  * Copyright 2011-2019 Branimir Karadzic. All rights reserved.
3  * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
4  */
5 
6 #include "bgfx_p.h"
7 #include "shader_dx9bc.h"
8 
9 BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wunused-parameter");
10 BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG("-Wunneeded-internal-declaration");
11 
12 namespace bgfx
13 {
14 	struct Dx9bcOpcodeInfo
15 	{
16 		uint8_t numOperands;
17 		uint8_t numValues;
18 	};
19 
20 	static const Dx9bcOpcodeInfo s_dx9bcOpcodeInfo[] =
21 	{
22 		{ 0, 0 }, // NOP
23 		{ 2, 0 }, // MOV
24 		{ 3, 0 }, // ADD
25 		{ 1, 0 }, // SUB
26 		{ 4, 0 }, // MAD
27 		{ 3, 0 }, // MUL
28 		{ 2, 0 }, // RCP
29 		{ 2, 0 }, // RSQ
30 		{ 3, 0 }, // DP3
31 		{ 3, 0 }, // DP4
32 		{ 3, 0 }, // MIN
33 		{ 3, 0 }, // MAX
34 		{ 3, 0 }, // SLT
35 		{ 3, 0 }, // SGE
36 		{ 2, 0 }, // EXP
37 		{ 2, 0 }, // LOG
38 		{ 1, 0 }, // LIT
39 		{ 1, 0 }, // DST
40 		{ 4, 0 }, // LRP
41 		{ 2, 0 }, // FRC
42 		{ 1, 0 }, // M4X4
43 		{ 1, 0 }, // M4X3
44 		{ 1, 0 }, // M3X4
45 		{ 1, 0 }, // M3X3
46 		{ 1, 0 }, // M3X2
47 		{ 0, 0 }, // CALL
48 		{ 0, 0 }, // CALLNZ
49 		{ 0, 0 }, // LOOP
50 		{ 0, 0 }, // RET
51 		{ 0, 0 }, // ENDLOOP
52 		{ 0, 0 }, // LABEL
53 		{ 1, 1 }, // DCL
54 		{ 3, 0 }, // POW
55 		{ 1, 0 }, // CRS
56 		{ 1, 0 }, // SGN
57 		{ 1, 0 }, // ABS
58 		{ 2, 0 }, // NRM
59 		{ 4, 0 }, // SINCOS
60 		{ 1, 0 }, // REP
61 		{ 0, 0 }, // ENDREP
62 		{ 1, 0 }, // IF
63 		{ 2, 0 }, // IFC
64 		{ 0, 0 }, // ELSE
65 		{ 0, 0 }, // ENDIF
66 		{ 0, 0 }, // BREAK
67 		{ 2, 0 }, // BREAKC
68 		{ 2, 0 }, // MOVA
69 		{ 1, 4 }, // DEFB
70 		{ 1, 4 }, // DEFI
71 		{ 0, 0 }, // 0
72 		{ 0, 0 }, // 1
73 		{ 0, 0 }, // 2
74 		{ 0, 0 }, // 3
75 		{ 0, 0 }, // 4
76 		{ 0, 0 }, // 5
77 		{ 0, 0 }, // 6
78 		{ 0, 0 }, // 7
79 		{ 0, 0 }, // 8
80 		{ 0, 0 }, // 9
81 		{ 0, 0 }, // 10
82 		{ 0, 0 }, // 11
83 		{ 0, 0 }, // 12
84 		{ 0, 0 }, // 13
85 		{ 0, 0 }, // 14
86 		{ 1, 0 }, // TEXCOORD
87 		{ 1, 0 }, // TEXKILL
88 		{ 3, 0 }, // TEX
89 		{ 1, 0 }, // TEXBEM
90 		{ 1, 0 }, // TEXBEM1
91 		{ 1, 0 }, // TEXREG2AR
92 		{ 1, 0 }, // TEXREG2GB
93 		{ 1, 0 }, // TEXM3X2PAD
94 		{ 1, 0 }, // TEXM3X2TEX
95 		{ 1, 0 }, // TEXM3X3PAD
96 		{ 1, 0 }, // TEXM3X3TEX
97 		{ 1, 0 }, // TEXM3X3DIFF
98 		{ 1, 0 }, // TEXM3X3SPEC
99 		{ 1, 0 }, // TEXM3X3VSPEC
100 		{ 2, 0 }, // EXPP
101 		{ 2, 0 }, // LOGP
102 		{ 4, 0 }, // CND
103 		{ 1, 4 }, // DEF
104 		{ 1, 0 }, // TEXREG2RGB
105 		{ 1, 0 }, // TEXDP3TEX
106 		{ 1, 0 }, // TEXM3X2DEPTH
107 		{ 1, 0 }, // TEXDP3
108 		{ 1, 0 }, // TEXM3X3
109 		{ 1, 0 }, // TEXDEPTH
110 		{ 4, 0 }, // CMP
111 		{ 1, 0 }, // BEM
112 		{ 4, 0 }, // DP2ADD
113 		{ 2, 0 }, // DSX
114 		{ 2, 0 }, // DSY
115 		{ 5, 0 }, // TEXLDD
116 		{ 1, 0 }, // SETP
117 		{ 3, 0 }, // TEXLDL
118 		{ 0, 0 }, // BREAKP
119 	};
120 	BX_STATIC_ASSERT(BX_COUNTOF(s_dx9bcOpcodeInfo) == Dx9bcOpcode::Count);
121 
122 	static const char* s_dx9bcOpcode[] =
123 	{
124 		"nop",
125 		"mov",
126 		"add",
127 		"sub",
128 		"mad",
129 		"mul",
130 		"rcp",
131 		"rsq",
132 		"dp3",
133 		"dp4",
134 		"min",
135 		"max",
136 		"slt",
137 		"sge",
138 		"exp",
139 		"log",
140 		"lit",
141 		"dst",
142 		"lrp",
143 		"frc",
144 		"m4x4",
145 		"m4x3",
146 		"m3x4",
147 		"m3x3",
148 		"m3x2",
149 		"call",
150 		"callnz",
151 		"loop",
152 		"ret",
153 		"endloop",
154 		"label",
155 		"dcl",
156 		"pow",
157 		"crs",
158 		"sgn",
159 		"abs",
160 		"nrm",
161 		"sincos",
162 		"rep",
163 		"endrep",
164 		"if",
165 		"ifc",
166 		"else",
167 		"endif",
168 		"break",
169 		"breakc",
170 		"mova",
171 		"defb",
172 		"defi",
173 
174 		NULL,
175 		NULL,
176 		NULL,
177 		NULL,
178 		NULL,
179 		NULL,
180 		NULL,
181 		NULL,
182 		NULL,
183 		NULL,
184 		NULL,
185 		NULL,
186 		NULL,
187 		NULL,
188 		NULL,
189 
190 		"texcoord",
191 		"texkill",
192 		"tex",
193 		"texbem",
194 		"texbem1",
195 		"texreg2ar",
196 		"texreg2gb",
197 		"texm3x2pad",
198 		"texm3x2tex",
199 		"texm3x3pad",
200 		"texm3x3tex",
201 		"texm3x3diff",
202 		"texm3x3spec",
203 		"texm3x3vspec",
204 		"expp",
205 		"logp",
206 		"cnd",
207 		"def",
208 		"texreg2rgb",
209 		"texdp3tex",
210 		"texm3x2depth",
211 		"texdp3",
212 		"texm3x3",
213 		"texdepth",
214 		"cmp",
215 		"bem",
216 		"dp2add",
217 		"dsx",
218 		"dsy",
219 		"texldd",
220 		"setp",
221 		"texldl",
222 		"breakp",
223 	};
224 	BX_STATIC_ASSERT(BX_COUNTOF(s_dx9bcOpcode) == Dx9bcOpcode::Count);
225 
getName(Dx9bcOpcode::Enum _opcode)226 	const char* getName(Dx9bcOpcode::Enum _opcode)
227 	{
228 		BX_CHECK(_opcode < Dx9bcOpcode::Count, "Unknown opcode id %d (%x).", _opcode, _opcode);
229 		return s_dx9bcOpcode[_opcode];
230 	}
231 
232 	static const char* s_dx9bcOperandType[] =
233 	{
234 		"r",           // Temporary Register File
235 		"v",           // Input Register File
236 		"c",           // Constant Register File
237 		"t",           // Texture Register File (PS)
238 		"oPos",        // Rasterizer Register File
239 		"oD",          // Attribute Output Register File
240 		"oT",          // Texture Coordinate Output Register File
241 		"output",      // Output register file for VS3.0+
242 		"i",           // Constant Integer Vector Register File
243 		"oColor",      // Color Output Register File
244 		"oDepth",      // Depth Output Register File
245 		"s",           // Sampler State Register File
246 		"c",           // Constant Register File  2048 - 4095
247 		"c",           // Constant Register File  4096 - 6143
248 		"c",           // Constant Register File  6144 - 8191
249 		"b",           // Constant Boolean register file
250 		"aL",          // Loop counter register file
251 		"tempfloat16", // 16-bit float temp register file
252 		"misctype",    // Miscellaneous (single) registers.
253 		"label",       // Label
254 		"p",           // Predicate register
255 	};
256 	BX_STATIC_ASSERT(BX_COUNTOF(s_dx9bcOperandType) == Dx9bcOperandType::Count);
257 
258 	static const char* s_dx9bcDeclUsage[] =
259 	{
260 		"position",
261 		"blendweight",
262 		"blendindices",
263 		"normal",
264 		"psize",
265 		"texcoord",
266 		"tangent",
267 		"binormal",
268 		"tessfactor",
269 		"positiont",
270 		"color",
271 		"fog",
272 		"depth",
273 		"sample",
274 	};
275 	BX_STATIC_ASSERT(BX_COUNTOF(s_dx9bcDeclUsage) == Dx9bcDeclUsage::Count);
276 
read(bx::ReaderI * _reader,Dx9bcSubOperand & _subOperand,bx::Error * _err)277 	int32_t read(bx::ReaderI* _reader, Dx9bcSubOperand& _subOperand, bx::Error* _err)
278 	{
279 		int32_t size = 0;
280 
281 		uint32_t token;
282 		size += bx::read(_reader, token, _err);
283 
284 		_subOperand.type        =   Dx9bcOperandType::Enum( ( (token & UINT32_C(0x70000000) ) >> 28)
285 		                                                  | ( (token & UINT32_C(0x00001800) ) >>  8) );
286 		_subOperand.regIndex    =                             (token & UINT32_C(0x000007ff) );
287 		_subOperand.swizzleBits =                    uint8_t( (token & UINT32_C(0x00ff0000) ) >> 16);
288 
289 		return size;
290 	}
291 
write(bx::WriterI * _writer,const Dx9bcSubOperand & _subOperand,bx::Error * _err)292 	int32_t write(bx::WriterI* _writer, const Dx9bcSubOperand& _subOperand, bx::Error* _err)
293 	{
294 		int32_t size = 0;
295 
296 		uint32_t token = 0;
297 		token |= (_subOperand.type        << 28) & UINT32_C(0x70000000);
298 		token |= (_subOperand.type        <<  8) & UINT32_C(0x00001800);
299 		token |=  _subOperand.regIndex           & UINT32_C(0x000007ff);
300 		token |= (_subOperand.swizzleBits << 16) & UINT32_C(0x00ff0000);
301 		size += bx::write(_writer, token, _err);
302 
303 		return size;
304 	}
305 
read(bx::ReaderI * _reader,Dx9bcOperand & _operand,bx::Error * _err)306 	int32_t read(bx::ReaderI* _reader, Dx9bcOperand& _operand, bx::Error* _err)
307 	{
308 		int32_t size = 0;
309 
310 		uint32_t token;
311 		size += bx::read(_reader, token, _err);
312 
313 		_operand.type     =   Dx9bcOperandType::Enum( ( (token & UINT32_C(0x70000000) ) >> 28)
314 													| ( (token & UINT32_C(0x00001800) ) >>  8) );
315 		_operand.regIndex =                             (token & UINT32_C(0x000007ff) );
316 		_operand.addrMode = Dx9bcOperandAddrMode::Enum( (token & UINT32_C(0x00002000) ) >> 13);
317 
318 		if (_operand.destination)
319 		{
320 			// Destination Parameter Token
321 			// https://msdn.microsoft.com/en-us/library/ff552738.aspx
322 
323 			_operand.writeMask        = uint8_t( (token & UINT32_C(0x000f0000) ) >> 16);
324 			_operand.saturate         =     0 != (token & UINT32_C(0x00100000) );
325 			_operand.partialPrecision =     0 != (token & UINT32_C(0x00200000) );
326 			_operand.centroid         =     0 != (token & UINT32_C(0x00400000) );
327 		}
328 		else
329 		{
330 			// Source Parameter Token
331 			// https://msdn.microsoft.com/en-us/library/ff569716%28v=vs.85%29.aspx
332 
333 			_operand.writeMask        = 0;
334 			_operand.saturate         = false;
335 			_operand.partialPrecision = false;
336 			_operand.centroid         = false;
337 			_operand.swizzleBits      = uint8_t( (token & UINT32_C(0x00ff0000) ) >> 16);
338 		}
339 
340 		if (Dx9bcOperandAddrMode::Relative == _operand.addrMode)
341 		{
342 			size += read(_reader, _operand.subOperand, _err);
343 		}
344 
345 		return size;
346 	}
347 
write(bx::WriterI * _writer,const Dx9bcOperand & _operand,bx::Error * _err)348 	int32_t write(bx::WriterI* _writer, const Dx9bcOperand& _operand, bx::Error* _err)
349 	{
350 		int32_t size = 0;
351 
352 		uint32_t token = 0;
353 		token |= (_operand.type     << 28) & UINT32_C(0x70000000);
354 		token |= (_operand.type     <<  8) & UINT32_C(0x00001800);
355 		token |=  _operand.regIndex        & UINT32_C(0x000007ff);
356 		token |= (_operand.addrMode << 13) & UINT32_C(0x00002000);
357 		size += bx::write(_writer, token, _err);
358 
359 		if (Dx9bcOperandAddrMode::Relative == _operand.addrMode)
360 		{
361 			size += write(_writer, _operand.subOperand, _err);
362 		}
363 
364 		return size;
365 	}
366 
read(bx::ReaderI * _reader,Dx9bcInstruction & _instruction,bx::Error * _err)367 	int32_t read(bx::ReaderI* _reader, Dx9bcInstruction& _instruction, bx::Error* _err)
368 	{
369 		int32_t size = 0;
370 
371 		uint32_t token;
372 		size += bx::read(_reader, token, _err);
373 
374 		_instruction.opcode = Dx9bcOpcode::Enum( (token & UINT32_C(0x0000ffff) ) );
375 
376 		if (Dx9bcOpcode::Comment == _instruction.opcode)
377 		{
378 			_instruction.specific   = 0;
379 			_instruction.length     = uint16_t( (token & UINT32_C(0x7fff0000) ) >> 16) + 1;
380 			_instruction.predicated = false;
381 			_instruction.coissue    = false;
382 		}
383 		else
384 		{
385 			_instruction.specific   = uint8_t( (token & UINT32_C(0x00ff0000) ) >> 16);
386 			_instruction.length     = uint8_t( (token & UINT32_C(0x0f000000) ) >> 24) + 1;
387 			_instruction.predicated =     0 != (token & UINT32_C(0x10000000) );
388 			_instruction.coissue    =     0 != (token & UINT32_C(0x40000000) );
389 		}
390 
391 		if (Dx9bcOpcode::Count <= _instruction.opcode)
392 		{
393 			if (Dx9bcOpcode::Comment == _instruction.opcode)
394 			{
395 				for (int32_t ii = 0, num = _instruction.length-1; ii < num; ++ii)
396 				{
397 					uint32_t tmp;
398 					size += bx::read(_reader, tmp, _err);
399 				}
400 			}
401 
402 			return size;
403 		}
404 
405 		uint32_t currOp = 0;
406 
407 		const Dx9bcOpcodeInfo& info = s_dx9bcOpcodeInfo[bx::uint32_min(_instruction.opcode, Dx9bcOpcode::Count)];
408 		_instruction.numOperands = info.numOperands;
409 		_instruction.numValues   = info.numValues;
410 
411 		switch (_instruction.opcode)
412 		{
413 		case Dx9bcOpcode::SINCOS:
414 			if (5 > _instruction.length)
415 			{
416 				_instruction.numOperands = 2;
417 			}
418 			break;
419 
420 		default:
421 			break;
422 		};
423 
424 //BX_TRACE("%d (%d), %d, %d, 0x%08x"
425 //		, _instruction.opcode
426 //		, bx::uint32_min(_instruction.opcode, Dx9bcOpcode::Count)
427 //		, _instruction.length
428 //		, _instruction.numOperands
429 //		, token
430 //		);
431 
432 		const bool valuesBeforeOpcode = false
433 				|| Dx9bcOpcode::DCL == _instruction.opcode
434 				;
435 
436 		if (valuesBeforeOpcode
437 		&&  0 < info.numValues)
438 		{
439 			size += read(_reader, _instruction.value, info.numValues*sizeof(uint32_t), _err);
440 		}
441 
442 		_instruction.operand[0].destination = true;
443 
444 		switch (_instruction.numOperands)
445 		{
446 		case 6: size += read(_reader, _instruction.operand[currOp++], _err); BX_FALLTHROUGH;
447 		case 5: size += read(_reader, _instruction.operand[currOp++], _err); BX_FALLTHROUGH;
448 		case 4: size += read(_reader, _instruction.operand[currOp++], _err); BX_FALLTHROUGH;
449 		case 3: size += read(_reader, _instruction.operand[currOp++], _err); BX_FALLTHROUGH;
450 		case 2: size += read(_reader, _instruction.operand[currOp++], _err); BX_FALLTHROUGH;
451 		case 1: size += read(_reader, _instruction.operand[currOp++], _err); BX_FALLTHROUGH;
452 		case 0:
453 			if (!valuesBeforeOpcode
454 			&&  0 < info.numValues)
455 			{
456 				size += read(_reader, _instruction.value, info.numValues*sizeof(uint32_t), _err);
457 			}
458 			break;
459 
460 		default:
461 			BX_CHECK(false, "Instruction %s with invalid number of operands %d (numValues %d)."
462 					, getName(_instruction.opcode)
463 					, _instruction.numOperands
464 					, info.numValues
465 					);
466 			break;
467 		}
468 
469 		return size;
470 	}
471 
write(bx::WriterI * _writer,const Dx9bcInstruction & _instruction,bx::Error * _err)472 	int32_t write(bx::WriterI* _writer, const Dx9bcInstruction& _instruction, bx::Error* _err)
473 	{
474 		int32_t size = 0;
475 
476 		uint32_t token = 0;
477 		token |=    _instruction.opcode             & UINT32_C(0x0000ffff);
478 		token |=   (_instruction.specific    << 16) & UINT32_C(0x00ff0000);
479 		token |= ( (_instruction.length - 1) << 24) & UINT32_C(0x0f000000);
480 		size += bx::write(_writer, token, _err);
481 
482 		uint32_t currOp = 0;
483 		switch (_instruction.numOperands)
484 		{
485 		case 6: size += write(_writer, _instruction.operand[currOp++], _err); BX_FALLTHROUGH;
486 		case 5: size += write(_writer, _instruction.operand[currOp++], _err); BX_FALLTHROUGH;
487 		case 4: size += write(_writer, _instruction.operand[currOp++], _err); BX_FALLTHROUGH;
488 		case 3: size += write(_writer, _instruction.operand[currOp++], _err); BX_FALLTHROUGH;
489 		case 2: size += write(_writer, _instruction.operand[currOp++], _err); BX_FALLTHROUGH;
490 		case 1: size += write(_writer, _instruction.operand[currOp++], _err); BX_FALLTHROUGH;
491 		case 0:
492 			break;
493 		}
494 
495 		return 0;
496 	}
497 
toString(char * _out,int32_t _size,const Dx9bcInstruction & _instruction)498 	int32_t toString(char* _out, int32_t _size, const Dx9bcInstruction& _instruction)
499 	{
500 		int32_t size = 0;
501 
502 		if (Dx9bcOpcode::Comment == _instruction.opcode
503 		||  Dx9bcOpcode::Phase   == _instruction.opcode)
504 		{
505 			size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size)
506 						, "// %x"
507 						, _instruction.opcode
508 						);
509 			return size;
510 		}
511 
512 		size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size)
513 							, "%2d %s"
514 							, _instruction.opcode
515 							, getName(_instruction.opcode)
516 							);
517 
518 		switch (_instruction.opcode)
519 		{
520 		case Dx9bcOpcode::DCL:
521 			size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size)
522 					, "_%s%d (%d, %d, %d, %d)"
523 					, s_dx9bcDeclUsage[_instruction.value[0] & UINT32_C(0x0000000f)]
524 					, (_instruction.value[0] & UINT32_C(0x000f0000) )>>16
525 					, (_instruction.value[0] & UINT32_C(0x08000000) )>>27 // ?
526 					, (_instruction.value[0] & UINT32_C(0x10000000) )>>28 // texture2d
527 					, (_instruction.value[0] & UINT32_C(0x20000000) )>>29 // textureCube
528 					, (_instruction.value[0] & UINT32_C(0x40000000) )>>30 // texture3d
529 					);
530 			break;
531 
532 		default:
533 			break;
534 		}
535 
536 		for (uint32_t ii = 0; ii < _instruction.numOperands; ++ii)
537 		{
538 			const Dx9bcOperand& operand = _instruction.operand[ii];
539 			size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size)
540 								, "%s%s%d"
541 								, 0 == ii ? " " : ", "
542 								, s_dx9bcOperandType[operand.type]
543 								, operand.regIndex
544 								);
545 
546 			if (operand.destination)
547 			{
548 				if (0xf > operand.writeMask
549 				&&  0   < operand.writeMask)
550 				{
551 					size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size)
552 										, ".%s%s%s%s"
553 										, 0 == (operand.writeMask & 1) ? "" : "x"
554 										, 0 == (operand.writeMask & 2) ? "" : "y"
555 										, 0 == (operand.writeMask & 4) ? "" : "z"
556 										, 0 == (operand.writeMask & 8) ? "" : "w"
557 										);
558 				}
559 			}
560 			else
561 			{
562 				if (Dx9bcOperandAddrMode::Relative == operand.addrMode)
563 				{
564 					const bool array = true;
565 
566 					size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size)
567 										, "["
568 										);
569 
570 					size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size)
571 										, "%s%d"
572 										, s_dx9bcOperandType[operand.subOperand.type]
573 										, operand.subOperand.regIndex
574 										);
575 
576 					size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size)
577 										, "%s"
578 										, array ? "]" : ""
579 										);
580 				}
581 
582 				if (0xe4 != operand.swizzleBits)
583 				{
584 					size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size)
585 										, ".%c%c%c%c"
586 										, "xyzw"[(operand.swizzleBits   )&0x3]
587 										, "xyzw"[(operand.swizzleBits>>2)&0x3]
588 										, "xyzw"[(operand.swizzleBits>>4)&0x3]
589 										, "xyzw"[(operand.swizzleBits>>6)&0x3]
590 										);
591 				}
592 			}
593 		}
594 
595 		switch (_instruction.opcode)
596 		{
597 		case Dx9bcOpcode::DEF:
598 			for (uint32_t jj = 0; jj < _instruction.numValues; ++jj)
599 			{
600 				union { int32_t i; float f; } cast = { _instruction.value[jj] };
601 				size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size)
602 						, "%s%f%s"
603 						, 0 == jj ? " (" : ", "
604 						, cast.f
605 						, uint32_t(_instruction.numValues-1) == jj ? ")" : ""
606 						);
607 			}
608 			break;
609 
610 		case Dx9bcOpcode::DEFI:
611 			for (uint32_t jj = 0; jj < _instruction.numValues; ++jj)
612 			{
613 				size += bx::snprintf(&_out[size], bx::uint32_imax(0, _size-size)
614 						, "%s%d%s"
615 						, 0 == jj ? " (" : ", "
616 						, _instruction.value[jj]
617 						, uint32_t(_instruction.numValues-1) == jj ? ")" : ""
618 						);
619 			}
620 			break;
621 
622 		default:
623 			break;
624 		}
625 
626 		return size;
627 	}
628 
read(bx::ReaderSeekerI * _reader,Dx9bcShader & _shader,bx::Error * _err)629 	int32_t read(bx::ReaderSeekerI* _reader, Dx9bcShader& _shader, bx::Error* _err)
630 	{
631 		int32_t size = 0;
632 		int64_t offset = bx::seek(_reader);
633 
634 		for (;;)
635 		{
636 			Dx9bcInstruction instruction;
637 			int32_t length = read(_reader, instruction, _err);
638 			size += length;
639 
640 			if (Dx9bcOpcode::Count > instruction.opcode)
641 			{
642 				char temp[512];
643 				toString(temp, 512, instruction);
644 
645 				BX_CHECK(length/4 == instruction.length
646 						, "%s\nread %d, expected %d"
647 						, temp
648 						, length/4
649 						, instruction.length
650 						);
651 			}
652 			else
653 			{
654 				if (Dx9bcOpcode::End == instruction.opcode)
655 				{
656 					size -= length;
657 					break;
658 				}
659 			}
660 		}
661 
662 		bx::seek(_reader, offset, bx::Whence::Begin);
663 
664 		_shader.byteCode.resize(size);
665 		bx::read(_reader, _shader.byteCode.data(), size, _err);
666 
667 		return size;
668 	}
669 
write(bx::WriterI * _writer,const Dx9bcShader & _shader,bx::Error * _err)670 	int32_t write(bx::WriterI* _writer, const Dx9bcShader& _shader, bx::Error* _err)
671 	{
672 		BX_UNUSED(_writer, _shader, _err);
673 		return 0;
674 	}
675 
read(bx::ReaderSeekerI * _reader,Dx9bc & _bc,bx::Error * _err)676 	int32_t read(bx::ReaderSeekerI* _reader, Dx9bc& _bc, bx::Error* _err)
677 	{
678 		int32_t size = 0;
679 
680 		size += bx::read(_reader, _bc.version, _err);
681 
682 		bool pixelShader = (0xffff0000 == (_bc.version & 0xffff0000) );
683 		uint32_t versionMajor = (_bc.version>>8)&0xff;
684 		uint32_t versionMinor = _bc.version&0xff;
685 		BX_UNUSED(pixelShader, versionMajor, versionMinor);
686 		BX_TRACE("%s shader %d.%d"
687 			, pixelShader ? "pixel" : "vertex"
688 			, versionMajor
689 			, versionMinor
690 			);
691 
692 		size += read(_reader, _bc.shader, _err);
693 
694 		return size;
695 	}
696 
write(bx::WriterSeekerI * _writer,const Dx9bc & _dxbc,bx::Error * _err)697 	int32_t write(bx::WriterSeekerI* _writer, const Dx9bc& _dxbc, bx::Error* _err)
698 	{
699 		BX_UNUSED(_writer, _dxbc, _err);
700 		return 0;
701 	}
702 
parse(const Dx9bcShader & _src,Dx9bcParseFn _fn,void * _userData,bx::Error * _err)703 	void parse(const Dx9bcShader& _src, Dx9bcParseFn _fn, void* _userData, bx::Error* _err)
704 	{
705 		BX_ERROR_SCOPE(_err);
706 
707 		bx::MemoryReader reader(_src.byteCode.data(), uint32_t(_src.byteCode.size() ) );
708 
709 		bx::Error err;
710 
711 		for (uint32_t token = 0, numTokens = uint32_t(_src.byteCode.size() / sizeof(uint32_t) ); token < numTokens;)
712 		{
713 			Dx9bcInstruction instruction;
714 			uint32_t size = read(&reader, instruction, _err);
715 			BX_CHECK(size/4 == instruction.length, "read %d, expected %d", size/4, instruction.length); BX_UNUSED(size);
716 
717 			bool cont = _fn(token * sizeof(uint32_t), instruction, _userData);
718 			if (!cont)
719 			{
720 				return;
721 			}
722 
723 			token += instruction.length;
724 		}
725 	}
726 
filter(Dx9bcShader & _dst,const Dx9bcShader & _src,Dx9bcFilterFn _fn,void * _userData,bx::Error * _err)727 	void filter(Dx9bcShader& _dst, const Dx9bcShader& _src, Dx9bcFilterFn _fn, void* _userData, bx::Error* _err)
728 	{
729 		BX_ERROR_SCOPE(_err);
730 
731 		bx::MemoryReader reader(_src.byteCode.data(), uint32_t(_src.byteCode.size() ) );
732 
733 		bx::MemoryBlock mb(g_allocator);
734 		bx::MemoryWriter writer(&mb);
735 
736 		for (uint32_t token = 0, numTokens = uint32_t(_src.byteCode.size() / sizeof(uint32_t) ); token < numTokens;)
737 		{
738 			Dx9bcInstruction instruction;
739 			uint32_t size = read(&reader, instruction, _err);
740 			BX_CHECK(size/4 == instruction.length, "read %d, expected %d", size/4, instruction.length); BX_UNUSED(size);
741 
742 			_fn(instruction, _userData);
743 
744 			write(&writer, instruction, _err);
745 
746 			token += instruction.length;
747 		}
748 
749 		uint8_t* data = (uint8_t*)mb.more();
750 		uint32_t size = uint32_t(bx::getSize(&writer) );
751 		_dst.byteCode.reserve(size);
752 		bx::memCopy(_dst.byteCode.data(), data, size);
753 	}
754 
755 } // namespace bgfx
756