From 184c418d353882cb68071eeaf0b9778cbc854101 Mon Sep 17 00:00:00 2001 From: Lewis Smith Date: Wed, 11 May 2022 00:08:11 +0100 Subject: [PATCH] Formatting --- D3D_Shaders/Assembler.cpp | 185 +- HLSLDecompiler/DecompileHLSL.cpp | 4854 ++++++++--------- .../cmd_Decompiler/cmd_Decompiler.cpp | 92 +- 3 files changed, 2527 insertions(+), 2604 deletions(-) diff --git a/D3D_Shaders/Assembler.cpp b/D3D_Shaders/Assembler.cpp index fc4e72fdd..45ac6c782 100644 --- a/D3D_Shaders/Assembler.cpp +++ b/D3D_Shaders/Assembler.cpp @@ -67,7 +67,7 @@ static DWORD strToDWORD(string s) return atoi(s.c_str()); } -static uint64_t str_to_raw_double(string &s) +static uint64_t str_to_raw_double(string& s) { double d; @@ -87,10 +87,10 @@ static string convertF(DWORD original) { char buf[80]; char scientific[80]; - char *scientific_exp = NULL; + char* scientific_exp = NULL; int exp; - float fOriginal = reinterpret_cast(original); + float fOriginal = reinterpret_cast(original); // This printf produces different results depending on the toolchain // and/or SDK we are using. e.g. the value 0x3CAAAAAB will produce: @@ -154,7 +154,7 @@ static string convertD(DWORD v1, DWORD v2) { char buf[80]; uint64_t q = (uint64_t)v1 | ((uint64_t)v2 << 32); - double *d = (double*)&q; + double* d = (double*)&q; if (isnan(*d) || isinf(*d)) { // As above, if we ever get called on a NAN/INF value just @@ -219,7 +219,7 @@ void writeLUT() static void handleSwizzle(string s, token_operand* tOp, bool special = false) { - if (special == true){ + if (special == true) { // Mask tOp->mode = 0; // Mask if (s.size() > 0 && s[0] == 'x') { @@ -243,7 +243,7 @@ static void handleSwizzle(string s, token_operand* tOp, bool special = false) tOp->mode = 0; tOp->comps_enum = 0; return; - } else if(s.size() == 4) { + } else if (s.size() == 4) { // Swizzle tOp->mode = 1; // Swizzle for (int i = 0; i < 4; i++) { @@ -256,7 +256,7 @@ static void handleSwizzle(string s, token_operand* tOp, bool special = false) if (s[i] == 'w') tOp->sel |= 3 << (2 * i); } - } else if (s.size() == 1){ + } else if (s.size() == 1) { tOp->mode = 2; // Scalar if (s[0] == 'x') tOp->sel = 0; @@ -308,7 +308,7 @@ struct special_purpose_register // may interact with this, but this is at least passing all test cases. unsigned comps_enum; - char *name; + char* name; }; static struct special_purpose_register special_purpose_registers[] = { @@ -338,7 +338,7 @@ static struct special_purpose_register special_purpose_registers[] = { // https://msdn.microsoft.com/en-us/library/windows/desktop/hh446903(v=vs.85).aspx }; -static bool assemble_special_purpose_register(string &s, vector &v, token_operand *tOp, bool special) +static bool assemble_special_purpose_register(string& s, vector& v, token_operand* tOp, bool special) { size_t swiz_pos = s.find('.'); int i; @@ -364,7 +364,7 @@ static bool assemble_special_purpose_register(string &s, vector &v, token static vector assembleOp(string s, bool special = false); -static vector assemble_cbvox_operand(string &s, vector &v, token_operand *tOp, bool special, DWORD num) +static vector assemble_cbvox_operand(string& s, vector& v, token_operand* tOp, bool special, DWORD num) { tOp->num_indices = 2; if (s[0] == 'x') { // Indexable temp array @@ -376,7 +376,7 @@ static vector assemble_cbvox_operand(string &s, vector &v, token_o s.erase(s.begin()); } else if (s[0] == 'v') { // Input register tOp->file = 1; - if (s.size() > 4 && s[1] == 'i' && s[2] == 'c' && s[3] == 'p') { // Hull shader vicp + if (s.size() > 4 && s[1] == 'i' && s[2] == 'c' && s[3] == 'p') { // Hull shader vicp tOp->file = 0x19; s.erase(s.begin()); s.erase(s.begin()); @@ -516,7 +516,7 @@ static vector assemble_cbvox_operand(string &s, vector &v, token_o return v; } -static vector assemble_literal_operand(string &s, vector &v, token_operand *tOp) +static vector assemble_literal_operand(string& s, vector& v, token_operand* tOp) { tOp->file = 4; s.erase(s.begin()); @@ -550,7 +550,7 @@ static vector assemble_literal_operand(string &s, vector &v, token return v; } -static vector assemble_double_operand(string &s, vector &v, token_operand *tOp) +static vector assemble_double_operand(string& s, vector& v, token_operand* tOp) { // Examples of double literals (from RE2): // d(0.000000l, 766800.000000l) @@ -615,17 +615,17 @@ static vector assemble_double_operand(string &s, vector &v, token_ return v; } -static DWORD encode_min_precision_type(const char *type) +static DWORD encode_min_precision_type(const char* type) { if (!strncmp(type, "min", 3)) { - if (!strncmp(type+3, "16", 2)) { // min16* - switch(type[5]) { - case 'f': return 1 << 14; - case 'i': return 4 << 14; - case 'u': return 5 << 14; + if (!strncmp(type + 3, "16", 2)) { // min16* + switch (type[5]) { + case 'f': return 1 << 14; + case 'i': return 4 << 14; + case 'u': return 5 << 14; }; } - if (!strncmp(type+3, "2_8f", 4)) // min10float + if (!strncmp(type + 3, "2_8f", 4)) // min10float return 2 << 14; } if (!strncmp(type, "def32", 5)) @@ -634,7 +634,7 @@ static DWORD encode_min_precision_type(const char *type) return 0; } -static void parse_min_precision_tag(string &s, vector &v, token_operand *tOp, DWORD *ext) +static void parse_min_precision_tag(string& s, vector& v, token_operand* tOp, DWORD* ext) { size_t tag; @@ -658,11 +658,11 @@ static void parse_min_precision_tag(string &s, vector &v, token_operand * #if 0 // Debugging size_t as = s.find(" as ", tag + 1); if (as != string::npos) { - string stype1 = s.substr(tag+1, as - tag - 1); + string stype1 = s.substr(tag + 1, as - tag - 1); string stype2 = s.substr(as + 4, s.size() - as - 5); printf("min precision cast from: \"%s\" to: \"%s\"\n", stype1.c_str(), stype2.c_str()); } else { - string stype1 = s.substr(tag+1, s.length() - tag - 2); + string stype1 = s.substr(tag + 1, s.length() - tag - 2); printf("min precision type: \"%s\"\n", stype1.c_str()); } #endif @@ -736,11 +736,11 @@ static vector assembleOp(string s, bool special) return v; if (s[0] == 'i' && s[1] == 'c' && s[2] == 'b' - || s[0] == 'c' && s[1] == 'b' - || s[0] == 'C' && s[1] == 'B' // Compatibility with d3dcompiler_47 disassembly -DarkStarSword - || s[0] == 'x' - || s[0] == 'o' - || s[0] == 'v') { + || s[0] == 'c' && s[1] == 'b' + || s[0] == 'C' && s[1] == 'B' // Compatibility with d3dcompiler_47 disassembly -DarkStarSword + || s[0] == 'x' + || s[0] == 'o' + || s[0] == 'v') { return assemble_cbvox_operand(s, v, tOp, special, num); } @@ -824,7 +824,7 @@ static vector strToWords(string s) // type here to avoid grouping something we don't want // -DarkStarSword: if (end != string::npos && (!s.compare(end, 5, " {min") - || !s.compare(end, 5, " {def"))) { + || !s.compare(end, 5, " {def"))) { // We will match to the next comma or end of line. We // can't just match until the closing brace, because of // cases where minimum precision and absolute value are @@ -1176,7 +1176,7 @@ static unordered_map> insMap = { { "utod", { 2, 0xd9 } }, // Added and verified -DarkStarSword }; -static void assembleResourceDeclarationType(string *type, vector *v) +static void assembleResourceDeclarationType(string* type, vector* v) { // The resource declarations all use the same format strings and // encoding, so do this once, consistently, and handle all confirmed @@ -1206,7 +1206,7 @@ static void assembleResourceDeclarationType(string *type, vector *v) // nothing here will cause a hang! } -static void assembleSystemValue(string *sv, vector *os) +static void assembleSystemValue(string* sv, vector* os) { // All possible system values used in any of the dcl_*_s?v // declarations (s?v = system value). Not all system values make sense @@ -1263,7 +1263,7 @@ static void assembleSystemValue(string *sv, vector *os) // otherwise we might generate a corrupt shader and crash DirectX. } -static int interpolationMode(vector &w, int def) +static int interpolationMode(vector& w, int def) { // https://msdn.microsoft.com/en-us/library/windows/desktop/dn280473(v=vs.85).aspx @@ -1287,7 +1287,7 @@ static int interpolationMode(vector &w, int def) return 2; } -static unsigned parseSyncFlags(string *w) +static unsigned parseSyncFlags(string* w) { unsigned flags = 0; int pos = 4; @@ -1348,7 +1348,7 @@ static unsigned parseSyncFlags(string *w) } -static void check_num_ops(string &s, vector &w, int min_expected, int max_expected = -1) +static void check_num_ops(string& s, vector& w, int min_expected, int max_expected = -1) { int num_operands = (int)w.size() - 1; char buf[80]; @@ -1381,29 +1381,29 @@ static void check_num_ops(string &s, vector &w, int min_expected, int ma } } -static string translate_string_operand(string &in) +static string translate_string_operand(string& in) { // Strip quote characters: string ret = in.substr(1, in.size() - 2); // Translate escape sequences: for (size_t pos = ret.find('\\'); pos < ret.size() - 1; pos = ret.find('\\', pos + 1)) { - switch(ret[pos+1]) { - case 'b': - ret.replace(pos, 2, "\b"); - break; - case 'n': - ret.replace(pos, 2, "\n"); - break; - case 'r': - ret.replace(pos, 2, "\r"); - break; - case 't': - ret.replace(pos, 2, "\t"); - break; - case '\\': - ret.replace(pos, 2, "\\"); - break; + switch (ret[pos + 1]) { + case 'b': + ret.replace(pos, 2, "\b"); + break; + case 'n': + ret.replace(pos, 2, "\n"); + break; + case 'r': + ret.replace(pos, 2, "\r"); + break; + case 't': + ret.replace(pos, 2, "\t"); + break; + case '\\': + ret.replace(pos, 2, "\\"); + break; // The disassembler does not encode all non-printable // characters as escape sequences, so some will show up // as an ambiguous dot "." instead. We could add a @@ -1416,9 +1416,9 @@ static string translate_string_operand(string &in) // Printf/errorf instructions can potentially allow us to extract data from the // shader when the debug layer is enabled, potentially making them quite valuable -static vector assemble_printf(string &s, vector &v, vector &w, bool errorf) +static vector assemble_printf(string& s, vector& v, vector& w, bool errorf) { - shader_ins ins = {0}; + shader_ins ins = { 0 }; ins.opcode = 0x35; ins._11_23 = 0x4; v.push_back(ins.op); @@ -1455,7 +1455,7 @@ static vector assemble_printf(string &s, vector &v, vector return v; } -static vector assemble_undecipherable_custom_data(string &s, vector &v, vector &w) +static vector assemble_undecipherable_custom_data(string& s, vector& v, vector& w) { uint32_t numOps, word, i; @@ -2445,8 +2445,8 @@ static string assembleAndCompare(string s, vector v) // If it's a hex literal it is split over four components instead of two: if (!sNew.compare(lastLiteral + 2, 2, "0x")) lastEnd = sNew.find(",", lastLiteral + 1); - if (v[i-1] != v2[i-1] || v[i] != v2[i]) { - string sLiteral = convertD(v[i-1], v[i]); + if (v[i - 1] != v2[i - 1] || v[i] != v2[i]) { + string sLiteral = convertD(v[i - 1], v[i]); string sBegin = sNew.substr(0, lastLiteral + 2); lastLiteral = sBegin.size(); sBegin.append(sLiteral); @@ -2459,8 +2459,8 @@ static string assembleAndCompare(string s, vector v) if (!sNew.compare(lastLiteral + 2, 2, "0x")) lastLiteral = sNew.find(",", lastLiteral + 1); lastEnd = sNew.find(")", lastLiteral + 1); - if (v[i-1] != v2[i-1] || v[i] != v2[i]) { - string sLiteral = convertD(v[i-1], v[i]); + if (v[i - 1] != v2[i - 1] || v[i] != v2[i]) { + string sLiteral = convertD(v[i - 1], v[i]); string sBegin = sNew.substr(0, lastLiteral + 1); if (sNew[lastLiteral + 1] == ' ') sBegin = sNew.substr(0, lastLiteral + 2); @@ -2610,10 +2610,10 @@ static vector stringToLinesDX9(const char* start, size_t size) { return lines; } -static void hexdump_instruction(string &s, vector &v, - vector &lines, DWORD *i, - int *multiLines, uint32_t line_byte_offset, - int hexdump_mode) +static void hexdump_instruction(string& s, vector& v, + vector& lines, DWORD* i, + int* multiLines, uint32_t line_byte_offset, + int hexdump_mode) { string hd; char buf[16]; @@ -2622,7 +2622,7 @@ static void hexdump_instruction(string &s, vector &v, try { v2 = assembleIns(s.substr(s.find_first_not_of(" "))); - } catch (AssemblerParseError &e) { + } catch (AssemblerParseError& e) { parse_error = e.desc; } @@ -2657,7 +2657,7 @@ static void hexdump_instruction(string &s, vector &v, lines.insert(pos, hd); } -static void encode_custom_data(string &s, vector &v) +static void encode_custom_data(string& s, vector& v) { char buf[16]; @@ -2673,7 +2673,7 @@ static void encode_custom_data(string &s, vector &v) // other differences ("cb" vs "CB" in dcl_constantbuffer lines, number of // digits used in certain number formatting routines), but this is the most // likely to interfere with ShaderRegex patterns. -static inline void patch_d3dcompiler_47_rdef(string *line, int *rdef_state) +static inline void patch_d3dcompiler_47_rdef(string* line, int* rdef_state) { char name[256], type[16], format[16], dim[16], bind_type[16]; int bind_idx, count, numRead; @@ -2683,16 +2683,16 @@ static inline void patch_d3dcompiler_47_rdef(string *line, int *rdef_state) if (line->compare("// Name Type Format Dim HLSL Bind Count")) return; *line = "// Name Type Format Dim Slot Elements"; - ++*rdef_state; + ++* rdef_state; return; case 1: if (!line->compare("// ------------------------------ ---------- ------- ----------- -------------- ------")) *line = "// ------------------------------ ---------- ------- ----------- ---- --------"; - ++*rdef_state; + ++* rdef_state; return; case 2: if (!line->compare("//")) { - ++*rdef_state; + ++* rdef_state; return; } numRead = sscanf_s(line->c_str(), "// %s %s %s %s %[a-z]%d %d", @@ -2701,8 +2701,8 @@ static inline void patch_d3dcompiler_47_rdef(string *line, int *rdef_state) if (numRead == 7) { vector buf(line->length() + 1); // d3dcompiler_47 lines should always be longer _snprintf_s(buf.data(), buf.size(), _TRUNCATE, - "// %-30s %10s %7s %11s %4d %8d", - name, type, format, dim, bind_idx, count); + "// %-30s %10s %7s %11s %4d %8d", + name, type, format, dim, bind_idx, count); *line = buf.data(); } return; @@ -2765,7 +2765,7 @@ static char txt_swiz[] = { // int m_PatchX; // Index: 0 // int m_PatchZ; // Index: 0.y // -static inline void replace_cb_offsets_with_indices(string *line) +static inline void replace_cb_offsets_with_indices(string* line) { int numRead, end1 = 0, end2 = 0; unsigned offset = 0, size = 0; @@ -2805,8 +2805,8 @@ static inline void replace_cb_offsets_with_indices(string *line) // Offset is not on a cb boundary, or this entry has 4 // or less components (if known). Show the swizzle: for (n = 0; first_swiz + n <= (first_idx == last_idx ? last_swiz : first_swiz); n++) - buf[1+n] = txt_swiz[first_swiz + n]; - buf[n+1] = '\0'; + buf[1 + n] = txt_swiz[first_swiz + n]; + buf[n + 1] = '\0'; buf[0] = '.'; n++; *line += buf; } @@ -2814,7 +2814,7 @@ static inline void replace_cb_offsets_with_indices(string *line) if (last_idx > first_idx) { if ((last_idx - first_idx < 4) && (first_swiz == 0 && last_swiz == 3)) { // 2-4 indices, show each for ShaderRegex matching: - for (unsigned i = first_idx+1; i <= last_idx; i++) { + for (unsigned i = first_idx + 1; i <= last_idx; i++) { n += _snprintf_s(buf, 32, _TRUNCATE, " %u", i); *line += buf; } @@ -2833,7 +2833,7 @@ static inline void replace_cb_offsets_with_indices(string *line) } // Minimum 15 character (3 characters x (room for 4 digits + 1 space)) // field length for the above will keep most entries aligned: - for (; n < 3*5; n++) + for (; n < 3 * 5; n++) *line += ' '; if (numRead == 2) { @@ -2851,7 +2851,7 @@ static inline void replace_cb_offsets_with_indices(string *line) } #if MIGOTO_DX == 9 -HRESULT disassemblerDX9(vector *buffer, vector *ret, const char *comment) +HRESULT disassemblerDX9(vector* buffer, vector* ret, const char* comment) { char* asmBuffer; size_t asmSize; @@ -2863,15 +2863,14 @@ HRESULT disassemblerDX9(vector *buffer, vector *ret, const char *com ok = D3DDisassemble(buffer->data(), buffer->size(), NULL, comment, &pDissassembly); if (FAILED(ok)) ok = D3DDisassemble(buffer->data(), buffer->size(), D3D_DISASM_DISABLE_DEBUG_INFO, comment, &pDissassembly); - if (FAILED(ok)){ + if (FAILED(ok)) { //below sometimes give an access violation for some reason //ok = D3DXDisassembleShader((DWORD*)buffer->data(), false, NULL, &pD3DXDissassembly); //if (FAILED(ok)) - return ok; + return ok; //asmBuffer = (char*)pD3DXDissassembly->GetBufferPointer(); //asmSize = pD3DXDissassembly->GetBufferSize(); - } - else { + } else { asmBuffer = (char*)pDissassembly->GetBufferPointer(); asmSize = pDissassembly->GetBufferSize(); } @@ -2891,10 +2890,10 @@ HRESULT disassemblerDX9(vector *buffer, vector *ret, const char *com } #endif -HRESULT disassembler(vector *buffer, vector *ret, const char *comment, - int hexdump, bool d3dcompiler_46_compat, - bool disassemble_undecipherable_data, - bool patch_cb_offsets) +HRESULT disassembler(vector* buffer, vector* ret, const char* comment, + int hexdump, bool d3dcompiler_46_compat, + bool disassemble_undecipherable_data, + bool patch_cb_offsets) { byte fourcc[4]; DWORD fHash[4]; @@ -2931,9 +2930,9 @@ HRESULT disassembler(vector *buffer, vector *ret, const char *commen // We disable debug info in the disassembler as it interferes with our // ability to match assembly lines with bytecode below HRESULT ok = D3DDisassemble(buffer->data(), buffer->size(), - D3D_DISASM_ENABLE_DEFAULT_VALUE_PRINTS | - D3D_DISASM_DISABLE_DEBUG_INFO, - comment, &pDissassembly); + D3D_DISASM_ENABLE_DEFAULT_VALUE_PRINTS | + D3D_DISASM_DISABLE_DEBUG_INFO, + comment, &pDissassembly); if (FAILED(ok)) return ok; @@ -3062,9 +3061,9 @@ HRESULT disassembler(vector *buffer, vector *ret, const char *commen return S_OK; } -static void preprocessLine(string &line) +static void preprocessLine(string& line) { - const char *p; + const char* p; size_t i; for (p = line.c_str(), i = 0; *p; p++, i++) { @@ -3221,8 +3220,8 @@ static vector ComputeHash(byte const* input, DWORD size) // origByteCode is modified in this function, so passing it by value! // asmFile is not modified, so passing it by pointer -DarkStarSword -vector assembler(vector *asmFile, vector origBytecode, - vector *parse_errors) +vector assembler(vector* asmFile, vector origBytecode, + vector* parse_errors) { byte fourcc[4]; DWORD fHash[4]; @@ -3298,7 +3297,7 @@ vector assembler(vector *asmFile, vector origBytecode, vector ins = assembleIns(s); o.insert(o.end(), ins.begin(), ins.end()); } - } catch (AssemblerParseError &e) { + } catch (AssemblerParseError& e) { e.line_no = i + 1; e.update_msg(); @@ -3343,7 +3342,7 @@ vector assembler(vector *asmFile, vector origBytecode, return origBytecode; } #if MIGOTO_DX == 9 -vector assemblerDX9(vector *asmFile) +vector assemblerDX9(vector* asmFile) { vector ret; LPD3DXBUFFER pAssembly; diff --git a/HLSLDecompiler/DecompileHLSL.cpp b/HLSLDecompiler/DecompileHLSL.cpp index c52c51ffd..dc560b980 100644 --- a/HLSLDecompiler/DecompileHLSL.cpp +++ b/HLSLDecompiler/DecompileHLSL.cpp @@ -119,7 +119,7 @@ struct ConstantValue // Convenience routine to calculate just the number of swizzle components. // Used for ibfe. Inputs like 'o1.xy', return 2. -static string swizCount(char *operand) +static string swizCount(char* operand) { if (!operand) return ""; @@ -167,14 +167,14 @@ class Decompiler string mShaderType; string mSV_Position; bool mUsesProjection; - Instruction *mLastStatement; + Instruction* mLastStatement; string mMulOperand, mMulOperand2, mMulTarget; StringStringMap mCorrectedIndexRegisters; StringStringMap mRemappedOutputRegisters; vector > mRemappedInputRegisters; set mBooleanRegisters; - DecompilerSettings *G; + DecompilerSettings* G; vector mOutput; size_t mCodeStartPos; // Used as index into buffer, name misleadingly suggests pointer usage. @@ -192,13 +192,13 @@ class Decompiler nestCount(0) {} - void logDecompileError(const string &err) + void logDecompileError(const string& err) { mErrorOccurred = true; LogInfo(" error parsing shader> %s\n", err.c_str()); } - DataType TranslateType(const char *name) + DataType TranslateType(const char* name) { if (!strcmp(name, "float4x4")) return DT_float4x4; if (!strcmp(name, "float4x3")) return DT_float4x3; @@ -251,22 +251,22 @@ class Decompiler } // Make this bump to new line slightly more clear by making it a convenience routine. - static void NextLine(const char *c, size_t &pos, size_t max) + static void NextLine(const char* c, size_t& pos, size_t max) { - while (c[pos] != 0x0a && pos < max) - pos++; + while (c[pos] != 0x0a && pos < max) + pos++; pos++; } // Just take the current input line, and copy it to the output. // This is used when we aren't sure what to do with something, and gives us the lines // in the output as ASM for reference. Specifically modifying the input pos. - void ASMLineOut(const char *c, size_t &pos, size_t max) + void ASMLineOut(const char* c, size_t& pos, size_t max) { char buffer[256]; - const char *startPos = c + pos; - const char *eolPos = strchr(startPos, '\n'); + const char* startPos = c + pos; + const char* eolPos = strchr(startPos, '\n'); std::string line(startPos, eolPos); sprintf(buffer, "%s\n", line.c_str()); appendOutput(buffer); @@ -298,7 +298,7 @@ class Decompiler // This does also unfortunately create warnings for the TEXCOORD outputs, but // I was unable to find any other way to avoid the fxc packing optimization. - bool SkipPacking(const char *c, map inUse) + bool SkipPacking(const char* c, map inUse) { char name[256], mask[16], sysvalue[16], format[16]; int index, reg1, reg2; format[0] = 0; mask[0] = 0; @@ -360,11 +360,11 @@ class Decompiler // Input Signature, so we are fetching them from the already parsed James- // Jones input. Otherwise we'd need to parse the dcl_input_ps phrases. - string GetInterpolation(Shader *shader, string vRegister) + string GetInterpolation(Shader* shader, string vRegister) { string interpolation = ""; - for each(Declaration declaration in shader->asPhase[MAIN_PHASE].ppsDecl[0]) + for each (Declaration declaration in shader->asPhase[MAIN_PHASE].ppsDecl[0]) { if (declaration.eOpcode == OPCODE_DCL_INPUT_PS) { @@ -380,10 +380,10 @@ class Decompiler // Seen in Arkham Knight interpolation = "nointerpolation "; break; - // Let's skip adding this, as it's the default, and adds noise. - //case INTERPOLATION_LINEAR: - // interpolation = "linear "; - // break; + // Let's skip adding this, as it's the default, and adds noise. + //case INTERPOLATION_LINEAR: + // interpolation = "linear "; + // break; case INTERPOLATION_LINEAR_CENTROID: interpolation = "linear centroid "; break; @@ -419,18 +419,18 @@ class Decompiler // TEXCOORD 1 xy 1 NONE float xy // COLOR 3 xyz 2 NONE float xyz - void ParseInputSignature(Shader *shader, const char *c, size_t size) + void ParseInputSignature(Shader* shader, const char* c, size_t size) { // DataType is not used here, just a convenience for calling SkipPacking. map usedInputRegisters; mRemappedInputRegisters.clear(); // Write header. Extra space handles odd case for no input and no output sections. - const char *inputHeader = "\nvoid main(\n"; + const char* inputHeader = "\nvoid main(\n"; mOutput.insert(mOutput.end(), inputHeader, inputHeader + strlen(inputHeader)); // Read until header. - const char *headerid = "// Input signature:"; + const char* headerid = "// Input signature:"; size_t pos = 0; while (pos < size - strlen(headerid)) { @@ -477,7 +477,7 @@ class Decompiler if (i != usedInputRegisters.end()) { sprintf(registerName, "w%d.", slot); - const char *INDEX_MASK = "xyzw"; + const char* INDEX_MASK = "xyzw"; string newName = registerName; for (size_t j = 0; j < strlen(mask); ++j) newName.push_back(INDEX_MASK[j]); @@ -495,8 +495,7 @@ class Decompiler } sprintf(registerName, "w%d", slot); regNameStr = registerName; - } - else + } else { usedInputRegisters[regNameStr] = TranslateType(format2); } @@ -515,13 +514,13 @@ class Decompiler } } - void ParseOutputSignature(const char *c, size_t size) + void ParseOutputSignature(const char* c, size_t size) { mOutputRegisterType.clear(); mRemappedOutputRegisters.clear(); mSV_Position.clear(); // Read until header. - const char *headerid = "// Output signature:"; + const char* headerid = "// Output signature:"; size_t pos = 0; while (pos < size - strlen(headerid)) { @@ -569,7 +568,7 @@ class Decompiler if (i != mOutputRegisterType.end()) { sprintf(registerName, "p%d.", slot); - const char *INDEX_MASK = "xyzw"; + const char* INDEX_MASK = "xyzw"; string newName = registerName; for (size_t j = 0; j < strlen(mask); ++j) newName.push_back(INDEX_MASK[j]); @@ -595,8 +594,7 @@ class Decompiler if (!strcmp(name, "SV_Position")) mSV_Position = regNameStr; mOutputRegisterType[regNameStr] = TranslateType(format2); - } - else if (numRead == 3) + } else if (numRead == 3) { char reg[64]; char sysValue[64]; @@ -622,14 +620,14 @@ class Decompiler // Write footer. mOutput.pop_back(); mOutput.pop_back(); - const char *mainFooter = ")\n{\n"; + const char* mainFooter = ")\n{\n"; mOutput.insert(mOutput.end(), mainFooter, mainFooter + strlen(mainFooter)); } - void WriteZeroOutputSignature(const char *c, size_t size) + void WriteZeroOutputSignature(const char* c, size_t size) { // Read until header. - const char *headerid = "// Output signature:"; + const char* headerid = "// Output signature:"; size_t pos = 0; while (pos < size - strlen(headerid)) { @@ -667,8 +665,7 @@ class Decompiler { sprintf(registerName, "p%d", slot); regNameStr = registerName; - } - else + } else { outputRegister.insert(regNameStr); } @@ -676,8 +673,7 @@ class Decompiler char buffer[256]; sprintf(buffer, " %s = 0;\n", regNameStr.c_str()); mOutput.insert(mOutput.end(), buffer, buffer + strlen(buffer)); - } - else if (numRead == 3) + } else if (numRead == 3) { char sysValue[64]; int numRead = sscanf_s(c + pos, "// %s %d %s %s %s %s", @@ -700,7 +696,7 @@ class Decompiler } //dx9 - size_t getLineEnd(const char * c, size_t size, size_t & pos, bool & foundLineEnd) + size_t getLineEnd(const char* c, size_t size, size_t& pos, bool& foundLineEnd) { size_t lineStart = pos; while (pos < size) @@ -716,8 +712,7 @@ class Decompiler pos += 2; return pos - lineStart - 2; break; - } - else if (c[pos] == 0x0a) + } else if (c[pos] == 0x0a) { foundLineEnd = true; pos += 1; @@ -750,7 +745,7 @@ class Decompiler v.push_back(s.substr(pos1)); } - void ReadResourceBindingsDX9(const char *c, size_t size) + void ReadResourceBindingsDX9(const char* c, size_t size) { mCBufferNames.clear(); mSamplerNames.clear(); @@ -767,7 +762,7 @@ class Decompiler while (pos < size) { - const char * lineStart = c + pos; + const char* lineStart = c + pos; bool foundLineEnd = false; size_t lineSize = getLineEnd(c, size, pos, foundLineEnd); @@ -783,7 +778,7 @@ class Decompiler break; } - const char * headerid = "// Parameters:"; + const char* headerid = "// Parameters:"; if (!strncmp(lineStart, headerid, strlen(headerid))) { parseParameters = true; @@ -801,7 +796,7 @@ class Decompiler if (parseRegisters) { - char * lineStr = new char[lineSize + 1]; + char* lineStr = new char[lineSize + 1]; memcpy(lineStr, lineStart, lineSize); lineStr[lineSize] = 0; @@ -826,8 +821,7 @@ class Decompiler mTextureNames[slot] = result[1]; mTextureNamesArraySize[slot] = 1; mTextureType[slot] = "Texture2D"; - } - else if (result[2].c_str()[0] == 'c') + } else if (result[2].c_str()[0] == 'c') { int index = atoi(&result[2].c_str()[1]); mUniformNames[index] = result[1]; @@ -842,7 +836,7 @@ class Decompiler } //dx9 - void ReadResourceBindings(const char *c, size_t size) + void ReadResourceBindings(const char* c, size_t size) { mCBufferNames.clear(); mSamplerNames.clear(); @@ -854,7 +848,7 @@ class Decompiler mUAVNames.clear(); mUAVNamesArraySize.clear(); // Read until header. - const char *headerid = "// Resource Bindings:"; + const char* headerid = "// Resource Bindings:"; size_t pos = 0; while (pos < size - strlen(headerid)) { @@ -896,7 +890,7 @@ class Decompiler if (!strcmp(type, "sampler")) { - char *escapePos = strchr(name, '['); if (escapePos) *escapePos = '_'; + char* escapePos = strchr(name, '['); if (escapePos) *escapePos = '_'; escapePos = strchr(name, ']'); if (escapePos) *escapePos = '_'; string baseName = string(name) + "_s"; mSamplerNames[slot] = baseName; @@ -904,13 +898,12 @@ class Decompiler if (arraySize > 1) for (int i = 0; i < arraySize; ++i) { - sprintf(name, "%s[%d]", baseName.c_str(), i); - mSamplerNames[slot + i] = name; + sprintf(name, "%s[%d]", baseName.c_str(), i); + mSamplerNames[slot + i] = name; } - } - else if (!strcmp(type, "sampler_c")) + } else if (!strcmp(type, "sampler_c")) { - char *escapePos = strchr(name, '['); if (escapePos) *escapePos = '_'; + char* escapePos = strchr(name, '['); if (escapePos) *escapePos = '_'; escapePos = strchr(name, ']'); if (escapePos) *escapePos = '_'; string baseName = string(name) + "_s"; mSamplerComparisonNames[slot] = baseName; @@ -918,18 +911,17 @@ class Decompiler if (arraySize > 1) for (int i = 0; i < arraySize; ++i) { - sprintf(name, "%s[%d]", baseName.c_str(), i); - mSamplerComparisonNames[slot + i] = name; + sprintf(name, "%s[%d]", baseName.c_str(), i); + mSamplerComparisonNames[slot + i] = name; } - } - else if (!strcmp(type, "texture") || !strcmp(type, "UAV")) + } else if (!strcmp(type, "texture") || !strcmp(type, "UAV")) { - char *escapePos = strchr(name, '['); if (escapePos) *escapePos = '_'; + char* escapePos = strchr(name, '['); if (escapePos) *escapePos = '_'; escapePos = strchr(name, ']'); if (escapePos) *escapePos = '_'; string baseName = string(name); - map *mNames = &mTextureNames; - map *mNamesArraySize = &mTextureNamesArraySize; - map *mType = &mTextureType; + map* mNames = &mTextureNames; + map* mNamesArraySize = &mTextureNamesArraySize; + map* mType = &mTextureType; std::string rw; if (!strcmp(type, "UAV")) { @@ -944,12 +936,12 @@ class Decompiler if (arraySize > 1) for (int i = 0; i < arraySize; ++i) { - sprintf(name, "%s[%d]", baseName.c_str(), i); - (*mNames)[slot + i] = name; + sprintf(name, "%s[%d]", baseName.c_str(), i); + (*mNames)[slot + i] = name; } if (!strcmp(dim, "1d")) (*mType)[slot] = rw + "Texture1D<" + string(format) + ">"; - else if(!strcmp(dim, "2d")) + else if (!strcmp(dim, "2d")) (*mType)[slot] = rw + "Texture2D<" + string(format) + ">"; else if (!strcmp(dim, "2darray")) (*mType)[slot] = rw + "Texture2DArray<" + string(format) + ">"; @@ -985,8 +977,7 @@ class Decompiler (*mType)[slot] = rw + "ByteAddressBuffer"; else logDecompileError("Unknown " + string(type) + " dimension: " + string(dim)); - } - else if (!strcmp(type, "cbuffer")) + } else if (!strcmp(type, "cbuffer")) mCBufferNames[name] = slot; NextLine(c, pos, size); // End? @@ -1019,8 +1010,7 @@ class Decompiler "};\n", i->second.c_str(), i->first+5); */ mOutput.insert(mOutput.end(), buffer, buffer + strlen(buffer)); - } - else if (mSamplerNamesArraySize[i->first] > 1) + } else if (mSamplerNamesArraySize[i->first] > 1) { string baseName = i->second.substr(0, i->second.find('[')); sprintf(buffer, "SamplerState %s[%d] : register(s%d);\n", baseName.c_str(), mSamplerNamesArraySize[i->first], i->first); @@ -1045,8 +1035,7 @@ class Decompiler "};\n", i->second.c_str(), i->first+5); */ mOutput.insert(mOutput.end(), buffer, buffer + strlen(buffer)); - } - else if (mSamplerComparisonNamesArraySize[i->first] > 1) + } else if (mSamplerComparisonNamesArraySize[i->first] > 1) { string baseName = i->second.substr(0, i->second.find('[')); sprintf(buffer, "SamplerComparisonState %s[%d] : register(s%d);\n", baseName.c_str(), mSamplerComparisonNamesArraySize[i->first], i->first); @@ -1059,8 +1048,7 @@ class Decompiler { sprintf(buffer, "%s %s : register(t%d);\n", mTextureType[i->first].c_str(), i->second.c_str(), i->first); mOutput.insert(mOutput.end(), buffer, buffer + strlen(buffer)); - } - else if (mTextureNamesArraySize[i->first] > 1) + } else if (mTextureNamesArraySize[i->first] > 1) { string baseName = i->second.substr(0, i->second.find('[')); sprintf(buffer, "%s %s[%d] : register(t%d);\n", mTextureType[i->first].c_str(), baseName.c_str(), mTextureNamesArraySize[i->first], i->first); @@ -1073,8 +1061,7 @@ class Decompiler { sprintf(buffer, "%s %s : register(u%d);\n", mUAVType[i->first].c_str(), i->second.c_str(), i->first); mOutput.insert(mOutput.end(), buffer, buffer + strlen(buffer)); - } - else if (mUAVNamesArraySize[i->first] > 1) + } else if (mUAVNamesArraySize[i->first] > 1) { string baseName = i->second.substr(0, i->second.find('[')); sprintf(buffer, "%s %s[%d] : register(u%d);\n", mUAVType[i->first].c_str(), baseName.c_str(), mUAVNamesArraySize[i->first], i->first); @@ -1087,41 +1074,41 @@ class Decompiler { switch (d) { - case DT_bool: - case DT_uint: - case DT_int: - case DT_float: - return 4; - case DT_float2: - case DT_uint2: - case DT_int2: - return 8; - case DT_float3: - case DT_uint3: - case DT_int3: - return 12; - case DT_bool4: - case DT_float4: - case DT_uint4: - case DT_int4: - return 16; - case DT_float2x4: - case DT_float4x2: - return 32; - case DT_float3x3: - return 36; - case DT_float3x4: - return 48; - case DT_float4x3: - return 48; - case DT_float4x4: - return 64; + case DT_bool: + case DT_uint: + case DT_int: + case DT_float: + return 4; + case DT_float2: + case DT_uint2: + case DT_int2: + return 8; + case DT_float3: + case DT_uint3: + case DT_int3: + return 12; + case DT_bool4: + case DT_float4: + case DT_uint4: + case DT_int4: + return 16; + case DT_float2x4: + case DT_float4x2: + return 32; + case DT_float3x3: + return 36; + case DT_float3x4: + return 48; + case DT_float4x3: + return 48; + case DT_float4x4: + return 64; } logDecompileError("Unknown data type in getDataTypeSize"); return 0; } - void ParseBufferDefinitions(Shader *shader, const char *c, size_t size) + void ParseBufferDefinitions(Shader* shader, const char* c, size_t size) { mUsesProjection = false; mCBufferData.clear(); @@ -1135,7 +1122,7 @@ class Decompiler vector pendingStructAttributes[8]; int structLevel = -1; // Search for buffer. - const char *headerid = "// cbuffer "; + const char* headerid = "// cbuffer "; size_t pos = 0; while (pos < size - strlen(headerid)) { @@ -1174,7 +1161,7 @@ class Decompiler mOutput.insert(mOutput.end(), buffer, buffer + strlen(buffer)); do { - const char *eolPos = strchr(c + pos, '\n'); + const char* eolPos = strchr(c + pos, '\n'); memcpy(buffer, c + pos, eolPos - c - pos + 1); buffer[eolPos - c - pos + 1] = 0; // Skip opening bracket. @@ -1204,7 +1191,7 @@ class Decompiler { mOutput.insert(mOutput.end(), ' '); mOutput.insert(mOutput.end(), ' '); } - const char *structHeader = strstr(buffer, "struct"); + const char* structHeader = strstr(buffer, "struct"); // Can't use structure declaration: If we use the structure name, it has to be copied on top. //if (structLevel) structHeader = "struct\n"; @@ -1213,7 +1200,7 @@ class Decompiler { mOutput.push_back(' '); mOutput.push_back(' '); } - const char *structHeader2 = "{\n"; + const char* structHeader2 = "{\n"; mOutput.insert(mOutput.end(), structHeader2, structHeader2 + strlen(structHeader2)); //skip struct's next line"// {\r\n" //dx9 (Was there a point to this commented out line? -DSS) NextLine(c, pos, size); @@ -1259,8 +1246,7 @@ class Decompiler if (structLevel) pendingStructAttributes[structLevel - 1].push_back(*i); } - } - else + } else { int arraySize; if (sscanf_s(structName.c_str() + arrayPos + 1, "%d", &arraySize) != 1) @@ -1370,11 +1356,11 @@ class Decompiler size_t ep = e.Name.find('['); if (ep != string::npos && (e.bt == DT_bool || e.bt == DT_bool4 || - e.bt == DT_float || e.bt == DT_float2 || e.bt == DT_float3 || e.bt == DT_float4 || - e.bt == DT_uint || e.bt == DT_uint2 || e.bt == DT_uint3 || e.bt == DT_uint4 || - e.bt == DT_int || e.bt == DT_int2 || e.bt == DT_int3 || e.bt == DT_int4 || - e.bt == DT_float4x4 || e.bt == DT_float3x4 || e.bt == DT_float4x3 || e.bt == DT_float3x3 || - e.bt == DT_float4x2 || e.bt == DT_float2x4)) + e.bt == DT_float || e.bt == DT_float2 || e.bt == DT_float3 || e.bt == DT_float4 || + e.bt == DT_uint || e.bt == DT_uint2 || e.bt == DT_uint3 || e.bt == DT_uint4 || + e.bt == DT_int || e.bt == DT_int2 || e.bt == DT_int3 || e.bt == DT_int4 || + e.bt == DT_float4x4 || e.bt == DT_float3x4 || e.bt == DT_float4x3 || e.bt == DT_float3x3 || + e.bt == DT_float4x2 || e.bt == DT_float2x4)) { // Register each array element. int numElements = 0; @@ -1393,8 +1379,8 @@ class Decompiler // Correct possible invalid array size. (16 byte boundaries) int byteSize; sscanf_s(strstr(c + pos, "Size:") + 5, "%d", &byteSize); - if ((counter == 4 && numElements*counter < byteSize) || - (counter == 12 && numElements*counter < byteSize)) + if ((counter == 4 && numElements * counter < byteSize) || + (counter == 12 && numElements * counter < byteSize)) counter = 16; for (int i = 0; i < numElements; ++i) @@ -1405,29 +1391,29 @@ class Decompiler switch (e.bt) { - case DT_float4x4: - case DT_float3x4: - case DT_float2x4: // Not positive this is right - e.matrixRow = 3; - offsetPos = (bufferRegister << 16) + offset + i*counter + 3 * 16; - mCBufferData[offsetPos] = e; if (structLevel >= 0) pendingStructAttributes[structLevel].push_back(offsetPos); - case DT_float4x3: - case DT_float3x3: - e.matrixRow = 2; - offsetPos = (bufferRegister << 16) + offset + i*counter + 2 * 16; - mCBufferData[offsetPos] = e; if (structLevel >= 0) pendingStructAttributes[structLevel].push_back(offsetPos); - case DT_float4x2: - e.matrixRow = 1; - offsetPos = (bufferRegister << 16) + offset + i*counter + 1 * 16; - mCBufferData[offsetPos] = e; if (structLevel >= 0) pendingStructAttributes[structLevel].push_back(offsetPos); - e.matrixRow = 0; - offsetPos = (bufferRegister << 16) + offset + i*counter; - mCBufferData[offsetPos] = e; if (structLevel >= 0) pendingStructAttributes[structLevel].push_back(offsetPos); + case DT_float4x4: + case DT_float3x4: + case DT_float2x4: // Not positive this is right + e.matrixRow = 3; + offsetPos = (bufferRegister << 16) + offset + i * counter + 3 * 16; + mCBufferData[offsetPos] = e; if (structLevel >= 0) pendingStructAttributes[structLevel].push_back(offsetPos); + case DT_float4x3: + case DT_float3x3: + e.matrixRow = 2; + offsetPos = (bufferRegister << 16) + offset + i * counter + 2 * 16; + mCBufferData[offsetPos] = e; if (structLevel >= 0) pendingStructAttributes[structLevel].push_back(offsetPos); + case DT_float4x2: + e.matrixRow = 1; + offsetPos = (bufferRegister << 16) + offset + i * counter + 1 * 16; + mCBufferData[offsetPos] = e; if (structLevel >= 0) pendingStructAttributes[structLevel].push_back(offsetPos); + e.matrixRow = 0; + offsetPos = (bufferRegister << 16) + offset + i * counter; + mCBufferData[offsetPos] = e; if (structLevel >= 0) pendingStructAttributes[structLevel].push_back(offsetPos); - break; - default: - offsetPos = (bufferRegister << 16) + offset + i*counter; - mCBufferData[offsetPos] = e; if (structLevel >= 0) pendingStructAttributes[structLevel].push_back(offsetPos); + break; + default: + offsetPos = (bufferRegister << 16) + offset + i * counter; + mCBufferData[offsetPos] = e; if (structLevel >= 0) pendingStructAttributes[structLevel].push_back(offsetPos); } } } @@ -1435,17 +1421,17 @@ class Decompiler else if (e.bt == DT_float4x2 || e.bt == DT_float3x3 || e.bt == DT_float4x3 || e.bt == DT_float2x4 || e.bt == DT_float3x4 || e.bt == DT_float4x4) { - e.matrixRow = 0; int offsetPos = (bufferRegister << 16) + offset; + e.matrixRow = 0; int offsetPos = (bufferRegister << 16) + offset; mCBufferData[offsetPos] = e; if (structLevel >= 0) pendingStructAttributes[structLevel].push_back(offsetPos); - e.matrixRow = 1; offsetPos = (bufferRegister << 16) + offset + 1 * 16; + e.matrixRow = 1; offsetPos = (bufferRegister << 16) + offset + 1 * 16; mCBufferData[offsetPos] = e; if (structLevel >= 0) pendingStructAttributes[structLevel].push_back(offsetPos); if (e.bt != DT_float4x2) { - e.matrixRow = 2; offsetPos = (bufferRegister << 16) + offset + 2 * 16; + e.matrixRow = 2; offsetPos = (bufferRegister << 16) + offset + 2 * 16; mCBufferData[offsetPos] = e; if (structLevel >= 0) pendingStructAttributes[structLevel].push_back(offsetPos); if (e.bt != DT_float4x3 && e.bt != DT_float3x3) { // Nearly sure this missing nesting was a bug - e.matrixRow = 3; offsetPos = (bufferRegister << 16) + offset + 3 * 16; + e.matrixRow = 3; offsetPos = (bufferRegister << 16) + offset + 3 * 16; mCBufferData[offsetPos] = e; if (structLevel >= 0) pendingStructAttributes[structLevel].push_back(offsetPos); } } @@ -1459,7 +1445,7 @@ class Decompiler // Default value? NextLine(c, pos, size); - const char *defaultid = "// = "; + const char* defaultid = "// = "; int packoffset = offset / 16; int suboffset = (offset % 16) / 4; const char INDEX_MASK[] = "xyzw"; string structSpacing; @@ -1483,8 +1469,7 @@ class Decompiler sprintf(buffer, " %s%s %s : packoffset(c%d) = %s;\n", modifier.c_str(), type, name, packoffset, bString.c_str()); else sprintf(buffer, " %s%s %s : packoffset(c%d.%c) = %s;\n", modifier.c_str(), type, name, packoffset, INDEX_MASK[suboffset], bString.c_str()); - } - else + } else sprintf(buffer, " %s%s%s %s = %s;\n", structSpacing.c_str(), modifier.c_str(), type, name, bString.c_str()); mOutput.insert(mOutput.end(), buffer, buffer + strlen(buffer)); } @@ -1502,10 +1487,9 @@ class Decompiler sprintf(buffer, " %s%s %s : packoffset(c%d) = {", modifier.c_str(), type, name, packoffset); else sprintf(buffer, " %s%s %s : packoffset(c%d.%c) = {", modifier.c_str(), type, name, packoffset, INDEX_MASK[suboffset]); - } - else + } else sprintf(buffer, " %s%s%s %s = {", structSpacing.c_str(), modifier.c_str(), type, name); - + mOutput.insert(mOutput.end(), buffer, buffer + strlen(buffer)); for (int i = 0; i < numRead - 1; ++i) @@ -1515,8 +1499,7 @@ class Decompiler } sprintf(buffer, "%i};\n", in[numRead - 1]); mOutput.insert(mOutput.end(), buffer, buffer + strlen(buffer)); - } - else if (e.bt == DT_float || e.bt == DT_float2 || e.bt == DT_float3 || e.bt == DT_float4) + } else if (e.bt == DT_float || e.bt == DT_float2 || e.bt == DT_float3 || e.bt == DT_float4) { float v[4] = { 0, 0, 0, 0 }; numRead = sscanf_s(c + pos, "// = 0x%lx 0x%lx 0x%lx 0x%lx", (unsigned long*)v + 0, (unsigned long*)v + 1, (unsigned long*)v + 2, (unsigned long*)v + 3); @@ -1528,8 +1511,7 @@ class Decompiler sprintf(buffer, " %s%s %s : packoffset(c%d) = {", modifier.c_str(), type, name, packoffset); else sprintf(buffer, " %s%s %s : packoffset(c%d.%c) = {", modifier.c_str(), type, name, packoffset, INDEX_MASK[suboffset]); - } - else + } else sprintf(buffer, " %s%s%s %s = {", structSpacing.c_str(), modifier.c_str(), type, name); mOutput.insert(mOutput.end(), buffer, buffer + strlen(buffer)); @@ -1563,8 +1545,7 @@ class Decompiler sprintf(buffer, " %s%s %s : packoffset(c%d) = {", modifier.c_str(), type, name, packoffset); else sprintf(buffer, " %s%s %s : packoffset(c%d.%c) = {", modifier.c_str(), type, name, packoffset, INDEX_MASK[suboffset]); - } - else + } else sprintf(buffer, " %s%s%s %s = {", structSpacing.c_str(), modifier.c_str(), type, name); mOutput.insert(mOutput.end(), buffer, buffer + strlen(buffer)); @@ -1590,7 +1571,7 @@ class Decompiler NextLine(c, pos, size); // Loop through any remaining constant declarations to output - const char *con = "// 0x"; + const char* con = "// 0x"; while (!strncmp(c + pos, con, strlen(con))) { ASMLineOut(c, pos, size); @@ -1607,21 +1588,20 @@ class Decompiler sprintf(buffer, " %s%s %s : packoffset(c%d);\n", modifier.c_str(), type, name, packoffset); else sprintf(buffer, " %s%s %s : packoffset(c%d.%c);\n", modifier.c_str(), type, name, packoffset, INDEX_MASK[suboffset]); - } - else + } else sprintf(buffer, " %s%s%s %s;\n", structSpacing.c_str(), modifier.c_str(), type, name); mOutput.insert(mOutput.end(), buffer, buffer + strlen(buffer)); } } while (strncmp(c + pos, "// }", 4)); - + // Write closing declaration. - const char *endBuffer = "}\n"; + const char* endBuffer = "}\n"; mOutput.insert(mOutput.end(), endBuffer, endBuffer + strlen(endBuffer)); } } // TODO: Convert other parsers to use this helper - static size_t find_next_header(const char *headerid, const char *c, size_t pos, size_t size) + static size_t find_next_header(const char* headerid, const char* c, size_t pos, size_t size) { size_t header_len = strlen(headerid); @@ -1635,18 +1615,18 @@ class Decompiler return 0; } - bool warn_if_line_is_not(const char *expect, const char *c) + bool warn_if_line_is_not(const char* expect, const char* c) { if (strncmp(c, expect, strlen(expect))) { logDecompileError("WARNING: Unexpected string in shader" - "\n Expected: " + string(expect) + - "\n Found: " + string(c, 80)); + "\n Expected: " + string(expect) + + "\n Found: " + string(c, 80)); return true; } return false; } - void ParseStructureDefinitions(Shader *shader, const char *c, size_t size) + void ParseStructureDefinitions(Shader* shader, const char* c, size_t size) { // Pulls out struct type declaration for structured buffers. // These will be referenced later when parsing the resource @@ -1775,7 +1755,7 @@ class Decompiler } } - static void applySwizzleLiteral(char *right, char *right2, bool useInt, size_t pos, char idx[4]) + static void applySwizzleLiteral(char* right, char* right2, bool useInt, size_t pos, char idx[4]) { // Single literal? if (!strchr(right, ',')) @@ -1785,13 +1765,13 @@ class Decompiler return; } - char *beginPos = right + 2; + char* beginPos = right + 2; float args[4]; unsigned hex_args[4]; bool is_hex[4]; for (int i = 0; i < 4; ++i) { - char *endPos = strchr(beginPos, ','); + char* endPos = strchr(beginPos, ','); if (endPos) *endPos = 0; sscanf_s(beginPos, "%f", args + i); is_hex[i] = (sscanf_s(beginPos, " 0x%x", hex_args + i) == 1); @@ -1800,8 +1780,7 @@ class Decompiler if (pos == 1) { sprintf_s(right2, opcodeSize, "%.9g", args[idx[0]]); - } - else + } else { // Only integer values? bool isInt = true; @@ -1818,8 +1797,7 @@ class Decompiler } right2[strlen(right2) - 1] = 0; strcat_s(right2, opcodeSize, ")"); - } - else + } else { sprintf_s(right2, opcodeSize, "float%Id(", pos); for (int i = 0; idx[i] >= 0 && i < 4; ++i) @@ -1830,7 +1808,7 @@ class Decompiler } } - void applySwizzle(const char *left, char *right, bool useInt = false) + void applySwizzle(const char* left, char* right, bool useInt = false) { char right2[opcodeSize]; @@ -1875,11 +1853,11 @@ class Decompiler // Fairly bold change here- this fetches the source swizzle from 'left', and it previously would // find the first dot in the string. That's not right for left side array indices, so I changed it // to look for the far right dot instead. Should be correct, but this is used everywhere. - const char *strPos = strrchr(left, '.') + 1; + const char* strPos = strrchr(left, '.') + 1; char idx[4] = { -1, -1, -1, -1 }; char map[4] = { 3, 0, 1, 2 }; size_t pos = 0; // Used as index into string buffer - if (strPos == (const char *)1) + if (strPos == (const char*)1) strPos = "x"; while (*strPos && pos < 4) idx[pos++] = map[*strPos++ - 'w']; @@ -1892,7 +1870,7 @@ class Decompiler //dx9 const register, start with c // FIXME: Refactor this into a dedicated function - char * result = strrchr(right, '.'); + char* result = strrchr(right, '.'); if (result == NULL) //if don't have swizzle info,add .xyzw { strcat_s(right, opcodeSize, ".xyzw"); @@ -1912,7 +1890,7 @@ class Decompiler right2[pos] = 0; } - const char *strPos1 = strrchr(right2, '.') + 1; + const char* strPos1 = strrchr(right2, '.') + 1; char idx1[4] = { -1, -1, -1, -1 }; size_t pos1 = 0; while (*strPos1 && pos1 < 4) @@ -1920,7 +1898,7 @@ class Decompiler char buff[opcodeSize]; char suffix[opcodeSize]; - char * pos = strchr(right2, '.'); + char* pos = strchr(right2, '.'); if (pos != NULL) { strncpy(buff, right2, pos - right2); @@ -1928,8 +1906,7 @@ class Decompiler size_t len = strlen(right2) - (right2 - pos) - 1; strncpy(suffix, pos + 1, len); suffix[len] = 0; - } - else + } else { strcpy_s(buff, opcodeSize, right2); suffix[0] = 0; @@ -1957,16 +1934,13 @@ class Decompiler if (idx1[i] == 0) { sprintf_s(buff, opcodeSize, "%s %f", buff, cit->second.x); - } - else if (idx1[i] == 1) + } else if (idx1[i] == 1) { sprintf_s(buff, opcodeSize, "%s %f", buff, cit->second.y); - } - else if (idx1[i] == 2) + } else if (idx1[i] == 2) { sprintf_s(buff, opcodeSize, "%s %f", buff, cit->second.z); - } - else if (idx1[i] == 3) + } else if (idx1[i] == 3) { sprintf_s(buff, opcodeSize, "%s %f", buff, cit->second.w); } @@ -1974,16 +1948,15 @@ class Decompiler } strcpy_s(right2, opcodeSize, buff); - /*else if (right[0] == 'v') - + { - + strcpy_s(right2, opcodeSize, right); - + }*/ - //dx9 - } - else + /*else if (right[0] == 'v') + + { + + strcpy_s(right2, opcodeSize, right); + + }*/ + //dx9 + } else { //dx9 - char * result = strrchr(right, '.'); + char* result = strrchr(right, '.'); if (result == NULL) //if don't have swizzle info,add .xyzw { strcat_s(right, opcodeSize, ".xyzw"); @@ -1991,7 +1964,7 @@ class Decompiler //dx9 strPos = strrchr(right, '.') + 1; - if (strPos == (const char *)1) { + if (strPos == (const char*)1) { // If there's no '.' in the string, strrchr // will have returned a NULL pointer. If we // were to continue we would write a 0 to a @@ -2027,7 +2000,7 @@ class Decompiler int bufIndex = 0; int bufOffset; char regAndSwiz[opcodeSize]; - + // By scanning these in this order, we are sure to cover every variant, without mismatches. // We use the unusual format of [^+] for the string lookup because ReadStatement has already // crushed the spaces out of the input. @@ -2078,8 +2051,7 @@ class Decompiler { bufIndex = -1; // -1 is used as 'index' for icb entries. bufOffset = 0; - } - else + } else { logDecompileError("Error parsing buffer register, unknown variant: " + string(right2)); return; @@ -2127,7 +2099,7 @@ class Decompiler if (i->second.bt == DT_float || i->second.bt == DT_uint || i->second.bt == DT_int) skip = 1; else if (i->second.bt == DT_float2 || i->second.bt == DT_uint2 || i->second.bt == DT_int2) skip = 2; else if (i->second.bt == DT_float3 || i->second.bt == DT_uint3 || i->second.bt == DT_int3) skip = 3; - char *dotPos = strrchr(right2, '.'); + char* dotPos = strrchr(right2, '.'); int lowOffset = dotPos[1] - 'x'; if (dotPos[1] == 'w') lowOffset = 3; if (lowOffset >= skip) { @@ -2143,7 +2115,7 @@ class Decompiler logDecompileError("Error parsing buffer low offset: " + string(right2)); return; } - const char *INDEX_MASK = "xyzw"; + const char* INDEX_MASK = "xyzw"; for (int cpos = 1; dotPos[cpos] >= 'w' && dotPos[cpos] <= 'z'; ++cpos) { lowOffset = dotPos[cpos] - 'x'; if (dotPos[cpos] == 'w') lowOffset = 3; @@ -2162,7 +2134,7 @@ class Decompiler if (regAndSwiz[0]) { // Remove existing index. - char *indexPos = strchr(right3, '['); + char* indexPos = strchr(right3, '['); if (indexPos) *indexPos = 0; string indexRegisterName(regAndSwiz, strchr(regAndSwiz, '.')); StringStringMap::iterator isCorrected = mCorrectedIndexRegisters.find(indexRegisterName); @@ -2171,17 +2143,15 @@ class Decompiler char newOperand[opcodeSize]; strcpy(newOperand, isCorrected->second.c_str()); applySwizzle(regAndSwiz, newOperand, true); sprintf_s(right3 + strlen(right3), sizeof(right3) - strlen(right3), "[%s]", newOperand); - } - else if (mLastStatement && mLastStatement->eOpcode == OPCODE_IMUL && + } else if (mLastStatement && mLastStatement->eOpcode == OPCODE_IMUL && (i->second.bt == DT_float4x4 || i->second.bt == DT_float4x3 || i->second.bt == DT_float4x2 || i->second.bt == DT_float2x4 || - i->second.bt == DT_float3x4 || i->second.bt == DT_float3x3)) + i->second.bt == DT_float3x4 || i->second.bt == DT_float3x3)) { char newOperand[opcodeSize]; strcpy(newOperand, mMulOperand.c_str()); applySwizzle(regAndSwiz, newOperand, true); sprintf_s(right3 + strlen(right3), sizeof(right3) - strlen(right3), "[%s]", newOperand); mCorrectedIndexRegisters[indexRegisterName] = mMulOperand; - } - else if (i->second.bt == DT_float4x2 || i->second.bt == DT_float2x4) + } else if (i->second.bt == DT_float4x2 || i->second.bt == DT_float2x4) sprintf_s(right3 + strlen(right3), sizeof(right3) - strlen(right3), "[%s/2]", regAndSwiz); else if (i->second.bt == DT_float4x3 || i->second.bt == DT_float3x4) sprintf_s(right3 + strlen(right3), sizeof(right3) - strlen(right3), "[%s/3]", regAndSwiz); @@ -2194,7 +2164,7 @@ class Decompiler // Bug was to not handle the struct case here, and truncate string. // Like g_OmniLights[r5.w].m_PositionFar -> g_OmniLights[r5.w] //sprintf(right3 + strlen(right3), "[%s]", indexRegister); - + // Start fresh with original string and just replace, not char* manipulate. // base e.g: g_OmniLights[0].m_PositionFar string base = i->second.Name; @@ -2212,8 +2182,7 @@ class Decompiler { // e.g. cb0[r21.y + 55] -> PointLight[r21.y] base.replace(left, length, regAndSwiz); - } - else + } else { // leave it named with register and bufOffset, e.g. cb0[r19.w + 63] -> Globals[r19.w+63] char regAndOffset[opcodeSize]; @@ -2235,23 +2204,22 @@ class Decompiler { switch (*strPos) { - case 'x': - sprintf_s(right3 + strlen(right3), sizeof(right3) - strlen(right3), i->second.isRowMajor ? "_m%d0" : "_m0%d", i->second.matrixRow); - break; - case 'y': - sprintf_s(right3 + strlen(right3), sizeof(right3) - strlen(right3), i->second.isRowMajor ? "_m%d1" : "_m1%d", i->second.matrixRow); - break; - case 'z': - sprintf_s(right3 + strlen(right3), sizeof(right3) - strlen(right3), i->second.isRowMajor ? "_m%d2" : "_m2%d", i->second.matrixRow); - break; - case 'w': - sprintf_s(right3 + strlen(right3), sizeof(right3) - strlen(right3), i->second.isRowMajor ? "_m%d3" : "_m3%d", i->second.matrixRow); - break; - default: logDecompileError("Error parsing matrix index: " + string(right2)); + case 'x': + sprintf_s(right3 + strlen(right3), sizeof(right3) - strlen(right3), i->second.isRowMajor ? "_m%d0" : "_m0%d", i->second.matrixRow); + break; + case 'y': + sprintf_s(right3 + strlen(right3), sizeof(right3) - strlen(right3), i->second.isRowMajor ? "_m%d1" : "_m1%d", i->second.matrixRow); + break; + case 'z': + sprintf_s(right3 + strlen(right3), sizeof(right3) - strlen(right3), i->second.isRowMajor ? "_m%d2" : "_m2%d", i->second.matrixRow); + break; + case 'w': + sprintf_s(right3 + strlen(right3), sizeof(right3) - strlen(right3), i->second.isRowMajor ? "_m%d3" : "_m3%d", i->second.matrixRow); + break; + default: logDecompileError("Error parsing matrix index: " + string(right2)); } } - } - else + } else { strPos = strrchr(right2, '.'); strcat(right3, strPos + 1); @@ -2274,12 +2242,12 @@ class Decompiler char statement[128], op1[opcodeSize], op2[opcodeSize], op3[opcodeSize], op4[opcodeSize], op5[opcodeSize], op6[opcodeSize], op7[opcodeSize], op8[opcodeSize], op9[opcodeSize], op10[opcodeSize], op11[opcodeSize], op12[opcodeSize], op13[opcodeSize], op14[opcodeSize], op15[opcodeSize]; - int ReadStatement(const char *pos) + int ReadStatement(const char* pos) { // Kill newline. char lineBuffer[256]; strncpy(lineBuffer, pos, 255); lineBuffer[255] = 0; - char *newlinePos = strchr(lineBuffer, '\n'); if (newlinePos) *newlinePos = 0; + char* newlinePos = strchr(lineBuffer, '\n'); if (newlinePos) *newlinePos = 0; op1[0] = 0; op2[0] = 0; op3[0] = 0; op4[0] = 0; op5[0] = 0; op6[0] = 0; op7[0] = 0; op8[0] = 0; op9[0] = 0; op10[0] = 0; op11[0] = 0; op12[0] = 0; op13[0] = 0; op14[0] = 0; op15[0] = 0; @@ -2403,10 +2371,10 @@ class Decompiler return buffer; } - string GetSuffix(char *s, int index) + string GetSuffix(char* s, int index) { if (s[strlen(s) - 1] == ',') s[strlen(s) - 1] = 0; - char *dotPos = strrchr(s, '.'); + char* dotPos = strrchr(s, '.'); // Single byte? if (dotPos && dotPos[1] >= 'w' && dotPos[1] <= 'z') { @@ -2439,7 +2407,7 @@ class Decompiler if (index == 2) { dotPos = strchr(s, ',') + 1; - char *endPos = strchr(dotPos, ','); + char* endPos = strchr(dotPos, ','); if (!endPos) endPos = strchr(dotPos, ')'); string buffer = endPos + 1; buffer.resize(buffer.find_first_of(",)")); @@ -2463,9 +2431,9 @@ class Decompiler // the constant to match. So, for example, float4(0.5, 0.5, 0, 0) with Texture2D // becomes float2(0.5, 0.5) as the two elements. - void truncateTexturePos(char *op, const char *textype) + void truncateTexturePos(char* op, const char* textype) { - char *cpos; + char* cpos; if (!strncmp(op, "float", 5)) { @@ -2477,8 +2445,7 @@ class Decompiler cpos[0] = ')'; cpos[1] = 0; op[5] = '2'; // now: float2(x,y) - } - else if (!strncmp(textype, "Texture3D", 9)) + } else if (!strncmp(textype, "Texture3D", 9)) { cpos = strchr(op, ','); cpos++; @@ -2488,13 +2455,11 @@ class Decompiler cpos[0] = ')'; cpos[1] = 0; op[5] = '3'; // now: float3(x,y,z) - } - else // if (!strncmp(textype, "TextureCube", 11) || !strncmp(textype, "TextureCubeArray", 11)) + } else // if (!strncmp(textype, "TextureCube", 11) || !strncmp(textype, "TextureCubeArray", 11)) { // left as: float4(x,y,z,w) } - } - else + } else { // Normal variant like r1.xyxx int pos = 5; @@ -2519,12 +2484,12 @@ class Decompiler // The reason there is a second version of this .xyzw truncator, is because this version is for the _LD // operands, and for that version it's one parameter larger. Texture2D is 3 components, not 2 for this one. // The extra bracket for comparison is to avoid early mismatch like Texture1D instead of Texture1DArray. - void truncateTextureLoadPos(char *op, const char *textype) + void truncateTextureLoadPos(char* op, const char* textype) { if (!strncmp(op, "float", 5)) return; - int pos = 5; + int pos = 5; if (!strncmp(textype, "Buffer<", strlen("Buffer<"))) pos = 2; // int .x else if (!strncmp(textype, "Texture1D<", strlen("Texture1D<"))) pos = 3; // int2 .xy else if (!strncmp(textype, "Texture2DMS<", strlen("Texture2DMS<"))) pos = 3; @@ -2534,17 +2499,17 @@ class Decompiler else if (!strncmp(textype, "Texture2DArray<", strlen("Texture2DArray<"))) pos = 5; // int4 .xyzw else if (!strncmp(textype, "Texture3D<", strlen("Texture3D<"))) pos = 5; else logDecompileError(" unknown texture type for truncation: " + string(textype)); - char *cpos = strrchr(op, '.'); + char* cpos = strrchr(op, '.'); cpos[pos] = 0; } // Lops off excess mask/swizzle for textures of float1/2/3 or other vector // types to eliminate invalid subscript errors - static void truncateTextureSwiz(char *op, const char *textype) + static void truncateTextureSwiz(char* op, const char* textype) { // Search for the end of the type, either a comma // (Texture2DMS) or the closing > - const char *tpos = strchr(textype, ','); + const char* tpos = strchr(textype, ','); if (!tpos) tpos = strchr(textype, '>'); if (!tpos) @@ -2559,24 +2524,24 @@ class Decompiler pos = 3; else // float1, float, etc pos = 2; - char *cpos = strrchr(op, '.'); + char* cpos = strrchr(op, '.'); if (strlen(cpos) >= (size_t)pos) cpos[pos] = 0; } - void remapTarget(char *target) + void remapTarget(char* target) { - char *pos = strchr(target, ','); + char* pos = strchr(target, ','); if (pos) *pos = 0; } - void stripMask(char *target) + void stripMask(char* target) { - char *pos = strchr(target, '.'); + char* pos = strchr(target, '.'); if (pos) *pos = 0; } - char *writeTarget(char *target) + char* writeTarget(char* target) { StringStringMap::iterator i = mRemappedOutputRegisters.find(target); if (i != mRemappedOutputRegisters.end()) @@ -2589,7 +2554,7 @@ class Decompiler vector >::iterator i; for (i = mRemappedInputRegisters.begin(); i != mRemappedInputRegisters.end(); ++i) { - const char *pos = strstr(input.c_str(), i->first.c_str()); + const char* pos = strstr(input.c_str(), i->first.c_str()); if (pos) { string ret(input.c_str(), pos); @@ -2613,7 +2578,7 @@ class Decompiler // This would generate a QNAN as float. Made the hex comparison more strict with 0x%x, and thus that will fail // if it's an int type, and allow for converting that variant. - void convertHexToFloat(char *target) + void convertHexToFloat(char* target) { char convert[opcodeSize]; int count; @@ -2630,8 +2595,7 @@ class Decompiler { for (int i = 0; i < count; i++) printed += sprintf_s(&convert[printed], sizeof(convert) - printed, "%f,", lit[i]); - } - else + } else { count = sscanf_s(target, "l(%i,%i,%i,%i)", &ilit[0], &ilit[1], &ilit[2], &ilit[3]); assert(count != 0); @@ -2647,7 +2611,7 @@ class Decompiler } } - char *_convertToInt(char *target, bool fixupCBs) + char* _convertToInt(char* target, bool fixupCBs) { char buffer[opcodeSize]; @@ -2675,7 +2639,7 @@ class Decompiler strcpy_s(target, opcodeSize, buffer); return target; } - char *pos = strrchr(target, '.'); + char* pos = strrchr(target, '.'); if (pos) { size_t size = strlen(pos + 1); @@ -2688,7 +2652,7 @@ class Decompiler return target; } - char *_convertToUInt(char *target, bool fixupCBs) + char* _convertToUInt(char* target, bool fixupCBs) { char buffer[opcodeSize]; @@ -2718,7 +2682,7 @@ class Decompiler strcpy_s(target, opcodeSize, buffer); return target; } - char *pos = strrchr(target, '.'); + char* pos = strrchr(target, '.'); if (pos) { size_t size = strlen(pos + 1); @@ -2731,22 +2695,22 @@ class Decompiler return target; } - char *convertToInt(char *target) + char* convertToInt(char* target) { return _convertToInt(target, true); } - char *convertToUInt(char *target) + char* convertToUInt(char* target) { return _convertToUInt(target, true); } - char *castToInt(char *target) + char* castToInt(char* target) { return _convertToInt(target, false); } - char *castToUInt(char *target) + char* castToUInt(char* target) { return _convertToUInt(target, false); } @@ -2771,7 +2735,7 @@ class Decompiler // is intended to fix the problems we see where the assembly is using the -1 numerically // and not as a boolean. The helper is now just a macro "#define cmp -" to negate. - void addBoolean(char *arg) + void addBoolean(char* arg) { string op = (arg[0] == '-') ? arg + 1 : arg; size_t dotspot = op.find('.'); @@ -2788,7 +2752,7 @@ class Decompiler } } - bool isBoolean(char *arg) + bool isBoolean(char* arg) { if (mBooleanRegisters.empty()) return false; @@ -2814,7 +2778,7 @@ class Decompiler return false; } - void removeBoolean(char *arg) + void removeBoolean(char* arg) { if (mBooleanRegisters.empty()) return; @@ -2835,7 +2799,7 @@ class Decompiler } - char *fixImm(char *op, Operand &o) + char* fixImm(char* op, Operand& o) { // Check old value. if (o.eType == OPERAND_TYPE_IMMEDIATE32) @@ -2860,7 +2824,7 @@ class Decompiler void WritePatches() { bool stereoParamsWritten = false; - const char *StereoDecl = "\n\n// Auto-fixed shader\nfloat4 stereo = StereoParams.Load(0);\nfloat separation = stereo.x;\nfloat convergence = stereo.y;"; + const char* StereoDecl = "\n\n// Auto-fixed shader\nfloat4 stereo = StereoParams.Load(0);\nfloat separation = stereo.x;\nfloat convergence = stereo.y;"; // float4 stereoScreenRes = StereoParams.Load(int3(2,0,0));\n float4 stereoTune = StereoParams.Load(int3(1,0,0));"; // Vertex shader patches @@ -2884,25 +2848,24 @@ class Decompiler { mOutput.push_back(0); - char *screenToWorldPos; + char* screenToWorldPos; if (screenToWorldMatrix1) { backProjectVector1 += '.'; screenToWorldPos = strstr(mOutput.data(), backProjectVector1.c_str()); - } - else + } else { backProjectVector2 += '.'; screenToWorldPos = strstr(mOutput.data(), backProjectVector2.c_str()); } - char *viewProjectMatrix = strstr(mOutput.data(), "ViewProjectionMatrix."); + char* viewProjectMatrix = strstr(mOutput.data(), "ViewProjectionMatrix."); if (screenToWorldPos) { // This is a deferred rendering vertex shader. isMono = true; // Add view direction out parameter. - char *lastPos = 0; - char *pos = mOutput.data(); + char* lastPos = 0; + char* pos = mOutput.data(); while (pos) { lastPos = pos; @@ -2911,7 +2874,7 @@ class Decompiler if (lastPos && lastPos != mOutput.data()) { pos = strchr(lastPos, '\n'); - const char *viewDirectionDecl = "\nout float3 viewDirection : TEXCOORD31,"; + const char* viewDirectionDecl = "\nout float3 viewDirection : TEXCOORD31,"; mOutput.insert(mOutput.begin() + (pos - mOutput.data()), viewDirectionDecl, viewDirectionDecl + strlen(viewDirectionDecl)); } // Add view direction calculation. @@ -3017,15 +2980,15 @@ class Decompiler mOutput.push_back(0); // Search depth texture usage. sprintf(op1, " = %s.Sample", G->ZRepair_DepthTexture1.c_str()); - char *pos = strstr(mOutput.data(), op1); + char* pos = strstr(mOutput.data(), op1); ptrdiff_t searchPos = 0; // used as difference between pointers. while (pos) { - char *bpos = pos; + char* bpos = pos; while (*--bpos != ' '); string regName(bpos + 1, pos); // constant expression? - char *endPos = strchr(pos, ',') + 2; + char* endPos = strchr(pos, ',') + 2; bool constantDeclaration = endPos[0] == 'v' && endPos[1] >= '0' && endPos[1] <= '9'; endPos = strchr(endPos, '\n'); while (*--endPos != ')'); ++endPos; pos += 3; @@ -3038,8 +3001,7 @@ class Decompiler "float zTex = zpos4.%c;\n" "float zpos = %s;\n" "float wpos = 1.0 / zpos;\n", depthBufferStatement.c_str(), G->ZRepair_DepthTextureReg1, G->ZRepair_ZPosCalc1.c_str()); - } - else + } else { sprintf(buf, "zpos4 = %s;\n" "zTex = zpos4.%c;\n" @@ -3053,8 +3015,7 @@ class Decompiler vector::iterator iter = mOutput.insert(mOutput.begin() + mCodeStartPos, buf, buf + strlen(buf)); mCodeStartPos = iter - mOutput.begin(); mCodeStartPos += strlen(buf); - } - else if (!wposAvailable) + } else if (!wposAvailable) { // Leave declaration where it is. while (*pos != '\n') --pos; @@ -3062,8 +3023,7 @@ class Decompiler vector::iterator iter = mOutput.insert(mOutput.begin() + (pos + 1 - mOutput.data()), buf, buf + strlen(buf)); mCodeStartPos = iter - mOutput.begin(); mCodeStartPos += strlen(buf); - } - else + } else { while (*pos != '\n') --pos; mOutput.insert(mOutput.begin() + (pos + 1 - mOutput.data()), buf, buf + strlen(buf)); @@ -3094,14 +3054,14 @@ class Decompiler mOutput.push_back(0); // Search depth texture usage. sprintf(op1, " = %s.Sample", G->ZRepair_DepthTexture2.c_str()); - char *pos = strstr(mOutput.data(), op1); + char* pos = strstr(mOutput.data(), op1); if (pos) { - char *bpos = pos; + char* bpos = pos; while (*--bpos != ' '); string regName(bpos + 1, pos); // constant expression? - char *endPos = strchr(pos, ',') + 2; + char* endPos = strchr(pos, ',') + 2; bool constantDeclaration = endPos[0] == 'v' && endPos[1] >= '0' && endPos[1] <= '9'; endPos = strchr(endPos, '\n'); while (*--endPos != ')'); ++endPos; pos += 3; @@ -3135,8 +3095,7 @@ class Decompiler vector::iterator iter = mOutput.insert(mOutput.begin() + mCodeStartPos, buf, buf + strlen(buf)); mCodeStartPos = iter - mOutput.begin(); mCodeStartPos += strlen(buf); - } - else + } else { // Leave declaration where it is. while (*wpos != '\n') --wpos; @@ -3166,10 +3125,10 @@ class Decompiler mOutput.push_back(0); // Search position texture usage. sprintf(op1, " = %s.Sample", G->ZRepair_PositionTexture.c_str()); - char *pos = strstr(mOutput.data(), op1); + char* pos = strstr(mOutput.data(), op1); if (pos) { - char *bpos = pos; + char* bpos = pos; while (*--bpos != ' '); char buf[512]; memcpy(buf, bpos + 1, pos - (bpos + 1)); @@ -3195,7 +3154,7 @@ class Decompiler // Add depth texture, as a last resort, but only if it's specified in d3dx.ini if (!wposAvailable && G->ZRepair_DepthBuffer) { - const char *INJECT_HEADER = "float4 zpos4 = InjectedDepthTexture.Load((int3) injectedScreenPos.xyz);\n" + const char* INJECT_HEADER = "float4 zpos4 = InjectedDepthTexture.Load((int3) injectedScreenPos.xyz);\n" "float zpos = zpos4.x - 1;\n" "float wpos = 1.0 / zpos;\n"; // Copy depth texture usage to top. @@ -3205,7 +3164,7 @@ class Decompiler mCodeStartPos += strlen(INJECT_HEADER); // Add screen position parameter. - char *pos = strstr(mOutput.data(), "void main("); + char* pos = strstr(mOutput.data(), "void main("); // This section appeared to back up the pos pointer too far, and write the injection // text into the header instead of the var block. It looks to me like this was intended @@ -3223,7 +3182,7 @@ class Decompiler while (*++pos != '\n'); assert(pos != NULL); - const char *PARAM_HEADER = "\nfloat4 injectedScreenPos : SV_Position,"; + const char* PARAM_HEADER = "\nfloat4 injectedScreenPos : SV_Position,"; mOutput.insert(mOutput.begin() + (pos - mOutput.data()), PARAM_HEADER, PARAM_HEADER + strlen(PARAM_HEADER)); mCodeStartPos += strlen(PARAM_HEADER); wposAvailable = true; @@ -3263,15 +3222,15 @@ class Decompiler { char buf[128]; sprintf(buf, " %s._m00", invT->c_str()); - char *pos = strstr(mOutput.data(), buf); + char* pos = strstr(mOutput.data(), buf); if (pos) { pos += strlen(buf); - char *mpos = pos; + char* mpos = pos; while (*mpos != '*' && *mpos != '\n') ++mpos; if (*mpos == '*') { - char *bpos = mpos + 2; + char* bpos = mpos + 2; while (*bpos != ' ' && *bpos != ';') ++bpos; string regName(mpos + 2, bpos); size_t dotPos = regName.rfind('.'); @@ -3280,14 +3239,13 @@ class Decompiler sprintf(buf, "\n%s -= separation * (wpos - convergence);", regName.c_str()); mOutput.insert(mOutput.begin() + (mpos - mOutput.data()), buf, buf + strlen(buf)); mPatched = true; - } - else + } else { mpos = pos; while (*mpos != '(' && *mpos != '\n') --mpos; if (!strncmp(mpos - 3, "dot(", 4)) { - char *bpos = mpos + 1; + char* bpos = mpos + 1; while (*bpos != ' ' && *bpos != ',' && *bpos != ';') ++bpos; string regName(mpos + 1, bpos); size_t dotPos = regName.rfind('.'); @@ -3301,16 +3259,16 @@ class Decompiler } } bool parameterWritten = false; - const char *ParamPos1 = "SV_Position0,"; - const char *ParamPos2 = "\n out "; - const char *NewParam = "\nfloat3 viewDirection : TEXCOORD31,"; + const char* ParamPos1 = "SV_Position0,"; + const char* ParamPos2 = "\n out "; + const char* NewParam = "\nfloat3 viewDirection : TEXCOORD31,"; if (!G->ObjectPos_ID1.empty()) { size_t offset = strstr(mOutput.data(), "void main(") - mOutput.data(); // pointer difference, but only used as offset. while (offset < mOutput.size()) { - char *pos = strstr(mOutput.data() + offset, G->ObjectPos_ID1.c_str()); + char* pos = strstr(mOutput.data() + offset, G->ObjectPos_ID1.c_str()); if (!pos) break; pos += G->ObjectPos_ID1.length(); offset = pos - mOutput.data(); @@ -3319,9 +3277,9 @@ class Decompiler (pos[2] == 'x' || pos[2] == 'y' || pos[2] == 'z') && (pos[3] == 'x' || pos[3] == 'y' || pos[3] == 'z')) { - char *lightPosDecl = pos + 1; + char* lightPosDecl = pos + 1; while (*--pos != '='); - char *bpos = pos; + char* bpos = pos; while (*--bpos != '\n'); size_t size = (pos - 1) - (bpos + 3); memcpy(op1, bpos + 3, size); @@ -3348,9 +3306,9 @@ class Decompiler mPatched = true; if (!parameterWritten) { - char *posParam1 = strstr(mOutput.data(), ParamPos1); - char *posParam2 = strstr(mOutput.data(), ParamPos2); - char *posParam = posParam1 ? posParam1 : posParam2; + char* posParam1 = strstr(mOutput.data(), ParamPos1); + char* posParam2 = strstr(mOutput.data(), ParamPos2); + char* posParam = posParam1 ? posParam1 : posParam2; while (*posParam != '\n') --posParam; mOutput.insert(mOutput.begin() + (posParam - mOutput.data()), NewParam, NewParam + strlen(NewParam)); offset += strlen(NewParam); @@ -3365,7 +3323,7 @@ class Decompiler size_t offset = strstr(mOutput.data(), "void main(") - mOutput.data(); // pointer difference, but only used as offset. while (offset < mOutput.size()) { - char *pos = strstr(mOutput.data() + offset, G->ObjectPos_ID2.c_str()); + char* pos = strstr(mOutput.data() + offset, G->ObjectPos_ID2.c_str()); if (!pos) break; pos += G->ObjectPos_ID2.length(); offset = pos - mOutput.data(); @@ -3374,9 +3332,9 @@ class Decompiler (pos[2] == 'x' || pos[2] == 'y' || pos[2] == 'z') && (pos[3] == 'x' || pos[3] == 'y' || pos[3] == 'z')) { - char *spotPosDecl = pos + 1; + char* spotPosDecl = pos + 1; while (*--pos != '='); - char *bpos = pos; + char* bpos = pos; while (*--bpos != '\n'); size_t size = (pos - 1) - (bpos + 3); memcpy(op1, bpos + 3, size); @@ -3403,9 +3361,9 @@ class Decompiler mPatched = true; if (!parameterWritten) { - char *posParam1 = strstr(mOutput.data(), ParamPos1); - char *posParam2 = strstr(mOutput.data(), ParamPos2); - char *posParam = posParam1 ? posParam1 : posParam2; + char* posParam1 = strstr(mOutput.data(), ParamPos1); + char* posParam2 = strstr(mOutput.data(), ParamPos2); + char* posParam = posParam1 ? posParam1 : posParam2; while (*posParam != '\n') --posParam; mOutput.insert(mOutput.begin() + (posParam - mOutput.data()), NewParam, NewParam + strlen(NewParam)); offset += strlen(NewParam); @@ -3420,15 +3378,15 @@ class Decompiler string ShadowPos1 = G->MatrixPos_ID1 + "._m00_m10_m20_m30 * "; string ShadowPos2 = G->MatrixPos_ID1 + "._m01_m11_m21_m31 * "; string ShadowPos3 = G->MatrixPos_ID1 + "._m02_m12_m22_m32 * "; - char *pos1 = strstr(mOutput.data(), ShadowPos1.c_str()); - char *pos2 = strstr(mOutput.data(), ShadowPos2.c_str()); - char *pos3 = strstr(mOutput.data(), ShadowPos3.c_str()); + char* pos1 = strstr(mOutput.data(), ShadowPos1.c_str()); + char* pos2 = strstr(mOutput.data(), ShadowPos2.c_str()); + char* pos3 = strstr(mOutput.data(), ShadowPos3.c_str()); if (pos1 && pos2 && pos3) { string regName1(pos1 + ShadowPos1.length(), strchr(pos1 + ShadowPos1.length(), '.') + 2); string regName2(pos2 + ShadowPos2.length(), strchr(pos2 + ShadowPos2.length(), '.') + 2); string regName3(pos3 + ShadowPos3.length(), strchr(pos3 + ShadowPos3.length(), '.') + 2); - char *pos = std::min(std::min(pos1, pos2), pos3); + char* pos = std::min(std::min(pos1, pos2), pos3); while (*--pos != '\n'); char buf[512]; if (G->MatrixPos_MUL1.empty()) @@ -3447,9 +3405,9 @@ class Decompiler if (!parameterWritten) { - char *posParam1 = strstr(mOutput.data(), ParamPos1); - char *posParam2 = strstr(mOutput.data(), ParamPos2); - char *posParam = posParam1 ? posParam1 : posParam2; + char* posParam1 = strstr(mOutput.data(), ParamPos1); + char* posParam2 = strstr(mOutput.data(), ParamPos2); + char* posParam = posParam1 ? posParam1 : posParam2; if (posParam != NULL) { while (*posParam != '\n') --posParam; @@ -3507,134 +3465,134 @@ class Decompiler mOutput.insert(mOutput.end(), line, line + strlen(line)); } - static const char * offset2swiz(DataType type, int offset) + static const char* offset2swiz(DataType type, int offset) { // For StructuredBuffers, where the swizzle is really an offset modifier switch (type) { - case DT_float4x4: case DT_float4x3: case DT_float4x2: case DT_float4x1: - case DT_half4x4: case DT_half4x3: case DT_half4x2: case DT_half4x1: - case DT_uint4x4: case DT_uint4x3: case DT_uint4x2: case DT_uint4x1: - case DT_int4x4: case DT_int4x3: case DT_int4x2: case DT_int4x1: - case DT_bool4x4: case DT_bool4x3: case DT_bool4x2: case DT_bool4x1: - switch (offset) { - case 0: return "_m00"; case 4: return "_m10"; case 8: return "_m20"; case 12: return "_m30"; - case 16: return "_m01"; case 20: return "_m11"; case 24: return "_m21"; case 28: return "_m31"; - case 32: return "_m02"; case 36: return "_m12"; case 40: return "_m22"; case 44: return "_m32"; - case 48: return "_m03"; case 52: return "_m13"; case 56: return "_m23"; case 60: return "_m33"; - default: return "_m??"; - } - case DT_float3x4: case DT_float3x3: case DT_float3x2: case DT_float3x1: - case DT_half3x4: case DT_half3x3: case DT_half3x2: case DT_half3x1: - case DT_uint3x4: case DT_uint3x3: case DT_uint3x2: case DT_uint3x1: - case DT_int3x4: case DT_int3x3: case DT_int3x2: case DT_int3x1: - case DT_bool3x4: case DT_bool3x3: case DT_bool3x2: case DT_bool3x1: - switch (offset) { - case 0: return "_m00"; case 4: return "_m10"; case 8: return "_m20"; - case 12: return "_m01"; case 16: return "_m11"; case 20: return "_m21"; - case 24: return "_m02"; case 28: return "_m12"; case 32: return "_m22"; - case 36: return "_m03"; case 40: return "_m13"; case 44: return "_m23"; - default: return "_m??"; - } - case DT_float2x4: case DT_float2x3: case DT_float2x2: case DT_float2x1: - case DT_half2x4: case DT_half2x3: case DT_half2x2: case DT_half2x1: - case DT_uint2x4: case DT_uint2x3: case DT_uint2x2: case DT_uint2x1: - case DT_int2x4: case DT_int2x3: case DT_int2x2: case DT_int2x1: - case DT_bool2x4: case DT_bool2x3: case DT_bool2x2: case DT_bool2x1: - switch (offset) { - case 0: return "_m00"; case 4: return "_m10"; - case 8: return "_m01"; case 12: return "_m11"; - case 16: return "_m02"; case 20: return "_m12"; - case 24: return "_m03"; case 28: return "_m13"; - default: return "_m??"; - } - case DT_float1x4: case DT_float1x3: case DT_float1x2: case DT_float1x1: - case DT_half1x4: case DT_half1x3: case DT_half1x2: case DT_half1x1: - case DT_uint1x4: case DT_uint1x3: case DT_uint1x2: case DT_uint1x1: - case DT_int1x4: case DT_int1x3: case DT_int1x2: case DT_int1x1: - case DT_bool1x4: case DT_bool1x3: case DT_bool1x2: case DT_bool1x1: - switch (offset) { - case 0: return "_m00"; - case 4: return "_m01"; - case 8: return "_m02"; - case 12: return "_m03"; - default: return "_m0?"; - } - default: - switch (offset) { - case 0: return "x"; - case 4: return "y"; - case 8: return "z"; - case 12: return "w"; - default: return "?"; - } + case DT_float4x4: case DT_float4x3: case DT_float4x2: case DT_float4x1: + case DT_half4x4: case DT_half4x3: case DT_half4x2: case DT_half4x1: + case DT_uint4x4: case DT_uint4x3: case DT_uint4x2: case DT_uint4x1: + case DT_int4x4: case DT_int4x3: case DT_int4x2: case DT_int4x1: + case DT_bool4x4: case DT_bool4x3: case DT_bool4x2: case DT_bool4x1: + switch (offset) { + case 0: return "_m00"; case 4: return "_m10"; case 8: return "_m20"; case 12: return "_m30"; + case 16: return "_m01"; case 20: return "_m11"; case 24: return "_m21"; case 28: return "_m31"; + case 32: return "_m02"; case 36: return "_m12"; case 40: return "_m22"; case 44: return "_m32"; + case 48: return "_m03"; case 52: return "_m13"; case 56: return "_m23"; case 60: return "_m33"; + default: return "_m??"; + } + case DT_float3x4: case DT_float3x3: case DT_float3x2: case DT_float3x1: + case DT_half3x4: case DT_half3x3: case DT_half3x2: case DT_half3x1: + case DT_uint3x4: case DT_uint3x3: case DT_uint3x2: case DT_uint3x1: + case DT_int3x4: case DT_int3x3: case DT_int3x2: case DT_int3x1: + case DT_bool3x4: case DT_bool3x3: case DT_bool3x2: case DT_bool3x1: + switch (offset) { + case 0: return "_m00"; case 4: return "_m10"; case 8: return "_m20"; + case 12: return "_m01"; case 16: return "_m11"; case 20: return "_m21"; + case 24: return "_m02"; case 28: return "_m12"; case 32: return "_m22"; + case 36: return "_m03"; case 40: return "_m13"; case 44: return "_m23"; + default: return "_m??"; + } + case DT_float2x4: case DT_float2x3: case DT_float2x2: case DT_float2x1: + case DT_half2x4: case DT_half2x3: case DT_half2x2: case DT_half2x1: + case DT_uint2x4: case DT_uint2x3: case DT_uint2x2: case DT_uint2x1: + case DT_int2x4: case DT_int2x3: case DT_int2x2: case DT_int2x1: + case DT_bool2x4: case DT_bool2x3: case DT_bool2x2: case DT_bool2x1: + switch (offset) { + case 0: return "_m00"; case 4: return "_m10"; + case 8: return "_m01"; case 12: return "_m11"; + case 16: return "_m02"; case 20: return "_m12"; + case 24: return "_m03"; case 28: return "_m13"; + default: return "_m??"; + } + case DT_float1x4: case DT_float1x3: case DT_float1x2: case DT_float1x1: + case DT_half1x4: case DT_half1x3: case DT_half1x2: case DT_half1x1: + case DT_uint1x4: case DT_uint1x3: case DT_uint1x2: case DT_uint1x1: + case DT_int1x4: case DT_int1x3: case DT_int1x2: case DT_int1x1: + case DT_bool1x4: case DT_bool1x3: case DT_bool1x2: case DT_bool1x1: + switch (offset) { + case 0: return "_m00"; + case 4: return "_m01"; + case 8: return "_m02"; + case 12: return "_m03"; + default: return "_m0?"; + } + default: + switch (offset) { + case 0: return "x"; + case 4: return "y"; + case 8: return "z"; + case 12: return "w"; + default: return "?"; + } } } - static const char * shadervar_offset2swiz(ShaderVarType *var, int offset) + static const char* shadervar_offset2swiz(ShaderVarType* var, int offset) { if (!var) return ""; switch (var->Class) { - case SVC_SCALAR: - return ""; - case SVC_VECTOR: + case SVC_SCALAR: + return ""; + case SVC_VECTOR: + switch (offset) { + case 0: return "x"; + case 4: return "y"; + case 8: return "z"; + case 12: return "w"; + default: return "?"; + } + break; + case SVC_MATRIX_ROWS: + case SVC_MATRIX_COLUMNS: + switch (var->Rows) { + case 4: switch (offset) { - case 0: return "x"; - case 4: return "y"; - case 8: return "z"; - case 12: return "w"; - default: return "?"; + case 0: return "_m00"; case 4: return "_m10"; case 8: return "_m20"; case 12: return "_m30"; + case 16: return "_m01"; case 20: return "_m11"; case 24: return "_m21"; case 28: return "_m31"; + case 32: return "_m02"; case 36: return "_m12"; case 40: return "_m22"; case 44: return "_m32"; + case 48: return "_m03"; case 52: return "_m13"; case 56: return "_m23"; case 60: return "_m33"; } - break; - case SVC_MATRIX_ROWS: - case SVC_MATRIX_COLUMNS: - switch (var->Rows) { - case 4: - switch (offset) { - case 0: return "_m00"; case 4: return "_m10"; case 8: return "_m20"; case 12: return "_m30"; - case 16: return "_m01"; case 20: return "_m11"; case 24: return "_m21"; case 28: return "_m31"; - case 32: return "_m02"; case 36: return "_m12"; case 40: return "_m22"; case 44: return "_m32"; - case 48: return "_m03"; case 52: return "_m13"; case 56: return "_m23"; case 60: return "_m33"; - } - return "_m??"; - case 3: - switch (offset) { - case 0: return "_m00"; case 4: return "_m10"; case 8: return "_m20"; - case 12: return "_m01"; case 16: return "_m11"; case 20: return "_m21"; - case 24: return "_m02"; case 28: return "_m12"; case 32: return "_m22"; - case 36: return "_m03"; case 40: return "_m13"; case 44: return "_m23"; - } - return "_m??"; - case 2: - switch (offset) { - case 0: return "_m00"; case 4: return "_m10"; - case 8: return "_m01"; case 12: return "_m11"; - case 16: return "_m02"; case 20: return "_m12"; - case 24: return "_m03"; case 28: return "_m13"; - } - return "_m??"; - case 1: - switch (offset) { - case 0: return "_m00"; - case 4: return "_m01"; - case 8: return "_m02"; - case 12: return "_m03"; - } - return "_m0?"; + return "_m??"; + case 3: + switch (offset) { + case 0: return "_m00"; case 4: return "_m10"; case 8: return "_m20"; + case 12: return "_m01"; case 16: return "_m11"; case 20: return "_m21"; + case 24: return "_m02"; case 28: return "_m12"; case 32: return "_m22"; + case 36: return "_m03"; case 40: return "_m13"; case 44: return "_m23"; + } + return "_m??"; + case 2: + switch (offset) { + case 0: return "_m00"; case 4: return "_m10"; + case 8: return "_m01"; case 12: return "_m11"; + case 16: return "_m02"; case 20: return "_m12"; + case 24: return "_m03"; case 28: return "_m13"; } + return "_m??"; + case 1: + switch (offset) { + case 0: return "_m00"; + case 4: return "_m01"; + case 8: return "_m02"; + case 12: return "_m03"; + } + return "_m0?"; + } break; } return ""; } - static std::string shadervar_name(ShaderVarType *var, uint32_t offset) + static std::string shadervar_name(ShaderVarType* var, uint32_t offset) { std::string ret; uint32_t var_size, elem_size; uint32_t index; - const char *swiz; + const char* swiz; if (!var || !var->Name.compare("$Element")) return ""; @@ -3663,12 +3621,12 @@ class Decompiler return ret; } - bool translate_structured_var(Shader *shader, const char *c, size_t &pos, size_t &size, Instruction *instr, - std::string ret[4], bool *combined, char *idx, char *off, char *reg, Operand *texture, int swiz_offsets[4]) + bool translate_structured_var(Shader* shader, const char* c, size_t& pos, size_t& size, Instruction* instr, + std::string ret[4], bool* combined, char* idx, char* off, char* reg, Operand* texture, int swiz_offsets[4]) { Operand dst0 = instr->asOperands[0]; ResourceGroup group = (ResourceGroup)-1; - ResourceBinding *bindInfo; + ResourceBinding* bindInfo; char buffer[512]; applySwizzle(".x", idx); @@ -3701,7 +3659,7 @@ class Decompiler if (sscanf_s(off, "%d", &swiz_offset) == 1) { // Static offset: - ConstantBuffer *bufInfo = NULL; + ConstantBuffer* bufInfo = NULL; GetConstantBufferFromBindingPoint(group, texture->ui32RegisterNumber, shader->sInfo, &bufInfo); if (!bufInfo) { sprintf(buffer, "// BUG: Cannot locate struct layout:\n"); @@ -3712,7 +3670,7 @@ class Decompiler for (uint32_t component = 0; component < 4; component++) { - ShaderVarType *var = NULL; + ShaderVarType* var = NULL; int32_t byte_offset = swiz_offsets[component] + swiz_offset; uint32_t swiz = byte_offset % 16 / 4; int32_t index = -1; @@ -3733,9 +3691,9 @@ class Decompiler var_txt = shadervar_name(var, byte_offset); sprintf(buffer, "%s[%s].%s", - bindInfo->Name.c_str(), - ci(idx).c_str(), - var_txt.c_str()); + bindInfo->Name.c_str(), + ci(idx).c_str(), + var_txt.c_str()); ret[component] = buffer; } return true; @@ -3745,8 +3703,7 @@ class Decompiler ASMLineOut(c, pos, size); return false; } - } - else + } else { // This StructuredBuffer is using a primitive type rather // than a structure (e.g. StructuredBuffer foo). @@ -3758,11 +3715,11 @@ class Decompiler for (int component = 0; component < 4; component++) swiz_offsets[component] += swiz_offset; sprintf(buffer, "%s[%s].%s%s%s%s", - bindInfo->Name.c_str(), ci(idx).c_str(), - (dst0.ui32CompMask & 0x1 ? offset2swiz(struct_type, swiz_offsets[0]) : ""), - (dst0.ui32CompMask & 0x2 ? offset2swiz(struct_type, swiz_offsets[1]) : ""), - (dst0.ui32CompMask & 0x4 ? offset2swiz(struct_type, swiz_offsets[2]) : ""), - (dst0.ui32CompMask & 0x8 ? offset2swiz(struct_type, swiz_offsets[3]) : "")); + bindInfo->Name.c_str(), ci(idx).c_str(), + (dst0.ui32CompMask & 0x1 ? offset2swiz(struct_type, swiz_offsets[0]) : ""), + (dst0.ui32CompMask & 0x2 ? offset2swiz(struct_type, swiz_offsets[1]) : ""), + (dst0.ui32CompMask & 0x4 ? offset2swiz(struct_type, swiz_offsets[2]) : ""), + (dst0.ui32CompMask & 0x8 ? offset2swiz(struct_type, swiz_offsets[3]) : "")); } else { // Dynamic offset, use [] syntax: if (strcmp(strchr(reg, '.'), ".x")) { @@ -3772,15 +3729,14 @@ class Decompiler return false; } sprintf(buffer, "%s[%s][%s/4]", - bindInfo->Name.c_str(), ci(idx).c_str(), ci(off).c_str()); + bindInfo->Name.c_str(), ci(idx).c_str(), ci(off).c_str()); } // Returning all components combined together: *combined = true; ret[0] = buffer; return true; } - } - else + } else { // Missing reflection information - we have to use our fake // type information instead. Our fake type information is @@ -3801,30 +3757,30 @@ class Decompiler // The swizzle is a bit more complicated than the mask here, // because it represents extra 32bit offsets in the structure, // which is one whole index in the "val" array in our fake type. - char *swiz_offset = ""; + char* swiz_offset = ""; switch (swiz_offsets[component]) { - case 0: break; - case 4: swiz_offset = "+1"; break; - case 8: swiz_offset = "+2"; break; - case 12: swiz_offset = "+3"; break; - default: swiz_offset = "+?"; break; + case 0: break; + case 4: swiz_offset = "+1"; break; + case 8: swiz_offset = "+2"; break; + case 12: swiz_offset = "+3"; break; + default: swiz_offset = "+?"; break; } // Writing it like this should work for both dynamic and static // offsets. We could pre-compute static offsets to clean up the // output, but since we've lost the swizzle by using fake types // it may actually be more informative to use this way: sprintf(buffer, "%s[%s].val[%s/4%s]", - reg, - ci(idx).c_str(), - ci(off).c_str(), - swiz_offset); + reg, + ci(idx).c_str(), + ci(off).c_str(), + swiz_offset); ret[component] = buffer; } return true; } } - void parse_ld_structured(Shader *shader, const char *c, size_t &pos, size_t &size, Instruction *instr) + void parse_ld_structured(Shader* shader, const char* c, size_t& pos, size_t& size, Instruction* instr) { std::string translated[4]; char buffer[512]; @@ -3865,7 +3821,7 @@ class Decompiler // Shader model 5: ld_structured_indexable(structured_buffer, stride=N) dst, index, offset, register // That extra space throws out the opN variables, so we need // to check which it is. - char *dst = op1, *idx = op2, *off = op3, *reg = op4; + char* dst = op1, * idx = op2, * off = op3, * reg = op4; if (!strncmp(op1, "stride", 6)) dst = op2, idx = op3, off = op4, reg = op5; // Note comma operator Operand dst0 = instr->asOperands[0]; @@ -3875,13 +3831,13 @@ class Decompiler applySwizzle(dst, reg); // The swizzle represents extra 32bit offsets within the structure: - int swiz_offsets[4] = {0, 4, 8, 12}; + int swiz_offsets[4] = { 0, 4, 8, 12 }; for (int component = 0; component < 4; component++) { switch (texture.aui32Swizzle[component]) { - case OPERAND_4_COMPONENT_X: swiz_offsets[component] = 0; break; - case OPERAND_4_COMPONENT_Y: swiz_offsets[component] = 4; break; - case OPERAND_4_COMPONENT_Z: swiz_offsets[component] = 8; break; - case OPERAND_4_COMPONENT_W: swiz_offsets[component] = 12; break; + case OPERAND_4_COMPONENT_X: swiz_offsets[component] = 0; break; + case OPERAND_4_COMPONENT_Y: swiz_offsets[component] = 4; break; + case OPERAND_4_COMPONENT_Z: swiz_offsets[component] = 8; break; + case OPERAND_4_COMPONENT_W: swiz_offsets[component] = 12; break; } } @@ -3895,9 +3851,9 @@ class Decompiler if (!(dst0.ui32CompMask & (1 << component))) continue; sprintf(buffer, " %s.%c = %s;\n", - writeTarget(dst), - component == 3 ? 'w' : 'x' + component, - translated[component].c_str()); + writeTarget(dst), + component == 3 ? 'w' : 'x' + component, + translated[component].c_str()); appendOutput(buffer); } } @@ -3906,19 +3862,19 @@ class Decompiler removeBoolean(op1); } - void parse_store_structured(Shader *shader, const char *c, size_t &pos, size_t &size, Instruction *instr) + void parse_store_structured(Shader* shader, const char* c, size_t& pos, size_t& size, Instruction* instr) { std::string translated[4]; char buffer[512]; bool combined; // store_structured u1.x, v0.x, l(0), v1.x - char *dst = op1, *idx = op2, *off = op3, *src = op4; + char* dst = op1, * idx = op2, * off = op3, * src = op4; Operand dst0 = instr->asOperands[0]; Operand src0 = instr->asOperands[3]; remapTarget(dst); - int swiz_offsets[4] = {0, 4, 8, 12}; + int swiz_offsets[4] = { 0, 4, 8, 12 }; if (translate_structured_var(shader, c, pos, size, instr, translated, &combined, idx, off, dst, &dst0, swiz_offsets)) { if (combined) { @@ -3932,10 +3888,10 @@ class Decompiler strcpy(op5, src); fixImm(op5, src0); switch (component) { - case 0: applySwizzle(".x", op5); break; - case 1: applySwizzle(".y", op5); break; - case 2: applySwizzle(".z", op5); break; - case 3: applySwizzle(".w", op5); break; + case 0: applySwizzle(".x", op5); break; + case 1: applySwizzle(".y", op5); break; + case 2: applySwizzle(".z", op5); break; + case 3: applySwizzle(".w", op5); break; } sprintf(buffer, " %s = %s;\n", translated[component].c_str(), ci(op5).c_str()); @@ -3947,14 +3903,14 @@ class Decompiler //dx9 //get component from Instruction - string GetComponentStrFromInstruction(Instruction * instr, int opIndex) + string GetComponentStrFromInstruction(Instruction* instr, int opIndex) { assert(instr != NULL); - char * componentX = "x"; - char * componentY = "y"; - char * componentZ = "z"; - char * componentW = "w"; - char * component[] = { componentX, componentY, componentZ, componentW }; + char* componentX = "x"; + char* componentY = "y"; + char* componentZ = "z"; + char* componentW = "w"; + char* component[] = { componentX, componentY, componentZ, componentW }; char buff[opcodeSize]; @@ -3982,15 +3938,13 @@ class Decompiler sprintf_s(buff, opcodeSize, "%s%s", buff, componentW); } - } - else if (instr->asOperands[opIndex].eSelMode == OPERAND_4_COMPONENT_SWIZZLE_MODE) + } else if (instr->asOperands[opIndex].eSelMode == OPERAND_4_COMPONENT_SWIZZLE_MODE) { for (int i = 0; i < 4; i++) { sprintf_s(buff, opcodeSize, "%s%s", buff, component[instr->asOperands[opIndex].aui32Swizzle[i]]); } - } - else if ((instr->asOperands[opIndex].eSelMode == OPERAND_4_COMPONENT_SELECT_1_MODE)) + } else if ((instr->asOperands[opIndex].eSelMode == OPERAND_4_COMPONENT_SELECT_1_MODE)) { sprintf_s(buff, opcodeSize, "%s", component[instr->asOperands[opIndex].aui32Swizzle[0]]); } @@ -3999,10 +3953,10 @@ class Decompiler } //0 different, 1 same, 2 same but sign different - int IsInstructionOperandSame(Instruction * instr1, int opIndex1, Instruction * instr2, int opIndex2, const char * instr1Op1 = NULL, const char * instr2Op1 = NULL) + int IsInstructionOperandSame(Instruction* instr1, int opIndex1, Instruction* instr2, int opIndex2, const char* instr1Op1 = NULL, const char* instr2Op1 = NULL) { - Operand & op1 = instr1->asOperands[opIndex1]; - Operand & op2 = instr2->asOperands[opIndex2]; + Operand& op1 = instr1->asOperands[opIndex1]; + Operand& op2 = instr2->asOperands[opIndex2]; string component1 = GetComponentStrFromInstruction(instr1, opIndex1); string component2 = GetComponentStrFromInstruction(instr2, opIndex2); @@ -4054,7 +4008,7 @@ class Decompiler } //dx9 - void ParseCode(Shader *shader, const char *c, size_t size) + void ParseCode(Shader* shader, const char* c, size_t size) { mOutputRegisterValues.clear(); mBooleanRegisters.clear(); @@ -4065,12 +4019,12 @@ class Decompiler unsigned int iNr = 0; bool skip_shader = false; - vector *instructions = &shader->asPhase[MAIN_PHASE].ppsInst[0]; + vector* instructions = &shader->asPhase[MAIN_PHASE].ppsInst[0]; size_t inst_count = instructions->size(); while (pos < size && iNr < inst_count) { - Instruction *instr = &(*instructions)[iNr]; + Instruction* instr = &(*instructions)[iNr]; // Now ignore '#line' or 'undecipherable' debug info (DefenseGrid2) if (!strncmp(c + pos, "#line", 5) || @@ -4108,8 +4062,8 @@ class Decompiler // Ignore any instructions from old shader models that we do not handle to // avoid crashes. if (!shader->dx9Shader && ( - !strncmp(statement, "vs_1", 4) || !strncmp(statement, "vs_2", 4) || - !strncmp(statement, "ps_1", 4) || !strncmp(statement, "ps_2", 4))) { + !strncmp(statement, "vs_1", 4) || !strncmp(statement, "vs_2", 4) || + !strncmp(statement, "ps_1", 4) || !strncmp(statement, "ps_2", 4))) { skip_shader = true; NextLine(c, pos, size); continue; @@ -4124,13 +4078,11 @@ class Decompiler { skip_shader = false; mShaderType = statement; - } - else if (skip_shader) + } else if (skip_shader) { NextLine(c, pos, size); continue; - } - else if (!strcmp(statement, "def")) //dx9 const + } else if (!strcmp(statement, "def")) //dx9 const { int registerIndex = atoi(&op1[1]); @@ -4152,12 +4104,11 @@ class Decompiler while (c[pos] != 0x0a && pos < size) mOutput.insert(mOutput.end(), c[pos++]); mOutput.insert(mOutput.end(), '\n'); - } - else if (!strcmp(statement, "dcl_constantbuffer")) + } else if (!strcmp(statement, "dcl_constantbuffer")) { - char *strPos46 = strstr(op1, "cb"); // Match d3dcompiler_46 disassembly - char *strPos47 = strstr(op1, "CB"); // Match d3dcompiler_47 disassembly - char *strPos = strPos46 ? strPos46 : strPos47; + char* strPos46 = strstr(op1, "cb"); // Match d3dcompiler_46 disassembly + char* strPos47 = strstr(op1, "CB"); // Match d3dcompiler_47 disassembly + char* strPos = strPos46 ? strPos46 : strPos47; if (strPos) { int bufIndex = 0; @@ -4204,8 +4155,7 @@ class Decompiler } } } - } - else if (!strcmp(statement, "dcl_resource_structured") || !strcmp(statement, "dcl_uav_structured")) + } else if (!strcmp(statement, "dcl_resource_structured") || !strcmp(statement, "dcl_uav_structured")) { bool uav = statement[4] == 'u'; char prefix = uav ? 'u' : 't'; @@ -4244,13 +4194,12 @@ class Decompiler // precision types can theoretically be 16 bits on embedded implementations, // but in practice are 32bits on PC. If it does happen we need to know about it: sprintf(buffer, "FIXME: StructuredBuffer t%d stride %d is not a multiple of 4\n\n", - bufIndex, bufStride); + bufIndex, bufStride); mOutput.insert(mOutput.begin(), buffer, buffer + strlen(buffer)); mCodeStartPos += strlen(buffer); } } - } - else if (!strcmp(statement, "dcl_tgsm_structured")) + } else if (!strcmp(statement, "dcl_tgsm_structured")) { int bufIndex = 0; int bufStride = 0; @@ -4301,8 +4250,7 @@ class Decompiler mOutput.insert(mOutput.begin(), buffer, buffer + strlen(buffer)); mCodeStartPos += strlen(buffer); } - } - else if (!strcmp(op2, "mode_comparison")) + } else if (!strcmp(op2, "mode_comparison")) { map::iterator i = mSamplerComparisonNames.find(bufIndex); if (i == mSamplerComparisonNames.end()) @@ -4313,8 +4261,7 @@ class Decompiler mOutput.insert(mOutput.begin(), buffer, buffer + strlen(buffer)); mCodeStartPos += strlen(buffer); } - } - else + } else { logDecompileError("Error parsing dcl_sampler type: " + string(op2)); return; @@ -4346,8 +4293,7 @@ class Decompiler CreateRawFormat("Texture2D", bufIndex); } } - } - else if (!strcmp(statement, "dcl_resource_texture2darray")) // dcl_resource_texture2darray (float,float,float,float) t0 + } else if (!strcmp(statement, "dcl_resource_texture2darray")) // dcl_resource_texture2darray (float,float,float,float) t0 { if (op2[0] == 't') { @@ -4364,8 +4310,7 @@ class Decompiler CreateRawFormat("Texture2DArray", bufIndex); } } - } - else if (!strncmp(statement, "dcl_resource_texture2dms", strlen("dcl_resource_texture2dms"))) // dcl_resource_texture2dms(8) (float,float,float,float) t4 + } else if (!strncmp(statement, "dcl_resource_texture2dms", strlen("dcl_resource_texture2dms"))) // dcl_resource_texture2dms(8) (float,float,float,float) t4 { if (op2[0] == 't') { @@ -4401,8 +4346,7 @@ class Decompiler mCodeStartPos += strlen(buffer); } } - } - else if (!strcmp(statement, "dcl_resource_texture3d")) + } else if (!strcmp(statement, "dcl_resource_texture3d")) { if (op2[0] == 't') { @@ -4419,8 +4363,7 @@ class Decompiler CreateRawFormat("Texture3D", bufIndex); } } - } - else if (!strcmp(statement, "dcl_resource_texturecube")) + } else if (!strcmp(statement, "dcl_resource_texturecube")) { if (op2[0] == 't') { @@ -4437,8 +4380,7 @@ class Decompiler CreateRawFormat("TextureCube", bufIndex); } } - } - else if (!strcmp(statement, "dcl_resource_texturecubearray")) + } else if (!strcmp(statement, "dcl_resource_texturecubearray")) { if (op2[0] == 't') { @@ -4455,8 +4397,7 @@ class Decompiler CreateRawFormat("TextureCubeArray", bufIndex); } } - } - else if (!strcmp(statement, "dcl_resource_buffer")) // dcl_resource_buffer (sint,sint,sint,sint) t2 + } else if (!strcmp(statement, "dcl_resource_buffer")) // dcl_resource_buffer (sint,sint,sint,sint) t2 { if (op2[0] == 't') { @@ -4473,8 +4414,7 @@ class Decompiler CreateRawFormat("Buffer", bufIndex); } } - } - else if (!strcmp(statement, "{")) + } else if (!strcmp(statement, "{")) { // Declaration from // dcl_immediateConstantBuffer { { 1.000000, 0, 0, 0}, @@ -4487,8 +4427,7 @@ class Decompiler mOutput.insert(mOutput.end(), ';'); mOutput.insert(mOutput.end(), c[pos++]); continue; - } - else if (!strcmp(statement, "dcl_indexrange")) + } else if (!strcmp(statement, "dcl_indexrange")) { int numIndex = 0; sscanf_s(op2, "%d", &numIndex); @@ -4498,8 +4437,7 @@ class Decompiler buffer[strlen(buffer) - 1] = 0; strcat(buffer, " };\n"); mOutput.insert(mOutput.end(), buffer, buffer + strlen(buffer)); - } - else if (!strcmp(statement, "dcl_indexableTemp")) + } else if (!strcmp(statement, "dcl_indexableTemp")) { // Always returned 4, not actual index. ToDo: likely not always float4. // format as: dcl_indexableTemp x0[40], 4 @@ -4508,22 +4446,20 @@ class Decompiler sscanf_s(op1, "%[^[][%d]", varName, opcodeSize, &numIndex); sprintf(buffer, " float4 %s[%d];\n", varName, numIndex); mOutput.insert(mOutput.end(), buffer, buffer + strlen(buffer)); - } - else if (!strcmp(statement, "dcl_input")) + } else if (!strcmp(statement, "dcl_input")) { // Can have 'vCoverage' variable implicitly defined, // not in input signature when reflection is stripped. if (!strcmp(op1, "vCoverage")) { - char *pos = strstr(mOutput.data(), "void main("); + char* pos = strstr(mOutput.data(), "void main("); while (*pos != 0x0a) pos++; pos++; sprintf(buffer, " uint vCoverage : SV_Coverage,\n"); mOutput.insert(mOutput.begin() + (pos - mOutput.data()), buffer, buffer + strlen(buffer)); } - } - else if (!strcmp(statement, "dcl_temps")) + } else if (!strcmp(statement, "dcl_temps")) { - const char *varDecl = " float4 "; + const char* varDecl = " float4 "; mOutput.insert(mOutput.end(), varDecl, varDecl + strlen(varDecl)); int numTemps; sscanf_s(c + pos, "%s %d", statement, UCOUNTOF(statement), &numTemps); @@ -4535,7 +4471,7 @@ class Decompiler mOutput.pop_back(); mOutput.push_back(';'); mOutput.push_back('\n'); - const char *helperDecl = " uint4 bitmask, uiDest;\n float4 fDest;\n\n"; + const char* helperDecl = " uint4 bitmask, uiDest;\n float4 fDest;\n\n"; mOutput.insert(mOutput.end(), helperDecl, helperDecl + strlen(helperDecl)); } // For Geometry Shaders, e.g. dcl_stream m0 TODO: make it StreamN, add to varlist @@ -4546,28 +4482,27 @@ class Decompiler mOutput.insert(mOutput.end(), buffer, buffer + strlen(buffer)); ASMLineOut(c, pos, size); // Move back to input section and output something close to right - char *main_ptr = strstr(mOutput.data(), "void main("); + char* main_ptr = strstr(mOutput.data(), "void main("); size_t offset = main_ptr - mOutput.data(); NextLine(mOutput.data(), offset, mOutput.size()); sprintf(buffer, " inout TriangleStream m0,\n"); - mOutput.insert(mOutput.begin() + offset , buffer, buffer + strlen(buffer)); + mOutput.insert(mOutput.begin() + offset, buffer, buffer + strlen(buffer)); } // For Geometry Shaders, e.g. dcl_maxout n else if (!strcmp(statement, "dcl_maxout")) { - char *main_ptr = strstr(mOutput.data(), "void main("); + char* main_ptr = strstr(mOutput.data(), "void main("); size_t offset = main_ptr - mOutput.data(); sprintf(buffer, "[maxvertexcount(%s)]\n", op1); mOutput.insert(mOutput.begin() + offset, buffer, buffer + strlen(buffer)); - } - else if (!strncmp(statement, "dcl_", 4)) + } else if (!strncmp(statement, "dcl_", 4)) { // Hateful strcmp logic is upside down, only output for ones we aren't already handling. - if (strcmp(statement, "dcl_output") && + if (strcmp(statement, "dcl_output") && strcmp(statement, "dcl_output_siv") && strcmp(statement, "dcl_globalFlags") && //strcmp(statement, "dcl_input_siv") && - strcmp(statement, "dcl_input_ps") && + strcmp(statement, "dcl_input_ps") && strcmp(statement, "dcl_input_ps_sgv") && strcmp(statement, "dcl_input_ps_siv")) { @@ -4578,8 +4513,7 @@ class Decompiler mOutput.insert(mOutput.end(), buffer, buffer + strlen(buffer)); ASMLineOut(c, pos, size); } - } - else if (!strcmp(statement, "dcl")) //dx9 dcl vFace + } else if (!strcmp(statement, "dcl")) //dx9 dcl vFace { // Ummm... why is this empty block here? Is this here // intentionally to avoid the next else block, or was it @@ -4590,2076 +4524,2069 @@ class Decompiler switch (instr->eOpcode) { - case OPCODE_ITOF: - remapTarget(op1); - applySwizzle(op1, fixImm(op2, instr->asOperands[1])); - sprintf(buffer, " %s = %s;\n", writeTarget(op1), ci(convertToInt(op2)).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; - case OPCODE_UTOF: - remapTarget(op1); - applySwizzle(op1, fixImm(op2, instr->asOperands[1])); - sprintf(buffer, " %s = %s;\n", writeTarget(op1), ci(convertToUInt(op2)).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; + case OPCODE_ITOF: + remapTarget(op1); + applySwizzle(op1, fixImm(op2, instr->asOperands[1])); + sprintf(buffer, " %s = %s;\n", writeTarget(op1), ci(convertToInt(op2)).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; + case OPCODE_UTOF: + remapTarget(op1); + applySwizzle(op1, fixImm(op2, instr->asOperands[1])); + sprintf(buffer, " %s = %s;\n", writeTarget(op1), ci(convertToUInt(op2)).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; - case OPCODE_MOV: - remapTarget(op1); - applySwizzle(op1, fixImm(op2, instr->asOperands[1])); - if (!instr->bSaturate) - sprintf(buffer, " %s = %s;\n", writeTarget(op1), ci(op2).c_str()); - else - sprintf(buffer, " %s = saturate(%s);\n", writeTarget(op1), ci(op2).c_str()); - appendOutput(buffer); - if (op1[0] == 'o') - { - char *dotPos = strchr(op1, '.'); if (dotPos) *dotPos = 0; - if (!dotPos || dotPos[1] == 'x') - mOutputRegisterValues[op1] = op2; - } - removeBoolean(op1); - break; + case OPCODE_MOV: + remapTarget(op1); + applySwizzle(op1, fixImm(op2, instr->asOperands[1])); + if (!instr->bSaturate) + sprintf(buffer, " %s = %s;\n", writeTarget(op1), ci(op2).c_str()); + else + sprintf(buffer, " %s = saturate(%s);\n", writeTarget(op1), ci(op2).c_str()); + appendOutput(buffer); + if (op1[0] == 'o') + { + char* dotPos = strchr(op1, '.'); if (dotPos) *dotPos = 0; + if (!dotPos || dotPos[1] == 'x') + mOutputRegisterValues[op1] = op2; + } + removeBoolean(op1); + break; - case OPCODE_RCP: - remapTarget(op1); - applySwizzle(op1, op2); - if (!instr->bSaturate) - sprintf(buffer, " %s = rcp(%s);\n", writeTarget(op1), ci(op2).c_str()); - else - sprintf(buffer, " %s = saturate(rcp(%s));\n", writeTarget(op1), ci(op2).c_str()); - appendOutput(buffer); - break; + case OPCODE_RCP: + remapTarget(op1); + applySwizzle(op1, op2); + if (!instr->bSaturate) + sprintf(buffer, " %s = rcp(%s);\n", writeTarget(op1), ci(op2).c_str()); + else + sprintf(buffer, " %s = saturate(rcp(%s));\n", writeTarget(op1), ci(op2).c_str()); + appendOutput(buffer); + break; - case OPCODE_NOT: - remapTarget(op1); - applySwizzle(op1, op2); - sprintf(buffer, " %s = ~%s;\n", writeTarget(op1), ci(convertToInt(op2)).c_str()); - appendOutput(buffer); - break; + case OPCODE_NOT: + remapTarget(op1); + applySwizzle(op1, op2); + sprintf(buffer, " %s = ~%s;\n", writeTarget(op1), ci(convertToInt(op2)).c_str()); + appendOutput(buffer); + break; - case OPCODE_INEG: - remapTarget(op1); - applySwizzle(op1, op2, true); - sprintf(buffer, " %s = -%s;\n", writeTarget(op1), ci(convertToInt(op2)).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; + case OPCODE_INEG: + remapTarget(op1); + applySwizzle(op1, op2, true); + sprintf(buffer, " %s = -%s;\n", writeTarget(op1), ci(convertToInt(op2)).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; - case OPCODE_F32TOF16: - remapTarget(op1); - applySwizzle(op1, op2); - sprintf(buffer, " %s = f32tof16(%s);\n", writeTarget(op1), ci(op2).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; + case OPCODE_F32TOF16: + remapTarget(op1); + applySwizzle(op1, op2); + sprintf(buffer, " %s = f32tof16(%s);\n", writeTarget(op1), ci(op2).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; - case OPCODE_F16TOF32: - remapTarget(op1); - applySwizzle(op1, op2); - sprintf(buffer, " %s = f16tof32(%s);\n", writeTarget(op1), ci(op2).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; + case OPCODE_F16TOF32: + remapTarget(op1); + applySwizzle(op1, op2); + sprintf(buffer, " %s = f16tof32(%s);\n", writeTarget(op1), ci(op2).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; - case OPCODE_FRC: - remapTarget(op1); - applySwizzle(op1, op2); - if (!instr->bSaturate) - sprintf(buffer, " %s = frac(%s);\n", writeTarget(op1), ci(op2).c_str()); - else - sprintf(buffer, " %s = saturate(frac(%s));\n", writeTarget(op1), ci(op2).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; + case OPCODE_FRC: + remapTarget(op1); + applySwizzle(op1, op2); + if (!instr->bSaturate) + sprintf(buffer, " %s = frac(%s);\n", writeTarget(op1), ci(op2).c_str()); + else + sprintf(buffer, " %s = saturate(frac(%s));\n", writeTarget(op1), ci(op2).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; - case OPCODE_MUL: - remapTarget(op1); - applySwizzle(op1, fixImm(op2, instr->asOperands[1])); - applySwizzle(op1, fixImm(op3, instr->asOperands[2])); - mMulOperand = op3; mMulOperand2 = op2; mMulTarget = op1; - if (!instr->bSaturate) - sprintf(buffer, " %s = %s * %s;\n", writeTarget(op1), ci(op3).c_str(), ci(op2).c_str()); - else - sprintf(buffer, " %s = saturate(%s * %s);\n", writeTarget(op1), ci(op3).c_str(), ci(op2).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; + case OPCODE_MUL: + remapTarget(op1); + applySwizzle(op1, fixImm(op2, instr->asOperands[1])); + applySwizzle(op1, fixImm(op3, instr->asOperands[2])); + mMulOperand = op3; mMulOperand2 = op2; mMulTarget = op1; + if (!instr->bSaturate) + sprintf(buffer, " %s = %s * %s;\n", writeTarget(op1), ci(op3).c_str(), ci(op2).c_str()); + else + sprintf(buffer, " %s = saturate(%s * %s);\n", writeTarget(op1), ci(op3).c_str(), ci(op2).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; - case OPCODE_IMUL: - remapTarget(op2); - applySwizzle(op2, op3, true); - applySwizzle(op2, op4, true); - mMulOperand = strncmp(op3, "int", 3) ? op3 : op4; - sprintf(buffer, " %s = %s * %s;\n", writeTarget(op2), ci(convertToInt(op3)).c_str(), ci(convertToInt(op4)).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; + case OPCODE_IMUL: + remapTarget(op2); + applySwizzle(op2, op3, true); + applySwizzle(op2, op4, true); + mMulOperand = strncmp(op3, "int", 3) ? op3 : op4; + sprintf(buffer, " %s = %s * %s;\n", writeTarget(op2), ci(convertToInt(op3)).c_str(), ci(convertToInt(op4)).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; - case OPCODE_DIV: - remapTarget(op1); - applySwizzle(op1, fixImm(op2, instr->asOperands[1])); - applySwizzle(op1, fixImm(op3, instr->asOperands[2])); - if (!instr->bSaturate) - sprintf(buffer, " %s = %s / %s;\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str()); - else - sprintf(buffer, " %s = saturate(%s / %s);\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; + case OPCODE_DIV: + remapTarget(op1); + applySwizzle(op1, fixImm(op2, instr->asOperands[1])); + applySwizzle(op1, fixImm(op3, instr->asOperands[2])); + if (!instr->bSaturate) + sprintf(buffer, " %s = %s / %s;\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str()); + else + sprintf(buffer, " %s = saturate(%s / %s);\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; - // UDIV instruction also could damage the original register before finishing, giving wrong results. - // e.g. udiv r0.x, r1.x, r0.x, r0.y - // variant: udiv null, r1.xy, r3.zwzz, r2.zwzz - // To fix this, we are using the temp variables declared at the top. - // expected output: - // uiDest.x = (uint)r0.x / (uint)r0.y; - // r1.x = (uint)r0.x % (uint)r0.y; - // r0.x = uiDest.x; - // - // This will swizzle based on either op1 or op2, as long as it's not null. It's not clear whether - // the swizzle is allowed to vary for each half of the instruction, like xy for /, zw for %. - // To allow for that, we'll set the temp registers with full swizzle, then only use the specific - // parts required for each half, as the safest approach. Might not generate udiv though. - // Also removed saturate code, because udiv does not specify that. - // Creates operand copies to applySwizzle to unchanged operands, as constant l values are otherwise damaged. - case OPCODE_UDIV: - { - remapTarget(op1); - remapTarget(op2); - char divOut[opcodeSize] = "uiDest.xyzw"; - char *divSwiz = op1; - char *remSwiz = op2; - strcpy_s(op13, opcodeSize, op3); - strcpy_s(op14, opcodeSize, op4); - - if (instr->asOperands[0].eType != OPERAND_TYPE_NULL) - { - applySwizzle(divSwiz, divOut, true); - applySwizzle(divSwiz, fixImm(op13, instr->asOperands[2]), true); - applySwizzle(divSwiz, fixImm(op14, instr->asOperands[3]), true); - convertToUInt(op13); - convertToUInt(op14); + // UDIV instruction also could damage the original register before finishing, giving wrong results. + // e.g. udiv r0.x, r1.x, r0.x, r0.y + // variant: udiv null, r1.xy, r3.zwzz, r2.zwzz + // To fix this, we are using the temp variables declared at the top. + // expected output: + // uiDest.x = (uint)r0.x / (uint)r0.y; + // r1.x = (uint)r0.x % (uint)r0.y; + // r0.x = uiDest.x; + // + // This will swizzle based on either op1 or op2, as long as it's not null. It's not clear whether + // the swizzle is allowed to vary for each half of the instruction, like xy for /, zw for %. + // To allow for that, we'll set the temp registers with full swizzle, then only use the specific + // parts required for each half, as the safest approach. Might not generate udiv though. + // Also removed saturate code, because udiv does not specify that. + // Creates operand copies to applySwizzle to unchanged operands, as constant l values are otherwise damaged. + case OPCODE_UDIV: + { + remapTarget(op1); + remapTarget(op2); + char divOut[opcodeSize] = "uiDest.xyzw"; + char* divSwiz = op1; + char* remSwiz = op2; + strcpy_s(op13, opcodeSize, op3); + strcpy_s(op14, opcodeSize, op4); - sprintf(buffer, " %s = %s / %s;\n", divOut, ci(op13).c_str(), ci(op14).c_str()); - appendOutput(buffer); - } - if (instr->asOperands[1].eType != OPERAND_TYPE_NULL) - { - applySwizzle(remSwiz, fixImm(op3, instr->asOperands[2]), true); - applySwizzle(remSwiz, fixImm(op4, instr->asOperands[3]), true); - convertToUInt(op3); - convertToUInt(op4); + if (instr->asOperands[0].eType != OPERAND_TYPE_NULL) + { + applySwizzle(divSwiz, divOut, true); + applySwizzle(divSwiz, fixImm(op13, instr->asOperands[2]), true); + applySwizzle(divSwiz, fixImm(op14, instr->asOperands[3]), true); + convertToUInt(op13); + convertToUInt(op14); - sprintf(buffer, " %s = %s %% %s;\n", writeTarget(op2), ci(op3).c_str(), ci(op4).c_str()); - appendOutput(buffer); - } - if (instr->asOperands[0].eType != OPERAND_TYPE_NULL) - { - sprintf(buffer, " %s = %s;\n", writeTarget(op1), divOut); - appendOutput(buffer); - } - removeBoolean(op1); - removeBoolean(op2); - break; + sprintf(buffer, " %s = %s / %s;\n", divOut, ci(op13).c_str(), ci(op14).c_str()); + appendOutput(buffer); } + if (instr->asOperands[1].eType != OPERAND_TYPE_NULL) + { + applySwizzle(remSwiz, fixImm(op3, instr->asOperands[2]), true); + applySwizzle(remSwiz, fixImm(op4, instr->asOperands[3]), true); + convertToUInt(op3); + convertToUInt(op4); - case OPCODE_ADD: - // OPCODE_ADD is 0. Therefore, it is possible for us to - // arrive here if the line has simply not been parsed. - // Let's make sure we are actually parsing an 'add' before - // we go any further. Only check first three characters - // since we still want add_sat to parse. - if (strncmp(statement, "add", 3)) { - logDecompileError("No opcode: " + string(statement)); - return; - } - - remapTarget(op1); - applySwizzle(op1, fixImm(op2, instr->asOperands[1])); - applySwizzle(op1, fixImm(op3, instr->asOperands[2])); - if (!instr->bSaturate) { - // Reverting the DX9 port changes and going back to - // the original opcode order here, since they - // should be mathematically equivelent, but I seem - // to recall Bo3b noticing that this order tends to - // produce assembly closer to the original. -DSS - sprintf(buffer, " %s = %s + %s;\n", writeTarget(op1), ci(op3).c_str(), ci(op2).c_str()); - //sprintf(buffer, " %s = %s + %s;\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str()); //dx9 - } else { - sprintf(buffer, " %s = saturate(%s + %s);\n", writeTarget(op1), ci(op3).c_str(), ci(op2).c_str()); - //sprintf(buffer, " %s = saturate(%s + %s);\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str()); //dx9 - } + sprintf(buffer, " %s = %s %% %s;\n", writeTarget(op2), ci(op3).c_str(), ci(op4).c_str()); appendOutput(buffer); - removeBoolean(op1); - break; - - // IADD is apparently used by the fxc compiler in some cases like an AND operation. - // After boolean operations, it will sum up two boolean operators. Since we are now - // passing -1:0 instead of 1:0, it should work to just do the IADD operation, respecting - // any negation the source applies. A common sequence, compiler trick is: - // lt r0.y, l(0.000000), r0.x - // lt r0.x, r0.x, l(0.000000) - // iadd r0.x, r0.x, -r0.y - // itof r0.x, r0.x - // mul r0.xyz, r0.xxxx, r1.xzwx - case OPCODE_IADD: - remapTarget(op1); - applySwizzle(op1, op2, true); - applySwizzle(op1, op3, true); - sprintf(buffer, " %s = %s + %s;\n", writeTarget(op1), ci(convertToInt(op2)).c_str(), ci(convertToInt(op3)).c_str()); + } + if (instr->asOperands[0].eType != OPERAND_TYPE_NULL) + { + sprintf(buffer, " %s = %s;\n", writeTarget(op1), divOut); appendOutput(buffer); - removeBoolean(op1); - break; - - // AND opcodes were generating bad code, as the hex constants were being converted badly. - // The most common case was 0x3f800000 being converted directly to integer decimal of 1065353216, instead - // of the most likely answer of floating point 1.0f. - // This also happened for conversion of Pi. - // There are bitmasks used for AND, and those need to stay as Hex constants. - // But anything used after IF statements/booleans, needs to be converted as float. - // Rather than modify applySwizzle for this single opcode, it makes more sense to convert them here, - // if they are to be used in boolean operations. We make a copy of the incoming operands, so that we - // can applySwizzle in order to be able to look up isBoolean properly. Can be r3.xxxy, and becomes r3.xy. - // That applySwizzle damages constants though, so if we are boolean, we'll use the original l() value. - case OPCODE_AND: - remapTarget(op1); - strcpy(op12, op2); - strcpy(op13, op3); - applySwizzle(op1, op2, true); - applySwizzle(op1, op3, true); - if (isBoolean(op2) || isBoolean(op3)) - { - convertHexToFloat(op12); - convertHexToFloat(op13); - applySwizzle(op1, op12); - applySwizzle(op1, op13); - char *cmp = isBoolean(op2) ? op12 : op13; - char *arg = isBoolean(op2) ? op13 : op12; - sprintf(buffer, " %s = %s ? %s : 0;\n", writeTarget(op1), ci(cmp).c_str(), ci(arg).c_str()); - appendOutput(buffer); - } - else - { - sprintf(buffer, " %s = %s & %s;\n", writeTarget(op1), ci(convertToInt(op2)).c_str(), ci(convertToInt(op3)).c_str()); - appendOutput(buffer); - } - break; + } + removeBoolean(op1); + removeBoolean(op2); + break; + } - case OPCODE_OR: - remapTarget(op1); - applySwizzle(op1, op2); - applySwizzle(op1, op3); - sprintf(buffer, " %s = %s | %s;\n", writeTarget(op1), ci(convertToInt(op2)).c_str(), ci(convertToInt(op3)).c_str()); - appendOutput(buffer); - break; + case OPCODE_ADD: + // OPCODE_ADD is 0. Therefore, it is possible for us to + // arrive here if the line has simply not been parsed. + // Let's make sure we are actually parsing an 'add' before + // we go any further. Only check first three characters + // since we still want add_sat to parse. + if (strncmp(statement, "add", 3)) { + logDecompileError("No opcode: " + string(statement)); + return; + } - case OPCODE_XOR: - remapTarget(op1); - applySwizzle(op1, op2); - applySwizzle(op1, op3); - sprintf(buffer, " %s = %s ^ %s;\n", writeTarget(op1), ci(convertToInt(op2)).c_str(), ci(convertToInt(op3)).c_str()); - appendOutput(buffer); - break; + remapTarget(op1); + applySwizzle(op1, fixImm(op2, instr->asOperands[1])); + applySwizzle(op1, fixImm(op3, instr->asOperands[2])); + if (!instr->bSaturate) { + // Reverting the DX9 port changes and going back to + // the original opcode order here, since they + // should be mathematically equivelent, but I seem + // to recall Bo3b noticing that this order tends to + // produce assembly closer to the original. -DSS + sprintf(buffer, " %s = %s + %s;\n", writeTarget(op1), ci(op3).c_str(), ci(op2).c_str()); + //sprintf(buffer, " %s = %s + %s;\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str()); //dx9 + } else { + sprintf(buffer, " %s = saturate(%s + %s);\n", writeTarget(op1), ci(op3).c_str(), ci(op2).c_str()); + //sprintf(buffer, " %s = saturate(%s + %s);\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str()); //dx9 + } + appendOutput(buffer); + removeBoolean(op1); + break; - // Curiously enough, the documentation for ISHR and ISHL is wrong, and documents the parameters backwards. - // http://msdn.microsoft.com/en-us/library/windows/desktop/hh447145(v=vs.85).aspx - // This was proven by looking at actual game ASM, and trying to make the HLSL match the generated ASM. - // It is the C standard of: shift-expression << additive-expression - // So, we need op2 as the Shift-Expression, op3 as the # of bits to shift. - case OPCODE_ISHR: - remapTarget(op1); - applySwizzle(op1, op2, true); - applySwizzle(op1, op3, true); - sprintf(buffer, " %s = %s >> %s;\n", writeTarget(op1), ci(convertToUInt(op2)).c_str(), ci(convertToInt(op3)).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; + // IADD is apparently used by the fxc compiler in some cases like an AND operation. + // After boolean operations, it will sum up two boolean operators. Since we are now + // passing -1:0 instead of 1:0, it should work to just do the IADD operation, respecting + // any negation the source applies. A common sequence, compiler trick is: + // lt r0.y, l(0.000000), r0.x + // lt r0.x, r0.x, l(0.000000) + // iadd r0.x, r0.x, -r0.y + // itof r0.x, r0.x + // mul r0.xyz, r0.xxxx, r1.xzwx + case OPCODE_IADD: + remapTarget(op1); + applySwizzle(op1, op2, true); + applySwizzle(op1, op3, true); + sprintf(buffer, " %s = %s + %s;\n", writeTarget(op1), ci(convertToInt(op2)).c_str(), ci(convertToInt(op3)).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; - case OPCODE_ISHL: - remapTarget(op1); - applySwizzle(op1, op2, true); - applySwizzle(op1, op3, true); - sprintf(buffer, " %s = %s << %s;\n", writeTarget(op1), ci(convertToUInt(op2)).c_str(), ci(convertToInt(op3)).c_str()); + // AND opcodes were generating bad code, as the hex constants were being converted badly. + // The most common case was 0x3f800000 being converted directly to integer decimal of 1065353216, instead + // of the most likely answer of floating point 1.0f. + // This also happened for conversion of Pi. + // There are bitmasks used for AND, and those need to stay as Hex constants. + // But anything used after IF statements/booleans, needs to be converted as float. + // Rather than modify applySwizzle for this single opcode, it makes more sense to convert them here, + // if they are to be used in boolean operations. We make a copy of the incoming operands, so that we + // can applySwizzle in order to be able to look up isBoolean properly. Can be r3.xxxy, and becomes r3.xy. + // That applySwizzle damages constants though, so if we are boolean, we'll use the original l() value. + case OPCODE_AND: + remapTarget(op1); + strcpy(op12, op2); + strcpy(op13, op3); + applySwizzle(op1, op2, true); + applySwizzle(op1, op3, true); + if (isBoolean(op2) || isBoolean(op3)) + { + convertHexToFloat(op12); + convertHexToFloat(op13); + applySwizzle(op1, op12); + applySwizzle(op1, op13); + char* cmp = isBoolean(op2) ? op12 : op13; + char* arg = isBoolean(op2) ? op13 : op12; + sprintf(buffer, " %s = %s ? %s : 0;\n", writeTarget(op1), ci(cmp).c_str(), ci(arg).c_str()); + appendOutput(buffer); + } else + { + sprintf(buffer, " %s = %s & %s;\n", writeTarget(op1), ci(convertToInt(op2)).c_str(), ci(convertToInt(op3)).c_str()); appendOutput(buffer); - removeBoolean(op1); - break; + } + break; - // USHR appears to be documented correctly. - // But this code was still backwards. - case OPCODE_USHR: - remapTarget(op1); - applySwizzle(op1, op2, true); - applySwizzle(op1, op3, true); - sprintf(buffer, " %s = %s >> %s;\n", writeTarget(op1), ci(convertToUInt(op2)).c_str(), ci(convertToUInt(op3)).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; + case OPCODE_OR: + remapTarget(op1); + applySwizzle(op1, op2); + applySwizzle(op1, op3); + sprintf(buffer, " %s = %s | %s;\n", writeTarget(op1), ci(convertToInt(op2)).c_str(), ci(convertToInt(op3)).c_str()); + appendOutput(buffer); + break; - // Newly found in CS for Prey - case OPCODE_COUNTBITS: - remapTarget(op1); - applySwizzle(op1, op2, true); - sprintf(buffer, " %s = countbits(%s);\n", writeTarget(op1), ci(convertToUInt(op2)).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; + case OPCODE_XOR: + remapTarget(op1); + applySwizzle(op1, op2); + applySwizzle(op1, op3); + sprintf(buffer, " %s = %s ^ %s;\n", writeTarget(op1), ci(convertToInt(op2)).c_str(), ci(convertToInt(op3)).c_str()); + appendOutput(buffer); + break; - // Add the Firstbit ops, because now Just Cause 3 uses them. - // firstbit{_hi|_lo|_shi} dest[.mask], src0[.swizzle] - case OPCODE_FIRSTBIT_HI: - remapTarget(op1); - applySwizzle(op1, op2, true); - sprintf(buffer, " %s = firstbithigh(%s);\n", writeTarget(op1), ci(convertToUInt(op2)).c_str()); + // Curiously enough, the documentation for ISHR and ISHL is wrong, and documents the parameters backwards. + // http://msdn.microsoft.com/en-us/library/windows/desktop/hh447145(v=vs.85).aspx + // This was proven by looking at actual game ASM, and trying to make the HLSL match the generated ASM. + // It is the C standard of: shift-expression << additive-expression + // So, we need op2 as the Shift-Expression, op3 as the # of bits to shift. + case OPCODE_ISHR: + remapTarget(op1); + applySwizzle(op1, op2, true); + applySwizzle(op1, op3, true); + sprintf(buffer, " %s = %s >> %s;\n", writeTarget(op1), ci(convertToUInt(op2)).c_str(), ci(convertToInt(op3)).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; + + case OPCODE_ISHL: + remapTarget(op1); + applySwizzle(op1, op2, true); + applySwizzle(op1, op3, true); + sprintf(buffer, " %s = %s << %s;\n", writeTarget(op1), ci(convertToUInt(op2)).c_str(), ci(convertToInt(op3)).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; + + // USHR appears to be documented correctly. + // But this code was still backwards. + case OPCODE_USHR: + remapTarget(op1); + applySwizzle(op1, op2, true); + applySwizzle(op1, op3, true); + sprintf(buffer, " %s = %s >> %s;\n", writeTarget(op1), ci(convertToUInt(op2)).c_str(), ci(convertToUInt(op3)).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; + + // Newly found in CS for Prey + case OPCODE_COUNTBITS: + remapTarget(op1); + applySwizzle(op1, op2, true); + sprintf(buffer, " %s = countbits(%s);\n", writeTarget(op1), ci(convertToUInt(op2)).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; + + // Add the Firstbit ops, because now Just Cause 3 uses them. + // firstbit{_hi|_lo|_shi} dest[.mask], src0[.swizzle] + case OPCODE_FIRSTBIT_HI: + remapTarget(op1); + applySwizzle(op1, op2, true); + sprintf(buffer, " %s = firstbithigh(%s);\n", writeTarget(op1), ci(convertToUInt(op2)).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; + case OPCODE_FIRSTBIT_LO: + remapTarget(op1); + applySwizzle(op1, op2, true); + sprintf(buffer, " %s = firstbitlow(%s);\n", writeTarget(op1), ci(convertToUInt(op2)).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; + case OPCODE_FIRSTBIT_SHI: + remapTarget(op1); + applySwizzle(op1, op2, true); + sprintf(buffer, " %s = firstbithigh(%s);\n", writeTarget(op1), ci(convertToInt(op2)).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; + + // Code generation for this weird instruction is tuned to indent the way we want, + // and still look like a single instruction. Still has weird indent in middle of instruction, + // but it seems more valuable to have it be a single line. + // + // Meh, you think this is weird? Looks like a less powerful version of rlwinm to me + case OPCODE_UBFE: + { + remapTarget(op1); + removeBoolean(op1); + applySwizzle(op1, op2); // width + applySwizzle(op1, op3); // offset + applySwizzle(op1, op4); + int idx = 0; + char* pop1 = strrchr(op1, '.'); *pop1 = 0; + while (*++pop1) + { + sprintf(op5, "%s.%c", op1, *pop1); + sprintf(buffer, " if (%s == 0) %s = 0; else if (%s+%s < 32) { ", + ci(GetSuffix(op2, idx)).c_str(), writeTarget(op5), ci(GetSuffix(op2, idx)).c_str(), ci(GetSuffix(op3, idx)).c_str()); appendOutput(buffer); - removeBoolean(op1); - break; - case OPCODE_FIRSTBIT_LO: - remapTarget(op1); - applySwizzle(op1, op2, true); - sprintf(buffer, " %s = firstbitlow(%s);\n", writeTarget(op1), ci(convertToUInt(op2)).c_str()); + // FIXME: May need fixup for read from constant buffer of unidentified type? + sprintf(buffer, "%s = (uint)%s << (32-(%s + %s)); %s = (uint)%s >> (32-%s); ", writeTarget(op5), ci(GetSuffix(op4, idx)).c_str(), ci(GetSuffix(op2, idx)).c_str(), ci(GetSuffix(op3, idx)).c_str(), writeTarget(op5), writeTarget(op5), ci(GetSuffix(op2, idx)).c_str()); appendOutput(buffer); - removeBoolean(op1); - break; - case OPCODE_FIRSTBIT_SHI: - remapTarget(op1); - applySwizzle(op1, op2, true); - sprintf(buffer, " %s = firstbithigh(%s);\n", writeTarget(op1), ci(convertToInt(op2)).c_str()); + sprintf(buffer, " } else %s = (uint)%s >> %s;\n", + writeTarget(op5), ci(GetSuffix(op4, idx)).c_str(), ci(GetSuffix(op3, idx)).c_str()); appendOutput(buffer); - removeBoolean(op1); - break; - - // Code generation for this weird instruction is tuned to indent the way we want, - // and still look like a single instruction. Still has weird indent in middle of instruction, - // but it seems more valuable to have it be a single line. - // - // Meh, you think this is weird? Looks like a less powerful version of rlwinm to me - case OPCODE_UBFE: - { - remapTarget(op1); - removeBoolean(op1); - applySwizzle(op1, op2); // width - applySwizzle(op1, op3); // offset - applySwizzle(op1, op4); - int idx = 0; - char *pop1 = strrchr(op1, '.'); *pop1 = 0; - while (*++pop1) - { - sprintf(op5, "%s.%c", op1, *pop1); - sprintf(buffer, " if (%s == 0) %s = 0; else if (%s+%s < 32) { ", - ci(GetSuffix(op2, idx)).c_str(), writeTarget(op5), ci(GetSuffix(op2, idx)).c_str(), ci(GetSuffix(op3, idx)).c_str()); - appendOutput(buffer); - // FIXME: May need fixup for read from constant buffer of unidentified type? - sprintf(buffer, "%s = (uint)%s << (32-(%s + %s)); %s = (uint)%s >> (32-%s); ", writeTarget(op5), ci(GetSuffix(op4, idx)).c_str(), ci(GetSuffix(op2, idx)).c_str(), ci(GetSuffix(op3, idx)).c_str(), writeTarget(op5), writeTarget(op5), ci(GetSuffix(op2, idx)).c_str()); - appendOutput(buffer); - sprintf(buffer, " } else %s = (uint)%s >> %s;\n", - writeTarget(op5), ci(GetSuffix(op4, idx)).c_str(), ci(GetSuffix(op3, idx)).c_str()); - appendOutput(buffer); - ++idx; - } - break; + ++idx; } + break; + } - case OPCODE_IBFE: - { - // Instruction for sign extending field extraction. Used in new versions of Dolphin - // ibfe r0.xyzw, l(24, 24, 24, 24), l(0, 0, 0, 0), cb0[12].xyzw - remapTarget(op1); - removeBoolean(op1); - applySwizzle(op1, op2, true); - applySwizzle(op1, op3, true); - applySwizzle(op1, op4); - sprintf(buffer, " %s = (%s == 0 ? 0 : (" - "%s + %s < 32 ? (" - "((int%s)%s << (32 - %s - %s)) >> (32 - %s)" - ") : (" - "(int%s)%s >> %s" - ")));\n", - writeTarget(op1), ci(op2).c_str(), - ci(op2).c_str(), ci(op3).c_str(), - swizCount(op4).c_str(), ci(op4).c_str(), ci(op2).c_str(), ci(op3).c_str(), ci(op2).c_str(), - swizCount(op4).c_str(), ci(op4).c_str(), ci(op3).c_str() - ); + case OPCODE_IBFE: + { + // Instruction for sign extending field extraction. Used in new versions of Dolphin + // ibfe r0.xyzw, l(24, 24, 24, 24), l(0, 0, 0, 0), cb0[12].xyzw + remapTarget(op1); + removeBoolean(op1); + applySwizzle(op1, op2, true); + applySwizzle(op1, op3, true); + applySwizzle(op1, op4); + sprintf(buffer, " %s = (%s == 0 ? 0 : (" + "%s + %s < 32 ? (" + "((int%s)%s << (32 - %s - %s)) >> (32 - %s)" + ") : (" + "(int%s)%s >> %s" + ")));\n", + writeTarget(op1), ci(op2).c_str(), + ci(op2).c_str(), ci(op3).c_str(), + swizCount(op4).c_str(), ci(op4).c_str(), ci(op2).c_str(), ci(op3).c_str(), ci(op2).c_str(), + swizCount(op4).c_str(), ci(op4).c_str(), ci(op3).c_str() + ); - appendOutput(buffer); - } - break; + appendOutput(buffer); + } + break; - case OPCODE_BFREV: - remapTarget(op1); - applySwizzle(op1, op2); - sprintf(buffer, " %s = reversebits(%s);\n", writeTarget(op1), ci(convertToUInt(op2)).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; + case OPCODE_BFREV: + remapTarget(op1); + applySwizzle(op1, op2); + sprintf(buffer, " %s = reversebits(%s);\n", writeTarget(op1), ci(convertToUInt(op2)).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; - case OPCODE_EXP: - remapTarget(op1); - applySwizzle(op1, op2); - if (!instr->bSaturate) - sprintf(buffer, " %s = exp2(%s);\n", writeTarget(op1), ci(op2).c_str()); - else - sprintf(buffer, " %s = saturate(exp2(%s));\n", writeTarget(op1), ci(op2).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; + case OPCODE_EXP: + remapTarget(op1); + applySwizzle(op1, op2); + if (!instr->bSaturate) + sprintf(buffer, " %s = exp2(%s);\n", writeTarget(op1), ci(op2).c_str()); + else + sprintf(buffer, " %s = saturate(exp2(%s));\n", writeTarget(op1), ci(op2).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; - case OPCODE_LOG: + case OPCODE_LOG: + { + const int lookahead = 6; + if (shader->dx9Shader && (iNr + lookahead < inst_count)) // FIXME: This is actually a lookahead code path and may not be DX9 specific { - const int lookahead = 6; - if (shader->dx9Shader && (iNr + lookahead < inst_count)) // FIXME: This is actually a lookahead code path and may not be DX9 specific + Instruction* nextIns[lookahead]; + for (int i = 0; i < lookahead; i++) + { + nextIns[i] = &(*instructions)[iNr + i + 1]; + } + + if (nextIns[0]->eOpcode == OPCODE_LOG && nextIns[1]->eOpcode == OPCODE_LOG && nextIns[2]->eOpcode == OPCODE_MUL && + nextIns[3]->eOpcode == OPCODE_EXP && nextIns[4]->eOpcode == OPCODE_EXP && nextIns[5]->eOpcode == OPCODE_EXP && + instr->asOperands[1].ui32RegisterNumber == nextIns[0]->asOperands[1].ui32RegisterNumber && + nextIns[0]->asOperands[1].ui32RegisterNumber == nextIns[1]->asOperands[1].ui32RegisterNumber) { - Instruction * nextIns[lookahead]; + string op1Str; + string op3Str; + + //read next instruction for (int i = 0; i < lookahead; i++) { - nextIns[i] = &(*instructions)[iNr + i + 1]; - } + while (c[pos] != 0x0a && pos < size) pos++; pos++; - if (nextIns[0]->eOpcode == OPCODE_LOG && nextIns[1]->eOpcode == OPCODE_LOG && nextIns[2]->eOpcode == OPCODE_MUL && - nextIns[3]->eOpcode == OPCODE_EXP && nextIns[4]->eOpcode == OPCODE_EXP && nextIns[5]->eOpcode == OPCODE_EXP && - instr->asOperands[1].ui32RegisterNumber == nextIns[0]->asOperands[1].ui32RegisterNumber && - nextIns[0]->asOperands[1].ui32RegisterNumber == nextIns[1]->asOperands[1].ui32RegisterNumber) - { - string op1Str; - string op3Str; + if (ReadStatement(c + pos) < 1) + { + logDecompileError("Error parsing statement: " + string(c + pos, 80)); + return; + } - //read next instruction - for (int i = 0; i < lookahead; i++) + if (i == 2) { - while (c[pos] != 0x0a && pos < size) pos++; pos++; - - if (ReadStatement(c + pos) < 1) - { - logDecompileError("Error parsing statement: " + string(c + pos, 80)); - return; - } - - if (i == 2) - { - op1Str = op1; - applySwizzle(op1, op3); - op3Str = op3; - } + op1Str = op1; + applySwizzle(op1, op3); + op3Str = op3; } + } - sprintf(buffer, " r%d.%s%s%s = pow(r%d.%s%s%s, %s);\n", nextIns[3]->asOperands[0].ui32RegisterNumber, GetComponentStrFromInstruction(nextIns[3], 0).c_str(), - GetComponentStrFromInstruction(nextIns[4], 0).c_str(), GetComponentStrFromInstruction(nextIns[5], 0).c_str(), - instr->asOperands[1].ui32RegisterNumber, GetComponentStrFromInstruction(instr, 1).c_str(), GetComponentStrFromInstruction(nextIns[0], 1).c_str(), - GetComponentStrFromInstruction(nextIns[1], 1).c_str(), op3Str.c_str()); + sprintf(buffer, " r%d.%s%s%s = pow(r%d.%s%s%s, %s);\n", nextIns[3]->asOperands[0].ui32RegisterNumber, GetComponentStrFromInstruction(nextIns[3], 0).c_str(), + GetComponentStrFromInstruction(nextIns[4], 0).c_str(), GetComponentStrFromInstruction(nextIns[5], 0).c_str(), + instr->asOperands[1].ui32RegisterNumber, GetComponentStrFromInstruction(instr, 1).c_str(), GetComponentStrFromInstruction(nextIns[0], 1).c_str(), + GetComponentStrFromInstruction(nextIns[1], 1).c_str(), op3Str.c_str()); - appendOutput(buffer); + appendOutput(buffer); - while (c[pos] != 0x0a && pos < size) pos++; pos++; - mLastStatement = nextIns[5]; - iNr += lookahead + 1; - continue; - } + while (c[pos] != 0x0a && pos < size) pos++; pos++; + mLastStatement = nextIns[5]; + iNr += lookahead + 1; + continue; } - - remapTarget(op1); - applySwizzle(op1, op2); - if (!instr->bSaturate) - sprintf(buffer, " %s = log2(%s);\n", writeTarget(op1), ci(op2).c_str()); - else - sprintf(buffer, " %s = saturate(log2(%s));\n", writeTarget(op1), ci(op2).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; } - // Opcodes for Sqrt, Min, Max, IMin, IMax all were using a 'statement' that is parsed - // from the text ASM. This did not match the Mov, or Add or other opcodes, and was - // generating errors when we'd see 'max_sat'. Anything with saturation added of these - // 5 could generate an error. - // This fix removes the dependency on 'statement', and codes the generated HLSL line directly. - // We are guessing, but it appears that this was a left-over from a conversion to using the - // James-Jones opcode parser as the primary parser. - case OPCODE_SQRT: - remapTarget(op1); - applySwizzle(op1, op2); - if (!instr->bSaturate) - sprintf(buffer, " %s = sqrt(%s);\n", writeTarget(op1), ci(op2).c_str()); - else - sprintf(buffer, " %s = saturate(sqrt(%s));\n", writeTarget(op1), ci(op2).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; + remapTarget(op1); + applySwizzle(op1, op2); + if (!instr->bSaturate) + sprintf(buffer, " %s = log2(%s);\n", writeTarget(op1), ci(op2).c_str()); + else + sprintf(buffer, " %s = saturate(log2(%s));\n", writeTarget(op1), ci(op2).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; + } - // Minor tweak, but if we reverse the order of Min/Max parameters here, the - // recompile comes out identical. - case OPCODE_MIN: - remapTarget(op1); - applySwizzle(op1, fixImm(op2, instr->asOperands[1])); - applySwizzle(op1, fixImm(op3, instr->asOperands[2])); - if (!instr->bSaturate) - sprintf(buffer, " %s = min(%s, %s);\n", writeTarget(op1), ci(op3).c_str(), ci(op2).c_str()); - else - sprintf(buffer, " %s = saturate(min(%s, %s));\n", writeTarget(op1), ci(op3).c_str(), ci(op2).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; + // Opcodes for Sqrt, Min, Max, IMin, IMax all were using a 'statement' that is parsed + // from the text ASM. This did not match the Mov, or Add or other opcodes, and was + // generating errors when we'd see 'max_sat'. Anything with saturation added of these + // 5 could generate an error. + // This fix removes the dependency on 'statement', and codes the generated HLSL line directly. + // We are guessing, but it appears that this was a left-over from a conversion to using the + // James-Jones opcode parser as the primary parser. + case OPCODE_SQRT: + remapTarget(op1); + applySwizzle(op1, op2); + if (!instr->bSaturate) + sprintf(buffer, " %s = sqrt(%s);\n", writeTarget(op1), ci(op2).c_str()); + else + sprintf(buffer, " %s = saturate(sqrt(%s));\n", writeTarget(op1), ci(op2).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; - // Missing opcode for UMin, used in Dragon Age - case OPCODE_UMIN: - remapTarget(op1); - applySwizzle(op1, fixImm(op2, instr->asOperands[1])); - applySwizzle(op1, fixImm(op3, instr->asOperands[2])); - sprintf(buffer, " %s = min(%s, %s);\n", writeTarget(op1), ci(convertToUInt(op3)).c_str(), ci(convertToUInt(op2)).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; + // Minor tweak, but if we reverse the order of Min/Max parameters here, the + // recompile comes out identical. + case OPCODE_MIN: + remapTarget(op1); + applySwizzle(op1, fixImm(op2, instr->asOperands[1])); + applySwizzle(op1, fixImm(op3, instr->asOperands[2])); + if (!instr->bSaturate) + sprintf(buffer, " %s = min(%s, %s);\n", writeTarget(op1), ci(op3).c_str(), ci(op2).c_str()); + else + sprintf(buffer, " %s = saturate(min(%s, %s));\n", writeTarget(op1), ci(op3).c_str(), ci(op2).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; - // Missing opcode for UMax, used in Witcher3 - case OPCODE_UMAX: - remapTarget(op1); - applySwizzle(op1, fixImm(op2, instr->asOperands[1])); - applySwizzle(op1, fixImm(op3, instr->asOperands[2])); - sprintf(buffer, " %s = max(%s, %s);\n", writeTarget(op1), ci(convertToUInt(op3)).c_str(), ci(convertToUInt(op2)).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; + // Missing opcode for UMin, used in Dragon Age + case OPCODE_UMIN: + remapTarget(op1); + applySwizzle(op1, fixImm(op2, instr->asOperands[1])); + applySwizzle(op1, fixImm(op3, instr->asOperands[2])); + sprintf(buffer, " %s = min(%s, %s);\n", writeTarget(op1), ci(convertToUInt(op3)).c_str(), ci(convertToUInt(op2)).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; - // Add remaining atomic ops, we see atomic_or in Song of the Deep. - // Needs an unclear manual fix, but better than not generating any HLSL at all. - // Opcodes found in Witcher3 Compute Shader, manual fix needed. - case OPCODE_ATOMIC_AND: - { - sprintf(buffer, " // Needs manual fix for instruction:\n"); - appendOutput(buffer); - ASMLineOut(c, pos, size); - sprintf(buffer, " InterlockedAnd(dest, value, orig_value);\n"); - appendOutput(buffer); - break; - } - case OPCODE_ATOMIC_OR: - { - sprintf(buffer, " // Needs manual fix for instruction:\n"); - appendOutput(buffer); - ASMLineOut(c, pos, size); - sprintf(buffer, " InterlockedOr(dest, value, orig_value);\n"); - appendOutput(buffer); - break; - } - case OPCODE_ATOMIC_XOR: - { - sprintf(buffer, " // Needs manual fix for instruction:\n"); - appendOutput(buffer); - ASMLineOut(c, pos, size); - sprintf(buffer, " InterlockedXor(dest, value, orig_value);\n"); - appendOutput(buffer); - break; - } - case OPCODE_ATOMIC_CMP_STORE: - { - sprintf(buffer, " // Needs manual fix for instruction:\n"); - appendOutput(buffer); - ASMLineOut(c, pos, size); - sprintf(buffer, " InterlockedCompareStore(dest, value, orig_value);\n"); - appendOutput(buffer); - break; - } - case OPCODE_ATOMIC_IADD: - { - sprintf(buffer, " // Needs manual fix for instruction:\n"); - appendOutput(buffer); - ASMLineOut(c, pos, size); - sprintf(buffer, " InterlockedAdd(dest, value, orig_value);\n"); - appendOutput(buffer); - break; - } - case OPCODE_ATOMIC_IMAX: - { - sprintf(buffer, " // Needs manual fix for instruction:\n"); - appendOutput(buffer); - ASMLineOut(c, pos, size); - sprintf(buffer, " InterlockedMax(dest, value, orig_value);\n"); - appendOutput(buffer); - break; - } - case OPCODE_ATOMIC_IMIN: - { - sprintf(buffer, " // Needs manual fix for instruction:\n"); - appendOutput(buffer); - ASMLineOut(c, pos, size); - sprintf(buffer, " InterlockedMin(dest, value, orig_value);\n"); - appendOutput(buffer); - break; - } - case OPCODE_ATOMIC_UMAX: - { - sprintf(buffer, " // Needs manual fix for instruction:\n"); - appendOutput(buffer); - ASMLineOut(c, pos, size); - sprintf(buffer, " InterlockedMax(dest, value, orig_value);\n"); - appendOutput(buffer); - break; - } - case OPCODE_ATOMIC_UMIN: - { - sprintf(buffer, " // Needs manual fix for instruction:\n"); - appendOutput(buffer); - ASMLineOut(c, pos, size); - sprintf(buffer, " InterlockedMin(dest, value, orig_value);\n"); - appendOutput(buffer); - break; - } - case OPCODE_IMM_ATOMIC_ALLOC: - { - sprintf(buffer, " // Needs manual fix for instruction:\n"); - appendOutput(buffer); - ASMLineOut(c, pos, size); - sprintf(buffer, " InterlockedExchange ?(dest, value, orig_value);\n"); - appendOutput(buffer); - break; - } - case OPCODE_IMM_ATOMIC_CONSUME: - { - sprintf(buffer, " // Needs manual fix for instruction:\n"); - appendOutput(buffer); - ASMLineOut(c, pos, size); - sprintf(buffer, " Interlocked... ?(dest, value, orig_value);\n"); - appendOutput(buffer); - break; - } - case OPCODE_IMM_ATOMIC_IADD: - { - sprintf(buffer, " // Needs manual fix for instruction:\n"); - appendOutput(buffer); - ASMLineOut(c, pos, size); - sprintf(buffer, " InterlockedAdd(dest, imm_value, orig_value);\n"); - appendOutput(buffer); - break; - } - case OPCODE_IMM_ATOMIC_AND: - { - sprintf(buffer, " // Needs manual fix for instruction:\n"); - appendOutput(buffer); - ASMLineOut(c, pos, size); - sprintf(buffer, " InterlockedAnd(dest, imm_value, orig_value);\n"); - appendOutput(buffer); - break; - } - case OPCODE_IMM_ATOMIC_OR: - { - sprintf(buffer, " // Needs manual fix for instruction:\n"); - appendOutput(buffer); - ASMLineOut(c, pos, size); - sprintf(buffer, " InterlockedOr(dest, imm_value, orig_value);\n"); - appendOutput(buffer); - break; - } - case OPCODE_IMM_ATOMIC_XOR: - { - sprintf(buffer, " // Needs manual fix for instruction:\n"); - appendOutput(buffer); - ASMLineOut(c, pos, size); - sprintf(buffer, " InterlockedXor(dest, imm_value, orig_value);\n"); - appendOutput(buffer); - break; - } - case OPCODE_IMM_ATOMIC_EXCH: - { - sprintf(buffer, " // Needs manual fix for instruction:\n"); - appendOutput(buffer); - ASMLineOut(c, pos, size); - sprintf(buffer, " InterlockedExchange(dest, imm_value, orig_value);\n"); - appendOutput(buffer); - break; - } - case OPCODE_IMM_ATOMIC_CMP_EXCH: - { - sprintf(buffer, " // Needs manual fix for instruction:\n"); - appendOutput(buffer); - ASMLineOut(c, pos, size); - sprintf(buffer, " InterlockedCompareExchange(dest, compare_value, imm_value, orig_value);\n"); - appendOutput(buffer); - break; - } - case OPCODE_IMM_ATOMIC_IMAX: - { - sprintf(buffer, " // Needs manual fix for instruction:\n"); - appendOutput(buffer); - ASMLineOut(c, pos, size); - sprintf(buffer, " InterlockedMax(dest, imm_value, orig_value);\n"); - appendOutput(buffer); - break; - } - case OPCODE_IMM_ATOMIC_IMIN: - { - sprintf(buffer, " // Needs manual fix for instruction:\n"); - appendOutput(buffer); - ASMLineOut(c, pos, size); - sprintf(buffer, " InterlockedMin(dest, imm_value, orig_value);\n"); - appendOutput(buffer); - break; - } - case OPCODE_IMM_ATOMIC_UMAX: - { - sprintf(buffer, " // Needs manual fix for instruction:\n"); - appendOutput(buffer); - ASMLineOut(c, pos, size); - sprintf(buffer, " InterlockedMax(dest, imm_value, orig_value);\n"); - appendOutput(buffer); - break; - } - case OPCODE_IMM_ATOMIC_UMIN: - { - sprintf(buffer, " // Needs manual fix for instruction:\n"); - appendOutput(buffer); - ASMLineOut(c, pos, size); - sprintf(buffer, " InterlockedMin(dest, imm_value, orig_value);\n"); - appendOutput(buffer); - break; - } + // Missing opcode for UMax, used in Witcher3 + case OPCODE_UMAX: + remapTarget(op1); + applySwizzle(op1, fixImm(op2, instr->asOperands[1])); + applySwizzle(op1, fixImm(op3, instr->asOperands[2])); + sprintf(buffer, " %s = max(%s, %s);\n", writeTarget(op1), ci(convertToUInt(op3)).c_str(), ci(convertToUInt(op2)).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; + + // Add remaining atomic ops, we see atomic_or in Song of the Deep. + // Needs an unclear manual fix, but better than not generating any HLSL at all. + // Opcodes found in Witcher3 Compute Shader, manual fix needed. + case OPCODE_ATOMIC_AND: + { + sprintf(buffer, " // Needs manual fix for instruction:\n"); + appendOutput(buffer); + ASMLineOut(c, pos, size); + sprintf(buffer, " InterlockedAnd(dest, value, orig_value);\n"); + appendOutput(buffer); + break; + } + case OPCODE_ATOMIC_OR: + { + sprintf(buffer, " // Needs manual fix for instruction:\n"); + appendOutput(buffer); + ASMLineOut(c, pos, size); + sprintf(buffer, " InterlockedOr(dest, value, orig_value);\n"); + appendOutput(buffer); + break; + } + case OPCODE_ATOMIC_XOR: + { + sprintf(buffer, " // Needs manual fix for instruction:\n"); + appendOutput(buffer); + ASMLineOut(c, pos, size); + sprintf(buffer, " InterlockedXor(dest, value, orig_value);\n"); + appendOutput(buffer); + break; + } + case OPCODE_ATOMIC_CMP_STORE: + { + sprintf(buffer, " // Needs manual fix for instruction:\n"); + appendOutput(buffer); + ASMLineOut(c, pos, size); + sprintf(buffer, " InterlockedCompareStore(dest, value, orig_value);\n"); + appendOutput(buffer); + break; + } + case OPCODE_ATOMIC_IADD: + { + sprintf(buffer, " // Needs manual fix for instruction:\n"); + appendOutput(buffer); + ASMLineOut(c, pos, size); + sprintf(buffer, " InterlockedAdd(dest, value, orig_value);\n"); + appendOutput(buffer); + break; + } + case OPCODE_ATOMIC_IMAX: + { + sprintf(buffer, " // Needs manual fix for instruction:\n"); + appendOutput(buffer); + ASMLineOut(c, pos, size); + sprintf(buffer, " InterlockedMax(dest, value, orig_value);\n"); + appendOutput(buffer); + break; + } + case OPCODE_ATOMIC_IMIN: + { + sprintf(buffer, " // Needs manual fix for instruction:\n"); + appendOutput(buffer); + ASMLineOut(c, pos, size); + sprintf(buffer, " InterlockedMin(dest, value, orig_value);\n"); + appendOutput(buffer); + break; + } + case OPCODE_ATOMIC_UMAX: + { + sprintf(buffer, " // Needs manual fix for instruction:\n"); + appendOutput(buffer); + ASMLineOut(c, pos, size); + sprintf(buffer, " InterlockedMax(dest, value, orig_value);\n"); + appendOutput(buffer); + break; + } + case OPCODE_ATOMIC_UMIN: + { + sprintf(buffer, " // Needs manual fix for instruction:\n"); + appendOutput(buffer); + ASMLineOut(c, pos, size); + sprintf(buffer, " InterlockedMin(dest, value, orig_value);\n"); + appendOutput(buffer); + break; + } + case OPCODE_IMM_ATOMIC_ALLOC: + { + sprintf(buffer, " // Needs manual fix for instruction:\n"); + appendOutput(buffer); + ASMLineOut(c, pos, size); + sprintf(buffer, " InterlockedExchange ?(dest, value, orig_value);\n"); + appendOutput(buffer); + break; + } + case OPCODE_IMM_ATOMIC_CONSUME: + { + sprintf(buffer, " // Needs manual fix for instruction:\n"); + appendOutput(buffer); + ASMLineOut(c, pos, size); + sprintf(buffer, " Interlocked... ?(dest, value, orig_value);\n"); + appendOutput(buffer); + break; + } + case OPCODE_IMM_ATOMIC_IADD: + { + sprintf(buffer, " // Needs manual fix for instruction:\n"); + appendOutput(buffer); + ASMLineOut(c, pos, size); + sprintf(buffer, " InterlockedAdd(dest, imm_value, orig_value);\n"); + appendOutput(buffer); + break; + } + case OPCODE_IMM_ATOMIC_AND: + { + sprintf(buffer, " // Needs manual fix for instruction:\n"); + appendOutput(buffer); + ASMLineOut(c, pos, size); + sprintf(buffer, " InterlockedAnd(dest, imm_value, orig_value);\n"); + appendOutput(buffer); + break; + } + case OPCODE_IMM_ATOMIC_OR: + { + sprintf(buffer, " // Needs manual fix for instruction:\n"); + appendOutput(buffer); + ASMLineOut(c, pos, size); + sprintf(buffer, " InterlockedOr(dest, imm_value, orig_value);\n"); + appendOutput(buffer); + break; + } + case OPCODE_IMM_ATOMIC_XOR: + { + sprintf(buffer, " // Needs manual fix for instruction:\n"); + appendOutput(buffer); + ASMLineOut(c, pos, size); + sprintf(buffer, " InterlockedXor(dest, imm_value, orig_value);\n"); + appendOutput(buffer); + break; + } + case OPCODE_IMM_ATOMIC_EXCH: + { + sprintf(buffer, " // Needs manual fix for instruction:\n"); + appendOutput(buffer); + ASMLineOut(c, pos, size); + sprintf(buffer, " InterlockedExchange(dest, imm_value, orig_value);\n"); + appendOutput(buffer); + break; + } + case OPCODE_IMM_ATOMIC_CMP_EXCH: + { + sprintf(buffer, " // Needs manual fix for instruction:\n"); + appendOutput(buffer); + ASMLineOut(c, pos, size); + sprintf(buffer, " InterlockedCompareExchange(dest, compare_value, imm_value, orig_value);\n"); + appendOutput(buffer); + break; + } + case OPCODE_IMM_ATOMIC_IMAX: + { + sprintf(buffer, " // Needs manual fix for instruction:\n"); + appendOutput(buffer); + ASMLineOut(c, pos, size); + sprintf(buffer, " InterlockedMax(dest, imm_value, orig_value);\n"); + appendOutput(buffer); + break; + } + case OPCODE_IMM_ATOMIC_IMIN: + { + sprintf(buffer, " // Needs manual fix for instruction:\n"); + appendOutput(buffer); + ASMLineOut(c, pos, size); + sprintf(buffer, " InterlockedMin(dest, imm_value, orig_value);\n"); + appendOutput(buffer); + break; + } + case OPCODE_IMM_ATOMIC_UMAX: + { + sprintf(buffer, " // Needs manual fix for instruction:\n"); + appendOutput(buffer); + ASMLineOut(c, pos, size); + sprintf(buffer, " InterlockedMax(dest, imm_value, orig_value);\n"); + appendOutput(buffer); + break; + } + case OPCODE_IMM_ATOMIC_UMIN: + { + sprintf(buffer, " // Needs manual fix for instruction:\n"); + appendOutput(buffer); + ASMLineOut(c, pos, size); + sprintf(buffer, " InterlockedMin(dest, imm_value, orig_value);\n"); + appendOutput(buffer); + break; + } - case OPCODE_MAX: + case OPCODE_MAX: + { + const int lookahead = 1; + if (shader->dx9Shader && (iNr + lookahead < inst_count)) // FIXME: This is actually a lookahead code path and may not be DX9 specific { - const int lookahead = 1; - if (shader->dx9Shader && (iNr + lookahead < inst_count)) // FIXME: This is actually a lookahead code path and may not be DX9 specific + Instruction* nextIns = &(*instructions)[iNr + 1]; + if (nextIns->eOpcode == OPCODE_MAD && + IsInstructionOperandSame(instr, 3, nextIns, 3, GetComponentStrFromInstruction(instr, 0).c_str(), GetComponentStrFromInstruction(nextIns, 0).c_str()) == 2 && + IsInstructionOperandSame(instr, 0, nextIns, 2, NULL, GetComponentStrFromInstruction(nextIns, 0).c_str()) == 1) { - Instruction * nextIns = &(*instructions)[iNr + 1]; - if (nextIns->eOpcode == OPCODE_MAD && - IsInstructionOperandSame(instr, 3, nextIns, 3, GetComponentStrFromInstruction(instr, 0).c_str(), GetComponentStrFromInstruction(nextIns, 0).c_str()) == 2 && - IsInstructionOperandSame(instr, 0, nextIns, 2, NULL, GetComponentStrFromInstruction(nextIns, 0).c_str()) == 1) - { - applySwizzle(op1, op2); - applySwizzle(op1, op3); - - char y[opcodeSize]; - sprintf_s(y, opcodeSize, "%s * %s", op2, op3); - - //read next instruction - for (int i = 0; i < lookahead; i++) - { - while (c[pos] != 0x0a && pos < size) pos++; pos++; - - if (ReadStatement(c + pos) < 1) - { - logDecompileError("Error parsing statement: " + string(c + pos, 80)); - return; - } - } - - remapTarget(op1); - applySwizzle(op1, op2); - applySwizzle(op1, op4); - sprintf_s(buffer, opcodeSize, " %s = lerp(%s, %s, %s);\n", op1, op4, y, op2); - appendOutput(buffer); - - while (c[pos] != 0x0a && pos < size) pos++; pos++; - mLastStatement = nextIns; - iNr += lookahead + 1; - continue; - } - } - - remapTarget(op1); - applySwizzle(op1, fixImm(op2, instr->asOperands[1])); - applySwizzle(op1, fixImm(op3, instr->asOperands[2])); - if (!instr->bSaturate) - sprintf(buffer, " %s = max(%s, %s);\n", writeTarget(op1), ci(op3).c_str(), ci(op2).c_str()); - else - sprintf(buffer, " %s = saturate(max(%s, %s));\n", writeTarget(op1), ci(op3).c_str(), ci(op2).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; - } - case OPCODE_IMIN: - remapTarget(op1); - applySwizzle(op1, fixImm(op2, instr->asOperands[1]), true); - applySwizzle(op1, fixImm(op3, instr->asOperands[2]), true); - if (!instr->bSaturate) - sprintf(buffer, " %s = min(%s, %s);\n", writeTarget(op1), ci(convertToInt(op3)).c_str(), ci(convertToInt(op2)).c_str()); - else - sprintf(buffer, " %s = saturate(min(%s, %s));\n", writeTarget(op1), ci(convertToInt(op3)).c_str(), ci(convertToInt(op2)).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; - case OPCODE_IMAX: - remapTarget(op1); - applySwizzle(op1, fixImm(op2, instr->asOperands[1]), true); - applySwizzle(op1, fixImm(op3, instr->asOperands[2]), true); - if (!instr->bSaturate) - sprintf(buffer, " %s = max(%s, %s);\n", writeTarget(op1), ci(convertToInt(op3)).c_str(), ci(convertToInt(op2)).c_str()); - else - sprintf(buffer, " %s = saturate(max(%s, %s));\n", writeTarget(op1), ci(convertToInt(op3)).c_str(), ci(convertToInt(op2)).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; - - case OPCODE_MAD: - remapTarget(op1); - applySwizzle(op1, fixImm(op2, instr->asOperands[1])); - applySwizzle(op1, fixImm(op3, instr->asOperands[2])); - applySwizzle(op1, fixImm(op4, instr->asOperands[3])); - // Check for operation reorder. - /* - if (mLastStatement && mLastStatement->eOpcode == OPCODE_MUL && strstr(op4, mMulTarget.c_str()) && - mMulTarget.compare(0, 3, mMulOperand, mMulOperand[0] == '-' ? 1 : 0, 3) && - mMulTarget.compare(0, 3, mMulOperand2, mMulOperand2[0] == '-' ? 1 : 0, 3)) - sprintf(op4 + ((op4[0] == '-') ? 1 : 0), "(%s * %s)", mMulOperand.c_str(), mMulOperand2.c_str()); - */ - if (!instr->bSaturate) - sprintf(buffer, " %s = %s * %s + %s;\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str(), ci(op4).c_str()); - else - sprintf(buffer, " %s = saturate(%s * %s + %s);\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str(), ci(op4).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; - - case OPCODE_IMAD: - remapTarget(op1); - applySwizzle(op1, op2, true); - applySwizzle(op1, op3, true); - applySwizzle(op1, op4, true); - sprintf(buffer, " %s = mad(%s, %s, %s);\n", writeTarget(op1), ci(convertToInt(op2)).c_str(), ci(convertToInt(op3)).c_str(), ci(convertToInt(op4)).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; - case OPCODE_UMAD: - remapTarget(op1); - applySwizzle(op1, op2, true); - applySwizzle(op1, op3, true); - applySwizzle(op1, op4, true); - sprintf(buffer, " %s = mad(%s, %s, %s);\n", writeTarget(op1), ci(convertToUInt(op2)).c_str(), ci(convertToUInt(op3)).c_str(), ci(convertToUInt(op4)).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; + applySwizzle(op1, op2); + applySwizzle(op1, op3); - case OPCODE_DP2: - remapTarget(op1); - applySwizzle(".xy", fixImm(op2, instr->asOperands[1])); - applySwizzle(".xy", fixImm(op3, instr->asOperands[2])); - if (!instr->bSaturate) - sprintf(buffer, " %s = dot(%s, %s);\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str()); - else - sprintf(buffer, " %s = saturate(dot(%s, %s));\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; + char y[opcodeSize]; + sprintf_s(y, opcodeSize, "%s * %s", op2, op3); - case OPCODE_DP3: - { - const int lookahead = 2; - if (shader->dx9Shader && (iNr + lookahead < inst_count)) // FIXME: This is actually a lookahead code path and may not be DX9 specific - { - Instruction * nextIns[lookahead]; + //read next instruction for (int i = 0; i < lookahead; i++) { - nextIns[i] = &(*instructions)[iNr + i + 1]; - } - - string outputOp1 = GetComponentStrFromInstruction(nextIns[1], 0); + while (c[pos] != 0x0a && pos < size) pos++; pos++; - if (nextIns[0]->eOpcode == OPCODE_ADD && nextIns[1]->eOpcode == OPCODE_MAD && - IsInstructionOperandSame(instr, 0, nextIns[0], 1) == 1 && IsInstructionOperandSame(instr, 0, nextIns[0], 2) == 1 && - IsInstructionOperandSame(nextIns[0], 0, nextIns[1], 2) == 2 && - IsInstructionOperandSame(instr, 1, nextIns[1], 3, NULL, outputOp1.c_str()) == 1 && IsInstructionOperandSame(instr, 2, nextIns[1], 1, NULL, outputOp1.c_str()) == 1) - { - //read next instruction - for (int i = 0; i < lookahead; i++) + if (ReadStatement(c + pos) < 1) { - while (c[pos] != 0x0a && pos < size) pos++; pos++; - - if (ReadStatement(c + pos) < 1) - { - logDecompileError("Error parsing statement: " + string(c + pos, 80)); - return; - } + logDecompileError("Error parsing statement: " + string(c + pos, 80)); + return; } + } - remapTarget(op1); - sprintf_s(op2, opcodeSize, "r%d.%s", nextIns[1]->asOperands[3].ui32RegisterNumber, GetComponentStrFromInstruction(nextIns[1], 3).c_str()); - sprintf_s(op3, opcodeSize, "r%d.%s", nextIns[1]->asOperands[1].ui32RegisterNumber, GetComponentStrFromInstruction(nextIns[1], 1).c_str()); - applySwizzle(op1, op2); - applySwizzle(op1, op3); - - sprintf(buffer, " %s = reflect(%s, %s);\n", writeTarget(op1), op2, op3); - - appendOutput(buffer); + remapTarget(op1); + applySwizzle(op1, op2); + applySwizzle(op1, op4); + sprintf_s(buffer, opcodeSize, " %s = lerp(%s, %s, %s);\n", op1, op4, y, op2); + appendOutput(buffer); - while (c[pos] != 0x0a && pos < size) pos++; pos++; - mLastStatement = nextIns[1]; - iNr += lookahead + 1; - continue; - } + while (c[pos] != 0x0a && pos < size) pos++; pos++; + mLastStatement = nextIns; + iNr += lookahead + 1; + continue; } - - remapTarget(op1); - applySwizzle(".xyz", fixImm(op2, instr->asOperands[1])); - applySwizzle(".xyz", fixImm(op3, instr->asOperands[2])); - if (!instr->bSaturate) - sprintf(buffer, " %s = dot(%s, %s);\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str()); - else - sprintf(buffer, " %s = saturate(dot(%s, %s));\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; } - case OPCODE_DP4: - { - const int lookahead = 1; - if (shader->dx9Shader && (iNr + lookahead < inst_count)) // FIXME: This is actually a lookahead code path and may not be DX9 specific - { - remapTarget(op1); - Instruction * nextInstr = &(*instructions)[iNr + 1]; - string outputOp0 = GetComponentStrFromInstruction(instr, 0); - - //nrm generate two instructions,dp4 and rsq - if (nextInstr->eOpcode == OPCODE_RSQ && outputOp0.size() == 3) - { - applySwizzle(op1, op2); - sprintf(buffer, " %s = normalize(%s);\n", writeTarget(op1), ci(op2).c_str()); - appendOutput(buffer); - - //asm just one line,don't need call ReadStatement - //have two instructions - iNr++; - - // NOTE: NO CONTINUE HERE - NEED ONE BEFORE ELIMINATING DUPLICATE CODE BELOW - // AND NEED A REGRESSION TEST BEFORE DOING THAT. - } - else - { - // XXX NOTE Duplicated code below!!! - applySwizzle(".xyzw", fixImm(op2, instr->asOperands[1])); - applySwizzle(".xyzw", fixImm(op3, instr->asOperands[2])); - if (!instr->bSaturate) - sprintf(buffer, " %s = dot(%s, %s);\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str()); - else - sprintf(buffer, " %s = saturate(dot(%s, %s));\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str()); - appendOutput(buffer); - // XXX NOTE Duplicated code below!!! - } - } - else - { - // XXX NOTE Duplicated code above!!! - remapTarget(op1); - applySwizzle(".xyzw", fixImm(op2, instr->asOperands[1])); - applySwizzle(".xyzw", fixImm(op3, instr->asOperands[2])); - if (!instr->bSaturate) - sprintf(buffer, " %s = dot(%s, %s);\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str()); - else - sprintf(buffer, " %s = saturate(dot(%s, %s));\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str()); - appendOutput(buffer); - removeBoolean(op1); - // XXX NOTE Duplicated code above!!! - } - break; - } - case OPCODE_DP2ADD: - remapTarget(op1); - applySwizzle(".xy", op2); - applySwizzle(".xy", op3); - applySwizzle(".xy", op4); - sprintf(buffer, " %s = dot2(%s, %s) + %s;\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str(), ci(op4).c_str()); - appendOutput(buffer); - - //dx9 - break; - - //dx9 - case OPCODE_LRP: - remapTarget(op1); - applySwizzle(op1, op2); - applySwizzle(op1, op3); - applySwizzle(op1, op4); - sprintf(buffer, " %s = lerp(%s, %s, %s);\n", writeTarget(op1), ci(op4).c_str(), ci(op3).c_str(), ci(op2).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; - - case OPCODE_POW: - remapTarget(op1); - applySwizzle(op1, op2); - applySwizzle(op1, op3); - sprintf(buffer, " %s = pow(%s, %s);\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str()); - appendOutput(buffer); - break; - //dx9 - case OPCODE_RSQ: - { - remapTarget(op1); - applySwizzle(op1, op2); - if (!instr->bSaturate) { - // The DX9 port switched this to 1/sqrt(), however - // it is unclear why that was necessary - rsqrt - // should work in everything since vs_1_1 and - // ps_2_0 (and in fact the regular sqrt didn't - // exist until shader model 4). Look up "fast - // inverse square root" to have your mind blown and - // get an idea of why this matters. - // - // Reverting this to rsqrt since the DX9 decompiler - // support is clearly unfinished and no explanation - // for this change was provided. - // - sprintf(buffer, " %s = rsqrt(%s);\n", writeTarget(op1), ci(op2).c_str()); - } else { - sprintf(buffer, " %s = saturate(rsqrt(%s));\n", writeTarget(op1), ci(op2).c_str()); - } - appendOutput(buffer); - removeBoolean(op1); - break; - } - - // Double checked this while looking at other round bugs. Looks correct to use 'floor'. - case OPCODE_ROUND_NI: - { - remapTarget(op1); - applySwizzle(op1, op2); - if (!instr->bSaturate) - sprintf(buffer, " %s = floor(%s);\n", writeTarget(op1), ci(op2).c_str()); - else - sprintf(buffer, " %s = saturate(floor(%s));\n", writeTarget(op1), ci(op2).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; - } - case OPCODE_ROUND_PI: - { - remapTarget(op1); - applySwizzle(op1, op2); - if (!instr->bSaturate) - sprintf(buffer, " %s = ceil(%s);\n", writeTarget(op1), ci(op2).c_str()); - else - sprintf(buffer, " %s = saturate(ceil(%s));\n", writeTarget(op1), ci(op2).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; - } - - // Was previously doing a Round operation, but that is not correct because this needs to - // round toward zero, and Round can go larger. Trunc(1.6)->1.0 Round(1.6)->2.0 - // Also removed the unrolling, the instruction works with swizzle. e.g. r0.xy = trunc(r2.yz) - case OPCODE_ROUND_Z: - { - remapTarget(op1); - applySwizzle(op1, op2); - if (!instr->bSaturate) - sprintf(buffer, " %s = trunc(%s);\n", writeTarget(op1), ci(op2).c_str()); - else - sprintf(buffer, " %s = saturate(trunc(%s));\n", writeTarget(op1), ci(op2).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; - } - - // Round_NE is Round Nearest Even, and using HLSL Round here is correct. - // But it previously used a *0.5*2 rounding which is unnecessary. - // The HLSL intrinsics of Round will already do that. - case OPCODE_ROUND_NE: - { - remapTarget(op1); - applySwizzle(op1, op2); - if (!instr->bSaturate) - sprintf(buffer, " %s = round(%s);\n", writeTarget(op1), ci(op2).c_str()); - else - sprintf(buffer, " %s = saturate(round(%s));\n", writeTarget(op1), ci(op2).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; - } - case OPCODE_FTOI: - remapTarget(op1); - applySwizzle(op1, op2); - sprintf(buffer, " %s = %s;\n", writeTarget(op1), ci(castToInt(op2)).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; - - case OPCODE_FTOU: - remapTarget(op1); - applySwizzle(op1, op2); - sprintf(buffer, " %s = %s;\n", writeTarget(op1), ci(castToUInt(op2)).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; - - case OPCODE_SINCOS: - remapTarget(op1); - remapTarget(op2); - if (!strncmp(op1, "null", 4)) - applySwizzle(op2, op3); - else - applySwizzle(op1, op3); - if (!strncmp(op1, "null", 4)) - sprintf(buffer, " %s = cos(%s);\n", writeTarget(op2), ci(op3).c_str()); - else if (!strncmp(op2, "null", 4)) - sprintf(buffer, " %s = sin(%s);\n", writeTarget(op1), ci(op3).c_str()); - else - sprintf(buffer, " sincos(%s, %s, %s);\n", ci(op3).c_str(), writeTarget(op1), writeTarget(op2)); - appendOutput(buffer); - removeBoolean(op1); - removeBoolean(op2); - break; - - // Failing case of: "movc_sat r2.xyzw, r2.xxxx, r7.xyzw, r4.xyzw" - // Turned into: - // r2.x = saturate(r2.x ? r7.x : r4.x); - // r2.y = saturate(r2.x ? r7.y : r4.y); - // r2.z = saturate(r2.x ? r7.z : r4.z); - // r2.w = saturate(r2.x ? r7.w : r4.w); - // which damages r2.x at the first line, and uses it in each. - // Changed it to just be: "r2.xyzw = saturate(r2.xxxx ? r7.xyzw : r4.xyzw);" - // But I'm not sure why this was unrolled to begin with. - case OPCODE_MOVC: - { - remapTarget(op1); - applySwizzle(op1, fixImm(op2, instr->asOperands[1])); - applySwizzle(op1, fixImm(op3, instr->asOperands[2])); - applySwizzle(op1, fixImm(op4, instr->asOperands[3])); - if (!instr->bSaturate) - sprintf(buffer, " %s = %s ? %s : %s;\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str(), ci(op4).c_str()); - else - sprintf(buffer, " %s = saturate(%s ? %s : %s);\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str(), ci(op4).c_str()); - appendOutput(buffer); - - //int idx = 0; - //char *pop1 = strrchr(op1, '.'); *pop1 = 0; - //char *pop2 = strrchr(op2, '.'); if (pop2) *pop2 = 0; - //while (*++pop1) - //{ - //if (pop1) sprintf(op5, "%s.%c", op1, *pop1); else sprintf(op5, "%s", op1); - //if (pop2) sprintf(op6, "%s.%c", op2, *++pop2); else sprintf(op6, "%s", op2); - //if (!instr->bSaturate) - // sprintf(buffer, " %s = %s ? %s : %s;\n", writeTarget(op5), ci(op6).c_str(), ci(GetSuffix(op3, idx)).c_str(), ci(GetSuffix(op4, idx)).c_str()); - //else - // sprintf(buffer, " %s = saturate(%s ? %s : %s);\n", writeTarget(op5), ci(op6).c_str(), ci(GetSuffix(op3, idx)).c_str(), ci(GetSuffix(op4, idx)).c_str()); - //appendOutput(buffer); - // ++idx; - //} - removeBoolean(op1); - break; - } - - // Big change to all these boolean test opcodes. All were unrolled and generated a code line per component. - // To make the boolean tests work correctly for AND, these were rolled back into one, and added to the boolean - // set list as a complete operand, like 'r0.xyw'. - case OPCODE_NE: - { - remapTarget(op1); - applySwizzle(op1, op2); - applySwizzle(op1, op3); - sprintf(buffer, " %s = cmp(%s != %s);\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str()); - appendOutput(buffer); - addBoolean(op1); - break; - } - case OPCODE_INE: - { - remapTarget(op1); - applySwizzle(op1, op2, true); - applySwizzle(op1, op3, true); - sprintf(buffer, " %s = cmp(%s != %s);\n", writeTarget(op1), ci(convertToInt(op2)).c_str(), ci(convertToInt(op3)).c_str()); - appendOutput(buffer); - addBoolean(op1); - break; - } - case OPCODE_EQ: - { - remapTarget(op1); - applySwizzle(op1, op2); - applySwizzle(op1, op3); - sprintf(buffer, " %s = cmp(%s == %s);\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str()); - appendOutput(buffer); - addBoolean(op1); - break; - } - case OPCODE_IEQ: - { - remapTarget(op1); - applySwizzle(op1, op2, true); - applySwizzle(op1, op3, true); - sprintf(buffer, " %s = cmp(%s == %s);\n", writeTarget(op1), ci(convertToInt(op2)).c_str(), ci(convertToInt(op3)).c_str()); - appendOutput(buffer); - addBoolean(op1); - break; - } - case OPCODE_LT: - { - remapTarget(op1); - applySwizzle(op1, fixImm(op2, instr->asOperands[1])); - applySwizzle(op1, fixImm(op3, instr->asOperands[2])); - sprintf(buffer, " %s = cmp(%s < %s);\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str()); - appendOutput(buffer); - addBoolean(op1); - break; - } - case OPCODE_ILT: - { - remapTarget(op1); - applySwizzle(op1, op2, true); - applySwizzle(op1, op3, true); - sprintf(buffer, " %s = cmp(%s < %s);\n", writeTarget(op1), ci(convertToInt(op2)).c_str(), ci(convertToInt(op3)).c_str()); - appendOutput(buffer); - addBoolean(op1); - break; - } - case OPCODE_ULT: - { - remapTarget(op1); - applySwizzle(op1, op2, true); - applySwizzle(op1, op3, true); - sprintf(buffer, " %s = cmp(%s < %s);\n", writeTarget(op1), ci(convertToUInt(op2)).c_str(), ci(convertToUInt(op3)).c_str()); - appendOutput(buffer); - addBoolean(op1); - break; - } - case OPCODE_GE: - { - remapTarget(op1); - applySwizzle(op1, fixImm(op2, instr->asOperands[1])); - applySwizzle(op1, fixImm(op3, instr->asOperands[2])); - sprintf(buffer, " %s = cmp(%s >= %s);\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str()); - appendOutput(buffer); - addBoolean(op1); - break; - } - case OPCODE_IGE: - { - remapTarget(op1); - applySwizzle(op1, op2, true); - applySwizzle(op1, op3, true); - sprintf(buffer, " %s = cmp(%s >= %s);\n", writeTarget(op1), ci(convertToInt(op2)).c_str(), ci(convertToInt(op3)).c_str()); - appendOutput(buffer); - addBoolean(op1); - break; - } - case OPCODE_UGE: - { - remapTarget(op1); - applySwizzle(op1, op2, true); - applySwizzle(op1, op3, true); - sprintf(buffer, " %s = cmp(%s >= %s);\n", writeTarget(op1), ci(convertToUInt(op2)).c_str(), ci(convertToUInt(op3)).c_str()); - appendOutput(buffer); - addBoolean(op1); - break; - } - - // Switch statement in HLSL was missing. Added because AC4 uses it. - case OPCODE_SWITCH: - sprintf(buffer, " switch (%s) {\n", ci(op1).c_str()); - appendOutput(buffer); - break; - case OPCODE_CASE: - sprintf(buffer, " case %s :", ci(op1).substr(2, 1).c_str()); - appendOutput(buffer); - break; - case OPCODE_ENDSWITCH: - sprintf(buffer, " }\n"); - appendOutput(buffer); - break; - case OPCODE_DEFAULT: - sprintf(buffer, " default :\n"); - appendOutput(buffer); - break; - - case OPCODE_IF: - applySwizzle(".x", op1); - if (instr->eBooleanTestType == INSTRUCTION_TEST_ZERO) - sprintf(buffer, " if (%s == 0) {\n", ci(op1).c_str()); - else - sprintf(buffer, " if (%s != 0) {\n", ci(op1).c_str()); - appendOutput(buffer); - break; - case OPCODE_ELSE: - sprintf(buffer, " } else {\n"); - appendOutput(buffer); - break; - case OPCODE_ENDIF: - sprintf(buffer, " }\n"); - appendOutput(buffer); - break; - - case OPCODE_LOOP: - sprintf(buffer, " while (true) {\n"); - appendOutput(buffer); - break; - case OPCODE_BREAK: - sprintf(buffer, " break;\n"); - appendOutput(buffer); - break; - case OPCODE_BREAKC: - applySwizzle(".x", op1); - if (instr->eBooleanTestType == INSTRUCTION_TEST_ZERO) - sprintf(buffer, " if (%s == 0) break;\n", ci(op1).c_str()); - else - sprintf(buffer, " if (%s != 0) break;\n", ci(op1).c_str()); - appendOutput(buffer); - break; - case OPCODE_CONTINUE: - sprintf(buffer, " continue;\n"); - appendOutput(buffer); - break; - case OPCODE_CONTINUEC: - applySwizzle(".x", op1); - if (instr->eBooleanTestType == INSTRUCTION_TEST_ZERO) - sprintf(buffer, " if (%s == 0) continue;\n", ci(op1).c_str()); - else - sprintf(buffer, " if (%s != 0) continue;\n", ci(op1).c_str()); - appendOutput(buffer); - break; - case OPCODE_ENDLOOP: - sprintf(buffer, " }\n"); - appendOutput(buffer); - break; - - // Found in Witcher3 Compute Shaders - case OPCODE_SYNC: - if (!strcmp(statement, "sync_g_t")) - sprintf(buffer, " GroupMemoryBarrierWithGroupSync();\n"); - else - sprintf(buffer, " Unknown sync instruction;\n"); - appendOutput(buffer); - break; - - case OPCODE_SWAPC: - { - remapTarget(op1); - remapTarget(op2); - removeBoolean(op1); // The code damages the op1, op2 below. - removeBoolean(op2); - applySwizzle(op1, op3); - applySwizzle(op1, op4); - applySwizzle(op1, op5); - int idx = 0; - char *pop1 = strrchr(op1, '.'); *pop1 = 0; - char *pop2 = strrchr(op2, '.'); if (pop2) *pop2 = 0; - char *pop3 = strrchr(op3, '.'); if (pop3) *pop3 = 0; - while (*++pop1) - { - sprintf(op6, "%s.%c", op1, *pop1); - if (pop2) sprintf(op7, "%s.%c", op2, *++pop2); else sprintf(op7, "%s", op2); - if (pop3) sprintf(op8, "%s.%c", op3, *++pop3); else sprintf(op8, "%s", op3); - // FIXME: May need fixup for read from constant buffer of unidentified type - sprintf(buffer, " %s = (int)%s ? %s : %s; %s = (int)%s ? %s : %s;\n", - writeTarget(op6), ci(op8).c_str(), ci(GetSuffix(op5, idx)).c_str(), ci(GetSuffix(op4, idx)).c_str(), - writeTarget(op7), ci(op8).c_str(), ci(GetSuffix(op4, idx)).c_str(), ci(GetSuffix(op5, idx)).c_str()); - appendOutput(buffer); - ++idx; - } - break; - } - - // This generated code needed to change because the fxc compiler generates bad code when - // using the sample that they specify in the documentation at: - // http://msdn.microsoft.com/en-us/library/windows/desktop/hh446837(v=vs.85).aspx - // I worked out the alternate technique that works for all, and does not tickle - // the bug that treats 0x80000000 as "-0" as a uint, where it should not exist. - case OPCODE_BFI: - { - remapTarget(op1); - removeBoolean(op1); - applySwizzle(op1, op2); - applySwizzle(op1, op3); - applySwizzle(op1, op4); - applySwizzle(op1, op5); - int idx = 0; - char *pop1 = strrchr(op1, '.'); *pop1 = 0; - while (*++pop1) - { - sprintf(op6, "%s.%c", op1, *pop1); - - // Fails: bitmask.%c = (((1 << %s) - 1) << %s) & 0xffffffff; - - // FIXME: May need fixup for read from constant buffer of unidentified type - sprintf(buffer, " bitmask.%c = ((~(-1 << %s)) << %s) & 0xffffffff;" - " %s = (((uint)%s << %s) & bitmask.%c) | ((uint)%s & ~bitmask.%c);\n", - *pop1, ci(GetSuffix(op2, idx)).c_str(), ci(GetSuffix(op3, idx)).c_str(), - writeTarget(op6), ci(GetSuffix(op4, idx)).c_str(), ci(GetSuffix(op3, idx)).c_str(), *pop1, ci(GetSuffix(op5, idx)).c_str(), *pop1); - appendOutput(buffer); - ++idx; - } - break; - } - - // Was missing the sample_aoffimmi variant. Added as matching sample_b type. Used in FC4. - case OPCODE_SAMPLE: - { - if (shader->dx9Shader) - { - remapTarget(op1); - applySwizzle(".xyzw", op2); - - int textureId = atoi(&op3[1]); - sprintf(buffer, " %s = %s.Sample(%s);\n", writeTarget(op1), - mTextureNames[textureId].c_str(), ci(op2).c_str()); + remapTarget(op1); + applySwizzle(op1, fixImm(op2, instr->asOperands[1])); + applySwizzle(op1, fixImm(op3, instr->asOperands[2])); + if (!instr->bSaturate) + sprintf(buffer, " %s = max(%s, %s);\n", writeTarget(op1), ci(op3).c_str(), ci(op2).c_str()); + else + sprintf(buffer, " %s = saturate(max(%s, %s));\n", writeTarget(op1), ci(op3).c_str(), ci(op2).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; + } + case OPCODE_IMIN: + remapTarget(op1); + applySwizzle(op1, fixImm(op2, instr->asOperands[1]), true); + applySwizzle(op1, fixImm(op3, instr->asOperands[2]), true); + if (!instr->bSaturate) + sprintf(buffer, " %s = min(%s, %s);\n", writeTarget(op1), ci(convertToInt(op3)).c_str(), ci(convertToInt(op2)).c_str()); + else + sprintf(buffer, " %s = saturate(min(%s, %s));\n", writeTarget(op1), ci(convertToInt(op3)).c_str(), ci(convertToInt(op2)).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; + case OPCODE_IMAX: + remapTarget(op1); + applySwizzle(op1, fixImm(op2, instr->asOperands[1]), true); + applySwizzle(op1, fixImm(op3, instr->asOperands[2]), true); + if (!instr->bSaturate) + sprintf(buffer, " %s = max(%s, %s);\n", writeTarget(op1), ci(convertToInt(op3)).c_str(), ci(convertToInt(op2)).c_str()); + else + sprintf(buffer, " %s = saturate(max(%s, %s));\n", writeTarget(op1), ci(convertToInt(op3)).c_str(), ci(convertToInt(op2)).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; - appendOutput(buffer); - } - else - { - // else if (!strncmp(statement, "sample_indexable", strlen("sample_indexable"))) - remapTarget(op1); - applySwizzle(".xyzw", op2); - applySwizzle(op1, op3); - int textureId, samplerId; - sscanf_s(op3, "t%d.", &textureId); - sscanf_s(op4, "s%d", &samplerId); - truncateTexturePos(op2, mTextureType[textureId].c_str()); - truncateTextureSwiz(op1, mTextureType[textureId].c_str()); - truncateTextureSwiz(op3, mTextureType[textureId].c_str()); - if (!instr->bAddressOffset) - sprintf(buffer, " %s = %s.Sample(%s, %s)%s;\n", writeTarget(op1), - mTextureNames[textureId].c_str(), mSamplerNames[samplerId].c_str(), ci(op2).c_str(), strrchr(op3, '.')); - else - { - int offsetx = 0, offsety = 0, offsetz = 0; - sscanf_s(statement, "sample_aoffimmi(%d,%d,%d", &offsetx, &offsety, &offsetz); - sprintf(buffer, " %s = %s.Sample(%s, %s, int2(%d, %d))%s;\n", writeTarget(op1), - mTextureNames[textureId].c_str(), mSamplerNames[samplerId].c_str(), ci(op2).c_str(), - offsetx, offsety, strrchr(op3, '.')); - } - appendOutput(buffer); - removeBoolean(op1); - } + case OPCODE_MAD: + remapTarget(op1); + applySwizzle(op1, fixImm(op2, instr->asOperands[1])); + applySwizzle(op1, fixImm(op3, instr->asOperands[2])); + applySwizzle(op1, fixImm(op4, instr->asOperands[3])); + // Check for operation reorder. + /* + if (mLastStatement && mLastStatement->eOpcode == OPCODE_MUL && strstr(op4, mMulTarget.c_str()) && + mMulTarget.compare(0, 3, mMulOperand, mMulOperand[0] == '-' ? 1 : 0, 3) && + mMulTarget.compare(0, 3, mMulOperand2, mMulOperand2[0] == '-' ? 1 : 0, 3)) + sprintf(op4 + ((op4[0] == '-') ? 1 : 0), "(%s * %s)", mMulOperand.c_str(), mMulOperand2.c_str()); + */ + if (!instr->bSaturate) + sprintf(buffer, " %s = %s * %s + %s;\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str(), ci(op4).c_str()); + else + sprintf(buffer, " %s = saturate(%s * %s + %s);\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str(), ci(op4).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; - break; - } + case OPCODE_IMAD: + remapTarget(op1); + applySwizzle(op1, op2, true); + applySwizzle(op1, op3, true); + applySwizzle(op1, op4, true); + sprintf(buffer, " %s = mad(%s, %s, %s);\n", writeTarget(op1), ci(convertToInt(op2)).c_str(), ci(convertToInt(op3)).c_str(), ci(convertToInt(op4)).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; + case OPCODE_UMAD: + remapTarget(op1); + applySwizzle(op1, op2, true); + applySwizzle(op1, op3, true); + applySwizzle(op1, op4, true); + sprintf(buffer, " %s = mad(%s, %s, %s);\n", writeTarget(op1), ci(convertToUInt(op2)).c_str(), ci(convertToUInt(op3)).c_str(), ci(convertToUInt(op4)).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; - // Missing opcode for WatchDogs. Very similar to SAMPLE_L, so copied from there. - case OPCODE_SAMPLE_B: - { - remapTarget(op1); - applySwizzle(".xyzw", op2); - applySwizzle(op1, op3); - applySwizzle(".x", fixImm(op5, instr->asOperands[4])); - int textureId, samplerId; - sscanf_s(op3, "t%d.", &textureId); - sscanf_s(op4, "s%d", &samplerId); - truncateTexturePos(op2, mTextureType[textureId].c_str()); - truncateTextureSwiz(op1, mTextureType[textureId].c_str()); - truncateTextureSwiz(op3, mTextureType[textureId].c_str()); - if (!instr->bAddressOffset) - sprintf(buffer, " %s = %s.SampleBias(%s, %s, %s)%s;\n", writeTarget(op1), - mTextureNames[textureId].c_str(), mSamplerNames[samplerId].c_str(), ci(op2).c_str(), ci(op5).c_str(), strrchr(op3, '.')); - else - { - int offsetx = 0, offsety = 0, offsetz = 0; - sscanf_s(statement, "sample_b_aoffimmi_indexable(%d,%d,%d", &offsetx, &offsety, &offsetz); - sprintf(buffer, " %s = %s.SampleBias(%s, %s, %s, int2(%d, %d))%s;\n", writeTarget(op1), - mTextureNames[textureId].c_str(), mSamplerNames[samplerId].c_str(), ci(op2).c_str(), ci(op5).c_str(), - offsetx, offsety, strrchr(op3, '.')); - } - appendOutput(buffer); - removeBoolean(op1); - break; - } - case OPCODE_SAMPLE_L: - { - remapTarget(op1); - applySwizzle(".xyzw", op2); - applySwizzle(op1, op3); - applySwizzle(".x", fixImm(op5, instr->asOperands[4])); - int textureId, samplerId; - sscanf_s(op3, "t%d.", &textureId); - sscanf_s(op4, "s%d", &samplerId); - truncateTexturePos(op2, mTextureType[textureId].c_str()); - truncateTextureSwiz(op1, mTextureType[textureId].c_str()); - truncateTextureSwiz(op3, mTextureType[textureId].c_str()); - if (!instr->bAddressOffset) - sprintf(buffer, " %s = %s.SampleLevel(%s, %s, %s)%s;\n", writeTarget(op1), - mTextureNames[textureId].c_str(), mSamplerNames[samplerId].c_str(), ci(op2).c_str(), ci(op5).c_str(), strrchr(op3, '.')); - else - { - int offsetx = 0, offsety = 0, offsetz = 0; - sscanf_s(statement, "sample_l_aoffimmi_indexable(%d,%d,%d", &offsetx, &offsety, &offsetz); - sprintf(buffer, " %s = %s.SampleLevel(%s, %s, %s, int2(%d, %d))%s;\n", writeTarget(op1), - mTextureNames[textureId].c_str(), mSamplerNames[samplerId].c_str(), ci(op2).c_str(), ci(op5).c_str(), - offsetx, offsety, strrchr(op3, '.')); - } - appendOutput(buffer); - removeBoolean(op1); - break; - } - case OPCODE_SAMPLE_D: - { - remapTarget(op1); - applySwizzle(".xyzw", op2); - applySwizzle(op1, op3); - applySwizzle(op1, fixImm(op5, instr->asOperands[4])); - applySwizzle(op1, fixImm(op6, instr->asOperands[5])); - int textureId, samplerId; - sscanf_s(op3, "t%d.", &textureId); - sscanf_s(op4, "s%d", &samplerId); - truncateTexturePos(op2, mTextureType[textureId].c_str()); - truncateTextureSwiz(op1, mTextureType[textureId].c_str()); - truncateTextureSwiz(op3, mTextureType[textureId].c_str()); - if (!instr->bAddressOffset) - sprintf(buffer, " %s = %s.SampleGrad(%s, %s, %s, %s)%s;\n", writeTarget(op1), - mTextureNames[textureId].c_str(), mSamplerNames[samplerId].c_str(), ci(op2).c_str(), ci(op5).c_str(), ci(op6).c_str(), strrchr(op3, '.')); - else - { - int offsetx = 0, offsety = 0, offsetz = 0; - sscanf_s(statement, "sample_d_aoffimmi_indexable(%d,%d,%d", &offsetx, &offsety, &offsetz); - sprintf(buffer, " %s = %s.SampleGrad(%s, %s, %s, %s, int2(%d, %d))%s;\n", writeTarget(op1), - mTextureNames[textureId].c_str(), mSamplerNames[samplerId].c_str(), ci(op2).c_str(), ci(op5).c_str(), ci(op6).c_str(), - offsetx, offsety, strrchr(op3, '.')); - } - appendOutput(buffer); - removeBoolean(op1); - break; - } - case OPCODE_SAMPLE_C: - { - remapTarget(op1); - applySwizzle(".xyzw", op2); - applySwizzle(op1, op3); - applySwizzle(".x", fixImm(op5, instr->asOperands[4])); - int textureId, samplerId; - sscanf_s(op3, "t%d.", &textureId); - sscanf_s(op4, "s%d", &samplerId); - truncateTexturePos(op2, mTextureType[textureId].c_str()); - truncateTextureSwiz(op1, mTextureType[textureId].c_str()); - truncateTextureSwiz(op3, mTextureType[textureId].c_str()); - if (!instr->bAddressOffset) - sprintf(buffer, " %s = %s.SampleCmp(%s, %s, %s)%s;\n", writeTarget(op1), - mTextureNames[textureId].c_str(), mSamplerComparisonNames[samplerId].c_str(), ci(op2).c_str(), ci(op5).c_str(), strrchr(op3, '.')); - else - { - int offsetx = 0, offsety = 0, offsetz = 0; - sscanf_s(statement, "sample_c_aoffimmi_indexable(%d,%d,%d", &offsetx, &offsety, &offsetz); - sprintf(buffer, " %s = %s.SampleCmp(%s, %s, %s, int2(%d, %d))%s;\n", writeTarget(op1), - mTextureNames[textureId].c_str(), mSamplerComparisonNames[samplerId].c_str(), ci(op2).c_str(), ci(op5).c_str(), - offsetx, offsety, strrchr(op3, '.')); - } - appendOutput(buffer); - removeBoolean(op1); - break; - } - // sample_c_lz_indexable(texture2d)(float,float,float,float) r1.y, r3.zwzz, t0.xxxx, s1, r1.z - case OPCODE_SAMPLE_C_LZ: - { - remapTarget(op1); - applySwizzle(".xyzw", op2); - applySwizzle(op1, op3); - applySwizzle(".x", fixImm(op5, instr->asOperands[4])); - int textureId, samplerId; - sscanf_s(op3, "t%d.", &textureId); - sscanf_s(op4, "s%d", &samplerId); - truncateTexturePos(op2, mTextureType[textureId].c_str()); - truncateTextureSwiz(op1, mTextureType[textureId].c_str()); - truncateTextureSwiz(op3, mTextureType[textureId].c_str()); - if (!instr->bAddressOffset) - sprintf(buffer, " %s = %s.SampleCmpLevelZero(%s, %s, %s)%s;\n", writeTarget(op1), - mTextureNames[textureId].c_str(), mSamplerComparisonNames[samplerId].c_str(), ci(op2).c_str(), ci(op5).c_str(), strrchr(op3, '.')); - else - { - int offsetx = 0, offsety = 0, offsetz = 0; - sscanf_s(statement, "sample_c_lz_aoffimmi_indexable(%d,%d,%d", &offsetx, &offsety, &offsetz); - sprintf(buffer, " %s = %s.SampleCmpLevelZero(%s, %s, %s, int2(%d, %d))%s;\n", writeTarget(op1), - mTextureNames[textureId].c_str(), mSamplerComparisonNames[samplerId].c_str(), ci(op2).c_str(), ci(op5).c_str(), - offsetx, offsety, strrchr(op3, '.')); - } - appendOutput(buffer); - removeBoolean(op1); - break; - } - // This opcode was missing, and used in WatchDogs. - // expected code "samplepos r0.xy, t1.xyxx, v1.x" -> "r0.xy = t1.GetSamplePosition(v1.x);" - case OPCODE_SAMPLE_POS: - { - remapTarget(op1); - applySwizzle(op1, op2); - applySwizzle(op1, op3); - int textureId; - sscanf_s(op2, "t%d.", &textureId); - sprintf(buffer, " %s = %s.GetSamplePosition(%s);\n", writeTarget(op1), - mTextureNames[textureId].c_str(), ci(op3).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; - } + case OPCODE_DP2: + remapTarget(op1); + applySwizzle(".xy", fixImm(op2, instr->asOperands[1])); + applySwizzle(".xy", fixImm(op3, instr->asOperands[2])); + if (!instr->bSaturate) + sprintf(buffer, " %s = dot(%s, %s);\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str()); + else + sprintf(buffer, " %s = saturate(dot(%s, %s));\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; - // Missing opcode, used in FC4. Similar to 'sample' - // lod dest[.mask], srcAddress[.swizzle], srcResource[.swizzle], srcSampler - // ret Object.CalculateLevelOfDetail(sampler_state S, float x); - // "lod r0.x, r0.xyzx, t2.y, s2" -> "r0.x = t2.CalculateLevelOfDetailUnclamped(s2, r0.xyz);" - // CalculateLevelOfDetailUnclamped compiles to t2.y, - // CalculateLevelOfDetail compiles to t2.x - case OPCODE_LOD: + case OPCODE_DP3: + { + const int lookahead = 2; + if (shader->dx9Shader && (iNr + lookahead < inst_count)) // FIXME: This is actually a lookahead code path and may not be DX9 specific { - remapTarget(op1); - applySwizzle(".xyzw", op2); - applySwizzle(op1, op3); - int textureId, samplerId; - sscanf_s(op3, "t%d.", &textureId); - sscanf_s(op4, "s%d", &samplerId); - truncateTexturePos(op2, mTextureType[textureId].c_str()); - char *clamped = strrchr(op3, '.') + 1; - if (*clamped == 'x') - sprintf(buffer, " %s = %s.CalculateLevelOfDetail(%s, %s);\n", writeTarget(op1), - mTextureNames[textureId].c_str(), mSamplerNames[samplerId].c_str(), ci(op2).c_str()); - else - sprintf(buffer, " %s = %s.CalculateLevelOfDetailUnclamped(%s, %s);\n", writeTarget(op1), - mTextureNames[textureId].c_str(), mSamplerNames[samplerId].c_str(), ci(op2).c_str()); - appendOutput(buffer); - removeBoolean(op1); - break; - } + Instruction* nextIns[lookahead]; + for (int i = 0; i < lookahead; i++) + { + nextIns[i] = &(*instructions)[iNr + i + 1]; + } - case OPCODE_GATHER4: - { - remapTarget(op1); - applySwizzle(".xyzw", op2); - applySwizzle(op1, op3); - int textureId, samplerId; - sscanf_s(op3, "t%d.", &textureId); - sscanf_s(op4, "s%d", &samplerId); - truncateTexturePos(op2, mTextureType[textureId].c_str()); - if (!instr->bAddressOffset) - sprintf(buffer, " %s = %s.Gather(%s, %s)%s;\n", writeTarget(op1), - mTextureNames[textureId].c_str(), mSamplerNames[samplerId].c_str(), ci(op2).c_str(), strrchr(op3, '.')); - else + string outputOp1 = GetComponentStrFromInstruction(nextIns[1], 0); + + if (nextIns[0]->eOpcode == OPCODE_ADD && nextIns[1]->eOpcode == OPCODE_MAD && + IsInstructionOperandSame(instr, 0, nextIns[0], 1) == 1 && IsInstructionOperandSame(instr, 0, nextIns[0], 2) == 1 && + IsInstructionOperandSame(nextIns[0], 0, nextIns[1], 2) == 2 && + IsInstructionOperandSame(instr, 1, nextIns[1], 3, NULL, outputOp1.c_str()) == 1 && IsInstructionOperandSame(instr, 2, nextIns[1], 1, NULL, outputOp1.c_str()) == 1) { - int offsetx = 0, offsety = 0, offsetz = 0; - sscanf_s(statement, "gather4_aoffimmi_indexable(%d,%d,%d", &offsetx, &offsety, &offsetz); - sprintf(buffer, " %s = %s.Gather(%s, %s, int2(%d, %d))%s;\n", writeTarget(op1), - mTextureNames[textureId].c_str(), mSamplerNames[samplerId].c_str(), ci(op2).c_str(), - offsetx, offsety, strrchr(op3, '.')); + //read next instruction + for (int i = 0; i < lookahead; i++) + { + while (c[pos] != 0x0a && pos < size) pos++; pos++; + + if (ReadStatement(c + pos) < 1) + { + logDecompileError("Error parsing statement: " + string(c + pos, 80)); + return; + } + } + + remapTarget(op1); + sprintf_s(op2, opcodeSize, "r%d.%s", nextIns[1]->asOperands[3].ui32RegisterNumber, GetComponentStrFromInstruction(nextIns[1], 3).c_str()); + sprintf_s(op3, opcodeSize, "r%d.%s", nextIns[1]->asOperands[1].ui32RegisterNumber, GetComponentStrFromInstruction(nextIns[1], 1).c_str()); + applySwizzle(op1, op2); + applySwizzle(op1, op3); + + sprintf(buffer, " %s = reflect(%s, %s);\n", writeTarget(op1), op2, op3); + + appendOutput(buffer); + + while (c[pos] != 0x0a && pos < size) pos++; pos++; + mLastStatement = nextIns[1]; + iNr += lookahead + 1; + continue; } - appendOutput(buffer); - removeBoolean(op1); - break; } - case OPCODE_GATHER4_C: + remapTarget(op1); + applySwizzle(".xyz", fixImm(op2, instr->asOperands[1])); + applySwizzle(".xyz", fixImm(op3, instr->asOperands[2])); + if (!instr->bSaturate) + sprintf(buffer, " %s = dot(%s, %s);\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str()); + else + sprintf(buffer, " %s = saturate(dot(%s, %s));\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; + } + + case OPCODE_DP4: + { + const int lookahead = 1; + if (shader->dx9Shader && (iNr + lookahead < inst_count)) // FIXME: This is actually a lookahead code path and may not be DX9 specific { remapTarget(op1); - applySwizzle(".xyzw", op2); - applySwizzle(op1, op3); - int textureId, samplerId; - sscanf_s(op3, "t%d.", &textureId); - sscanf_s(op4, "s%d", &samplerId); - truncateTexturePos(op2, mTextureType[textureId].c_str()); - if (!instr->bAddressOffset) - sprintf(buffer, " %s = %s.GatherCmp(%s, %s, %s)%s;\n", writeTarget(op1), - mTextureNames[textureId].c_str(), mSamplerComparisonNames[samplerId].c_str(), ci(op2).c_str(), ci(op5).c_str(), strrchr(op3, '.')); - else + Instruction* nextInstr = &(*instructions)[iNr + 1]; + string outputOp0 = GetComponentStrFromInstruction(instr, 0); + + //nrm generate two instructions,dp4 and rsq + if (nextInstr->eOpcode == OPCODE_RSQ && outputOp0.size() == 3) { - int offsetx = 0, offsety = 0, offsetz = 0; - sscanf_s(statement, "gather4_c_aoffimmi_indexable(%d,%d,%d", &offsetx, &offsety, &offsetz); - sprintf(buffer, " %s = %s.GatherCmp(%s, %s, %s, int2(%d,%d))%s;\n", writeTarget(op1), - mTextureNames[textureId].c_str(), mSamplerComparisonNames[samplerId].c_str(), ci(op2).c_str(), ci(op5).c_str(), - offsetx, offsety, strrchr(op3, '.')); + applySwizzle(op1, op2); + sprintf(buffer, " %s = normalize(%s);\n", writeTarget(op1), ci(op2).c_str()); + appendOutput(buffer); + + //asm just one line,don't need call ReadStatement + //have two instructions + iNr++; + + // NOTE: NO CONTINUE HERE - NEED ONE BEFORE ELIMINATING DUPLICATE CODE BELOW + // AND NEED A REGRESSION TEST BEFORE DOING THAT. + } else + { + // XXX NOTE Duplicated code below!!! + applySwizzle(".xyzw", fixImm(op2, instr->asOperands[1])); + applySwizzle(".xyzw", fixImm(op3, instr->asOperands[2])); + if (!instr->bSaturate) + sprintf(buffer, " %s = dot(%s, %s);\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str()); + else + sprintf(buffer, " %s = saturate(dot(%s, %s));\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str()); + appendOutput(buffer); + // XXX NOTE Duplicated code below!!! } + } else + { + // XXX NOTE Duplicated code above!!! + remapTarget(op1); + applySwizzle(".xyzw", fixImm(op2, instr->asOperands[1])); + applySwizzle(".xyzw", fixImm(op3, instr->asOperands[2])); + if (!instr->bSaturate) + sprintf(buffer, " %s = dot(%s, %s);\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str()); + else + sprintf(buffer, " %s = saturate(dot(%s, %s));\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str()); appendOutput(buffer); removeBoolean(op1); - break; + // XXX NOTE Duplicated code above!!! } + break; + } + case OPCODE_DP2ADD: + remapTarget(op1); + applySwizzle(".xy", op2); + applySwizzle(".xy", op3); + applySwizzle(".xy", op4); + sprintf(buffer, " %s = dot2(%s, %s) + %s;\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str(), ci(op4).c_str()); + appendOutput(buffer); - // Add the Gather4_PO opcodes for Dragon Age. Copied from Gather4. - // gather4_po dest[.mask], srcAddress[.swizzle], srcOffset[.swizzle], srcResource[.swizzle], srcSampler[.select_component] - // output.color = texture2d.Gather(samplerState, input.texcoord, int2(0,0)); - case OPCODE_GATHER4_PO: - { - remapTarget(op1); - applySwizzle(op1, op2); + //dx9 + break; + + //dx9 + case OPCODE_LRP: + remapTarget(op1); + applySwizzle(op1, op2); + applySwizzle(op1, op3); + applySwizzle(op1, op4); + sprintf(buffer, " %s = lerp(%s, %s, %s);\n", writeTarget(op1), ci(op4).c_str(), ci(op3).c_str(), ci(op2).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; + + case OPCODE_POW: + remapTarget(op1); + applySwizzle(op1, op2); + applySwizzle(op1, op3); + sprintf(buffer, " %s = pow(%s, %s);\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str()); + appendOutput(buffer); + break; + //dx9 + case OPCODE_RSQ: + { + remapTarget(op1); + applySwizzle(op1, op2); + if (!instr->bSaturate) { + // The DX9 port switched this to 1/sqrt(), however + // it is unclear why that was necessary - rsqrt + // should work in everything since vs_1_1 and + // ps_2_0 (and in fact the regular sqrt didn't + // exist until shader model 4). Look up "fast + // inverse square root" to have your mind blown and + // get an idea of why this matters. + // + // Reverting this to rsqrt since the DX9 decompiler + // support is clearly unfinished and no explanation + // for this change was provided. + // + sprintf(buffer, " %s = rsqrt(%s);\n", writeTarget(op1), ci(op2).c_str()); + } else { + sprintf(buffer, " %s = saturate(rsqrt(%s));\n", writeTarget(op1), ci(op2).c_str()); + } + appendOutput(buffer); + removeBoolean(op1); + break; + } + + // Double checked this while looking at other round bugs. Looks correct to use 'floor'. + case OPCODE_ROUND_NI: + { + remapTarget(op1); + applySwizzle(op1, op2); + if (!instr->bSaturate) + sprintf(buffer, " %s = floor(%s);\n", writeTarget(op1), ci(op2).c_str()); + else + sprintf(buffer, " %s = saturate(floor(%s));\n", writeTarget(op1), ci(op2).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; + } + case OPCODE_ROUND_PI: + { + remapTarget(op1); + applySwizzle(op1, op2); + if (!instr->bSaturate) + sprintf(buffer, " %s = ceil(%s);\n", writeTarget(op1), ci(op2).c_str()); + else + sprintf(buffer, " %s = saturate(ceil(%s));\n", writeTarget(op1), ci(op2).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; + } + + // Was previously doing a Round operation, but that is not correct because this needs to + // round toward zero, and Round can go larger. Trunc(1.6)->1.0 Round(1.6)->2.0 + // Also removed the unrolling, the instruction works with swizzle. e.g. r0.xy = trunc(r2.yz) + case OPCODE_ROUND_Z: + { + remapTarget(op1); + applySwizzle(op1, op2); + if (!instr->bSaturate) + sprintf(buffer, " %s = trunc(%s);\n", writeTarget(op1), ci(op2).c_str()); + else + sprintf(buffer, " %s = saturate(trunc(%s));\n", writeTarget(op1), ci(op2).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; + } + + // Round_NE is Round Nearest Even, and using HLSL Round here is correct. + // But it previously used a *0.5*2 rounding which is unnecessary. + // The HLSL intrinsics of Round will already do that. + case OPCODE_ROUND_NE: + { + remapTarget(op1); + applySwizzle(op1, op2); + if (!instr->bSaturate) + sprintf(buffer, " %s = round(%s);\n", writeTarget(op1), ci(op2).c_str()); + else + sprintf(buffer, " %s = saturate(round(%s));\n", writeTarget(op1), ci(op2).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; + } + case OPCODE_FTOI: + remapTarget(op1); + applySwizzle(op1, op2); + sprintf(buffer, " %s = %s;\n", writeTarget(op1), ci(castToInt(op2)).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; + + case OPCODE_FTOU: + remapTarget(op1); + applySwizzle(op1, op2); + sprintf(buffer, " %s = %s;\n", writeTarget(op1), ci(castToUInt(op2)).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; + + case OPCODE_SINCOS: + remapTarget(op1); + remapTarget(op2); + if (!strncmp(op1, "null", 4)) + applySwizzle(op2, op3); + else applySwizzle(op1, op3); - applySwizzle(op1, op4); - int textureId, samplerId; - sscanf_s(op4, "t%d.", &textureId); - sscanf_s(op5, "s%d", &samplerId); - truncateTexturePos(op2, mTextureType[textureId].c_str()); - sprintf(buffer, " %s = %s.Gather(%s, %s, %s)%s;\n", writeTarget(op1), mTextureNames[textureId].c_str(), - mSamplerNames[samplerId].c_str(), ci(op2).c_str(), ci(op3).c_str(), strrchr(op4, '.')); - appendOutput(buffer); - removeBoolean(op1); - break; + if (!strncmp(op1, "null", 4)) + sprintf(buffer, " %s = cos(%s);\n", writeTarget(op2), ci(op3).c_str()); + else if (!strncmp(op2, "null", 4)) + sprintf(buffer, " %s = sin(%s);\n", writeTarget(op1), ci(op3).c_str()); + else + sprintf(buffer, " sincos(%s, %s, %s);\n", ci(op3).c_str(), writeTarget(op1), writeTarget(op2)); + appendOutput(buffer); + removeBoolean(op1); + removeBoolean(op2); + break; + + // Failing case of: "movc_sat r2.xyzw, r2.xxxx, r7.xyzw, r4.xyzw" + // Turned into: + // r2.x = saturate(r2.x ? r7.x : r4.x); + // r2.y = saturate(r2.x ? r7.y : r4.y); + // r2.z = saturate(r2.x ? r7.z : r4.z); + // r2.w = saturate(r2.x ? r7.w : r4.w); + // which damages r2.x at the first line, and uses it in each. + // Changed it to just be: "r2.xyzw = saturate(r2.xxxx ? r7.xyzw : r4.xyzw);" + // But I'm not sure why this was unrolled to begin with. + case OPCODE_MOVC: + { + remapTarget(op1); + applySwizzle(op1, fixImm(op2, instr->asOperands[1])); + applySwizzle(op1, fixImm(op3, instr->asOperands[2])); + applySwizzle(op1, fixImm(op4, instr->asOperands[3])); + if (!instr->bSaturate) + sprintf(buffer, " %s = %s ? %s : %s;\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str(), ci(op4).c_str()); + else + sprintf(buffer, " %s = saturate(%s ? %s : %s);\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str(), ci(op4).c_str()); + appendOutput(buffer); + + //int idx = 0; + //char *pop1 = strrchr(op1, '.'); *pop1 = 0; + //char *pop2 = strrchr(op2, '.'); if (pop2) *pop2 = 0; + //while (*++pop1) + //{ + //if (pop1) sprintf(op5, "%s.%c", op1, *pop1); else sprintf(op5, "%s", op1); + //if (pop2) sprintf(op6, "%s.%c", op2, *++pop2); else sprintf(op6, "%s", op2); + //if (!instr->bSaturate) + // sprintf(buffer, " %s = %s ? %s : %s;\n", writeTarget(op5), ci(op6).c_str(), ci(GetSuffix(op3, idx)).c_str(), ci(GetSuffix(op4, idx)).c_str()); + //else + // sprintf(buffer, " %s = saturate(%s ? %s : %s);\n", writeTarget(op5), ci(op6).c_str(), ci(GetSuffix(op3, idx)).c_str(), ci(GetSuffix(op4, idx)).c_str()); + //appendOutput(buffer); + // ++idx; + //} + removeBoolean(op1); + break; + } + + // Big change to all these boolean test opcodes. All were unrolled and generated a code line per component. + // To make the boolean tests work correctly for AND, these were rolled back into one, and added to the boolean + // set list as a complete operand, like 'r0.xyw'. + case OPCODE_NE: + { + remapTarget(op1); + applySwizzle(op1, op2); + applySwizzle(op1, op3); + sprintf(buffer, " %s = cmp(%s != %s);\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str()); + appendOutput(buffer); + addBoolean(op1); + break; + } + case OPCODE_INE: + { + remapTarget(op1); + applySwizzle(op1, op2, true); + applySwizzle(op1, op3, true); + sprintf(buffer, " %s = cmp(%s != %s);\n", writeTarget(op1), ci(convertToInt(op2)).c_str(), ci(convertToInt(op3)).c_str()); + appendOutput(buffer); + addBoolean(op1); + break; + } + case OPCODE_EQ: + { + remapTarget(op1); + applySwizzle(op1, op2); + applySwizzle(op1, op3); + sprintf(buffer, " %s = cmp(%s == %s);\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str()); + appendOutput(buffer); + addBoolean(op1); + break; + } + case OPCODE_IEQ: + { + remapTarget(op1); + applySwizzle(op1, op2, true); + applySwizzle(op1, op3, true); + sprintf(buffer, " %s = cmp(%s == %s);\n", writeTarget(op1), ci(convertToInt(op2)).c_str(), ci(convertToInt(op3)).c_str()); + appendOutput(buffer); + addBoolean(op1); + break; + } + case OPCODE_LT: + { + remapTarget(op1); + applySwizzle(op1, fixImm(op2, instr->asOperands[1])); + applySwizzle(op1, fixImm(op3, instr->asOperands[2])); + sprintf(buffer, " %s = cmp(%s < %s);\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str()); + appendOutput(buffer); + addBoolean(op1); + break; + } + case OPCODE_ILT: + { + remapTarget(op1); + applySwizzle(op1, op2, true); + applySwizzle(op1, op3, true); + sprintf(buffer, " %s = cmp(%s < %s);\n", writeTarget(op1), ci(convertToInt(op2)).c_str(), ci(convertToInt(op3)).c_str()); + appendOutput(buffer); + addBoolean(op1); + break; + } + case OPCODE_ULT: + { + remapTarget(op1); + applySwizzle(op1, op2, true); + applySwizzle(op1, op3, true); + sprintf(buffer, " %s = cmp(%s < %s);\n", writeTarget(op1), ci(convertToUInt(op2)).c_str(), ci(convertToUInt(op3)).c_str()); + appendOutput(buffer); + addBoolean(op1); + break; + } + case OPCODE_GE: + { + remapTarget(op1); + applySwizzle(op1, fixImm(op2, instr->asOperands[1])); + applySwizzle(op1, fixImm(op3, instr->asOperands[2])); + sprintf(buffer, " %s = cmp(%s >= %s);\n", writeTarget(op1), ci(op2).c_str(), ci(op3).c_str()); + appendOutput(buffer); + addBoolean(op1); + break; + } + case OPCODE_IGE: + { + remapTarget(op1); + applySwizzle(op1, op2, true); + applySwizzle(op1, op3, true); + sprintf(buffer, " %s = cmp(%s >= %s);\n", writeTarget(op1), ci(convertToInt(op2)).c_str(), ci(convertToInt(op3)).c_str()); + appendOutput(buffer); + addBoolean(op1); + break; + } + case OPCODE_UGE: + { + remapTarget(op1); + applySwizzle(op1, op2, true); + applySwizzle(op1, op3, true); + sprintf(buffer, " %s = cmp(%s >= %s);\n", writeTarget(op1), ci(convertToUInt(op2)).c_str(), ci(convertToUInt(op3)).c_str()); + appendOutput(buffer); + addBoolean(op1); + break; + } + + // Switch statement in HLSL was missing. Added because AC4 uses it. + case OPCODE_SWITCH: + sprintf(buffer, " switch (%s) {\n", ci(op1).c_str()); + appendOutput(buffer); + break; + case OPCODE_CASE: + sprintf(buffer, " case %s :", ci(op1).substr(2, 1).c_str()); + appendOutput(buffer); + break; + case OPCODE_ENDSWITCH: + sprintf(buffer, " }\n"); + appendOutput(buffer); + break; + case OPCODE_DEFAULT: + sprintf(buffer, " default :\n"); + appendOutput(buffer); + break; + + case OPCODE_IF: + applySwizzle(".x", op1); + if (instr->eBooleanTestType == INSTRUCTION_TEST_ZERO) + sprintf(buffer, " if (%s == 0) {\n", ci(op1).c_str()); + else + sprintf(buffer, " if (%s != 0) {\n", ci(op1).c_str()); + appendOutput(buffer); + break; + case OPCODE_ELSE: + sprintf(buffer, " } else {\n"); + appendOutput(buffer); + break; + case OPCODE_ENDIF: + sprintf(buffer, " }\n"); + appendOutput(buffer); + break; + + case OPCODE_LOOP: + sprintf(buffer, " while (true) {\n"); + appendOutput(buffer); + break; + case OPCODE_BREAK: + sprintf(buffer, " break;\n"); + appendOutput(buffer); + break; + case OPCODE_BREAKC: + applySwizzle(".x", op1); + if (instr->eBooleanTestType == INSTRUCTION_TEST_ZERO) + sprintf(buffer, " if (%s == 0) break;\n", ci(op1).c_str()); + else + sprintf(buffer, " if (%s != 0) break;\n", ci(op1).c_str()); + appendOutput(buffer); + break; + case OPCODE_CONTINUE: + sprintf(buffer, " continue;\n"); + appendOutput(buffer); + break; + case OPCODE_CONTINUEC: + applySwizzle(".x", op1); + if (instr->eBooleanTestType == INSTRUCTION_TEST_ZERO) + sprintf(buffer, " if (%s == 0) continue;\n", ci(op1).c_str()); + else + sprintf(buffer, " if (%s != 0) continue;\n", ci(op1).c_str()); + appendOutput(buffer); + break; + case OPCODE_ENDLOOP: + sprintf(buffer, " }\n"); + appendOutput(buffer); + break; + + // Found in Witcher3 Compute Shaders + case OPCODE_SYNC: + if (!strcmp(statement, "sync_g_t")) + sprintf(buffer, " GroupMemoryBarrierWithGroupSync();\n"); + else + sprintf(buffer, " Unknown sync instruction;\n"); + appendOutput(buffer); + break; + + case OPCODE_SWAPC: + { + remapTarget(op1); + remapTarget(op2); + removeBoolean(op1); // The code damages the op1, op2 below. + removeBoolean(op2); + applySwizzle(op1, op3); + applySwizzle(op1, op4); + applySwizzle(op1, op5); + int idx = 0; + char* pop1 = strrchr(op1, '.'); *pop1 = 0; + char* pop2 = strrchr(op2, '.'); if (pop2) *pop2 = 0; + char* pop3 = strrchr(op3, '.'); if (pop3) *pop3 = 0; + while (*++pop1) + { + sprintf(op6, "%s.%c", op1, *pop1); + if (pop2) sprintf(op7, "%s.%c", op2, *++pop2); else sprintf(op7, "%s", op2); + if (pop3) sprintf(op8, "%s.%c", op3, *++pop3); else sprintf(op8, "%s", op3); + // FIXME: May need fixup for read from constant buffer of unidentified type + sprintf(buffer, " %s = (int)%s ? %s : %s; %s = (int)%s ? %s : %s;\n", + writeTarget(op6), ci(op8).c_str(), ci(GetSuffix(op5, idx)).c_str(), ci(GetSuffix(op4, idx)).c_str(), + writeTarget(op7), ci(op8).c_str(), ci(GetSuffix(op4, idx)).c_str(), ci(GetSuffix(op5, idx)).c_str()); + appendOutput(buffer); + ++idx; } + break; + } - // gather4_po_c dest[.mask], srcAddress[.swizzle], srcOffset[.swizzle], srcResource[.swizzle], srcSampler[.R], srcReferenceValue - case OPCODE_GATHER4_PO_C: + // This generated code needed to change because the fxc compiler generates bad code when + // using the sample that they specify in the documentation at: + // http://msdn.microsoft.com/en-us/library/windows/desktop/hh446837(v=vs.85).aspx + // I worked out the alternate technique that works for all, and does not tickle + // the bug that treats 0x80000000 as "-0" as a uint, where it should not exist. + case OPCODE_BFI: + { + remapTarget(op1); + removeBoolean(op1); + applySwizzle(op1, op2); + applySwizzle(op1, op3); + applySwizzle(op1, op4); + applySwizzle(op1, op5); + int idx = 0; + char* pop1 = strrchr(op1, '.'); *pop1 = 0; + while (*++pop1) { - remapTarget(op1); - applySwizzle(op1, op2); - applySwizzle(op1, op3); - applySwizzle(op1, op4); - int textureId, samplerId; - sscanf_s(op4, "t%d.", &textureId); - sscanf_s(op5, "s%d", &samplerId); - truncateTexturePos(op2, mTextureType[textureId].c_str()); - sprintf(buffer, " %s = %s.GatherCmp(%s, %s, %s, %s)%s;\n", writeTarget(op1), mTextureNames[textureId].c_str(), - mSamplerComparisonNames[samplerId].c_str(), ci(op2).c_str(), ci(op6).c_str(), ci(op3).c_str(), strrchr(op4, '.')); + sprintf(op6, "%s.%c", op1, *pop1); + + // Fails: bitmask.%c = (((1 << %s) - 1) << %s) & 0xffffffff; + + // FIXME: May need fixup for read from constant buffer of unidentified type + sprintf(buffer, " bitmask.%c = ((~(-1 << %s)) << %s) & 0xffffffff;" + " %s = (((uint)%s << %s) & bitmask.%c) | ((uint)%s & ~bitmask.%c);\n", + *pop1, ci(GetSuffix(op2, idx)).c_str(), ci(GetSuffix(op3, idx)).c_str(), + writeTarget(op6), ci(GetSuffix(op4, idx)).c_str(), ci(GetSuffix(op3, idx)).c_str(), *pop1, ci(GetSuffix(op5, idx)).c_str(), *pop1); appendOutput(buffer); - removeBoolean(op1); - break; + ++idx; } + break; + } - // For the _aoffimmi format, this was picking up 0..15, instead of the necessary -8..7 - // It's a 4 bit number being used in an int, hence missing negatives. - // This fix follows the form of the _Gather opcode above, but should maybe use the - // instr-> parameters after they are fixed. - // Fixed both _LD and LD_MS - case OPCODE_LD: + // Was missing the sample_aoffimmi variant. Added as matching sample_b type. Used in FC4. + case OPCODE_SAMPLE: + { + if (shader->dx9Shader) { remapTarget(op1); applySwizzle(".xyzw", op2); - applySwizzle(op1, op3); - int textureId; - sscanf_s(op3, "t%d.", &textureId); - truncateTextureLoadPos(op2, mTextureType[textureId].c_str()); - truncateTextureSwiz(op1, mTextureType[textureId].c_str()); - truncateTextureSwiz(op3, mTextureType[textureId].c_str()); - if (!instr->bAddressOffset) - sprintf(buffer, " %s = %s.Load(%s)%s;\n", writeTarget(op1), mTextureNames[textureId].c_str(), ci(op2).c_str(), strrchr(op3, '.')); - else { - int offsetU = 0, offsetV = 0, offsetW = 0; - sscanf_s(statement, "ld_aoffimmi(%d,%d,%d", &offsetU, &offsetV, &offsetW); - sprintf(buffer, " %s = %s.Load(%s, int3(%d, %d, %d))%s;\n", writeTarget(op1), mTextureNames[textureId].c_str(), ci(op2).c_str(), - offsetU, offsetV, offsetW, strrchr(op3, '.')); - } + + int textureId = atoi(&op3[1]); + sprintf(buffer, " %s = %s.Sample(%s);\n", writeTarget(op1), + mTextureNames[textureId].c_str(), ci(op2).c_str()); + appendOutput(buffer); - removeBoolean(op1); - break; - } - case OPCODE_LD_MS: + } else { + // else if (!strncmp(statement, "sample_indexable", strlen("sample_indexable"))) remapTarget(op1); applySwizzle(".xyzw", op2); applySwizzle(op1, op3); - applySwizzle(".x", fixImm(op4, instr->asOperands[3]), true); - int textureId; + int textureId, samplerId; sscanf_s(op3, "t%d.", &textureId); - truncateTextureLoadPos(op2, mTextureType[textureId].c_str()); + sscanf_s(op4, "s%d", &samplerId); + truncateTexturePos(op2, mTextureType[textureId].c_str()); truncateTextureSwiz(op1, mTextureType[textureId].c_str()); truncateTextureSwiz(op3, mTextureType[textureId].c_str()); if (!instr->bAddressOffset) - sprintf(buffer, " %s = %s.Load(%s, %s)%s;\n", writeTarget(op1), mTextureNames[textureId].c_str(), ci(op2).c_str(), ci(op4).c_str(), strrchr(op3, '.')); - else{ - int offsetU = 0, offsetV = 0, offsetW = 0; - sscanf_s(statement, "ld_aoffimmi(%d,%d,%d", &offsetU, &offsetV, &offsetW); - sprintf(buffer, " %s = %s.Load(%s, %s, int3(%d, %d, %d))%s;\n", writeTarget(op1), mTextureNames[textureId].c_str(), ci(op2).c_str(), ci(op4).c_str(), - offsetU, offsetV, offsetW, strrchr(op3, '.')); + sprintf(buffer, " %s = %s.Sample(%s, %s)%s;\n", writeTarget(op1), + mTextureNames[textureId].c_str(), mSamplerNames[samplerId].c_str(), ci(op2).c_str(), strrchr(op3, '.')); + else + { + int offsetx = 0, offsety = 0, offsetz = 0; + sscanf_s(statement, "sample_aoffimmi(%d,%d,%d", &offsetx, &offsety, &offsetz); + sprintf(buffer, " %s = %s.Sample(%s, %s, int2(%d, %d))%s;\n", writeTarget(op1), + mTextureNames[textureId].c_str(), mSamplerNames[samplerId].c_str(), ci(op2).c_str(), + offsetx, offsety, strrchr(op3, '.')); } appendOutput(buffer); removeBoolean(op1); - break; } - case OPCODE_LD_STRUCTURED: + break; + } + + // Missing opcode for WatchDogs. Very similar to SAMPLE_L, so copied from there. + case OPCODE_SAMPLE_B: + { + remapTarget(op1); + applySwizzle(".xyzw", op2); + applySwizzle(op1, op3); + applySwizzle(".x", fixImm(op5, instr->asOperands[4])); + int textureId, samplerId; + sscanf_s(op3, "t%d.", &textureId); + sscanf_s(op4, "s%d", &samplerId); + truncateTexturePos(op2, mTextureType[textureId].c_str()); + truncateTextureSwiz(op1, mTextureType[textureId].c_str()); + truncateTextureSwiz(op3, mTextureType[textureId].c_str()); + if (!instr->bAddressOffset) + sprintf(buffer, " %s = %s.SampleBias(%s, %s, %s)%s;\n", writeTarget(op1), + mTextureNames[textureId].c_str(), mSamplerNames[samplerId].c_str(), ci(op2).c_str(), ci(op5).c_str(), strrchr(op3, '.')); + else { - parse_ld_structured(shader, c, pos, size, instr); - break; + int offsetx = 0, offsety = 0, offsetz = 0; + sscanf_s(statement, "sample_b_aoffimmi_indexable(%d,%d,%d", &offsetx, &offsety, &offsetz); + sprintf(buffer, " %s = %s.SampleBias(%s, %s, %s, int2(%d, %d))%s;\n", writeTarget(op1), + mTextureNames[textureId].c_str(), mSamplerNames[samplerId].c_str(), ci(op2).c_str(), ci(op5).c_str(), + offsetx, offsety, strrchr(op3, '.')); } - // gInstanceBuffer[worldMatrixOffset] = x.y; - case OPCODE_STORE_STRUCTURED: + appendOutput(buffer); + removeBoolean(op1); + break; + } + case OPCODE_SAMPLE_L: + { + remapTarget(op1); + applySwizzle(".xyzw", op2); + applySwizzle(op1, op3); + applySwizzle(".x", fixImm(op5, instr->asOperands[4])); + int textureId, samplerId; + sscanf_s(op3, "t%d.", &textureId); + sscanf_s(op4, "s%d", &samplerId); + truncateTexturePos(op2, mTextureType[textureId].c_str()); + truncateTextureSwiz(op1, mTextureType[textureId].c_str()); + truncateTextureSwiz(op3, mTextureType[textureId].c_str()); + if (!instr->bAddressOffset) + sprintf(buffer, " %s = %s.SampleLevel(%s, %s, %s)%s;\n", writeTarget(op1), + mTextureNames[textureId].c_str(), mSamplerNames[samplerId].c_str(), ci(op2).c_str(), ci(op5).c_str(), strrchr(op3, '.')); + else { - parse_store_structured(shader, c, pos, size, instr); - break; + int offsetx = 0, offsety = 0, offsetz = 0; + sscanf_s(statement, "sample_l_aoffimmi_indexable(%d,%d,%d", &offsetx, &offsety, &offsetz); + sprintf(buffer, " %s = %s.SampleLevel(%s, %s, %s, int2(%d, %d))%s;\n", writeTarget(op1), + mTextureNames[textureId].c_str(), mSamplerNames[samplerId].c_str(), ci(op2).c_str(), ci(op5).c_str(), + offsetx, offsety, strrchr(op3, '.')); } - - // Missing opcodes for SM5. Not implemented yet, but we want to generate some sort of code, in case - // these are used in needed shaders. That way we can hand edit the shader to make it usable, until - // this is completed. - case OPCODE_STORE_UAV_TYPED: - case OPCODE_LD_UAV_TYPED: - case OPCODE_LD_RAW: - case OPCODE_STORE_RAW: + appendOutput(buffer); + removeBoolean(op1); + break; + } + case OPCODE_SAMPLE_D: + { + remapTarget(op1); + applySwizzle(".xyzw", op2); + applySwizzle(op1, op3); + applySwizzle(op1, fixImm(op5, instr->asOperands[4])); + applySwizzle(op1, fixImm(op6, instr->asOperands[5])); + int textureId, samplerId; + sscanf_s(op3, "t%d.", &textureId); + sscanf_s(op4, "s%d", &samplerId); + truncateTexturePos(op2, mTextureType[textureId].c_str()); + truncateTextureSwiz(op1, mTextureType[textureId].c_str()); + truncateTextureSwiz(op3, mTextureType[textureId].c_str()); + if (!instr->bAddressOffset) + sprintf(buffer, " %s = %s.SampleGrad(%s, %s, %s, %s)%s;\n", writeTarget(op1), + mTextureNames[textureId].c_str(), mSamplerNames[samplerId].c_str(), ci(op2).c_str(), ci(op5).c_str(), ci(op6).c_str(), strrchr(op3, '.')); + else { - sprintf(buffer, "// No code for instruction (needs manual fix):\n"); - appendOutput(buffer); - ASMLineOut(c, pos, size); - break; + int offsetx = 0, offsety = 0, offsetz = 0; + sscanf_s(statement, "sample_d_aoffimmi_indexable(%d,%d,%d", &offsetx, &offsety, &offsetz); + sprintf(buffer, " %s = %s.SampleGrad(%s, %s, %s, %s, int2(%d, %d))%s;\n", writeTarget(op1), + mTextureNames[textureId].c_str(), mSamplerNames[samplerId].c_str(), ci(op2).c_str(), ci(op5).c_str(), ci(op6).c_str(), + offsetx, offsety, strrchr(op3, '.')); + } + appendOutput(buffer); + removeBoolean(op1); + break; + } + case OPCODE_SAMPLE_C: + { + remapTarget(op1); + applySwizzle(".xyzw", op2); + applySwizzle(op1, op3); + applySwizzle(".x", fixImm(op5, instr->asOperands[4])); + int textureId, samplerId; + sscanf_s(op3, "t%d.", &textureId); + sscanf_s(op4, "s%d", &samplerId); + truncateTexturePos(op2, mTextureType[textureId].c_str()); + truncateTextureSwiz(op1, mTextureType[textureId].c_str()); + truncateTextureSwiz(op3, mTextureType[textureId].c_str()); + if (!instr->bAddressOffset) + sprintf(buffer, " %s = %s.SampleCmp(%s, %s, %s)%s;\n", writeTarget(op1), + mTextureNames[textureId].c_str(), mSamplerComparisonNames[samplerId].c_str(), ci(op2).c_str(), ci(op5).c_str(), strrchr(op3, '.')); + else + { + int offsetx = 0, offsety = 0, offsetz = 0; + sscanf_s(statement, "sample_c_aoffimmi_indexable(%d,%d,%d", &offsetx, &offsety, &offsetz); + sprintf(buffer, " %s = %s.SampleCmp(%s, %s, %s, int2(%d, %d))%s;\n", writeTarget(op1), + mTextureNames[textureId].c_str(), mSamplerComparisonNames[samplerId].c_str(), ci(op2).c_str(), ci(op5).c_str(), + offsetx, offsety, strrchr(op3, '.')); + } + appendOutput(buffer); + removeBoolean(op1); + break; + } + // sample_c_lz_indexable(texture2d)(float,float,float,float) r1.y, r3.zwzz, t0.xxxx, s1, r1.z + case OPCODE_SAMPLE_C_LZ: + { + remapTarget(op1); + applySwizzle(".xyzw", op2); + applySwizzle(op1, op3); + applySwizzle(".x", fixImm(op5, instr->asOperands[4])); + int textureId, samplerId; + sscanf_s(op3, "t%d.", &textureId); + sscanf_s(op4, "s%d", &samplerId); + truncateTexturePos(op2, mTextureType[textureId].c_str()); + truncateTextureSwiz(op1, mTextureType[textureId].c_str()); + truncateTextureSwiz(op3, mTextureType[textureId].c_str()); + if (!instr->bAddressOffset) + sprintf(buffer, " %s = %s.SampleCmpLevelZero(%s, %s, %s)%s;\n", writeTarget(op1), + mTextureNames[textureId].c_str(), mSamplerComparisonNames[samplerId].c_str(), ci(op2).c_str(), ci(op5).c_str(), strrchr(op3, '.')); + else + { + int offsetx = 0, offsety = 0, offsetz = 0; + sscanf_s(statement, "sample_c_lz_aoffimmi_indexable(%d,%d,%d", &offsetx, &offsety, &offsetz); + sprintf(buffer, " %s = %s.SampleCmpLevelZero(%s, %s, %s, int2(%d, %d))%s;\n", writeTarget(op1), + mTextureNames[textureId].c_str(), mSamplerComparisonNames[samplerId].c_str(), ci(op2).c_str(), ci(op5).c_str(), + offsetx, offsety, strrchr(op3, '.')); } + appendOutput(buffer); + removeBoolean(op1); + break; + } + // This opcode was missing, and used in WatchDogs. + // expected code "samplepos r0.xy, t1.xyxx, v1.x" -> "r0.xy = t1.GetSamplePosition(v1.x);" + case OPCODE_SAMPLE_POS: + { + remapTarget(op1); + applySwizzle(op1, op2); + applySwizzle(op1, op3); + int textureId; + sscanf_s(op2, "t%d.", &textureId); + sprintf(buffer, " %s = %s.GetSamplePosition(%s);\n", writeTarget(op1), + mTextureNames[textureId].c_str(), ci(op3).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; + } - case OPCODE_DISCARD: - applySwizzle(".x", op1); - if (instr->eBooleanTestType == INSTRUCTION_TEST_ZERO) - sprintf(buffer, " if (%s == 0) discard;\n", ci(op1).c_str()); - else - sprintf(buffer, " if (%s != 0) discard;\n", ci(op1).c_str()); - appendOutput(buffer); - break; + // Missing opcode, used in FC4. Similar to 'sample' + // lod dest[.mask], srcAddress[.swizzle], srcResource[.swizzle], srcSampler + // ret Object.CalculateLevelOfDetail(sampler_state S, float x); + // "lod r0.x, r0.xyzx, t2.y, s2" -> "r0.x = t2.CalculateLevelOfDetailUnclamped(s2, r0.xyz);" + // CalculateLevelOfDetailUnclamped compiles to t2.y, + // CalculateLevelOfDetail compiles to t2.x + case OPCODE_LOD: + { + remapTarget(op1); + applySwizzle(".xyzw", op2); + applySwizzle(op1, op3); + int textureId, samplerId; + sscanf_s(op3, "t%d.", &textureId); + sscanf_s(op4, "s%d", &samplerId); + truncateTexturePos(op2, mTextureType[textureId].c_str()); + char* clamped = strrchr(op3, '.') + 1; + if (*clamped == 'x') + sprintf(buffer, " %s = %s.CalculateLevelOfDetail(%s, %s);\n", writeTarget(op1), + mTextureNames[textureId].c_str(), mSamplerNames[samplerId].c_str(), ci(op2).c_str()); + else + sprintf(buffer, " %s = %s.CalculateLevelOfDetailUnclamped(%s, %s);\n", writeTarget(op1), + mTextureNames[textureId].c_str(), mSamplerNames[samplerId].c_str(), ci(op2).c_str()); + appendOutput(buffer); + removeBoolean(op1); + break; + } - // The GetDimensions can also see a 4 parameter version in the immediate case. - // https://msdn.microsoft.com/en-us/library/windows/desktop/hh447214(v=vs.85).aspx - // - // resinfo[_uint|_rcpFloat] dest[.mask], srcMipLevel.select_component, srcResource[.swizzle] - // In different variants based on input texture, becomes: - // void Object.GetDimensions(UINT MipLevel, typeX Width, typeX Height, typeX Elements, typeX Depth, typeX NumberOfLevels, typeX NumberOfSamples); - // - // We only see the immediate version l(0) in use, like: - // - // resinfo_indexable(texture2d)(uint, uint, uint, uint)_uint r2.zw, l(0), t5.zwxy - // Becomes 2 param version: SectorAtlasTexture_UINT_TextureObject.GetDimensions(r2.z, r2.w); - // - // resinfo_indexable(texture2dms)(float, float, float, float)_uint r0.xy, l(0), t0.xyzw - // Becomes 3 param version: DepthVPSampler_TextureObject.GetDimensions(r0.x, r0.y, bitmask.x); - // - // resinfo_indexable(texture2darray)(float, float, float, float) r0.xy, l(0), t0.xyzw - // - // So, we'll only handle that immediate for now, and generate syntax errors if we see any other variant. - // We don't want to knowingly generate code that compiles, but has errors. Includes _rcpFloat as unknown. - // - // This also added new ResInfo parsing that was not in our older BinaryCompiler. - // - // bindInfo is zeroed out, and GetResourceFromBindingPoint fails when the headers have been stripped. - // With no reflection information, we are left with only the text. - case OPCODE_RESINFO: + case OPCODE_GATHER4: + { + remapTarget(op1); + applySwizzle(".xyzw", op2); + applySwizzle(op1, op3); + int textureId, samplerId; + sscanf_s(op3, "t%d.", &textureId); + sscanf_s(op4, "s%d", &samplerId); + truncateTexturePos(op2, mTextureType[textureId].c_str()); + if (!instr->bAddressOffset) + sprintf(buffer, " %s = %s.Gather(%s, %s)%s;\n", writeTarget(op1), + mTextureNames[textureId].c_str(), mSamplerNames[samplerId].c_str(), ci(op2).c_str(), strrchr(op3, '.')); + else { - remapTarget(op1); + int offsetx = 0, offsety = 0, offsetz = 0; + sscanf_s(statement, "gather4_aoffimmi_indexable(%d,%d,%d", &offsetx, &offsety, &offsetz); + sprintf(buffer, " %s = %s.Gather(%s, %s, int2(%d, %d))%s;\n", writeTarget(op1), + mTextureNames[textureId].c_str(), mSamplerNames[samplerId].c_str(), ci(op2).c_str(), + offsetx, offsety, strrchr(op3, '.')); + } + appendOutput(buffer); + removeBoolean(op1); + break; + } - bool unknownVariant = true; - Operand output = instr->asOperands[0]; - Operand constZero = instr->asOperands[1]; - Operand texture = instr->asOperands[2]; - RESINFO_RETURN_TYPE returnType = instr->eResInfoReturnType; - int texReg = texture.ui32RegisterNumber; - ResourceBinding bindInfo; - ResourceBinding *bindInfoPtr = &bindInfo; + case OPCODE_GATHER4_C: + { + remapTarget(op1); + applySwizzle(".xyzw", op2); + applySwizzle(op1, op3); + int textureId, samplerId; + sscanf_s(op3, "t%d.", &textureId); + sscanf_s(op4, "s%d", &samplerId); + truncateTexturePos(op2, mTextureType[textureId].c_str()); + if (!instr->bAddressOffset) + sprintf(buffer, " %s = %s.GatherCmp(%s, %s, %s)%s;\n", writeTarget(op1), + mTextureNames[textureId].c_str(), mSamplerComparisonNames[samplerId].c_str(), ci(op2).c_str(), ci(op5).c_str(), strrchr(op3, '.')); + else + { + int offsetx = 0, offsety = 0, offsetz = 0; + sscanf_s(statement, "gather4_c_aoffimmi_indexable(%d,%d,%d", &offsetx, &offsety, &offsetz); + sprintf(buffer, " %s = %s.GatherCmp(%s, %s, %s, int2(%d,%d))%s;\n", writeTarget(op1), + mTextureNames[textureId].c_str(), mSamplerComparisonNames[samplerId].c_str(), ci(op2).c_str(), ci(op5).c_str(), + offsetx, offsety, strrchr(op3, '.')); + } + appendOutput(buffer); + removeBoolean(op1); + break; + } - memset(&bindInfo, 0, sizeof(bindInfo)); - int bindstate = GetResourceFromBindingPoint(RGROUP_TEXTURE, texReg, shader->sInfo, &bindInfoPtr); - bool bindStripped = (bindstate == 0); + // Add the Gather4_PO opcodes for Dragon Age. Copied from Gather4. + // gather4_po dest[.mask], srcAddress[.swizzle], srcOffset[.swizzle], srcResource[.swizzle], srcSampler[.select_component] + // output.color = texture2d.Gather(samplerState, input.texcoord, int2(0,0)); + case OPCODE_GATHER4_PO: + { + remapTarget(op1); + applySwizzle(op1, op2); + applySwizzle(op1, op3); + applySwizzle(op1, op4); + int textureId, samplerId; + sscanf_s(op4, "t%d.", &textureId); + sscanf_s(op5, "s%d", &samplerId); + truncateTexturePos(op2, mTextureType[textureId].c_str()); + sprintf(buffer, " %s = %s.Gather(%s, %s, %s)%s;\n", writeTarget(op1), mTextureNames[textureId].c_str(), + mSamplerNames[samplerId].c_str(), ci(op2).c_str(), ci(op3).c_str(), strrchr(op4, '.')); + appendOutput(buffer); + removeBoolean(op1); + break; + } - if (bindStripped) - { - // In the case where the reflection information has been stripped from the headers, - // we are left with only the text line itself. Try to parse the text for variants - // we know, and add them to the bindInfo. - // - // e.g. from Batman and Witcher3: - // resinfo_indexable(texture2d)(float,float,float,float)_uint r1.yw, l(0), t3.zxwy + // gather4_po_c dest[.mask], srcAddress[.swizzle], srcOffset[.swizzle], srcResource[.swizzle], srcSampler[.R], srcReferenceValue + case OPCODE_GATHER4_PO_C: + { + remapTarget(op1); + applySwizzle(op1, op2); + applySwizzle(op1, op3); + applySwizzle(op1, op4); + int textureId, samplerId; + sscanf_s(op4, "t%d.", &textureId); + sscanf_s(op5, "s%d", &samplerId); + truncateTexturePos(op2, mTextureType[textureId].c_str()); + sprintf(buffer, " %s = %s.GatherCmp(%s, %s, %s, %s)%s;\n", writeTarget(op1), mTextureNames[textureId].c_str(), + mSamplerComparisonNames[samplerId].c_str(), ci(op2).c_str(), ci(op6).c_str(), ci(op3).c_str(), strrchr(op4, '.')); + appendOutput(buffer); + removeBoolean(op1); + break; + } - char texType[opcodeSize]; - char retType[opcodeSize]; - int numInfo = sscanf_s(statement, "resinfo_indexable(%[^)])%s", texType, opcodeSize, retType, opcodeSize) ; + // For the _aoffimmi format, this was picking up 0..15, instead of the necessary -8..7 + // It's a 4 bit number being used in an int, hence missing negatives. + // This fix follows the form of the _Gather opcode above, but should maybe use the + // instr-> parameters after they are fixed. + // Fixed both _LD and LD_MS + case OPCODE_LD: + { + remapTarget(op1); + applySwizzle(".xyzw", op2); + applySwizzle(op1, op3); + int textureId; + sscanf_s(op3, "t%d.", &textureId); + truncateTextureLoadPos(op2, mTextureType[textureId].c_str()); + truncateTextureSwiz(op1, mTextureType[textureId].c_str()); + truncateTextureSwiz(op3, mTextureType[textureId].c_str()); + if (!instr->bAddressOffset) + sprintf(buffer, " %s = %s.Load(%s)%s;\n", writeTarget(op1), mTextureNames[textureId].c_str(), ci(op2).c_str(), strrchr(op3, '.')); + else { + int offsetU = 0, offsetV = 0, offsetW = 0; + sscanf_s(statement, "ld_aoffimmi(%d,%d,%d", &offsetU, &offsetV, &offsetW); + sprintf(buffer, " %s = %s.Load(%s, int3(%d, %d, %d))%s;\n", writeTarget(op1), mTextureNames[textureId].c_str(), ci(op2).c_str(), + offsetU, offsetV, offsetW, strrchr(op3, '.')); + } + appendOutput(buffer); + removeBoolean(op1); + break; + } + case OPCODE_LD_MS: + { + remapTarget(op1); + applySwizzle(".xyzw", op2); + applySwizzle(op1, op3); + applySwizzle(".x", fixImm(op4, instr->asOperands[3]), true); + int textureId; + sscanf_s(op3, "t%d.", &textureId); + truncateTextureLoadPos(op2, mTextureType[textureId].c_str()); + truncateTextureSwiz(op1, mTextureType[textureId].c_str()); + truncateTextureSwiz(op3, mTextureType[textureId].c_str()); + if (!instr->bAddressOffset) + sprintf(buffer, " %s = %s.Load(%s, %s)%s;\n", writeTarget(op1), mTextureNames[textureId].c_str(), ci(op2).c_str(), ci(op4).c_str(), strrchr(op3, '.')); + else { + int offsetU = 0, offsetV = 0, offsetW = 0; + sscanf_s(statement, "ld_aoffimmi(%d,%d,%d", &offsetU, &offsetV, &offsetW); + sprintf(buffer, " %s = %s.Load(%s, %s, int3(%d, %d, %d))%s;\n", writeTarget(op1), mTextureNames[textureId].c_str(), ci(op2).c_str(), ci(op4).c_str(), + offsetU, offsetV, offsetW, strrchr(op3, '.')); + } + appendOutput(buffer); + removeBoolean(op1); + break; + } - bool isConstant = (!strcmp(op2, "l(0),")); + case OPCODE_LD_STRUCTURED: + { + parse_ld_structured(shader, c, pos, size, instr); + break; + } + // gInstanceBuffer[worldMatrixOffset] = x.y; + case OPCODE_STORE_STRUCTURED: + { + parse_store_structured(shader, c, pos, size, instr); + break; + } - if ((numInfo == 2) && isConstant) - { - constZero.eType = OPERAND_TYPE_IMMEDIATE32; - constZero.afImmediates[0] = 0.0; + // Missing opcodes for SM5. Not implemented yet, but we want to generate some sort of code, in case + // these are used in needed shaders. That way we can hand edit the shader to make it usable, until + // this is completed. + case OPCODE_STORE_UAV_TYPED: + case OPCODE_LD_UAV_TYPED: + case OPCODE_LD_RAW: + case OPCODE_STORE_RAW: + { + sprintf(buffer, "// No code for instruction (needs manual fix):\n"); + appendOutput(buffer); + ASMLineOut(c, pos, size); + break; + } - if (!strcmp(texType, "texture2d")) - bindInfoPtr->eDimension = REFLECT_RESOURCE_DIMENSION_TEXTURE2D; - else if (!strcmp(texType, "texture2dms")) - bindInfoPtr->eDimension = REFLECT_RESOURCE_DIMENSION_TEXTURE2DMS; - else if (!strcmp(texType, "texture2darray")) - bindInfoPtr->eDimension = REFLECT_RESOURCE_DIMENSION_TEXTURE2DARRAY; + case OPCODE_DISCARD: + applySwizzle(".x", op1); + if (instr->eBooleanTestType == INSTRUCTION_TEST_ZERO) + sprintf(buffer, " if (%s == 0) discard;\n", ci(op1).c_str()); + else + sprintf(buffer, " if (%s != 0) discard;\n", ci(op1).c_str()); + appendOutput(buffer); + break; - bindInfoPtr->Name = string(op3, strrchr(op3, '.')); + // The GetDimensions can also see a 4 parameter version in the immediate case. + // https://msdn.microsoft.com/en-us/library/windows/desktop/hh447214(v=vs.85).aspx + // + // resinfo[_uint|_rcpFloat] dest[.mask], srcMipLevel.select_component, srcResource[.swizzle] + // In different variants based on input texture, becomes: + // void Object.GetDimensions(UINT MipLevel, typeX Width, typeX Height, typeX Elements, typeX Depth, typeX NumberOfLevels, typeX NumberOfSamples); + // + // We only see the immediate version l(0) in use, like: + // + // resinfo_indexable(texture2d)(uint, uint, uint, uint)_uint r2.zw, l(0), t5.zwxy + // Becomes 2 param version: SectorAtlasTexture_UINT_TextureObject.GetDimensions(r2.z, r2.w); + // + // resinfo_indexable(texture2dms)(float, float, float, float)_uint r0.xy, l(0), t0.xyzw + // Becomes 3 param version: DepthVPSampler_TextureObject.GetDimensions(r0.x, r0.y, bitmask.x); + // + // resinfo_indexable(texture2darray)(float, float, float, float) r0.xy, l(0), t0.xyzw + // + // So, we'll only handle that immediate for now, and generate syntax errors if we see any other variant. + // We don't want to knowingly generate code that compiles, but has errors. Includes _rcpFloat as unknown. + // + // This also added new ResInfo parsing that was not in our older BinaryCompiler. + // + // bindInfo is zeroed out, and GetResourceFromBindingPoint fails when the headers have been stripped. + // With no reflection information, we are left with only the text. + case OPCODE_RESINFO: + { + remapTarget(op1); + + bool unknownVariant = true; + Operand output = instr->asOperands[0]; + Operand constZero = instr->asOperands[1]; + Operand texture = instr->asOperands[2]; + RESINFO_RETURN_TYPE returnType = instr->eResInfoReturnType; + int texReg = texture.ui32RegisterNumber; + ResourceBinding bindInfo; + ResourceBinding* bindInfoPtr = &bindInfo; + + memset(&bindInfo, 0, sizeof(bindInfo)); + int bindstate = GetResourceFromBindingPoint(RGROUP_TEXTURE, texReg, shader->sInfo, &bindInfoPtr); + bool bindStripped = (bindstate == 0); + + if (bindStripped) + { + // In the case where the reflection information has been stripped from the headers, + // we are left with only the text line itself. Try to parse the text for variants + // we know, and add them to the bindInfo. + // + // e.g. from Batman and Witcher3: + // resinfo_indexable(texture2d)(float,float,float,float)_uint r1.yw, l(0), t3.zxwy - if (strstr(retType, "_uint")) - returnType = RESINFO_INSTRUCTION_RETURN_UINT; - else - returnType = RESINFO_INSTRUCTION_RETURN_FLOAT; + char texType[opcodeSize]; + char retType[opcodeSize]; + int numInfo = sscanf_s(statement, "resinfo_indexable(%[^)])%s", texType, opcodeSize, retType, opcodeSize); - texture.eType = OPERAND_TYPE_RESOURCE; + bool isConstant = (!strcmp(op2, "l(0),")); - bindStripped = false; - } - } + if ((numInfo == 2) && isConstant) + { + constZero.eType = OPERAND_TYPE_IMMEDIATE32; + constZero.afImmediates[0] = 0.0; - // We only presently handle the float and _uint return types, and the const 0 mode. - // And the texture2d and textures2dms types. That's all we've seen so far. - // This same output sequence is used for both a normal parse case, and the stripped header case. + if (!strcmp(texType, "texture2d")) + bindInfoPtr->eDimension = REFLECT_RESOURCE_DIMENSION_TEXTURE2D; + else if (!strcmp(texType, "texture2dms")) + bindInfoPtr->eDimension = REFLECT_RESOURCE_DIMENSION_TEXTURE2DMS; + else if (!strcmp(texType, "texture2darray")) + bindInfoPtr->eDimension = REFLECT_RESOURCE_DIMENSION_TEXTURE2DARRAY; - if ((constZero.eType == OPERAND_TYPE_IMMEDIATE32) && (constZero.afImmediates[0] == 0.0) - && (returnType == RESINFO_INSTRUCTION_RETURN_UINT || returnType == RESINFO_INSTRUCTION_RETURN_FLOAT) - && texture.eType == OPERAND_TYPE_RESOURCE - && !bindStripped) - { - //string out1, out2, out3; - - // return results into uint variables forces compiler to generate _uint variant. - //if (returnType == RESINFO_INSTRUCTION_RETURN_UINT) - //{ - // out1 = "dst0.x"; - // out2 = "dst0.y"; - // out3 = "dst0.w"; - //} - //else - //{ - // out1 = ci(GetSuffix(op1, 0)); - // out2 = ci(GetSuffix(op1, 1)); - // out3 = "fDst0.x"; - //} - - if (bindInfoPtr->eDimension == REFLECT_RESOURCE_DIMENSION_TEXTURE2D) - { - if (returnType == RESINFO_INSTRUCTION_RETURN_UINT) - sprintf(buffer, " %s.GetDimensions(0, uiDest.x, uiDest.y, uiDest.z);\n", bindInfoPtr->Name.c_str()); - else - sprintf(buffer, " %s.GetDimensions(0, fDest.x, fDest.y, fDest.z);\n", bindInfoPtr->Name.c_str()); - appendOutput(buffer); - unknownVariant = false; - } - else if (bindInfoPtr->eDimension == REFLECT_RESOURCE_DIMENSION_TEXTURE2DMS) - { - if (returnType == RESINFO_INSTRUCTION_RETURN_UINT) - sprintf(buffer, " %s.GetDimensions(uiDest.x, uiDest.y, uiDest.z);\n", bindInfoPtr->Name.c_str()); - else - sprintf(buffer, " %s.GetDimensions(fDest.x, fDest.y, fDest.z);\n", bindInfoPtr->Name.c_str()); - appendOutput(buffer); - unknownVariant = false; - } - else if (bindInfoPtr->eDimension == REFLECT_RESOURCE_DIMENSION_TEXTURE2DARRAY) - { - if (returnType == RESINFO_INSTRUCTION_RETURN_UINT) - sprintf(buffer, " %s.GetDimensions(0, uiDest.x, uiDest.y, uiDest.z, uiDest.w);\n", bindInfoPtr->Name.c_str()); - else - sprintf(buffer, " %s.GetDimensions(0, fDest.x, fDest.y, fDest.z, fDest.w);\n", bindInfoPtr->Name.c_str()); - appendOutput(buffer); - unknownVariant = false; - } + bindInfoPtr->Name = string(op3, strrchr(op3, '.')); - // For the output, we saw a r3.xyzw which makes no sense for this instruction. - // Not sure this is fully correct, but the goal here is to apply the swizzle from the op3, which is the texture - // register, as the pieces that are valid to copy to the op1 output. - // The op3 texture swizzle can determine which components to use, and what order. - // The op1 output determines which ones are valid for output. - if (returnType == RESINFO_INSTRUCTION_RETURN_UINT) - { - char dest[opcodeSize] = "uiDest.xyzw"; - applySwizzle(op3, dest); - applySwizzle(op1, dest); - sprintf(buffer, " %s = %s;\n", op1, dest); - appendOutput(buffer); - } + if (strstr(retType, "_uint")) + returnType = RESINFO_INSTRUCTION_RETURN_UINT; else - { - char dest[opcodeSize] = "fDest.xyzw"; - applySwizzle(op3, dest); - applySwizzle(op1, dest); - sprintf(buffer, " %s = %s;\n", op1, dest); - appendOutput(buffer); - } + returnType = RESINFO_INSTRUCTION_RETURN_FLOAT; + + texture.eType = OPERAND_TYPE_RESOURCE; + + bindStripped = false; } - if (unknownVariant) + } + + // We only presently handle the float and _uint return types, and the const 0 mode. + // And the texture2d and textures2dms types. That's all we've seen so far. + // This same output sequence is used for both a normal parse case, and the stripped header case. + + if ((constZero.eType == OPERAND_TYPE_IMMEDIATE32) && (constZero.afImmediates[0] == 0.0) + && (returnType == RESINFO_INSTRUCTION_RETURN_UINT || returnType == RESINFO_INSTRUCTION_RETURN_FLOAT) + && texture.eType == OPERAND_TYPE_RESOURCE + && !bindStripped) + { + //string out1, out2, out3; + + // return results into uint variables forces compiler to generate _uint variant. + //if (returnType == RESINFO_INSTRUCTION_RETURN_UINT) + //{ + // out1 = "dst0.x"; + // out2 = "dst0.y"; + // out3 = "dst0.w"; + //} + //else + //{ + // out1 = ci(GetSuffix(op1, 0)); + // out2 = ci(GetSuffix(op1, 1)); + // out3 = "fDst0.x"; + //} + + if (bindInfoPtr->eDimension == REFLECT_RESOURCE_DIMENSION_TEXTURE2D) { - // Completely new variant, write out the reminder. - string line = string(c + pos); - line = line.substr(0, line.find('\n')); - sprintf(buffer, "// Unknown use of GetDimensions for resinfo_ from missing reflection info, need manual fix.\n"); - appendOutput(buffer); - sprintf(buffer, "// %s\n", line.c_str()); - appendOutput(buffer); - sprintf(buffer, "// Example for texture2d type, uint return:\n"); + if (returnType == RESINFO_INSTRUCTION_RETURN_UINT) + sprintf(buffer, " %s.GetDimensions(0, uiDest.x, uiDest.y, uiDest.z);\n", bindInfoPtr->Name.c_str()); + else + sprintf(buffer, " %s.GetDimensions(0, fDest.x, fDest.y, fDest.z);\n", bindInfoPtr->Name.c_str()); appendOutput(buffer); - sprintf(buffer, "tx.GetDimensions(0, uiDest.x, uiDest.y, uiDest.z);\n"); + unknownVariant = false; + } else if (bindInfoPtr->eDimension == REFLECT_RESOURCE_DIMENSION_TEXTURE2DMS) + { + if (returnType == RESINFO_INSTRUCTION_RETURN_UINT) + sprintf(buffer, " %s.GetDimensions(uiDest.x, uiDest.y, uiDest.z);\n", bindInfoPtr->Name.c_str()); + else + sprintf(buffer, " %s.GetDimensions(fDest.x, fDest.y, fDest.z);\n", bindInfoPtr->Name.c_str()); appendOutput(buffer); - sprintf(buffer, "rx = uiDest;\n"); + unknownVariant = false; + } else if (bindInfoPtr->eDimension == REFLECT_RESOURCE_DIMENSION_TEXTURE2DARRAY) + { + if (returnType == RESINFO_INSTRUCTION_RETURN_UINT) + sprintf(buffer, " %s.GetDimensions(0, uiDest.x, uiDest.y, uiDest.z, uiDest.w);\n", bindInfoPtr->Name.c_str()); + else + sprintf(buffer, " %s.GetDimensions(0, fDest.x, fDest.y, fDest.z, fDest.w);\n", bindInfoPtr->Name.c_str()); appendOutput(buffer); + unknownVariant = false; + } - sprintf(buffer, " state=%d, constZero.eType=%d, returnType=%d, texture.eType=%d, afImmediates[0]=%f\n", bindstate, constZero.eType, returnType, texture.eType, constZero.afImmediates[0]); + // For the output, we saw a r3.xyzw which makes no sense for this instruction. + // Not sure this is fully correct, but the goal here is to apply the swizzle from the op3, which is the texture + // register, as the pieces that are valid to copy to the op1 output. + // The op3 texture swizzle can determine which components to use, and what order. + // The op1 output determines which ones are valid for output. + if (returnType == RESINFO_INSTRUCTION_RETURN_UINT) + { + char dest[opcodeSize] = "uiDest.xyzw"; + applySwizzle(op3, dest); + applySwizzle(op1, dest); + sprintf(buffer, " %s = %s;\n", op1, dest); + appendOutput(buffer); + } else + { + char dest[opcodeSize] = "fDest.xyzw"; + applySwizzle(op3, dest); + applySwizzle(op1, dest); + sprintf(buffer, " %s = %s;\n", op1, dest); appendOutput(buffer); - - //logDecompileError("Unknown _resinfo variant: " + line); } - break; } - - case OPCODE_EVAL_SAMPLE_INDEX: - remapTarget(op1); - applySwizzle(op1, op2); - applySwizzle(".x", fixImm(op3, instr->asOperands[2]), true); - sprintf(buffer, " %s = EvaluateAttributeAtSample(%s, %s);\n", writeTarget(op1), op2, op3); - appendOutput(buffer); - break; - case OPCODE_EVAL_CENTROID: - remapTarget(op1); - applySwizzle(op1, op2); - sprintf(buffer, " %s = EvaluateAttributeCentroid(%s);\n", writeTarget(op1), op2); - appendOutput(buffer); - break; - case OPCODE_EVAL_SNAPPED: - remapTarget(op1); - applySwizzle(op1, op2); - applySwizzle(".xy", fixImm(op3, instr->asOperands[2]), true); - sprintf(buffer, " %s = EvaluateAttributeSnapped(%s, %s);\n", writeTarget(op1), op2, op3); - appendOutput(buffer); - break; - - case OPCODE_DERIV_RTX_COARSE: - remapTarget(op1); - applySwizzle(op1, op2); - sprintf(buffer, " %s = ddx_coarse(%s);\n", writeTarget(op1), op2); - appendOutput(buffer); - removeBoolean(op1); - break; - case OPCODE_DERIV_RTX_FINE: - remapTarget(op1); - applySwizzle(op1, op2); - sprintf(buffer, " %s = ddx_fine(%s);\n", writeTarget(op1), op2); + if (unknownVariant) + { + // Completely new variant, write out the reminder. + string line = string(c + pos); + line = line.substr(0, line.find('\n')); + sprintf(buffer, "// Unknown use of GetDimensions for resinfo_ from missing reflection info, need manual fix.\n"); appendOutput(buffer); - removeBoolean(op1); - break; - case OPCODE_DERIV_RTY_COARSE: - remapTarget(op1); - applySwizzle(op1, op2); - sprintf(buffer, " %s = ddy_coarse(%s);\n", writeTarget(op1), op2); + sprintf(buffer, "// %s\n", line.c_str()); appendOutput(buffer); - removeBoolean(op1); - break; - case OPCODE_DERIV_RTY_FINE: - remapTarget(op1); - applySwizzle(op1, op2); - sprintf(buffer, " %s = ddy_fine(%s);\n", writeTarget(op1), op2); + sprintf(buffer, "// Example for texture2d type, uint return:\n"); appendOutput(buffer); - removeBoolean(op1); - break; - case OPCODE_DERIV_RTX: - remapTarget(op1); - applySwizzle(op1, op2); - sprintf(buffer, " %s = ddx(%s);\n", writeTarget(op1), op2); + sprintf(buffer, "tx.GetDimensions(0, uiDest.x, uiDest.y, uiDest.z);\n"); appendOutput(buffer); - removeBoolean(op1); - break; - case OPCODE_DERIV_RTY: - remapTarget(op1); - applySwizzle(op1, op2); - sprintf(buffer, " %s = ddy(%s);\n", writeTarget(op1), op2); + sprintf(buffer, "rx = uiDest;\n"); appendOutput(buffer); - removeBoolean(op1); - break; - case OPCODE_RET: - sprintf(buffer, " return;\n"); + sprintf(buffer, " state=%d, constZero.eType=%d, returnType=%d, texture.eType=%d, afImmediates[0]=%f\n", bindstate, constZero.eType, returnType, texture.eType, constZero.afImmediates[0]); appendOutput(buffer); - break; - // Missing opcode needed for WatchDogs. Used as "retc_nz r0.x" - case OPCODE_RETC: - applySwizzle(".x", op1); - if (instr->eBooleanTestType == INSTRUCTION_TEST_ZERO) - sprintf(buffer, " if (%s == 0) return;\n", ci(op1).c_str()); - else - sprintf(buffer, " if (%s != 0) return;\n", ci(op1).c_str()); - appendOutput(buffer); - break; + //logDecompileError("Unknown _resinfo variant: " + line); + } + break; + } - // FarCry4 GeometryShader - case OPCODE_EMIT_STREAM: - sprintf(buffer, "// Needs manual fix for instruction, maybe. \n//"); - appendOutput(buffer); - ASMLineOut(c, pos, size); - sprintf(buffer, "m0.Append(0);\n"); - appendOutput(buffer); - break; - case OPCODE_CUT_STREAM: - sprintf(buffer, "// Needs manual fix for instruction, maybe. \n//"); - appendOutput(buffer); - ASMLineOut(c, pos, size); - sprintf(buffer, "m0.RestartStrip();\n"); - appendOutput(buffer); - break; + case OPCODE_EVAL_SAMPLE_INDEX: + remapTarget(op1); + applySwizzle(op1, op2); + applySwizzle(".x", fixImm(op3, instr->asOperands[2]), true); + sprintf(buffer, " %s = EvaluateAttributeAtSample(%s, %s);\n", writeTarget(op1), op2, op3); + appendOutput(buffer); + break; + case OPCODE_EVAL_CENTROID: + remapTarget(op1); + applySwizzle(op1, op2); + sprintf(buffer, " %s = EvaluateAttributeCentroid(%s);\n", writeTarget(op1), op2); + appendOutput(buffer); + break; + case OPCODE_EVAL_SNAPPED: + remapTarget(op1); + applySwizzle(op1, op2); + applySwizzle(".xy", fixImm(op3, instr->asOperands[2]), true); + sprintf(buffer, " %s = EvaluateAttributeSnapped(%s, %s);\n", writeTarget(op1), op2, op3); + appendOutput(buffer); + break; - case OPCODE_NOP: - // Used in MGSV:TPP, perhaps an artefact of having debug - // info enabled in the shaders? - break; + case OPCODE_DERIV_RTX_COARSE: + remapTarget(op1); + applySwizzle(op1, op2); + sprintf(buffer, " %s = ddx_coarse(%s);\n", writeTarget(op1), op2); + appendOutput(buffer); + removeBoolean(op1); + break; + case OPCODE_DERIV_RTX_FINE: + remapTarget(op1); + applySwizzle(op1, op2); + sprintf(buffer, " %s = ddx_fine(%s);\n", writeTarget(op1), op2); + appendOutput(buffer); + removeBoolean(op1); + break; + case OPCODE_DERIV_RTY_COARSE: + remapTarget(op1); + applySwizzle(op1, op2); + sprintf(buffer, " %s = ddy_coarse(%s);\n", writeTarget(op1), op2); + appendOutput(buffer); + removeBoolean(op1); + break; + case OPCODE_DERIV_RTY_FINE: + remapTarget(op1); + applySwizzle(op1, op2); + sprintf(buffer, " %s = ddy_fine(%s);\n", writeTarget(op1), op2); + appendOutput(buffer); + removeBoolean(op1); + break; + case OPCODE_DERIV_RTX: + remapTarget(op1); + applySwizzle(op1, op2); + sprintf(buffer, " %s = ddx(%s);\n", writeTarget(op1), op2); + appendOutput(buffer); + removeBoolean(op1); + break; + case OPCODE_DERIV_RTY: + remapTarget(op1); + applySwizzle(op1, op2); + sprintf(buffer, " %s = ddy(%s);\n", writeTarget(op1), op2); + appendOutput(buffer); + removeBoolean(op1); + break; - default: - logDecompileError("Unknown statement: " + string(statement)); - return; + case OPCODE_RET: + sprintf(buffer, " return;\n"); + appendOutput(buffer); + break; + + // Missing opcode needed for WatchDogs. Used as "retc_nz r0.x" + case OPCODE_RETC: + applySwizzle(".x", op1); + if (instr->eBooleanTestType == INSTRUCTION_TEST_ZERO) + sprintf(buffer, " if (%s == 0) return;\n", ci(op1).c_str()); + else + sprintf(buffer, " if (%s != 0) return;\n", ci(op1).c_str()); + appendOutput(buffer); + break; + + // FarCry4 GeometryShader + case OPCODE_EMIT_STREAM: + sprintf(buffer, "// Needs manual fix for instruction, maybe. \n//"); + appendOutput(buffer); + ASMLineOut(c, pos, size); + sprintf(buffer, "m0.Append(0);\n"); + appendOutput(buffer); + break; + case OPCODE_CUT_STREAM: + sprintf(buffer, "// Needs manual fix for instruction, maybe. \n//"); + appendOutput(buffer); + ASMLineOut(c, pos, size); + sprintf(buffer, "m0.RestartStrip();\n"); + appendOutput(buffer); + break; + + case OPCODE_NOP: + // Used in MGSV:TPP, perhaps an artefact of having debug + // info enabled in the shaders? + break; + + default: + logDecompileError("Unknown statement: " + string(statement)); + return; } iNr++; } @@ -6675,7 +6602,7 @@ class Decompiler WritePatches(); } - void ParseCodeOnlyShaderType(Shader *shader, const char *c, size_t size) + void ParseCodeOnlyShaderType(Shader* shader, const char* c, size_t size) { mOutputRegisterValues.clear(); mBooleanRegisters.clear(); @@ -6718,7 +6645,7 @@ class Decompiler void WriteAddOnDeclarations() { - string declaration = + string declaration = "\n\n" "// 3Dmigoto declarations\n"; @@ -6769,7 +6696,7 @@ class Decompiler } }; -const string DecompileBinaryHLSL(ParseParameters ¶ms, bool &patched, std::string &shaderModel, bool &errorOccurred) +const string DecompileBinaryHLSL(ParseParameters& params, bool& patched, std::string& shaderModel, bool& errorOccurred) { Decompiler d; @@ -6787,20 +6714,19 @@ const string DecompileBinaryHLSL(ParseParameters ¶ms, bool &patched, std::st // block to handle any exceptions and mark the shader as presently bad. // In order for this to work, the /EHa option must be enabled for code-generation // so that system level exceptions are caught too. - + // It's worth noting that some fatal exceptions will still bypass this catch, // like a stack corruption, stack overflow, or out of memory, and crash the game. // The termination handler approach does not catch those errors either. try { - Shader *shader = DecodeDXBC((uint32_t*)params.bytecode); + Shader* shader = DecodeDXBC((uint32_t*)params.bytecode); if (!shader) return string(); if (shader->dx9Shader) { d.ReadResourceBindingsDX9(params.decompiled, params.decompiledSize); - } - else + } else { d.ParseStructureDefinitions(shader, params.decompiled, params.decompiledSize); d.ReadResourceBindings(params.decompiled, params.decompiledSize); @@ -6814,8 +6740,7 @@ const string DecompileBinaryHLSL(ParseParameters ¶ms, bool &patched, std::st if (!params.ZeroOutput) { d.ParseCode(shader, params.decompiled, params.decompiledSize); - } - else + } else { d.ParseCodeOnlyShaderType(shader, params.decompiled, params.decompiledSize); d.WriteZeroOutputSignature(params.decompiled, params.decompiledSize); @@ -6829,8 +6754,7 @@ const string DecompileBinaryHLSL(ParseParameters ¶ms, bool &patched, std::st delete shader; patched = d.mPatched; return string(d.mOutput.begin(), d.mOutput.end()); - } - catch (...) + } catch (...) { // Fatal error, but catch it and mark it as bad. LogInfo(" ******* Exception caught while decompiling shader ******\n"); diff --git a/HLSLDecompiler/cmd_Decompiler/cmd_Decompiler.cpp b/HLSLDecompiler/cmd_Decompiler/cmd_Decompiler.cpp index 2e6df4384..d9854ed87 100644 --- a/HLSLDecompiler/cmd_Decompiler/cmd_Decompiler.cpp +++ b/HLSLDecompiler/cmd_Decompiler/cmd_Decompiler.cpp @@ -10,17 +10,17 @@ #include "version.h" #include "log.h" #define MIGOTO_DX 11 // Selects the DX11 disassembler in util.h - the DX9 dis/assembler is not very - // interesting since it is just Microsoft's - we can add it later, but low priority. - // The DX9 decompiler is more interesting, which is unrelated to this flag. + // interesting since it is just Microsoft's - we can add it later, but low priority. + // The DX9 decompiler is more interesting, which is unrelated to this flag. #include "util.h" #include "shader.h" using namespace std; -FILE *LogFile = stderr; // Log to stderr by default +FILE* LogFile = stderr; // Log to stderr by default bool gLogDebug = false; -static void PrintHelp(int argc, char *argv[]) +static void PrintHelp(int argc, char* argv[]) { LogInfo("usage: %s [OPTION] FILE...\n\n", argv[0]); @@ -98,10 +98,10 @@ static struct { bool stop; } args; -void parse_args(int argc, char *argv[]) +void parse_args(int argc, char* argv[]) { bool terminated = false; - char *arg; + char* arg; int i; // I'd prefer to use an existing library for this (e.g. that allows @@ -191,11 +191,11 @@ void parse_args(int argc, char *argv[]) } if (args.decompile + args.compile - + args.disassemble_ms - + args.disassemble_flugan - + args.disassemble_hexdump - + args.disassemble_46 - + args.assemble < 1) { + + args.disassemble_ms + + args.disassemble_flugan + + args.disassemble_hexdump + + args.disassemble_46 + + args.assemble < 1) { LogInfo("No action specified\n"); PrintHelp(argc, argv); // Does not return } @@ -206,9 +206,9 @@ void parse_args(int argc, char *argv[]) // to bug in MS's disassembler that always prints floats with %f, which does // not have sufficient precision to reproduce a 32bit floating point value // exactly. Might still be useful for comparison: -static HRESULT DisassembleMS(const void *pShaderBytecode, size_t BytecodeLength, string *asmText) +static HRESULT DisassembleMS(const void* pShaderBytecode, size_t BytecodeLength, string* asmText) { - ID3DBlob *disassembly = nullptr; + ID3DBlob* disassembly = nullptr; UINT flags = D3D_DISASM_ENABLE_DEFAULT_VALUE_PRINTS; string comments = "// using 3Dmigoto command line v" + string(VER_FILE_VERSION_STR) + " on " + LogTime() + "//\n"; @@ -227,8 +227,8 @@ static HRESULT DisassembleMS(const void *pShaderBytecode, size_t BytecodeLength, return S_OK; } -static HRESULT DisassembleFlugan(const void *pShaderBytecode, size_t BytecodeLength, string *asmText, - int hexdump, bool d3dcompiler_46_compat) +static HRESULT DisassembleFlugan(const void* pShaderBytecode, size_t BytecodeLength, string* asmText, + int hexdump, bool d3dcompiler_46_compat) { // FIXME: This is a bit of a waste - we convert from a vector to // a void* + size_t to a vector @@ -240,9 +240,9 @@ static HRESULT DisassembleFlugan(const void *pShaderBytecode, size_t BytecodeLen return S_OK; } -static int validate_section(char section[4], unsigned char *old_section, unsigned char *new_section, size_t size, struct dxbc_header *old_dxbc) +static int validate_section(char section[4], unsigned char* old_section, unsigned char* new_section, size_t size, struct dxbc_header* old_dxbc) { - unsigned char *p1 = old_section, *p2 = new_section; + unsigned char* p1 = old_section, * p2 = new_section; int rc = 0; size_t pos; size_t off = (size_t)(old_section - (unsigned char*)old_dxbc); @@ -254,21 +254,21 @@ static int validate_section(char section[4], unsigned char *old_section, unsigne if (!rc) LogInfo("\n*** Assembly verification pass failed: mismatch in section %.4s:\n", section); LogInfo(" %.4s+0x%04Ix (0x%08Ix): expected 0x%02x, found 0x%02x\n", - section, pos, off+pos, *p1, *p2); + section, pos, off + pos, *p1, *p2); rc = 1; } return rc; } -static int validate_assembly(string *assembly, vector *old_shader) +static int validate_assembly(string* assembly, vector* old_shader) { vector assembly_vec(assembly->begin(), assembly->end()); vector new_shader; - struct dxbc_header *old_dxbc_header = NULL, *new_dxbc_header = NULL; - struct section_header *old_section_header = NULL, *new_section_header = NULL; - uint32_t *old_section_offset_ptr = NULL, *new_section_offset_ptr = NULL; - unsigned char *old_section = NULL, *new_section = NULL; + struct dxbc_header* old_dxbc_header = NULL, * new_dxbc_header = NULL; + struct section_header* old_section_header = NULL, * new_section_header = NULL; + uint32_t* old_section_offset_ptr = NULL, * new_section_offset_ptr = NULL; + unsigned char* old_section = NULL, * new_section = NULL; uint32_t size; unsigned i, j; int rc = 0; @@ -285,7 +285,7 @@ static int validate_assembly(string *assembly, vector *old_shader) LogInfo("\n*** Assembly verification pass failed: Reassembly failed 0x%x\n", hret); return 1; } - } catch (AssemblerParseError &e) { + } catch (AssemblerParseError& e) { string disassembly; LogInfo("\n%s\n\n", e.what()); @@ -317,9 +317,9 @@ static int validate_assembly(string *assembly, vector *old_shader) // warn, but still compare since the sections // are identical if ((!strncmp(old_section_header->signature, "SHDR", 4) && - !strncmp(new_section_header->signature, "SHEX", 4)) || - (!strncmp(old_section_header->signature, "SHEX", 4) && - !strncmp(new_section_header->signature, "SHDR", 4))) { + !strncmp(new_section_header->signature, "SHEX", 4)) || + (!strncmp(old_section_header->signature, "SHEX", 4) && + !strncmp(new_section_header->signature, "SHDR", 4))) { if (args.lenient) { LogInfo("Notice: SHDR / SHEX mismatch\n"); } else { @@ -342,7 +342,7 @@ static int validate_assembly(string *assembly, vector *old_shader) // If the failure was in a bytecode section, // output the disassembly with hexdump enabled: if (!strncmp(old_section_header->signature, "SHDR", 4) || - !strncmp(old_section_header->signature, "SHEX", 4)) { + !strncmp(old_section_header->signature, "SHEX", 4)) { string disassembly; hret = DisassembleFlugan(old_shader->data(), old_shader->size(), &disassembly, 2, false); if (SUCCEEDED(hret)) @@ -353,7 +353,7 @@ static int validate_assembly(string *assembly, vector *old_shader) if (old_section_header->size != new_section_header->size) { LogInfo("\n*** Assembly verification pass failed: size mismatch in section %.4s, expected %i, found %i\n", - old_section_header->signature, old_section_header->size, new_section_header->size); + old_section_header->signature, old_section_header->size, new_section_header->size); rc = 1; } @@ -362,11 +362,11 @@ static int validate_assembly(string *assembly, vector *old_shader) if (j == new_dxbc_header->num_sections) { // Whitelist sections that are okay to be missed: if (!args.lenient && - strncmp(old_section_header->signature, "STAT", 4) && // Compiler Statistics - strncmp(old_section_header->signature, "RDEF", 4) && // Resource Definitions - strncmp(old_section_header->signature, "SDBG", 4) && // Debug Info - strncmp(old_section_header->signature, "Aon9", 4)) { // Level 9 shader bytecode - //strncmp(old_section_header->signature, "SFI0", 4)) { // Subtarget Feature Info (not yet sure if this is critical or not) + strncmp(old_section_header->signature, "STAT", 4) && // Compiler Statistics + strncmp(old_section_header->signature, "RDEF", 4) && // Resource Definitions + strncmp(old_section_header->signature, "SDBG", 4) && // Debug Info + strncmp(old_section_header->signature, "Aon9", 4)) { // Level 9 shader bytecode + //strncmp(old_section_header->signature, "SFI0", 4)) { // Subtarget Feature Info (not yet sure if this is critical or not) LogInfo("*** Assembly verification pass failed: Reassembled shader missing %.4s section (not whitelisted)\n", old_section_header->signature); rc = 1; } else @@ -395,10 +395,10 @@ static int validate_assembly(string *assembly, vector *old_shader) } -static HRESULT Decompile(const void *pShaderBytecode, size_t BytecodeLength, string *hlslText, string *shaderModel) +static HRESULT Decompile(const void* pShaderBytecode, size_t BytecodeLength, string* hlslText, string* shaderModel) { // Set all to zero, so we only init the ones we are using here: - ParseParameters p = {0}; + ParseParameters p = { 0 }; DecompilerSettings d; bool patched = false; bool errorOccurred = false; @@ -436,10 +436,10 @@ static HRESULT Decompile(const void *pShaderBytecode, size_t BytecodeLength, str return S_OK; } -static int validate_hlsl(string *hlsl, string *shaderModel) +static int validate_hlsl(string* hlsl, string* shaderModel) { - ID3DBlob *ppBytecode = NULL; - ID3DBlob *pErrorMsgs = NULL; + ID3DBlob* ppBytecode = NULL; + ID3DBlob* pErrorMsgs = NULL; HRESULT hr; // Using optimisation level 0 for faster verification: @@ -471,7 +471,7 @@ static int validate_hlsl(string *hlsl, string *shaderModel) } template -static int ReadInput(vector *srcData, string const *filename) +static int ReadInput(vector* srcData, string const* filename) { DWORD srcDataSize; DWORD readSize; @@ -499,10 +499,10 @@ static int ReadInput(vector *srcData, string const *filename) return EXIT_SUCCESS; } -static int WriteOutput(string const *in_filename, char const *extension, string const *output) +static int WriteOutput(string const* in_filename, char const* extension, string const* output) { string out_filename; - FILE *fp; + FILE* fp; // TODO: Use 3DMigoto style filenames when possible, but remember we // have no guarantee that the input filename is already in a form that @@ -526,7 +526,7 @@ static int WriteOutput(string const *in_filename, char const *extension, string return EXIT_SUCCESS; } -static int process(string const *filename) +static int process(string const* filename) { HRESULT hret; string output; @@ -615,16 +615,16 @@ static int process(string const *filename) //----------------------------------------------------------------------------- // Console App Entry-Point. //----------------------------------------------------------------------------- -int main(int argc, char *argv[]) +int main(int argc, char* argv[]) { int rc = EXIT_SUCCESS; parse_args(argc, argv); - for (string const &filename : args.files) { + for (string const& filename : args.files) { try { rc = process(&filename) || rc; - } catch (const exception & e) { + } catch (const exception& e) { LogInfo("\n*** UNHANDLED EXCEPTION: %s\n", e.what()); rc = EXIT_FAILURE; }