blob: fcbc839356f68df0f4e35f4d5ed3587be2d51f42 [file] [log] [blame]
John Bauman89401822014-05-06 15:04:28 -04001// SwiftShader Software Renderer
2//
John Bauman19bac1e2014-05-06 15:23:49 -04003// Copyright(c) 2005-2012 TransGaming Inc.
John Bauman89401822014-05-06 15:04:28 -04004//
5// All rights reserved. No part of this software may be copied, distributed, transmitted,
6// transcribed, stored in a retrieval system, translated into any human or computer
7// language by any means, or disclosed to third parties without the explicit written
8// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
9// or implied, including but not limited to any patent rights, are granted to you.
10//
11
12#include "Shader.hpp"
13
John Bauman19bac1e2014-05-06 15:23:49 -040014#include "VertexShader.hpp"
15#include "PixelShader.hpp"
John Bauman89401822014-05-06 15:04:28 -040016#include "Math.hpp"
17#include "Debug.hpp"
18
John Bauman89401822014-05-06 15:04:28 -040019#include <fstream>
20#include <sstream>
21
22namespace sw
23{
John Bauman19bac1e2014-05-06 15:23:49 -040024 volatile int Shader::serialCounter = 1;
25
26 Shader::Opcode Shader::OPCODE_DP(int i)
John Bauman89401822014-05-06 15:04:28 -040027 {
John Bauman19bac1e2014-05-06 15:23:49 -040028 switch(i)
29 {
30 default: ASSERT(false);
31 case 1: return OPCODE_DP1;
32 case 2: return OPCODE_DP2;
33 case 3: return OPCODE_DP3;
34 case 4: return OPCODE_DP4;
35 }
John Bauman89401822014-05-06 15:04:28 -040036 }
37
John Bauman19bac1e2014-05-06 15:23:49 -040038 Shader::Opcode Shader::OPCODE_LEN(int i)
39 {
40 switch(i)
41 {
42 default: ASSERT(false);
43 case 1: return OPCODE_ABS;
44 case 2: return OPCODE_LEN2;
45 case 3: return OPCODE_LEN3;
46 case 4: return OPCODE_LEN4;
47 }
48 }
49
50 Shader::Opcode Shader::OPCODE_DIST(int i)
51 {
52 switch(i)
53 {
54 default: ASSERT(false);
55 case 1: return OPCODE_DIST1;
56 case 2: return OPCODE_DIST2;
57 case 3: return OPCODE_DIST3;
58 case 4: return OPCODE_DIST4;
59 }
60 }
61
62 Shader::Opcode Shader::OPCODE_NRM(int i)
63 {
64 switch(i)
65 {
66 default: ASSERT(false);
67 case 1: return OPCODE_SGN;
68 case 2: return OPCODE_NRM2;
69 case 3: return OPCODE_NRM3;
70 case 4: return OPCODE_NRM4;
71 }
72 }
73
74 Shader::Opcode Shader::OPCODE_FORWARD(int i)
75 {
76 switch(i)
77 {
78 default: ASSERT(false);
79 case 1: return OPCODE_FORWARD1;
80 case 2: return OPCODE_FORWARD2;
81 case 3: return OPCODE_FORWARD3;
82 case 4: return OPCODE_FORWARD4;
83 }
84 }
85
86 Shader::Opcode Shader::OPCODE_REFLECT(int i)
87 {
88 switch(i)
89 {
90 default: ASSERT(false);
91 case 1: return OPCODE_REFLECT1;
92 case 2: return OPCODE_REFLECT2;
93 case 3: return OPCODE_REFLECT3;
94 case 4: return OPCODE_REFLECT4;
95 }
96 }
97
98 Shader::Opcode Shader::OPCODE_REFRACT(int i)
99 {
100 switch(i)
101 {
102 default: ASSERT(false);
103 case 1: return OPCODE_REFRACT1;
104 case 2: return OPCODE_REFRACT2;
105 case 3: return OPCODE_REFRACT3;
106 case 4: return OPCODE_REFRACT4;
107 }
108 }
109
110 Shader::Instruction::Instruction(Opcode opcode) : opcode(opcode), analysis(0)
111 {
112 control = CONTROL_RESERVED0;
113
114 predicate = false;
115 predicateNot = false;
116 predicateSwizzle = 0xE4;
117
118 coissue = false;
119 samplerType = SAMPLER_UNKNOWN;
120 usage = USAGE_POSITION;
121 usageIndex = 0;
122 }
123
124 Shader::Instruction::Instruction(const unsigned long *token, int size, unsigned char majorVersion) : analysis(0)
John Bauman89401822014-05-06 15:04:28 -0400125 {
126 parseOperationToken(*token++, majorVersion);
127
John Bauman19bac1e2014-05-06 15:23:49 -0400128 samplerType = SAMPLER_UNKNOWN;
129 usage = USAGE_POSITION;
130 usageIndex = 0;
131
132 if(opcode == OPCODE_IF ||
133 opcode == OPCODE_IFC ||
134 opcode == OPCODE_LOOP ||
135 opcode == OPCODE_REP ||
136 opcode == OPCODE_BREAKC ||
137 opcode == OPCODE_BREAKP) // No destination operand
John Bauman89401822014-05-06 15:04:28 -0400138 {
139 if(size > 0) parseSourceToken(0, token++, majorVersion);
140 if(size > 1) parseSourceToken(1, token++, majorVersion);
141 if(size > 2) parseSourceToken(2, token++, majorVersion);
142 if(size > 3) ASSERT(false);
143 }
John Bauman19bac1e2014-05-06 15:23:49 -0400144 else if(opcode == OPCODE_DCL)
John Bauman89401822014-05-06 15:04:28 -0400145 {
146 parseDeclarationToken(*token++);
147 parseDestinationToken(token++, majorVersion);
148 }
149 else
150 {
151 if(size > 0)
152 {
153 parseDestinationToken(token, majorVersion);
154
John Bauman19bac1e2014-05-06 15:23:49 -0400155 if(dst.rel.type != PARAMETER_VOID && majorVersion >= 3)
John Bauman89401822014-05-06 15:04:28 -0400156 {
157 token++;
158 size--;
159 }
160
161 token++;
162 size--;
163 }
164
John Bauman19bac1e2014-05-06 15:23:49 -0400165 if(predicate)
John Bauman89401822014-05-06 15:04:28 -0400166 {
167 ASSERT(size != 0);
168
John Bauman19bac1e2014-05-06 15:23:49 -0400169 predicateNot = (Modifier)((*token & 0x0F000000) >> 24) == MODIFIER_NOT;
170 predicateSwizzle = (unsigned char)((*token & 0x00FF0000) >> 16);
John Bauman89401822014-05-06 15:04:28 -0400171
172 token++;
173 size--;
174 }
175
176 for(int i = 0; size > 0; i++)
177 {
178 parseSourceToken(i, token, majorVersion);
179
180 token++;
181 size--;
182
John Bauman19bac1e2014-05-06 15:23:49 -0400183 if(src[i].rel.type != PARAMETER_VOID && majorVersion >= 2)
John Bauman89401822014-05-06 15:04:28 -0400184 {
185 token++;
186 size--;
187 }
188 }
189 }
190 }
191
192 Shader::Instruction::~Instruction()
193 {
194 }
195
John Bauman89401822014-05-06 15:04:28 -0400196 std::string Shader::Instruction::string(ShaderType shaderType, unsigned short version) const
197 {
198 std::string instructionString;
199
John Bauman19bac1e2014-05-06 15:23:49 -0400200 if(opcode != OPCODE_DCL)
John Bauman89401822014-05-06 15:04:28 -0400201 {
John Bauman19bac1e2014-05-06 15:23:49 -0400202 instructionString += coissue ? "+ " : "";
John Bauman89401822014-05-06 15:04:28 -0400203
John Bauman19bac1e2014-05-06 15:23:49 -0400204 if(predicate)
John Bauman89401822014-05-06 15:04:28 -0400205 {
John Bauman19bac1e2014-05-06 15:23:49 -0400206 instructionString += predicateNot ? "(!p0" : "(p0";
207 instructionString += swizzleString(PARAMETER_PREDICATE, predicateSwizzle);
John Bauman89401822014-05-06 15:04:28 -0400208 instructionString += ") ";
209 }
210
John Bauman19bac1e2014-05-06 15:23:49 -0400211 instructionString += operationString(version) + controlString() + dst.shiftString() + dst.modifierString();
John Bauman89401822014-05-06 15:04:28 -0400212
John Bauman19bac1e2014-05-06 15:23:49 -0400213 if(dst.type != PARAMETER_VOID)
John Bauman89401822014-05-06 15:04:28 -0400214 {
John Bauman19bac1e2014-05-06 15:23:49 -0400215 instructionString += " " + dst.string(shaderType, version) +
216 dst.relativeString() +
217 dst.maskString();
John Bauman89401822014-05-06 15:04:28 -0400218 }
219
220 for(int i = 0; i < 4; i++)
221 {
John Bauman19bac1e2014-05-06 15:23:49 -0400222 if(src[i].type != PARAMETER_VOID)
John Bauman89401822014-05-06 15:04:28 -0400223 {
John Bauman19bac1e2014-05-06 15:23:49 -0400224 instructionString += (dst.type != PARAMETER_VOID || i > 0) ? ", " : " ";
225 instructionString += src[i].preModifierString() +
226 src[i].string(shaderType, version) +
227 src[i].relativeString() +
228 src[i].postModifierString() +
229 src[i].swizzleString();
John Bauman89401822014-05-06 15:04:28 -0400230 }
231 }
232 }
233 else // DCL
234 {
235 instructionString += "dcl";
236
John Bauman19bac1e2014-05-06 15:23:49 -0400237 if(dst.type == PARAMETER_SAMPLER)
John Bauman89401822014-05-06 15:04:28 -0400238 {
John Bauman19bac1e2014-05-06 15:23:49 -0400239 switch(samplerType)
John Bauman89401822014-05-06 15:04:28 -0400240 {
John Bauman19bac1e2014-05-06 15:23:49 -0400241 case SAMPLER_UNKNOWN: instructionString += " "; break;
242 case SAMPLER_1D: instructionString += "_1d "; break;
243 case SAMPLER_2D: instructionString += "_2d "; break;
244 case SAMPLER_CUBE: instructionString += "_cube "; break;
245 case SAMPLER_VOLUME: instructionString += "_volume "; break;
John Bauman89401822014-05-06 15:04:28 -0400246 default:
247 ASSERT(false);
248 }
249
John Bauman19bac1e2014-05-06 15:23:49 -0400250 instructionString += dst.string(shaderType, version);
John Bauman89401822014-05-06 15:04:28 -0400251 }
John Bauman19bac1e2014-05-06 15:23:49 -0400252 else if(dst.type == PARAMETER_INPUT ||
253 dst.type == PARAMETER_OUTPUT ||
254 dst.type == PARAMETER_TEXTURE)
John Bauman89401822014-05-06 15:04:28 -0400255 {
256 if(version >= 0x0300)
257 {
John Bauman19bac1e2014-05-06 15:23:49 -0400258 switch(usage)
John Bauman89401822014-05-06 15:04:28 -0400259 {
John Bauman19bac1e2014-05-06 15:23:49 -0400260 case USAGE_POSITION: instructionString += "_position"; break;
261 case USAGE_BLENDWEIGHT: instructionString += "_blendweight"; break;
262 case USAGE_BLENDINDICES: instructionString += "_blendindices"; break;
263 case USAGE_NORMAL: instructionString += "_normal"; break;
264 case USAGE_PSIZE: instructionString += "_psize"; break;
265 case USAGE_TEXCOORD: instructionString += "_texcoord"; break;
266 case USAGE_TANGENT: instructionString += "_tangent"; break;
267 case USAGE_BINORMAL: instructionString += "_binormal"; break;
268 case USAGE_TESSFACTOR: instructionString += "_tessfactor"; break;
269 case USAGE_POSITIONT: instructionString += "_positiont"; break;
270 case USAGE_COLOR: instructionString += "_color"; break;
271 case USAGE_FOG: instructionString += "_fog"; break;
272 case USAGE_DEPTH: instructionString += "_depth"; break;
273 case USAGE_SAMPLE: instructionString += "_sample"; break;
John Bauman89401822014-05-06 15:04:28 -0400274 default:
275 ASSERT(false);
276 }
277
John Bauman19bac1e2014-05-06 15:23:49 -0400278 if(usageIndex > 0)
John Bauman89401822014-05-06 15:04:28 -0400279 {
280 std::ostringstream buffer;
281
John Bauman19bac1e2014-05-06 15:23:49 -0400282 buffer << (int)usageIndex;
John Bauman89401822014-05-06 15:04:28 -0400283
284 instructionString += buffer.str();
285 }
286 }
John Bauman19bac1e2014-05-06 15:23:49 -0400287 else ASSERT(dst.type != PARAMETER_OUTPUT);
John Bauman89401822014-05-06 15:04:28 -0400288
289 instructionString += " ";
290
John Bauman19bac1e2014-05-06 15:23:49 -0400291 instructionString += dst.string(shaderType, version);
292 instructionString += dst.maskString();
John Bauman89401822014-05-06 15:04:28 -0400293 }
John Bauman19bac1e2014-05-06 15:23:49 -0400294 else if(dst.type == PARAMETER_MISCTYPE) // vPos and vFace
John Bauman89401822014-05-06 15:04:28 -0400295 {
296 instructionString += " ";
297
John Bauman19bac1e2014-05-06 15:23:49 -0400298 instructionString += dst.string(shaderType, version);
John Bauman89401822014-05-06 15:04:28 -0400299 }
300 else ASSERT(false);
301 }
302
303 return instructionString;
304 }
305
John Bauman19bac1e2014-05-06 15:23:49 -0400306 std::string Shader::DestinationParameter::modifierString() const
John Bauman89401822014-05-06 15:04:28 -0400307 {
308 if(type == PARAMETER_VOID || type == PARAMETER_LABEL)
309 {
310 return "";
311 }
312
313 std::string modifierString;
314
John Bauman19bac1e2014-05-06 15:23:49 -0400315 if(integer)
316 {
317 modifierString += "_int";
318 }
319
John Bauman89401822014-05-06 15:04:28 -0400320 if(saturate)
321 {
322 modifierString += "_sat";
323 }
324
325 if(partialPrecision)
326 {
327 modifierString += "_pp";
328 }
329
330 if(centroid)
331 {
332 modifierString += "_centroid";
333 }
334
335 return modifierString;
336 }
337
John Bauman19bac1e2014-05-06 15:23:49 -0400338 std::string Shader::DestinationParameter::shiftString() const
John Bauman89401822014-05-06 15:04:28 -0400339 {
340 if(type == PARAMETER_VOID || type == PARAMETER_LABEL)
341 {
342 return "";
343 }
344
345 switch(shift)
346 {
347 case 0: return "";
348 case 1: return "_x2";
349 case 2: return "_x4";
350 case 3: return "_x8";
351 case -1: return "_d2";
352 case -2: return "_d4";
353 case -3: return "_d8";
354 default:
355 return "";
356 // ASSERT(false); // FIXME
357 }
358 }
359
John Bauman19bac1e2014-05-06 15:23:49 -0400360 std::string Shader::DestinationParameter::maskString() const
John Bauman89401822014-05-06 15:04:28 -0400361 {
362 if(type == PARAMETER_VOID || type == PARAMETER_LABEL)
363 {
364 return "";
365 }
366
367 switch(mask)
368 {
369 case 0x0: return "";
370 case 0x1: return ".x";
371 case 0x2: return ".y";
372 case 0x3: return ".xy";
373 case 0x4: return ".z";
374 case 0x5: return ".xz";
375 case 0x6: return ".yz";
376 case 0x7: return ".xyz";
377 case 0x8: return ".w";
378 case 0x9: return ".xw";
379 case 0xA: return ".yw";
380 case 0xB: return ".xyw";
381 case 0xC: return ".zw";
382 case 0xD: return ".xzw";
383 case 0xE: return ".yzw";
384 case 0xF: return "";
385 default:
386 ASSERT(false);
387 }
388
389 return "";
390 }
391
John Bauman19bac1e2014-05-06 15:23:49 -0400392 std::string Shader::SourceParameter::preModifierString() const
John Bauman89401822014-05-06 15:04:28 -0400393 {
394 if(type == PARAMETER_VOID)
395 {
396 return "";
397 }
398
399 switch(modifier)
400 {
401 case MODIFIER_NONE: return "";
402 case MODIFIER_NEGATE: return "-";
403 case MODIFIER_BIAS: return "";
404 case MODIFIER_BIAS_NEGATE: return "-";
405 case MODIFIER_SIGN: return "";
406 case MODIFIER_SIGN_NEGATE: return "-";
407 case MODIFIER_COMPLEMENT: return "1-";
408 case MODIFIER_X2: return "";
409 case MODIFIER_X2_NEGATE: return "-";
410 case MODIFIER_DZ: return "";
411 case MODIFIER_DW: return "";
412 case MODIFIER_ABS: return "";
413 case MODIFIER_ABS_NEGATE: return "-";
414 case MODIFIER_NOT: return "!";
415 default:
416 ASSERT(false);
417 }
418
419 return "";
420 }
421
John Bauman19bac1e2014-05-06 15:23:49 -0400422 std::string Shader::Parameter::relativeString() const
John Bauman89401822014-05-06 15:04:28 -0400423 {
John Bauman19bac1e2014-05-06 15:23:49 -0400424 if(type == PARAMETER_CONST || type == PARAMETER_INPUT || type == PARAMETER_OUTPUT || type == PARAMETER_TEMP)
John Bauman89401822014-05-06 15:04:28 -0400425 {
John Bauman19bac1e2014-05-06 15:23:49 -0400426 if(rel.type == PARAMETER_VOID)
John Bauman89401822014-05-06 15:04:28 -0400427 {
John Bauman19bac1e2014-05-06 15:23:49 -0400428 return "";
John Bauman89401822014-05-06 15:04:28 -0400429 }
John Bauman19bac1e2014-05-06 15:23:49 -0400430 else if(rel.type == PARAMETER_ADDR)
431 {
432 switch(rel.swizzle & 0x03)
433 {
434 case 0: return "[a0.x]";
435 case 1: return "[a0.y]";
436 case 2: return "[a0.z]";
437 case 3: return "[a0.w]";
438 }
439 }
440 else if(rel.type == PARAMETER_TEMP)
441 {
442 std::ostringstream buffer;
443 buffer << rel.index;
444
445 switch(rel.swizzle & 0x03)
446 {
447 case 0: return "[r" + buffer.str() + ".x]";
448 case 1: return "[r" + buffer.str() + ".y]";
449 case 2: return "[r" + buffer.str() + ".z]";
450 case 3: return "[r" + buffer.str() + ".w]";
451 }
452 }
453 else if(rel.type == PARAMETER_LOOP)
454 {
455 return "[aL]";
456 }
457 else ASSERT(false);
John Bauman89401822014-05-06 15:04:28 -0400458 }
John Bauman89401822014-05-06 15:04:28 -0400459
460 return "";
461 }
462
John Bauman19bac1e2014-05-06 15:23:49 -0400463 std::string Shader::SourceParameter::postModifierString() const
John Bauman89401822014-05-06 15:04:28 -0400464 {
465 if(type == PARAMETER_VOID)
466 {
467 return "";
468 }
469
470 switch(modifier)
471 {
472 case MODIFIER_NONE: return "";
473 case MODIFIER_NEGATE: return "";
474 case MODIFIER_BIAS: return "_bias";
475 case MODIFIER_BIAS_NEGATE: return "_bias";
476 case MODIFIER_SIGN: return "_bx2";
477 case MODIFIER_SIGN_NEGATE: return "_bx2";
478 case MODIFIER_COMPLEMENT: return "";
479 case MODIFIER_X2: return "_x2";
480 case MODIFIER_X2_NEGATE: return "_x2";
481 case MODIFIER_DZ: return "_dz";
482 case MODIFIER_DW: return "_dw";
483 case MODIFIER_ABS: return "_abs";
484 case MODIFIER_ABS_NEGATE: return "_abs";
485 case MODIFIER_NOT: return "";
486 default:
487 ASSERT(false);
488 }
489
490 return "";
491 }
492
John Bauman19bac1e2014-05-06 15:23:49 -0400493 std::string Shader::SourceParameter::swizzleString() const
John Bauman89401822014-05-06 15:04:28 -0400494 {
495 return Instruction::swizzleString(type, swizzle);
496 }
497
498 void Shader::Instruction::parseOperationToken(unsigned long token, unsigned char majorVersion)
499 {
500 if((token & 0xFFFF0000) == 0xFFFF0000 || (token & 0xFFFF0000) == 0xFFFE0000) // Version token
501 {
John Bauman19bac1e2014-05-06 15:23:49 -0400502 opcode = (Opcode)token;
503
504 control = CONTROL_RESERVED0;
505 predicate = false;
506 coissue = false;
John Bauman89401822014-05-06 15:04:28 -0400507 }
508 else
509 {
John Bauman19bac1e2014-05-06 15:23:49 -0400510 opcode = (Opcode)(token & 0x0000FFFF);
511 control = (Control)((token & 0x00FF0000) >> 16);
John Bauman89401822014-05-06 15:04:28 -0400512
513 int size = (token & 0x0F000000) >> 24;
514
John Bauman19bac1e2014-05-06 15:23:49 -0400515 predicate = (token & 0x10000000) != 0x00000000;
516 coissue = (token & 0x40000000) != 0x00000000;
John Bauman89401822014-05-06 15:04:28 -0400517
518 if(majorVersion < 2)
519 {
520 if(size != 0)
521 {
522 ASSERT(false); // Reserved
523 }
524 }
525
526 if(majorVersion < 2)
527 {
John Bauman19bac1e2014-05-06 15:23:49 -0400528 if(predicate)
John Bauman89401822014-05-06 15:04:28 -0400529 {
530 ASSERT(false);
531 }
532 }
533
534 if((token & 0x20000000) != 0x00000000)
535 {
536 ASSERT(false); // Reserved
537 }
538
539 if(majorVersion >= 2)
540 {
John Bauman19bac1e2014-05-06 15:23:49 -0400541 if(coissue)
John Bauman89401822014-05-06 15:04:28 -0400542 {
543 ASSERT(false); // Reserved
544 }
545 }
546
547 if((token & 0x80000000) != 0x00000000)
548 {
549 ASSERT(false);
550 }
551 }
552 }
553
554 void Shader::Instruction::parseDeclarationToken(unsigned long token)
555 {
John Bauman19bac1e2014-05-06 15:23:49 -0400556 samplerType = (SamplerType)((token & 0x78000000) >> 27);
557 usage = (Usage)(token & 0x0000001F);
558 usageIndex = (unsigned char)((token & 0x000F0000) >> 16);
John Bauman89401822014-05-06 15:04:28 -0400559 }
560
561 void Shader::Instruction::parseDestinationToken(const unsigned long *token, unsigned char majorVersion)
562 {
John Bauman19bac1e2014-05-06 15:23:49 -0400563 dst.index = (unsigned short)(token[0] & 0x000007FF);
564 dst.type = (ParameterType)(((token[0] & 0x00001800) >> 8) | ((token[0] & 0x70000000) >> 28));
John Bauman89401822014-05-06 15:04:28 -0400565
566 // TODO: Check type and index range
567
John Bauman19bac1e2014-05-06 15:23:49 -0400568 bool relative = (token[0] & 0x00002000) != 0x00000000;
569 dst.rel.type = relative ? PARAMETER_ADDR : PARAMETER_VOID;
570 dst.rel.swizzle = 0x00;
571 dst.rel.scale = 1;
John Bauman89401822014-05-06 15:04:28 -0400572
John Bauman19bac1e2014-05-06 15:23:49 -0400573 if(relative && majorVersion >= 3)
John Bauman89401822014-05-06 15:04:28 -0400574 {
John Bauman19bac1e2014-05-06 15:23:49 -0400575 dst.rel.type = (ParameterType)(((token[1] & 0x00001800) >> 8) | ((token[1] & 0x70000000) >> 28));
576 dst.rel.swizzle = (unsigned char)((token[1] & 0x00FF0000) >> 16);
John Bauman89401822014-05-06 15:04:28 -0400577 }
John Bauman19bac1e2014-05-06 15:23:49 -0400578 else if(relative) ASSERT(false); // Reserved
John Bauman89401822014-05-06 15:04:28 -0400579
580 if((token[0] & 0x0000C000) != 0x00000000)
581 {
582 ASSERT(false); // Reserved
583 }
584
John Bauman19bac1e2014-05-06 15:23:49 -0400585 dst.mask = (unsigned char)((token[0] & 0x000F0000) >> 16);
586 dst.saturate = (token[0] & 0x00100000) != 0;
587 dst.partialPrecision = (token[0] & 0x00200000) != 0;
588 dst.centroid = (token[0] & 0x00400000) != 0;
589 dst.shift = (signed char)((token[0] & 0x0F000000) >> 20) >> 4;
John Bauman89401822014-05-06 15:04:28 -0400590
591 if(majorVersion >= 2)
592 {
John Bauman19bac1e2014-05-06 15:23:49 -0400593 if(dst.shift)
John Bauman89401822014-05-06 15:04:28 -0400594 {
595 ASSERT(false); // Reserved
596 }
597 }
598
599 if((token[0] & 0x80000000) != 0x80000000)
600 {
601 ASSERT(false);
602 }
603 }
604
605 void Shader::Instruction::parseSourceToken(int i, const unsigned long *token, unsigned char majorVersion)
606 {
607 // Defaults
John Bauman19bac1e2014-05-06 15:23:49 -0400608 src[i].index = 0;
609 src[i].type = PARAMETER_VOID;
610 src[i].modifier = MODIFIER_NONE;
611 src[i].swizzle = 0xE4;
612 src[i].rel.type = PARAMETER_VOID;
613 src[i].rel.swizzle = 0x00;
614 src[i].rel.scale = 1;
John Bauman89401822014-05-06 15:04:28 -0400615
John Bauman19bac1e2014-05-06 15:23:49 -0400616 switch(opcode)
John Bauman89401822014-05-06 15:04:28 -0400617 {
John Bauman19bac1e2014-05-06 15:23:49 -0400618 case OPCODE_DEF:
619 src[0].type = PARAMETER_FLOAT4LITERAL;
620 src[0].value[i] = *(float*)token;
John Bauman89401822014-05-06 15:04:28 -0400621 break;
John Bauman19bac1e2014-05-06 15:23:49 -0400622 case OPCODE_DEFB:
623 src[0].type = PARAMETER_BOOL1LITERAL;
624 src[0].boolean[0] = *(int*)token;
John Bauman89401822014-05-06 15:04:28 -0400625 break;
John Bauman19bac1e2014-05-06 15:23:49 -0400626 case OPCODE_DEFI:
627 src[0].type = PARAMETER_INT4LITERAL;
628 src[0].integer[i] = *(int*)token;
John Bauman89401822014-05-06 15:04:28 -0400629 break;
630 default:
John Bauman19bac1e2014-05-06 15:23:49 -0400631 src[i].index = (unsigned short)(token[0] & 0x000007FF);
632 src[i].type = (ParameterType)(((token[0] & 0x00001800) >> 8) | ((token[0] & 0x70000000) >> 28));
John Bauman89401822014-05-06 15:04:28 -0400633
634 // FIXME: Check type and index range
635
John Bauman19bac1e2014-05-06 15:23:49 -0400636 bool relative = (token[0] & 0x00002000) != 0x00000000;
637 src[i].rel.type = relative ? PARAMETER_ADDR : PARAMETER_VOID;
John Bauman89401822014-05-06 15:04:28 -0400638
639 if((token[0] & 0x0000C000) != 0x00000000)
640 {
John Bauman19bac1e2014-05-06 15:23:49 -0400641 if(opcode != OPCODE_DEF &&
642 opcode != OPCODE_DEFI &&
643 opcode != OPCODE_DEFB)
John Bauman89401822014-05-06 15:04:28 -0400644 {
645 ASSERT(false);
646 }
647 }
648
John Bauman19bac1e2014-05-06 15:23:49 -0400649 src[i].swizzle = (unsigned char)((token[0] & 0x00FF0000) >> 16);
650 src[i].modifier = (Modifier)((token[0] & 0x0F000000) >> 24);
John Bauman89401822014-05-06 15:04:28 -0400651
652 if((token[0] & 0x80000000) != 0x80000000)
653 {
John Bauman19bac1e2014-05-06 15:23:49 -0400654 if(opcode != OPCODE_DEF &&
655 opcode != OPCODE_DEFI &&
656 opcode != OPCODE_DEFB)
John Bauman89401822014-05-06 15:04:28 -0400657 {
658 ASSERT(false);
659 }
660 }
661
John Bauman19bac1e2014-05-06 15:23:49 -0400662 if(relative && majorVersion >= 2)
John Bauman89401822014-05-06 15:04:28 -0400663 {
John Bauman19bac1e2014-05-06 15:23:49 -0400664 src[i].rel.type = (ParameterType)(((token[1] & 0x00001800) >> 8) | ((token[1] & 0x70000000) >> 28));
665 src[i].rel.swizzle = (unsigned char)((token[1] & 0x00FF0000) >> 16);
John Bauman89401822014-05-06 15:04:28 -0400666 }
667 }
668 }
669
John Bauman19bac1e2014-05-06 15:23:49 -0400670 std::string Shader::Instruction::swizzleString(ParameterType type, unsigned char swizzle)
John Bauman89401822014-05-06 15:04:28 -0400671 {
John Bauman19bac1e2014-05-06 15:23:49 -0400672 if(type == PARAMETER_VOID || type == PARAMETER_LABEL || swizzle == 0xE4)
John Bauman89401822014-05-06 15:04:28 -0400673 {
674 return "";
675 }
676
677 int x = (swizzle & 0x03) >> 0;
678 int y = (swizzle & 0x0C) >> 2;
679 int z = (swizzle & 0x30) >> 4;
680 int w = (swizzle & 0xC0) >> 6;
681
682 std::string swizzleString = ".";
683
684 switch(x)
685 {
686 case 0: swizzleString += "x"; break;
687 case 1: swizzleString += "y"; break;
688 case 2: swizzleString += "z"; break;
689 case 3: swizzleString += "w"; break;
690 }
691
692 if(!(x == y && y == z && z == w))
693 {
694 switch(y)
695 {
696 case 0: swizzleString += "x"; break;
697 case 1: swizzleString += "y"; break;
698 case 2: swizzleString += "z"; break;
699 case 3: swizzleString += "w"; break;
700 }
701
702 if(!(y == z && z == w))
703 {
704 switch(z)
705 {
706 case 0: swizzleString += "x"; break;
707 case 1: swizzleString += "y"; break;
708 case 2: swizzleString += "z"; break;
709 case 3: swizzleString += "w"; break;
710 }
711
712 if(!(z == w))
713 {
714 switch(w)
715 {
716 case 0: swizzleString += "x"; break;
717 case 1: swizzleString += "y"; break;
718 case 2: swizzleString += "z"; break;
719 case 3: swizzleString += "w"; break;
720 }
721 }
722 }
723 }
724
725 return swizzleString;
726 }
727
John Bauman19bac1e2014-05-06 15:23:49 -0400728 std::string Shader::Instruction::operationString(unsigned short version) const
John Bauman89401822014-05-06 15:04:28 -0400729 {
John Bauman19bac1e2014-05-06 15:23:49 -0400730 switch(opcode)
John Bauman89401822014-05-06 15:04:28 -0400731 {
John Bauman19bac1e2014-05-06 15:23:49 -0400732 case OPCODE_NOP: return "nop";
733 case OPCODE_MOV: return "mov";
734 case OPCODE_ADD: return "add";
735 case OPCODE_SUB: return "sub";
736 case OPCODE_MAD: return "mad";
737 case OPCODE_MUL: return "mul";
738 case OPCODE_RCPX: return "rcpx";
739 case OPCODE_DIV: return "div";
740 case OPCODE_MOD: return "mod";
741 case OPCODE_RSQX: return "rsqx";
742 case OPCODE_SQRT: return "sqrt";
743 case OPCODE_RSQ: return "rsq";
744 case OPCODE_LEN2: return "len2";
745 case OPCODE_LEN3: return "len3";
746 case OPCODE_LEN4: return "len4";
747 case OPCODE_DIST1: return "dist1";
748 case OPCODE_DIST2: return "dist2";
749 case OPCODE_DIST3: return "dist3";
750 case OPCODE_DIST4: return "dist4";
751 case OPCODE_DP3: return "dp3";
752 case OPCODE_DP4: return "dp4";
753 case OPCODE_MIN: return "min";
754 case OPCODE_MAX: return "max";
755 case OPCODE_SLT: return "slt";
756 case OPCODE_SGE: return "sge";
757 case OPCODE_EXP2X: return "exp2x";
758 case OPCODE_LOG2X: return "log2x";
759 case OPCODE_LIT: return "lit";
760 case OPCODE_ATT: return "att";
761 case OPCODE_LRP: return "lrp";
762 case OPCODE_STEP: return "step";
763 case OPCODE_SMOOTH: return "smooth";
764 case OPCODE_FRC: return "frc";
765 case OPCODE_M4X4: return "m4x4";
766 case OPCODE_M4X3: return "m4x3";
767 case OPCODE_M3X4: return "m3x4";
768 case OPCODE_M3X3: return "m3x3";
769 case OPCODE_M3X2: return "m3x2";
770 case OPCODE_CALL: return "call";
771 case OPCODE_CALLNZ: return "callnz";
772 case OPCODE_LOOP: return "loop";
773 case OPCODE_RET: return "ret";
774 case OPCODE_ENDLOOP: return "endloop";
775 case OPCODE_LABEL: return "label";
776 case OPCODE_DCL: return "dcl";
777 case OPCODE_POWX: return "powx";
778 case OPCODE_CRS: return "crs";
779 case OPCODE_SGN: return "sgn";
780 case OPCODE_ABS: return "abs";
781 case OPCODE_NRM2: return "nrm2";
782 case OPCODE_NRM3: return "nrm3";
783 case OPCODE_NRM4: return "nrm4";
784 case OPCODE_SINCOS: return "sincos";
785 case OPCODE_REP: return "rep";
786 case OPCODE_ENDREP: return "endrep";
787 case OPCODE_IF: return "if";
788 case OPCODE_IFC: return "ifc";
789 case OPCODE_ELSE: return "else";
790 case OPCODE_ENDIF: return "endif";
791 case OPCODE_BREAK: return "break";
792 case OPCODE_BREAKC: return "breakc";
793 case OPCODE_MOVA: return "mova";
794 case OPCODE_DEFB: return "defb";
795 case OPCODE_DEFI: return "defi";
796 case OPCODE_TEXCOORD: return "texcoord";
797 case OPCODE_TEXKILL: return "texkill";
798 case OPCODE_DISCARD: return "discard";
799 case OPCODE_TEX:
800 if(version < 0x0104) return "tex";
801 else return "texld";
802 case OPCODE_TEXBEM: return "texbem";
803 case OPCODE_TEXBEML: return "texbeml";
804 case OPCODE_TEXREG2AR: return "texreg2ar";
805 case OPCODE_TEXREG2GB: return "texreg2gb";
806 case OPCODE_TEXM3X2PAD: return "texm3x2pad";
807 case OPCODE_TEXM3X2TEX: return "texm3x2tex";
808 case OPCODE_TEXM3X3PAD: return "texm3x3pad";
809 case OPCODE_TEXM3X3TEX: return "texm3x3tex";
810 case OPCODE_RESERVED0: return "reserved0";
811 case OPCODE_TEXM3X3SPEC: return "texm3x3spec";
812 case OPCODE_TEXM3X3VSPEC: return "texm3x3vspec";
813 case OPCODE_EXPP: return "expp";
814 case OPCODE_LOGP: return "logp";
815 case OPCODE_CND: return "cnd";
816 case OPCODE_DEF: return "def";
817 case OPCODE_TEXREG2RGB: return "texreg2rgb";
818 case OPCODE_TEXDP3TEX: return "texdp3tex";
819 case OPCODE_TEXM3X2DEPTH: return "texm3x2depth";
820 case OPCODE_TEXDP3: return "texdp3";
821 case OPCODE_TEXM3X3: return "texm3x3";
822 case OPCODE_TEXDEPTH: return "texdepth";
823 case OPCODE_CMP0: return "cmp0";
824 case OPCODE_ICMP: return "icmp";
825 case OPCODE_SELECT: return "select";
826 case OPCODE_EXTRACT: return "extract";
827 case OPCODE_INSERT: return "insert";
828 case OPCODE_BEM: return "bem";
829 case OPCODE_DP2ADD: return "dp2add";
830 case OPCODE_DFDX: return "dFdx";
831 case OPCODE_DFDY: return "dFdy";
832 case OPCODE_FWIDTH: return "fwidth";
833 case OPCODE_TEXLDD: return "texldd";
834 case OPCODE_CMP: return "cmp";
835 case OPCODE_TEXLDL: return "texldl";
836 case OPCODE_BREAKP: return "breakp";
837 case OPCODE_PHASE: return "phase";
838 case OPCODE_COMMENT: return "comment";
839 case OPCODE_END: return "end";
840 case OPCODE_PS_1_0: return "ps_1_0";
841 case OPCODE_PS_1_1: return "ps_1_1";
842 case OPCODE_PS_1_2: return "ps_1_2";
843 case OPCODE_PS_1_3: return "ps_1_3";
844 case OPCODE_PS_1_4: return "ps_1_4";
845 case OPCODE_PS_2_0: return "ps_2_0";
846 case OPCODE_PS_2_x: return "ps_2_x";
847 case OPCODE_PS_3_0: return "ps_3_0";
848 case OPCODE_VS_1_0: return "vs_1_0";
849 case OPCODE_VS_1_1: return "vs_1_1";
850 case OPCODE_VS_2_0: return "vs_2_0";
851 case OPCODE_VS_2_x: return "vs_2_x";
852 case OPCODE_VS_2_sw: return "vs_2_sw";
853 case OPCODE_VS_3_0: return "vs_3_0";
854 case OPCODE_VS_3_sw: return "vs_3_sw";
855 case OPCODE_WHILE: return "while";
856 case OPCODE_ENDWHILE: return "endwhile";
857 case OPCODE_COS: return "cos";
858 case OPCODE_SIN: return "sin";
859 case OPCODE_TAN: return "tan";
860 case OPCODE_ACOS: return "acos";
861 case OPCODE_ASIN: return "asin";
862 case OPCODE_ATAN: return "atan";
863 case OPCODE_ATAN2: return "atan2";
864 case OPCODE_DP1: return "dp1";
865 case OPCODE_DP2: return "dp2";
866 case OPCODE_TRUNC: return "trunc";
867 case OPCODE_FLOOR: return "floor";
868 case OPCODE_CEIL: return "ceil";
869 case OPCODE_EXP2: return "exp2";
870 case OPCODE_LOG2: return "log2";
871 case OPCODE_EXP: return "exp";
872 case OPCODE_LOG: return "log";
873 case OPCODE_POW: return "pow";
874 case OPCODE_F2B: return "f2b";
875 case OPCODE_B2F: return "b2f";
876 case OPCODE_ALL: return "all";
877 case OPCODE_ANY: return "any";
878 case OPCODE_NOT: return "not";
879 case OPCODE_OR: return "or";
880 case OPCODE_XOR: return "xor";
881 case OPCODE_AND: return "and";
882 case OPCODE_FORWARD1: return "forward1";
883 case OPCODE_FORWARD2: return "forward2";
884 case OPCODE_FORWARD3: return "forward3";
885 case OPCODE_FORWARD4: return "forward4";
886 case OPCODE_REFLECT1: return "reflect1";
887 case OPCODE_REFLECT2: return "reflect2";
888 case OPCODE_REFLECT3: return "reflect3";
889 case OPCODE_REFLECT4: return "reflect4";
890 case OPCODE_REFRACT1: return "refract1";
891 case OPCODE_REFRACT2: return "refract2";
892 case OPCODE_REFRACT3: return "refract3";
893 case OPCODE_REFRACT4: return "refract4";
894 case OPCODE_LEAVE: return "leave";
895 case OPCODE_CONTINUE: return "continue";
896 case OPCODE_TEST: return "test";
897 default:
898 ASSERT(false);
John Bauman89401822014-05-06 15:04:28 -0400899 }
John Bauman89401822014-05-06 15:04:28 -0400900
John Bauman19bac1e2014-05-06 15:23:49 -0400901 return "<unknown>";
902 }
903
904 std::string Shader::Instruction::controlString() const
905 {
906 if(opcode != OPCODE_LOOP && opcode != OPCODE_BREAKC && opcode != OPCODE_IFC && opcode != OPCODE_CMP)
907 {
908 if(project) return "p";
909
910 if(bias) return "b";
911
912 // FIXME: LOD
913 }
914
915 switch(control)
916 {
917 case 1: return "_gt";
918 case 2: return "_eq";
919 case 3: return "_ge";
920 case 4: return "_lt";
921 case 5: return "_ne";
922 case 6: return "_le";
923 default:
924 return "";
925 // ASSERT(false); // FIXME
John Bauman89401822014-05-06 15:04:28 -0400926 }
927 }
928
John Bauman19bac1e2014-05-06 15:23:49 -0400929 std::string Shader::Parameter::string(ShaderType shaderType, unsigned short version) const
930 {
931 std::ostringstream buffer;
932
933 if(type == PARAMETER_FLOAT4LITERAL)
934 {
935 buffer << '{' << value[0] << ", " << value[1] << ", " << value[2] << ", " << value[3] << '}';
936
937 return buffer.str();
938 }
939 else if(type != PARAMETER_RASTOUT && !(type == PARAMETER_ADDR && shaderType == SHADER_VERTEX) && type != PARAMETER_LOOP && type != PARAMETER_PREDICATE && type != PARAMETER_MISCTYPE)
940 {
941 buffer << index;
942
943 return typeString(shaderType, version) + buffer.str();
944 }
945 else
946 {
947 return typeString(shaderType, version);
948 }
949 }
950
951 std::string Shader::Parameter::typeString(ShaderType shaderType, unsigned short version) const
John Bauman89401822014-05-06 15:04:28 -0400952 {
953 switch(type)
954 {
955 case PARAMETER_TEMP: return "r";
956 case PARAMETER_INPUT: return "v";
957 case PARAMETER_CONST: return "c";
958 case PARAMETER_TEXTURE:
959 // case PARAMETER_ADDR:
960 if(shaderType == SHADER_PIXEL) return "t";
961 else return "a0";
962 case PARAMETER_RASTOUT:
963 if(index == 0) return "oPos";
964 else if(index == 1) return "oFog";
965 else if(index == 2) return "oPts";
966 else ASSERT(false);
967 case PARAMETER_ATTROUT: return "oD";
968 case PARAMETER_TEXCRDOUT:
969 // case PARAMETER_OUTPUT: return "";
970 if(version < 0x0300) return "oT";
971 else return "o";
972 case PARAMETER_CONSTINT: return "i";
973 case PARAMETER_COLOROUT: return "oC";
974 case PARAMETER_DEPTHOUT: return "oDepth";
975 case PARAMETER_SAMPLER: return "s";
976 // case PARAMETER_CONST2: return "";
977 // case PARAMETER_CONST3: return "";
978 // case PARAMETER_CONST4: return "";
979 case PARAMETER_CONSTBOOL: return "b";
980 case PARAMETER_LOOP: return "aL";
981 // case PARAMETER_TEMPFLOAT16: return "";
982 case PARAMETER_MISCTYPE:
983 if(index == 0) return "vPos";
984 else if(index == 1) return "vFace";
985 else ASSERT(false);
986 case PARAMETER_LABEL: return "l";
987 case PARAMETER_PREDICATE: return "p0";
John Bauman19bac1e2014-05-06 15:23:49 -0400988 case PARAMETER_FLOAT4LITERAL: return "";
989 case PARAMETER_BOOL1LITERAL: return "";
990 case PARAMETER_INT4LITERAL: return "";
John Bauman89401822014-05-06 15:04:28 -0400991 // case PARAMETER_VOID: return "";
992 default:
993 ASSERT(false);
994 }
995
996 return "";
997 }
998
John Bauman19bac1e2014-05-06 15:23:49 -0400999 bool Shader::Instruction::isBranch() const
John Bauman89401822014-05-06 15:04:28 -04001000 {
John Bauman19bac1e2014-05-06 15:23:49 -04001001 return opcode == OPCODE_IF || opcode == OPCODE_IFC;
1002 }
1003
1004 bool Shader::Instruction::isCall() const
1005 {
1006 return opcode == OPCODE_CALL || opcode == OPCODE_CALLNZ;
1007 }
John Bauman89401822014-05-06 15:04:28 -04001008
John Bauman19bac1e2014-05-06 15:23:49 -04001009 bool Shader::Instruction::isBreak() const
1010 {
1011 return opcode == OPCODE_BREAK || opcode == OPCODE_BREAKC || opcode == OPCODE_BREAKP;
1012 }
John Bauman89401822014-05-06 15:04:28 -04001013
John Bauman19bac1e2014-05-06 15:23:49 -04001014 bool Shader::Instruction::isLoop() const
1015 {
1016 return opcode == OPCODE_LOOP || opcode == OPCODE_REP || opcode == OPCODE_WHILE;
1017 }
John Bauman89401822014-05-06 15:04:28 -04001018
John Bauman19bac1e2014-05-06 15:23:49 -04001019 bool Shader::Instruction::isEndLoop() const
1020 {
1021 return opcode == OPCODE_ENDLOOP || opcode == OPCODE_ENDREP || opcode == OPCODE_ENDWHILE;
1022 }
John Bauman89401822014-05-06 15:04:28 -04001023
John Bauman19bac1e2014-05-06 15:23:49 -04001024 Shader::Shader() : serialID(serialCounter++)
1025 {
1026 usedSamplers = 0;
John Bauman89401822014-05-06 15:04:28 -04001027 }
1028
1029 Shader::~Shader()
1030 {
John Bauman19bac1e2014-05-06 15:23:49 -04001031 for(unsigned int i = 0; i < instruction.size(); i++)
John Bauman89401822014-05-06 15:04:28 -04001032 {
1033 delete instruction[i];
1034 instruction[i] = 0;
1035 }
John Bauman89401822014-05-06 15:04:28 -04001036 }
1037
John Bauman19bac1e2014-05-06 15:23:49 -04001038 void Shader::parse(const unsigned long *token)
John Bauman89401822014-05-06 15:04:28 -04001039 {
John Bauman19bac1e2014-05-06 15:23:49 -04001040 minorVersion = (unsigned char)(token[0] & 0x000000FF);
1041 majorVersion = (unsigned char)((token[0] & 0x0000FF00) >> 8);
1042 shaderType = (ShaderType)((token[0] & 0xFFFF0000) >> 16);
1043
1044 int length;
1045
1046 if(shaderType == SHADER_VERTEX)
John Bauman89401822014-05-06 15:04:28 -04001047 {
John Bauman19bac1e2014-05-06 15:23:49 -04001048 length = VertexShader::validate(token);
John Bauman89401822014-05-06 15:04:28 -04001049 }
John Bauman19bac1e2014-05-06 15:23:49 -04001050 else if(shaderType == SHADER_PIXEL)
1051 {
1052 length = PixelShader::validate(token);
1053 }
1054 else ASSERT(false);
John Bauman89401822014-05-06 15:04:28 -04001055
John Bauman19bac1e2014-05-06 15:23:49 -04001056 ASSERT(length != 0);
1057 instruction.resize(length);
1058
1059 for(int i = 0; i < length; i++)
1060 {
1061 while((*token & 0x0000FFFF) == 0x0000FFFE) // Comment token
1062 {
1063 int length = (*token & 0x7FFF0000) >> 16;
1064
1065 token += length + 1;
1066 }
1067
1068 int tokenCount = size(*token);
1069
1070 instruction[i] = new Instruction(token, tokenCount, majorVersion);
1071
1072 token += 1 + tokenCount;
1073 }
John Bauman89401822014-05-06 15:04:28 -04001074 }
John Bauman19bac1e2014-05-06 15:23:49 -04001075
John Bauman89401822014-05-06 15:04:28 -04001076 int Shader::size(unsigned long opcode) const
1077 {
1078 return size(opcode, version);
1079 }
1080
1081 int Shader::size(unsigned long opcode, unsigned short version)
1082 {
1083 if(version > 0x0300)
1084 {
1085 ASSERT(false);
1086 }
1087
1088 static const char size[] =
1089 {
1090 0, // NOP = 0
1091 2, // MOV
1092 3, // ADD
1093 3, // SUB
1094 4, // MAD
1095 3, // MUL
1096 2, // RCP
1097 2, // RSQ
1098 3, // DP3
1099 3, // DP4
1100 3, // MIN
1101 3, // MAX
1102 3, // SLT
1103 3, // SGE
1104 2, // EXP
1105 2, // LOG
1106 2, // LIT
1107 3, // DST
1108 4, // LRP
1109 2, // FRC
1110 3, // M4x4
1111 3, // M4x3
1112 3, // M3x4
1113 3, // M3x3
1114 3, // M3x2
1115 1, // CALL
1116 2, // CALLNZ
1117 2, // LOOP
1118 0, // RET
1119 0, // ENDLOOP
1120 1, // LABEL
1121 2, // DCL
1122 3, // POW
1123 3, // CRS
1124 4, // SGN
1125 2, // ABS
1126 2, // NRM
1127 4, // SINCOS
1128 1, // REP
1129 0, // ENDREP
1130 1, // IF
1131 2, // IFC
1132 0, // ELSE
1133 0, // ENDIF
1134 0, // BREAK
1135 2, // BREAKC
1136 2, // MOVA
1137 2, // DEFB
1138 5, // DEFI
1139 -1, // 49
1140 -1, // 50
1141 -1, // 51
1142 -1, // 52
1143 -1, // 53
1144 -1, // 54
1145 -1, // 55
1146 -1, // 56
1147 -1, // 57
1148 -1, // 58
1149 -1, // 59
1150 -1, // 60
1151 -1, // 61
1152 -1, // 62
1153 -1, // 63
1154 1, // TEXCOORD = 64
1155 1, // TEXKILL
1156 1, // TEX
1157 2, // TEXBEM
1158 2, // TEXBEML
1159 2, // TEXREG2AR
1160 2, // TEXREG2GB
1161 2, // TEXM3x2PAD
1162 2, // TEXM3x2TEX
1163 2, // TEXM3x3PAD
1164 2, // TEXM3x3TEX
1165 -1, // RESERVED0
1166 3, // TEXM3x3SPEC
1167 2, // TEXM3x3VSPEC
1168 2, // EXPP
1169 2, // LOGP
1170 4, // CND
1171 5, // DEF
1172 2, // TEXREG2RGB
1173 2, // TEXDP3TEX
1174 2, // TEXM3x2DEPTH
1175 2, // TEXDP3
1176 2, // TEXM3x3
1177 1, // TEXDEPTH
1178 4, // CMP
1179 3, // BEM
1180 4, // DP2ADD
1181 2, // DSX
1182 2, // DSY
1183 5, // TEXLDD
1184 3, // SETP
1185 3, // TEXLDL
1186 2, // BREAKP
1187 -1, // 97
1188 -1, // 98
1189 -1, // 99
1190 -1, // 100
1191 -1, // 101
1192 -1, // 102
1193 -1, // 103
1194 -1, // 104
1195 -1, // 105
1196 -1, // 106
1197 -1, // 107
1198 -1, // 108
1199 -1, // 109
1200 -1, // 110
1201 -1, // 111
1202 -1, // 112
1203 };
1204
1205 int length = 0;
1206
John Bauman19bac1e2014-05-06 15:23:49 -04001207 if((opcode & 0x0000FFFF) == OPCODE_COMMENT)
John Bauman89401822014-05-06 15:04:28 -04001208 {
1209 return (opcode & 0x7FFF0000) >> 16;
1210 }
1211
John Bauman19bac1e2014-05-06 15:23:49 -04001212 if(opcode != OPCODE_PS_1_0 &&
1213 opcode != OPCODE_PS_1_1 &&
1214 opcode != OPCODE_PS_1_2 &&
1215 opcode != OPCODE_PS_1_3 &&
1216 opcode != OPCODE_PS_1_4 &&
1217 opcode != OPCODE_PS_2_0 &&
1218 opcode != OPCODE_PS_2_x &&
1219 opcode != OPCODE_PS_3_0 &&
1220 opcode != OPCODE_VS_1_0 &&
1221 opcode != OPCODE_VS_1_1 &&
1222 opcode != OPCODE_VS_2_0 &&
1223 opcode != OPCODE_VS_2_x &&
1224 opcode != OPCODE_VS_2_sw &&
1225 opcode != OPCODE_VS_3_0 &&
1226 opcode != OPCODE_VS_3_sw &&
1227 opcode != OPCODE_PHASE &&
1228 opcode != OPCODE_END)
John Bauman89401822014-05-06 15:04:28 -04001229 {
1230 if(version >= 0x0200)
1231 {
1232 length = (opcode & 0x0F000000) >> 24;
1233 }
1234 else
1235 {
1236 length = size[opcode & 0x0000FFFF];
1237 }
1238 }
1239
1240 if(length < 0)
1241 {
1242 ASSERT(false);
1243 }
1244
1245 if(version == 0x0104)
1246 {
1247 switch(opcode & 0x0000FFFF)
1248 {
John Bauman19bac1e2014-05-06 15:23:49 -04001249 case OPCODE_TEX:
John Bauman89401822014-05-06 15:04:28 -04001250 length += 1;
1251 break;
John Bauman19bac1e2014-05-06 15:23:49 -04001252 case OPCODE_TEXCOORD:
John Bauman89401822014-05-06 15:04:28 -04001253 length += 1;
1254 break;
1255 default:
1256 break;
1257 }
1258 }
1259
1260 return length;
1261 }
1262
1263 bool Shader::maskContainsComponent(int mask, int component)
1264 {
1265 return (mask & (1 << component)) != 0;
1266 }
1267
1268 bool Shader::swizzleContainsComponent(int swizzle, int component)
1269 {
1270 if((swizzle & 0x03) >> 0 == component) return true;
1271 if((swizzle & 0x0C) >> 2 == component) return true;
1272 if((swizzle & 0x30) >> 4 == component) return true;
1273 if((swizzle & 0xC0) >> 6 == component) return true;
1274
1275 return false;
1276 }
1277
1278 bool Shader::swizzleContainsComponentMasked(int swizzle, int component, int mask)
1279 {
1280 if(mask & 0x1) if((swizzle & 0x03) >> 0 == component) return true;
1281 if(mask & 0x2) if((swizzle & 0x0C) >> 2 == component) return true;
1282 if(mask & 0x4) if((swizzle & 0x30) >> 4 == component) return true;
1283 if(mask & 0x8) if((swizzle & 0xC0) >> 6 == component) return true;
1284
1285 return false;
1286 }
1287
1288 bool Shader::containsDynamicBranching() const
1289 {
1290 return dynamicBranching;
1291 }
1292
John Bauman19bac1e2014-05-06 15:23:49 -04001293 bool Shader::containsBreakInstruction() const
John Bauman89401822014-05-06 15:04:28 -04001294 {
John Bauman19bac1e2014-05-06 15:23:49 -04001295 return containsBreak;
John Bauman89401822014-05-06 15:04:28 -04001296 }
1297
John Bauman19bac1e2014-05-06 15:23:49 -04001298 bool Shader::containsContinueInstruction() const
John Bauman89401822014-05-06 15:04:28 -04001299 {
John Bauman19bac1e2014-05-06 15:23:49 -04001300 return containsContinue;
1301 }
1302
1303 bool Shader::containsLeaveInstruction() const
1304 {
1305 return containsLeave;
1306 }
1307
1308 bool Shader::usesSampler(int index) const
1309 {
1310 return (usedSamplers & (1 << index)) != 0;
1311 }
1312
1313 int Shader::getSerialID() const
1314 {
1315 return serialID;
John Bauman89401822014-05-06 15:04:28 -04001316 }
1317
1318 int Shader::getLength() const
1319 {
John Bauman19bac1e2014-05-06 15:23:49 -04001320 return instruction.size();
John Bauman89401822014-05-06 15:04:28 -04001321 }
1322
1323 Shader::ShaderType Shader::getShaderType() const
1324 {
1325 return shaderType;
1326 }
1327
1328 unsigned short Shader::getVersion() const
1329 {
1330 return version;
1331 }
1332
1333 void Shader::print(const char *fileName, ...) const
1334 {
1335 char fullName[1024 + 1];
1336
1337 va_list vararg;
1338 va_start(vararg, fileName);
1339 vsnprintf(fullName, 1024, fileName, vararg);
1340 va_end(vararg);
1341
John Bauman19bac1e2014-05-06 15:23:49 -04001342 std::ofstream file(fullName, std::ofstream::out);
John Bauman89401822014-05-06 15:04:28 -04001343
John Bauman19bac1e2014-05-06 15:23:49 -04001344 for(unsigned int i = 0; i < instruction.size(); i++)
John Bauman89401822014-05-06 15:04:28 -04001345 {
1346 file << instruction[i]->string(shaderType, version) << std::endl;
1347 }
1348 }
1349
1350 void Shader::printInstruction(int index, const char *fileName) const
1351 {
1352 std::ofstream file(fileName, std::ofstream::out | std::ofstream::app);
1353
1354 file << instruction[index]->string(shaderType, version) << std::endl;
1355 }
1356
John Bauman19bac1e2014-05-06 15:23:49 -04001357 void Shader::append(Instruction *instruction)
John Bauman89401822014-05-06 15:04:28 -04001358 {
John Bauman19bac1e2014-05-06 15:23:49 -04001359 this->instruction.push_back(instruction);
1360 }
1361
1362 void Shader::declareSampler(int i)
1363 {
1364 usedSamplers |= 1 << i;
1365 }
1366
1367 const Shader::Instruction *Shader::getInstruction(unsigned int i) const
1368 {
1369 ASSERT(i < instruction.size());
John Bauman89401822014-05-06 15:04:28 -04001370
1371 return instruction[i];
1372 }
1373
1374 void Shader::analyzeDirtyConstants()
1375 {
1376 dirtyConstantsF = 0;
1377 dirtyConstantsI = 0;
1378 dirtyConstantsB = 0;
1379
John Bauman19bac1e2014-05-06 15:23:49 -04001380 for(unsigned int i = 0; i < instruction.size(); i++)
John Bauman89401822014-05-06 15:04:28 -04001381 {
John Bauman19bac1e2014-05-06 15:23:49 -04001382 switch(instruction[i]->opcode)
John Bauman89401822014-05-06 15:04:28 -04001383 {
John Bauman19bac1e2014-05-06 15:23:49 -04001384 case OPCODE_DEF:
1385 if(instruction[i]->dst.index + 1 > dirtyConstantsF)
John Bauman89401822014-05-06 15:04:28 -04001386 {
John Bauman19bac1e2014-05-06 15:23:49 -04001387 dirtyConstantsF = instruction[i]->dst.index + 1;
John Bauman89401822014-05-06 15:04:28 -04001388 }
1389 break;
John Bauman19bac1e2014-05-06 15:23:49 -04001390 case OPCODE_DEFI:
1391 if(instruction[i]->dst.index + 1 > dirtyConstantsI)
John Bauman89401822014-05-06 15:04:28 -04001392 {
John Bauman19bac1e2014-05-06 15:23:49 -04001393 dirtyConstantsI = instruction[i]->dst.index + 1;
John Bauman89401822014-05-06 15:04:28 -04001394 }
1395 break;
John Bauman19bac1e2014-05-06 15:23:49 -04001396 case OPCODE_DEFB:
1397 if(instruction[i]->dst.index + 1 > dirtyConstantsB)
John Bauman89401822014-05-06 15:04:28 -04001398 {
John Bauman19bac1e2014-05-06 15:23:49 -04001399 dirtyConstantsB = instruction[i]->dst.index + 1;
John Bauman89401822014-05-06 15:04:28 -04001400 }
1401 break;
1402 }
1403 }
1404 }
1405
1406 void Shader::analyzeDynamicBranching()
1407 {
1408 dynamicBranching = false;
John Bauman19bac1e2014-05-06 15:23:49 -04001409 containsLeave = false;
1410 containsBreak = false;
1411 containsContinue = false;
John Bauman89401822014-05-06 15:04:28 -04001412
John Bauman19bac1e2014-05-06 15:23:49 -04001413 // Determine global presence of branching instructions
1414 for(unsigned int i = 0; i < instruction.size(); i++)
John Bauman89401822014-05-06 15:04:28 -04001415 {
John Bauman19bac1e2014-05-06 15:23:49 -04001416 switch(instruction[i]->opcode)
John Bauman89401822014-05-06 15:04:28 -04001417 {
John Bauman19bac1e2014-05-06 15:23:49 -04001418 case OPCODE_CALLNZ:
1419 case OPCODE_IF:
1420 case OPCODE_IFC:
1421 case OPCODE_BREAK:
1422 case OPCODE_BREAKC:
1423 case OPCODE_CMP:
1424 case OPCODE_BREAKP:
1425 case OPCODE_LEAVE:
1426 case OPCODE_CONTINUE:
1427 if(instruction[i]->src[0].type != PARAMETER_CONSTBOOL)
John Bauman89401822014-05-06 15:04:28 -04001428 {
1429 dynamicBranching = true;
John Bauman19bac1e2014-05-06 15:23:49 -04001430 }
1431
1432 if(instruction[i]->opcode == OPCODE_LEAVE)
1433 {
1434 containsLeave = true;
1435 }
1436
1437 if(instruction[i]->isBreak())
1438 {
1439 containsBreak = true;
1440 }
1441
1442 if(instruction[i]->opcode == OPCODE_CONTINUE)
1443 {
1444 containsContinue = true;
1445 }
1446 }
1447 }
1448
1449 // Conservatively determine which instructions are affected by dynamic branching
1450 int branchDepth = 0;
1451 int breakDepth = 0;
1452 int continueDepth = 0;
1453 bool leaveReturn = false;
1454
1455 for(unsigned int i = 0; i < instruction.size(); i++)
1456 {
1457 // If statements
1458 if(instruction[i]->isBranch())
1459 {
1460 branchDepth++;
1461 }
1462 else if(instruction[i]->opcode == OPCODE_ENDIF)
1463 {
1464 branchDepth--;
1465 }
1466
1467 if(branchDepth > 0)
1468 {
1469 instruction[i]->analysisBranch = true;
1470
1471 if(instruction[i]->isCall())
1472 {
1473 markFunctionAnalysis(instruction[i]->dst.label, ANALYSIS_BRANCH);
1474 }
1475 }
1476
1477 // Break statemement
1478 if(instruction[i]->isBreak())
1479 {
1480 breakDepth++;
1481 }
1482 else if(instruction[i]->isEndLoop())
1483 {
1484 breakDepth--;
1485 }
1486
1487 if(breakDepth > 0)
1488 {
1489 if(instruction[i]->isLoop()) // Nested loop, don't make the end of it disable the break execution mask
1490 {
1491 breakDepth++;
1492 }
1493
1494 instruction[i]->analysisBreak = true;
1495
1496 if(instruction[i]->isCall())
1497 {
1498 markFunctionAnalysis(instruction[i]->dst.label, ANALYSIS_BRANCH);
1499 }
1500 }
1501
1502 // Continue statement
1503 if(instruction[i]->opcode == OPCODE_CONTINUE)
1504 {
1505 continueDepth++;
1506 }
1507 else if(instruction[i]->isEndLoop())
1508 {
1509 continueDepth--;
1510 }
1511
1512 if(continueDepth > 0)
1513 {
1514 if(instruction[i]->isLoop()) // Nested loop, don't make the end of it disable the break execution mask
1515 {
1516 continueDepth++;
1517 }
1518
1519 instruction[i]->analysisContinue = true;
1520
1521 if(instruction[i]->isCall())
1522 {
1523 markFunctionAnalysis(instruction[i]->dst.label, ANALYSIS_CONTINUE);
1524 }
1525 }
1526
1527 // Return (leave) statement
1528 if(instruction[i]->opcode == OPCODE_LEAVE)
1529 {
1530 leaveReturn = true;
1531 }
1532 else if(instruction[i]->opcode == OPCODE_RET) // End of the function
1533 {
1534 leaveReturn = false;
1535 }
1536
1537 if(leaveReturn)
1538 {
1539 instruction[i]->analysisLeave = true;
1540
1541 if(instruction[i]->isCall())
1542 {
1543 markFunctionAnalysis(instruction[i]->dst.label, ANALYSIS_LEAVE);
1544 }
1545 }
1546 }
1547 }
1548
1549 void Shader::markFunctionAnalysis(int functionLabel, Analysis flag)
1550 {
1551 bool marker = false;
1552 for(unsigned int i = 0; i < instruction.size(); i++)
1553 {
1554 if(!marker)
1555 {
1556 if(instruction[i]->opcode == OPCODE_LABEL && instruction[i]->dst.label == functionLabel)
1557 {
1558 marker = true;
1559 }
1560 }
1561 else
1562 {
1563 if(instruction[i]->opcode == OPCODE_RET)
1564 {
John Bauman89401822014-05-06 15:04:28 -04001565 break;
1566 }
John Bauman19bac1e2014-05-06 15:23:49 -04001567 else if(instruction[i]->isCall())
1568 {
1569 markFunctionAnalysis(instruction[i]->dst.label, flag);
1570 }
1571
1572 instruction[i]->analysis |= flag;
John Bauman89401822014-05-06 15:04:28 -04001573 }
1574 }
1575 }
1576
1577 void Shader::analyzeSamplers()
1578 {
John Bauman19bac1e2014-05-06 15:23:49 -04001579 for(unsigned int i = 0; i < instruction.size(); i++)
John Bauman89401822014-05-06 15:04:28 -04001580 {
John Bauman19bac1e2014-05-06 15:23:49 -04001581 switch(instruction[i]->opcode)
John Bauman89401822014-05-06 15:04:28 -04001582 {
John Bauman19bac1e2014-05-06 15:23:49 -04001583 case OPCODE_TEX:
1584 case OPCODE_TEXBEM:
1585 case OPCODE_TEXBEML:
1586 case OPCODE_TEXREG2AR:
1587 case OPCODE_TEXREG2GB:
1588 case OPCODE_TEXM3X2TEX:
1589 case OPCODE_TEXM3X3TEX:
1590 case OPCODE_TEXM3X3SPEC:
1591 case OPCODE_TEXM3X3VSPEC:
1592 case OPCODE_TEXREG2RGB:
1593 case OPCODE_TEXDP3TEX:
1594 case OPCODE_TEXM3X2DEPTH:
1595 case OPCODE_TEXLDD:
1596 case OPCODE_TEXLDL:
John Bauman89401822014-05-06 15:04:28 -04001597 {
John Bauman19bac1e2014-05-06 15:23:49 -04001598 Parameter &dst = instruction[i]->dst;
1599 Parameter &src1 = instruction[i]->src[1];
John Bauman89401822014-05-06 15:04:28 -04001600
1601 if(majorVersion >= 2)
1602 {
John Bauman19bac1e2014-05-06 15:23:49 -04001603 usedSamplers |= 1 << src1.index;
John Bauman89401822014-05-06 15:04:28 -04001604 }
1605 else
1606 {
John Bauman19bac1e2014-05-06 15:23:49 -04001607 usedSamplers |= 1 << dst.index;
John Bauman89401822014-05-06 15:04:28 -04001608 }
1609 }
1610 break;
1611 }
1612 }
1613 }
1614
John Bauman19bac1e2014-05-06 15:23:49 -04001615 // Assigns a unique index to each call instruction, on a per label basis.
1616 // This is used to know what basic block to return to.
1617 void Shader::analyzeCallSites()
John Bauman89401822014-05-06 15:04:28 -04001618 {
John Bauman19bac1e2014-05-06 15:23:49 -04001619 int callSiteIndex[2048] = {0};
John Bauman89401822014-05-06 15:04:28 -04001620
John Bauman19bac1e2014-05-06 15:23:49 -04001621 for(unsigned int i = 0; i < instruction.size(); i++)
1622 {
1623 if(instruction[i]->opcode == OPCODE_CALL || instruction[i]->opcode == OPCODE_CALLNZ)
John Bauman89401822014-05-06 15:04:28 -04001624 {
John Bauman19bac1e2014-05-06 15:23:49 -04001625 int label = instruction[i]->dst.label;
1626
1627 instruction[i]->dst.callSite = callSiteIndex[label]++;
1628 }
1629 }
1630 }
1631
1632 void Shader::analyzeDynamicIndexing()
1633 {
1634 dynamicallyIndexedTemporaries = false;
1635 dynamicallyIndexedInput = false;
1636 dynamicallyIndexedOutput = false;
1637
1638 for(unsigned int i = 0; i < instruction.size(); i++)
1639 {
1640 if(instruction[i]->dst.rel.type == PARAMETER_ADDR ||
1641 instruction[i]->dst.rel.type == PARAMETER_LOOP ||
1642 instruction[i]->dst.rel.type == PARAMETER_TEMP)
1643 {
1644 switch(instruction[i]->dst.type)
John Bauman89401822014-05-06 15:04:28 -04001645 {
John Bauman19bac1e2014-05-06 15:23:49 -04001646 case PARAMETER_TEMP: dynamicallyIndexedTemporaries = true; break;
1647 case PARAMETER_INPUT: dynamicallyIndexedInput = true; break;
1648 case PARAMETER_OUTPUT: dynamicallyIndexedOutput = true; break;
John Bauman89401822014-05-06 15:04:28 -04001649 }
1650 }
1651
John Bauman19bac1e2014-05-06 15:23:49 -04001652 for(int j = 0; j < 3; j++)
1653 {
1654 if(instruction[i]->src[j].rel.type == PARAMETER_ADDR ||
1655 instruction[i]->src[j].rel.type == PARAMETER_LOOP ||
1656 instruction[i]->src[j].rel.type == PARAMETER_TEMP)
1657 {
1658 switch(instruction[i]->src[j].type)
1659 {
1660 case PARAMETER_TEMP: dynamicallyIndexedTemporaries = true; break;
1661 case PARAMETER_INPUT: dynamicallyIndexedInput = true; break;
1662 case PARAMETER_OUTPUT: dynamicallyIndexedOutput = true; break;
1663 }
1664 }
1665 }
John Bauman89401822014-05-06 15:04:28 -04001666 }
1667 }
1668}