From 8a17e159435f8c10e930c4bcf3f6f2ed9fd303de Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Tue, 30 Aug 2011 20:58:43 +0200 Subject: [PATCH 01/36] Various cleanups and TODOs. --- .../Core/VideoCommon/Src/PixelShaderGen.cpp | 110 +++++++----------- 1 file changed, 44 insertions(+), 66 deletions(-) diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp index 530ecd54bb..d05997c0c4 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp @@ -333,12 +333,6 @@ static const char *tevRasTable[] = "float4(0.0f, 0.0f, 0.0f, 0.0f)", // zero }; -static const char *alphaRef[2] = -{ - I_ALPHA"[0].r", - I_ALPHA"[0].g" -}; - //static const char *tevTexFunc[] = { "tex2D", "texRECT" }; static const char *tevCOutputTable[] = { "prev.rgb", "c0.rgb", "c1.rgb", "c2.rgb" }; @@ -385,7 +379,7 @@ const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType setlocale(LC_NUMERIC, "C"); // Reset locale for compilation text[sizeof(text) - 1] = 0x7C; // canary - BuildSwapModeTable(); + BuildSwapModeTable(); // Needed for WriteStage int numStages = bpmem.genMode.numtevstages + 1; int numTexgen = bpmem.genMode.numtexgens; @@ -505,10 +499,6 @@ const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType { // alpha test will always fail, so restart the shader and just make it an empty function WRITE(p, "ocol0 = 0;\n"); - if(DepthTextureEnable) - WRITE(p, "depth = 1.f;\n"); - if(dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND) - WRITE(p, "ocol1 = 0;\n"); WRITE(p, "discard;\n"); if(ApiType != API_D3D11) WRITE(p, "return;\n"); @@ -626,6 +616,7 @@ const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType if(RegisterStates[0].AlphaNeedOverflowControl || RegisterStates[0].ColorNeedOverflowControl) WRITE(p, "prev = frac(prev * (255.0f/256.0f)) * (256.0f/255.0f);\n"); + // TODO: Why are we doing a second alpha pretest here? if (!WriteAlphaTest(p, ApiType, dstAlphaMode)) { // alpha test will always fail, so restart the shader and just make it an empty function @@ -740,10 +731,6 @@ static const char *TEVCMPAlphaOPTable[16] = static void WriteStage(char *&p, int n, API_TYPE ApiType) { - char *rasswap = swapModeTable[bpmem.combiners[n].alphaC.rswap]; - char *texswap = swapModeTable[bpmem.combiners[n].alphaC.tswap]; - - int texcoord = bpmem.tevorders[n/2].getTexCoord(n&1); bool bHasTexCoord = (u32)texcoord < bpmem.genMode.numtexgens; bool bHasIndStage = bpmem.tevind[n].IsActive() && bpmem.tevind[n].bt < bpmem.genMode.numindstages; @@ -780,11 +767,13 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType) } else if (bpmem.tevind[n].mid <= 7 && bHasTexCoord) { // s matrix + // TODO: Might become negative? int mtxidx = 2*(bpmem.tevind[n].mid-5); WRITE(p, "float2 indtevtrans%d = "I_INDTEXMTX"[%d].ww * uv%d.xy * indtevcrd%d.xx;\n", n, mtxidx, texcoord, n); } else if (bpmem.tevind[n].mid <= 11 && bHasTexCoord) { // t matrix + // TODO: Might become negative? int mtxidx = 2*(bpmem.tevind[n].mid-9); WRITE(p, "float2 indtevtrans%d = "I_INDTEXMTX"[%d].ww * uv%d.xy * indtevcrd%d.yy;\n", n, mtxidx, texcoord, n); } @@ -823,11 +812,14 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType) TevStageCombiner::ColorCombiner &cc = bpmem.combiners[n].colorC; TevStageCombiner::AlphaCombiner &ac = bpmem.combiners[n].alphaC; - bool bCRas = cc.a == TEVCOLORARG_RASA || cc.a == TEVCOLORARG_RASC || cc.b == TEVCOLORARG_RASA || cc.b == TEVCOLORARG_RASC || cc.c == TEVCOLORARG_RASA || cc.c == TEVCOLORARG_RASC || cc.d == TEVCOLORARG_RASA || cc.d == TEVCOLORARG_RASC; - bool bARas = ac.a == TEVALPHAARG_RASA || ac.b == TEVALPHAARG_RASA || ac.c == TEVALPHAARG_RASA || ac.d == TEVALPHAARG_RASA; - - if(bCRas || bARas) + if(cc.a == TEVCOLORARG_RASA || cc.a == TEVCOLORARG_RASC + || cc.b == TEVCOLORARG_RASA || cc.b == TEVCOLORARG_RASC + || cc.c == TEVCOLORARG_RASA || cc.c == TEVCOLORARG_RASC + || cc.d == TEVCOLORARG_RASA || cc.d == TEVCOLORARG_RASC + || ac.a == TEVALPHAARG_RASA || ac.b == TEVALPHAARG_RASA + || ac.c == TEVALPHAARG_RASA || ac.d == TEVALPHAARG_RASA) { + char *rasswap = swapModeTable[bpmem.combiners[n].alphaC.rswap]; WRITE(p, "rastemp = %s.%s;\n", tevRasTable[bpmem.tevorders[n / 2].getColorChan(n & 1)], rasswap); WRITE(p, "crastemp = frac(rastemp * (255.0f/256.0f)) * (256.0f/255.0f);\n"); } @@ -835,7 +827,6 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType) if (bpmem.tevorders[n/2].getEnable(n&1)) { - int texmap = bpmem.tevorders[n/2].getTexMap(n&1); if(!bHasIndStage) { // calc tevcord @@ -845,20 +836,19 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType) WRITE(p, "tevcoord.xy = float2(0.0f, 0.0f);\n"); } + char *texswap = swapModeTable[bpmem.combiners[n].alphaC.tswap]; + int texmap = bpmem.tevorders[n/2].getTexMap(n&1); SampleTexture(p, "textemp", "tevcoord", texswap, texmap, ApiType); } else WRITE(p, "textemp = float4(1.0f, 1.0f, 1.0f, 1.0f);\n"); - int kc = bpmem.tevksel[n / 2].getKC(n & 1); - int ka = bpmem.tevksel[n / 2].getKA(n & 1); - - - bool bCKonst = cc.a == TEVCOLORARG_KONST || cc.b == TEVCOLORARG_KONST || cc.c == TEVCOLORARG_KONST || cc.d == TEVCOLORARG_KONST; - bool bAKonst = ac.a == TEVALPHAARG_KONST || ac.b == TEVALPHAARG_KONST || ac.c == TEVALPHAARG_KONST || ac.d == TEVALPHAARG_KONST; - if (bCKonst || bAKonst ) + if (cc.a == TEVCOLORARG_KONST || cc.b == TEVCOLORARG_KONST || cc.c == TEVCOLORARG_KONST || cc.d == TEVCOLORARG_KONST + || ac.a == TEVALPHAARG_KONST || ac.b == TEVALPHAARG_KONST || ac.c == TEVALPHAARG_KONST || ac.d == TEVALPHAARG_KONST) { + int kc = bpmem.tevksel[n / 2].getKC(n & 1); + int ka = bpmem.tevksel[n / 2].getKA(n & 1); WRITE(p, "konsttemp = float4(%s, %s);\n", tevKSelTableC[kc], tevKSelTableA[ka]); if(kc > 7 || ka > 7) { @@ -870,15 +860,10 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType) } } - if(cc.a == TEVCOLORARG_CPREV - || cc.a == TEVCOLORARG_APREV - || cc.b == TEVCOLORARG_CPREV - || cc.b == TEVCOLORARG_APREV - || cc.c == TEVCOLORARG_CPREV - || cc.c == TEVCOLORARG_APREV - || ac.a == TEVALPHAARG_APREV - || ac.b == TEVALPHAARG_APREV - || ac.c == TEVALPHAARG_APREV) + if(cc.a == TEVCOLORARG_CPREV || cc.a == TEVCOLORARG_APREV + || cc.b == TEVCOLORARG_CPREV || cc.b == TEVCOLORARG_APREV + || cc.c == TEVCOLORARG_CPREV || cc.c == TEVCOLORARG_APREV + || ac.a == TEVALPHAARG_APREV || ac.b == TEVALPHAARG_APREV || ac.c == TEVALPHAARG_APREV) { if(RegisterStates[0].AlphaNeedOverflowControl || RegisterStates[0].ColorNeedOverflowControl) { @@ -893,15 +878,10 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType) RegisterStates[0].AuxStored = true; } - if(cc.a == TEVCOLORARG_C0 - || cc.a == TEVCOLORARG_A0 - || cc.b == TEVCOLORARG_C0 - || cc.b == TEVCOLORARG_A0 - || cc.c == TEVCOLORARG_C0 - || cc.c == TEVCOLORARG_A0 - || ac.a == TEVALPHAARG_A0 - || ac.b == TEVALPHAARG_A0 - || ac.c == TEVALPHAARG_A0) + if(cc.a == TEVCOLORARG_C0 || cc.a == TEVCOLORARG_A0 + || cc.b == TEVCOLORARG_C0 || cc.b == TEVCOLORARG_A0 + || cc.c == TEVCOLORARG_C0 || cc.c == TEVCOLORARG_A0 + || ac.a == TEVALPHAARG_A0 || ac.b == TEVALPHAARG_A0 || ac.c == TEVALPHAARG_A0) { if(RegisterStates[1].AlphaNeedOverflowControl || RegisterStates[1].ColorNeedOverflowControl) { @@ -916,15 +896,10 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType) RegisterStates[1].AuxStored = true; } - if(cc.a == TEVCOLORARG_C1 - || cc.a == TEVCOLORARG_A1 - || cc.b == TEVCOLORARG_C1 - || cc.b == TEVCOLORARG_A1 - || cc.c == TEVCOLORARG_C1 - || cc.c == TEVCOLORARG_A1 - || ac.a == TEVALPHAARG_A1 - || ac.b == TEVALPHAARG_A1 - || ac.c == TEVALPHAARG_A1) + if(cc.a == TEVCOLORARG_C1 || cc.a == TEVCOLORARG_A1 + || cc.b == TEVCOLORARG_C1 || cc.b == TEVCOLORARG_A1 + || cc.c == TEVCOLORARG_C1 || cc.c == TEVCOLORARG_A1 + || ac.a == TEVALPHAARG_A1 || ac.b == TEVALPHAARG_A1 || ac.c == TEVALPHAARG_A1) { if(RegisterStates[2].AlphaNeedOverflowControl || RegisterStates[2].ColorNeedOverflowControl) { @@ -939,15 +914,10 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType) RegisterStates[2].AuxStored = true; } - if(cc.a == TEVCOLORARG_C2 - || cc.a == TEVCOLORARG_A2 - || cc.b == TEVCOLORARG_C2 - || cc.b == TEVCOLORARG_A2 - || cc.c == TEVCOLORARG_C2 - || cc.c == TEVCOLORARG_A2 - || ac.a == TEVALPHAARG_A2 - || ac.b == TEVALPHAARG_A2 - || ac.c == TEVALPHAARG_A2) + if(cc.a == TEVCOLORARG_C2 || cc.a == TEVCOLORARG_A2 + || cc.b == TEVCOLORARG_C2 || cc.b == TEVCOLORARG_A2 + || cc.c == TEVCOLORARG_C2 || cc.c == TEVCOLORARG_A2 + || ac.a == TEVALPHAARG_A2 || ac.b == TEVALPHAARG_A2 || ac.c == TEVALPHAARG_A2) { if(RegisterStates[3].AlphaNeedOverflowControl || RegisterStates[3].ColorNeedOverflowControl) { @@ -994,7 +964,7 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType) WRITE(p, "%s", tevBiasTable[cc.bias]); - if (cc.shift > 0) + if (cc.shift > TEVSCALE_1) WRITE(p, ")"); } else @@ -1122,6 +1092,11 @@ static int AlphaPreTest() static bool WriteAlphaTest(char *&p, API_TYPE ApiType,DSTALPHA_MODE dstAlphaMode) { + static const char *alphaRef[2] = + { + I_ALPHA"[0].r", + I_ALPHA"[0].g" + }; int Pretest = AlphaPreTest(); if(Pretest >= 0) @@ -1139,7 +1114,10 @@ static bool WriteAlphaTest(char *&p, API_TYPE ApiType,DSTALPHA_MODE dstAlphaMode compindex = bpmem.alphaFunc.comp1 % 8; WRITE(p, tevAlphaFuncsTable[compindex],alphaRef[1]);//lookup the second component from the alpha function table - WRITE(p, ")){ocol0 = 0;%s%sdiscard;%s}\n",dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND ? "ocol1 = 0;" : "",DepthTextureEnable ? "depth = 1.f;" : "",(ApiType != API_D3D11)? "return;" : ""); + WRITE(p, ")){ocol0 = 0;%s%s discard;%s}\n", + dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND ? "ocol1 = 0;" : "", + DepthTextureEnable ? "depth = 1.f;" : "", + (ApiType != API_D3D11) ? "return;" : ""); return true; } @@ -1197,4 +1175,4 @@ static void WriteFog(char *&p) WRITE(p, " prev.rgb = lerp(prev.rgb,"I_FOG"[0].rgb,fog);\n"); -} +} \ No newline at end of file From 08e06b22937fa79db165e5a31dfd4ccf67ef57db Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Wed, 31 Aug 2011 16:09:54 +0200 Subject: [PATCH 02/36] Partially revert revision d511b506120c. Slightly slows down emulation, but deobfuscates the pixel shader gen greatly... --- .../Core/VideoCommon/Src/PixelShaderGen.cpp | 102 +++--------------- 1 file changed, 12 insertions(+), 90 deletions(-) diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp index d05997c0c4..ade8a0865e 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp @@ -353,15 +353,6 @@ static char swapModeTable[4][5]; static char text[16384]; static bool DepthTextureEnable; -struct RegisterState -{ - bool ColorNeedOverflowControl; - bool AlphaNeedOverflowControl; - bool AuxStored; -}; - -static RegisterState RegisterStates[4]; - static void BuildSwapModeTable() { for (int i = 0; i < 4; i++) @@ -582,16 +573,6 @@ const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType } } - RegisterStates[0].AlphaNeedOverflowControl = false; - RegisterStates[0].ColorNeedOverflowControl = false; - RegisterStates[0].AuxStored = false; - for(int i = 1; i < 4; i++) - { - RegisterStates[i].AlphaNeedOverflowControl = true; - RegisterStates[i].ColorNeedOverflowControl = true; - RegisterStates[i].AuxStored = false; - } - for (int i = 0; i < numStages; i++) WriteStage(p, i, ApiType); //build the equation for this stage @@ -599,22 +580,11 @@ const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType { // The results of the last texenv stage are put onto the screen, // regardless of the used destination register - if(bpmem.combiners[numStages - 1].colorC.dest != 0) - { - bool retrieveFromAuxRegister = !RegisterStates[bpmem.combiners[numStages - 1].colorC.dest].ColorNeedOverflowControl && RegisterStates[bpmem.combiners[numStages - 1].colorC.dest].AuxStored; - WRITE(p, "prev.rgb = %s%s;\n", retrieveFromAuxRegister ? "c" : "" , tevCOutputTable[bpmem.combiners[numStages - 1].colorC.dest]); - RegisterStates[0].ColorNeedOverflowControl = RegisterStates[bpmem.combiners[numStages - 1].colorC.dest].ColorNeedOverflowControl; - } - if(bpmem.combiners[numStages - 1].alphaC.dest != 0) - { - bool retrieveFromAuxRegister = !RegisterStates[bpmem.combiners[numStages - 1].alphaC.dest].AlphaNeedOverflowControl && RegisterStates[bpmem.combiners[numStages - 1].alphaC.dest].AuxStored; - WRITE(p, "prev.a = %s%s;\n", retrieveFromAuxRegister ? "c" : "" , tevAOutputTable[bpmem.combiners[numStages - 1].alphaC.dest]); - RegisterStates[0].AlphaNeedOverflowControl = RegisterStates[bpmem.combiners[numStages - 1].alphaC.dest].AlphaNeedOverflowControl; - } - } - // emulation of unisgned 8 overflow when casting if needed - if(RegisterStates[0].AlphaNeedOverflowControl || RegisterStates[0].ColorNeedOverflowControl) - WRITE(p, "prev = frac(prev * (255.0f/256.0f)) * (256.0f/255.0f);\n"); + WRITE(p, "prev.rgb = %s;\n",tevCOutputTable[bpmem.combiners[numStages-1].colorC.dest]); + WRITE(p, "prev.a = %s;\n",tevAOutputTable[bpmem.combiners[numStages-1].alphaC.dest]); + } + // emulation of unsigned 8 overflow when casting + WRITE(p, "prev = frac(4.0f + prev * (255.0f/256.0f)) * (256.0f/255.0f);\n"); // TODO: Why are we doing a second alpha pretest here? if (!WriteAlphaTest(p, ApiType, dstAlphaMode)) @@ -864,76 +834,30 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType) || cc.b == TEVCOLORARG_CPREV || cc.b == TEVCOLORARG_APREV || cc.c == TEVCOLORARG_CPREV || cc.c == TEVCOLORARG_APREV || ac.a == TEVALPHAARG_APREV || ac.b == TEVALPHAARG_APREV || ac.c == TEVALPHAARG_APREV) - { - if(RegisterStates[0].AlphaNeedOverflowControl || RegisterStates[0].ColorNeedOverflowControl) - { - WRITE(p, "cprev = frac(prev * (255.0f/256.0f)) * (256.0f/255.0f);\n"); - RegisterStates[0].AlphaNeedOverflowControl = false; - RegisterStates[0].ColorNeedOverflowControl = false; - } - else - { - WRITE(p, "cprev = prev;\n"); - } - RegisterStates[0].AuxStored = true; - } + WRITE(p, "cprev = frac(prev * (255.0f/256.0f)) * (256.0f/255.0f);\n"); + if(cc.a == TEVCOLORARG_C0 || cc.a == TEVCOLORARG_A0 || cc.b == TEVCOLORARG_C0 || cc.b == TEVCOLORARG_A0 || cc.c == TEVCOLORARG_C0 || cc.c == TEVCOLORARG_A0 || ac.a == TEVALPHAARG_A0 || ac.b == TEVALPHAARG_A0 || ac.c == TEVALPHAARG_A0) - { - if(RegisterStates[1].AlphaNeedOverflowControl || RegisterStates[1].ColorNeedOverflowControl) - { - WRITE(p, "cc0 = frac(c0 * (255.0f/256.0f)) * (256.0f/255.0f);\n"); - RegisterStates[1].AlphaNeedOverflowControl = false; - RegisterStates[1].ColorNeedOverflowControl = false; - } - else - { - WRITE(p, "cc0 = c0;\n"); - } - RegisterStates[1].AuxStored = true; - } + WRITE(p, "cc0 = frac(c0 * (255.0f/256.0f)) * (256.0f/255.0f);\n"); + if(cc.a == TEVCOLORARG_C1 || cc.a == TEVCOLORARG_A1 || cc.b == TEVCOLORARG_C1 || cc.b == TEVCOLORARG_A1 || cc.c == TEVCOLORARG_C1 || cc.c == TEVCOLORARG_A1 || ac.a == TEVALPHAARG_A1 || ac.b == TEVALPHAARG_A1 || ac.c == TEVALPHAARG_A1) - { - if(RegisterStates[2].AlphaNeedOverflowControl || RegisterStates[2].ColorNeedOverflowControl) - { - WRITE(p, "cc1 = frac(c1 * (255.0f/256.0f)) * (256.0f/255.0f);\n"); - RegisterStates[2].AlphaNeedOverflowControl = false; - RegisterStates[2].ColorNeedOverflowControl = false; - } - else - { - WRITE(p, "cc1 = c1;\n"); - } - RegisterStates[2].AuxStored = true; - } + WRITE(p, "cc1 = frac(c1 * (255.0f/256.0f)) * (256.0f/255.0f);\n"); + if(cc.a == TEVCOLORARG_C2 || cc.a == TEVCOLORARG_A2 || cc.b == TEVCOLORARG_C2 || cc.b == TEVCOLORARG_A2 || cc.c == TEVCOLORARG_C2 || cc.c == TEVCOLORARG_A2 || ac.a == TEVALPHAARG_A2 || ac.b == TEVALPHAARG_A2 || ac.c == TEVALPHAARG_A2) - { - if(RegisterStates[3].AlphaNeedOverflowControl || RegisterStates[3].ColorNeedOverflowControl) - { WRITE(p, "cc2 = frac(c2 * (255.0f/256.0f)) * (256.0f/255.0f);\n"); - RegisterStates[3].AlphaNeedOverflowControl = false; - RegisterStates[3].ColorNeedOverflowControl = false; - } - else - { - WRITE(p, "cc2 = c2;\n"); - } - RegisterStates[3].AuxStored = true; - } - RegisterStates[cc.dest].ColorNeedOverflowControl = (cc.clamp == 0); - RegisterStates[cc.dest].AuxStored = false; + if (cc.clamp) WRITE(p, "%s = saturate(", tevCOutputTable[cc.dest]); else @@ -980,8 +904,6 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType) WRITE(p, ")"); WRITE(p,";\n"); - RegisterStates[ac.dest].AlphaNeedOverflowControl = (ac.clamp == 0); - RegisterStates[ac.dest].AuxStored = false; // combine the alpha channel if (ac.clamp) WRITE(p, "%s = saturate(", tevAOutputTable[ac.dest]); From 7f01139d13ad917d333548918492e92e2bcb436a Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Wed, 31 Aug 2011 03:18:19 +0200 Subject: [PATCH 03/36] Replace the pixel shader UID generation algorithm with a better one which reduces the number of redundant shader compilations by around 30% (can be optimized even further though). This should help some games which suffer from heavy stuttering like e.g. F-Zero GX or Red Steel 2. --- .../Core/VideoCommon/Src/PixelShaderGen.cpp | 2360 +++++++++-------- Source/Core/VideoCommon/Src/PixelShaderGen.h | 4 +- 2 files changed, 1267 insertions(+), 1097 deletions(-) diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp index ade8a0865e..6d0cc64964 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp @@ -1,1100 +1,1270 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include -#include -#include -#include - -#include "LightingShaderGen.h" -#include "PixelShaderGen.h" -#include "XFMemory.h" // for texture projection mode -#include "BPMemory.h" -#include "VideoConfig.h" -#include "NativeVertexFormat.h" - -PIXELSHADERUID last_pixel_shader_uid; - -// Mash together all the inputs that contribute to the code of a generated pixel shader into -// a unique identifier, basically containing all the bits. Yup, it's a lot .... -// It would likely be a lot more efficient to build this incrementally as the attributes -// are set... -void GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode) -{ - u32 numstages = bpmem.genMode.numtevstages + 1; - u32 projtexcoords = 0; - for (u32 i = 0; i < numstages; i++) - { - if (bpmem.tevorders[i/2].getEnable(i & 1)) - { - int texcoord = bpmem.tevorders[i / 2].getTexCoord(i & 1); - if (xfregs.texMtxInfo[i].projection) - projtexcoords |= 1 << texcoord; - } - } - uid->values[0] = (u32)bpmem.genMode.numtevstages | - ((u32)bpmem.genMode.numindstages << 4) | - ((u32)bpmem.genMode.numtexgens << 7) | - ((u32)dstAlphaMode << 11) | - ((u32)((bpmem.alphaFunc.hex >> 16) & 0xff) << 13) | - (projtexcoords << 21) | - ((u32)bpmem.ztex2.op << 29); - - // swap table - for (int i = 0; i < 8; i += 2) - ((u8*)&uid->values[1])[i / 2] = (bpmem.tevksel[i].hex & 0xf) | ((bpmem.tevksel[i + 1].hex & 0xf) << 4); - - u32 enableZTexture = (bpmem.ztex2.op != ZTEXTURE_DISABLE && !bpmem.zcontrol.zcomploc && bpmem.zmode.testenable && bpmem.zmode.updateenable) || g_ActiveConfig.bEnablePerPixelDepth ? 1 : 0; - - uid->values[2] = (u32)bpmem.fog.c_proj_fsel.fsel | - ((u32)bpmem.fog.c_proj_fsel.proj << 3) | - ((u32)enableZTexture << 4) | ((u32)bpmem.fogRange.Base.Enabled << 5); - - if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) - { - for (int i = 0; i < 2; ++i) { - uid->values[3 + i] = xfregs.color[i].enablelighting ? - (u32)xfregs.color[i].hex : - (u32)xfregs.color[i].matsource; - uid->values[3 + i] |= (xfregs.alpha[i].enablelighting ? - (u32)xfregs.alpha[i].hex : - (u32)xfregs.alpha[i].matsource) << 15; - } - } - uid->values[4] |= (g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) << 31; - - int hdr = 5; - u32 *pcurvalue = &uid->values[hdr]; - for (u32 i = 0; i < numstages; ++i) - { - TevStageCombiner::ColorCombiner &cc = bpmem.combiners[i].colorC; - TevStageCombiner::AlphaCombiner &ac = bpmem.combiners[i].alphaC; - - u32 val0 = cc.hex & 0xffffff; - u32 val1 = ac.hex & 0xffffff; - val0 |= bpmem.tevksel[i / 2].getKC(i & 1) << 24; - val1 |= bpmem.tevksel[i / 2].getKA(i & 1) << 24; - pcurvalue[0] = val0; - pcurvalue[1] = val1; - pcurvalue += 2; - } - - for (u32 i = 0; i < numstages / 2; ++i) - { - u32 val0, val1; - if (bpmem.tevorders[i].hex & 0x40) - val0 = bpmem.tevorders[i].hex & 0x3ff; - else - val0 = bpmem.tevorders[i].hex & 0x380; - if (bpmem.tevorders[i].hex & 0x40000) - val1 = (bpmem.tevorders[i].hex & 0x3ff000) >> 12; - else - val1 = (bpmem.tevorders[i].hex & 0x380000) >> 12; - - switch (i % 3) { - case 0: pcurvalue[0] = val0|(val1<<10); break; - case 1: pcurvalue[0] |= val0<<20; pcurvalue[1] = val1; pcurvalue++; break; - case 2: pcurvalue[1] |= (val0<<10)|(val1<<20); pcurvalue++; break; - default: PanicAlert("Unknown case for Tev Stages / 2: %08x", (i % 3)); - } - } - - if (numstages & 1) { // odd - u32 val0; - if (bpmem.tevorders[bpmem.genMode.numtevstages/2].hex & 0x40) - val0 = bpmem.tevorders[bpmem.genMode.numtevstages/2].hex & 0x3ff; - else - val0 = bpmem.tevorders[bpmem.genMode.numtevstages/2].hex & 0x380; - - switch (bpmem.genMode.numtevstages % 3) - { - case 0: pcurvalue[0] = val0; break; - case 1: pcurvalue[0] |= val0 << 20; break; - case 2: pcurvalue[1] |= val0 << 10; pcurvalue++; break; - default: PanicAlert("Unknown case for Tev Stages: %08x", bpmem.genMode.numtevstages % 3); - } - } - - if ((bpmem.genMode.numtevstages % 3) != 2) - ++pcurvalue; - - uid->tevstages = (u32)(pcurvalue - &uid->values[0] - hdr); - - for (u32 i = 0; i < bpmem.genMode.numindstages; ++i) - { - u32 val = bpmem.tevind[i].hex & 0x1fffff; // 21 bits - switch (i % 3) - { - case 0: pcurvalue[0] = val; break; - case 1: pcurvalue[0] |= val << 21; pcurvalue[1] = val >> 11; ++pcurvalue; break; - case 2: pcurvalue[0] |= val << 10; ++pcurvalue; break; - default: PanicAlert("Unknown case for Ind Stages: %08x", (i % 3)); - } - } - - // yeah, well .... - uid->indstages = (u32)(pcurvalue - &uid->values[0] - (hdr - 1) - uid->tevstages); - -} - -// old tev->pixelshader notes -// -// color for this stage (alpha, color) is given by bpmem.tevorders[0].colorchan0 -// konstant for this stage (alpha, color) is given by bpmem.tevksel -// inputs are given by bpmem.combiners[0].colorC.a/b/c/d << could be current chan color -// according to GXTevColorArg table above -// output is given by .outreg -// tevtemp is set according to swapmodetables and - -static void WriteStage(char *&p, int n, API_TYPE ApiType); -static void SampleTexture(char *&p, const char *destination, const char *texcoords, const char *texswap, int texmap, API_TYPE ApiType); -// static void WriteAlphaCompare(char *&p, int num, int comp); -static bool WriteAlphaTest(char *&p, API_TYPE ApiType,DSTALPHA_MODE dstAlphaMode); -static void WriteFog(char *&p); -static int AlphaPreTest(); - -static const char *tevKSelTableC[] = // KCSEL -{ - "1.0f,1.0f,1.0f", // 1 = 0x00 - "0.875f,0.875f,0.875f", // 7_8 = 0x01 - "0.75f,0.75f,0.75f", // 3_4 = 0x02 - "0.625f,0.625f,0.625f", // 5_8 = 0x03 - "0.5f,0.5f,0.5f", // 1_2 = 0x04 - "0.375f,0.375f,0.375f", // 3_8 = 0x05 - "0.25f,0.25f,0.25f", // 1_4 = 0x06 - "0.125f,0.125f,0.125f", // 1_8 = 0x07 - "ERROR", // 0x08 - "ERROR", // 0x09 - "ERROR", // 0x0a - "ERROR", // 0x0b - I_KCOLORS"[0].rgb", // K0 = 0x0C - I_KCOLORS"[1].rgb", // K1 = 0x0D - I_KCOLORS"[2].rgb", // K2 = 0x0E - I_KCOLORS"[3].rgb", // K3 = 0x0F - I_KCOLORS"[0].rrr", // K0_R = 0x10 - I_KCOLORS"[1].rrr", // K1_R = 0x11 - I_KCOLORS"[2].rrr", // K2_R = 0x12 - I_KCOLORS"[3].rrr", // K3_R = 0x13 - I_KCOLORS"[0].ggg", // K0_G = 0x14 - I_KCOLORS"[1].ggg", // K1_G = 0x15 - I_KCOLORS"[2].ggg", // K2_G = 0x16 - I_KCOLORS"[3].ggg", // K3_G = 0x17 - I_KCOLORS"[0].bbb", // K0_B = 0x18 - I_KCOLORS"[1].bbb", // K1_B = 0x19 - I_KCOLORS"[2].bbb", // K2_B = 0x1A - I_KCOLORS"[3].bbb", // K3_B = 0x1B - I_KCOLORS"[0].aaa", // K0_A = 0x1C - I_KCOLORS"[1].aaa", // K1_A = 0x1D - I_KCOLORS"[2].aaa", // K2_A = 0x1E - I_KCOLORS"[3].aaa", // K3_A = 0x1F -}; - -static const char *tevKSelTableA[] = // KASEL -{ - "1.0f", // 1 = 0x00 - "0.875f",// 7_8 = 0x01 - "0.75f", // 3_4 = 0x02 - "0.625f",// 5_8 = 0x03 - "0.5f", // 1_2 = 0x04 - "0.375f",// 3_8 = 0x05 - "0.25f", // 1_4 = 0x06 - "0.125f",// 1_8 = 0x07 - "ERROR", // 0x08 - "ERROR", // 0x09 - "ERROR", // 0x0a - "ERROR", // 0x0b - "ERROR", // 0x0c - "ERROR", // 0x0d - "ERROR", // 0x0e - "ERROR", // 0x0f - I_KCOLORS"[0].r", // K0_R = 0x10 - I_KCOLORS"[1].r", // K1_R = 0x11 - I_KCOLORS"[2].r", // K2_R = 0x12 - I_KCOLORS"[3].r", // K3_R = 0x13 - I_KCOLORS"[0].g", // K0_G = 0x14 - I_KCOLORS"[1].g", // K1_G = 0x15 - I_KCOLORS"[2].g", // K2_G = 0x16 - I_KCOLORS"[3].g", // K3_G = 0x17 - I_KCOLORS"[0].b", // K0_B = 0x18 - I_KCOLORS"[1].b", // K1_B = 0x19 - I_KCOLORS"[2].b", // K2_B = 0x1A - I_KCOLORS"[3].b", // K3_B = 0x1B - I_KCOLORS"[0].a", // K0_A = 0x1C - I_KCOLORS"[1].a", // K1_A = 0x1D - I_KCOLORS"[2].a", // K2_A = 0x1E - I_KCOLORS"[3].a", // K3_A = 0x1F -}; - -static const char *tevScaleTable[] = // CS -{ - "1.0f", // SCALE_1 - "2.0f", // SCALE_2 - "4.0f", // SCALE_4 - "0.5f", // DIVIDE_2 -}; - -static const char *tevBiasTable[] = // TB -{ - "", // ZERO, - "+0.5f", // ADDHALF, - "-0.5f", // SUBHALF, - "", -}; - -static const char *tevOpTable[] = { // TEV - "+", // TEVOP_ADD = 0, - "-", // TEVOP_SUB = 1, -}; - -static const char *tevCInputTable[] = // CC -{ - "(prev.rgb)", // CPREV, - "(prev.aaa)", // APREV, - "(c0.rgb)", // C0, - "(c0.aaa)", // A0, - "(c1.rgb)", // C1, - "(c1.aaa)", // A1, - "(c2.rgb)", // C2, - "(c2.aaa)", // A2, - "(textemp.rgb)", // TEXC, - "(textemp.aaa)", // TEXA, - "(rastemp.rgb)", // RASC, - "(rastemp.aaa)", // RASA, - "float3(1.0f, 1.0f, 1.0f)", // ONE - "float3(0.5f, 0.5f, 0.5f)", // HALF - "(konsttemp.rgb)", //"konsttemp.rgb", // KONST - "float3(0.0f, 0.0f, 0.0f)", // ZERO - ///aded extra values to map clamped values - "(cprev.rgb)", // CPREV, - "(cprev.aaa)", // APREV, - "(cc0.rgb)", // C0, - "(cc0.aaa)", // A0, - "(cc1.rgb)", // C1, - "(cc1.aaa)", // A1, - "(cc2.rgb)", // C2, - "(cc2.aaa)", // A2, - "(textemp.rgb)", // TEXC, - "(textemp.aaa)", // TEXA, - "(crastemp.rgb)", // RASC, - "(crastemp.aaa)", // RASA, - "float3(1.0f, 1.0f, 1.0f)", // ONE - "float3(0.5f, 0.5f, 0.5f)", // HALF - "(ckonsttemp.rgb)", //"konsttemp.rgb", // KONST - "float3(0.0f, 0.0f, 0.0f)", // ZERO - "PADERROR", "PADERROR", "PADERROR", "PADERROR" -}; - -static const char *tevAInputTable[] = // CA -{ - "prev", // APREV, - "c0", // A0, - "c1", // A1, - "c2", // A2, - "textemp", // TEXA, - "rastemp", // RASA, - "konsttemp", // KONST, (hw1 had quarter) - "float4(0.0f, 0.0f, 0.0f, 0.0f)", // ZERO - ///aded extra values to map clamped values - "cprev", // APREV, - "cc0", // A0, - "cc1", // A1, - "cc2", // A2, - "textemp", // TEXA, - "crastemp", // RASA, - "ckonsttemp", // KONST, (hw1 had quarter) - "float4(0.0f, 0.0f, 0.0f, 0.0f)", // ZERO - "PADERROR", "PADERROR", "PADERROR", "PADERROR", - "PADERROR", "PADERROR", "PADERROR", "PADERROR", -}; - -static const char *tevRasTable[] = -{ - "colors_0", - "colors_1", - "ERROR", //2 - "ERROR", //3 - "ERROR", //4 - "alphabump", // use bump alpha - "(alphabump*(255.0f/248.0f))", //normalized - "float4(0.0f, 0.0f, 0.0f, 0.0f)", // zero -}; - -//static const char *tevTexFunc[] = { "tex2D", "texRECT" }; - -static const char *tevCOutputTable[] = { "prev.rgb", "c0.rgb", "c1.rgb", "c2.rgb" }; -static const char *tevAOutputTable[] = { "prev.a", "c0.a", "c1.a", "c2.a" }; -static const char *tevIndAlphaSel[] = {"", "x", "y", "z"}; -//static const char *tevIndAlphaScale[] = {"", "*32", "*16", "*8"}; -static const char *tevIndAlphaScale[] = {"*(248.0f/255.0f)", "*(224.0f/255.0f)", "*(240.0f/255.0f)", "*(248.0f/255.0f)"}; -static const char *tevIndBiasField[] = {"", "x", "y", "xy", "z", "xz", "yz", "xyz"}; // indexed by bias -static const char *tevIndBiasAdd[] = {"-128.0f", "1.0f", "1.0f", "1.0f" }; // indexed by fmt -static const char *tevIndWrapStart[] = {"0.0f", "256.0f", "128.0f", "64.0f", "32.0f", "16.0f", "0.001f" }; -static const char *tevIndFmtScale[] = {"255.0f", "31.0f", "15.0f", "7.0f" }; - -#define WRITE p+=sprintf - -static const char *swapColors = "rgba"; -static char swapModeTable[4][5]; - -static char text[16384]; -static bool DepthTextureEnable; - -static void BuildSwapModeTable() -{ - for (int i = 0; i < 4; i++) - { - swapModeTable[i][0] = swapColors[bpmem.tevksel[i*2].swap1]; - swapModeTable[i][1] = swapColors[bpmem.tevksel[i*2].swap2]; - swapModeTable[i][2] = swapColors[bpmem.tevksel[i*2+1].swap1]; - swapModeTable[i][3] = swapColors[bpmem.tevksel[i*2+1].swap2]; - swapModeTable[i][4] = 0; - } -} - -const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType, u32 components) -{ - setlocale(LC_NUMERIC, "C"); // Reset locale for compilation - text[sizeof(text) - 1] = 0x7C; // canary - - BuildSwapModeTable(); // Needed for WriteStage - int numStages = bpmem.genMode.numtevstages + 1; - int numTexgen = bpmem.genMode.numtexgens; - - char *p = text; - WRITE(p, "//Pixel Shader for TEV stages\n"); - WRITE(p, "//%i TEV stages, %i texgens, %i IND stages\n", - numStages, numTexgen, bpmem.genMode.numindstages); - - int nIndirectStagesUsed = 0; - if (bpmem.genMode.numindstages > 0) - { - for (int i = 0; i < numStages; ++i) - { - if (bpmem.tevind[i].IsActive() && bpmem.tevind[i].bt < bpmem.genMode.numindstages) - nIndirectStagesUsed |= 1 << bpmem.tevind[i].bt; - } - } - DepthTextureEnable = (bpmem.ztex2.op != ZTEXTURE_DISABLE && !bpmem.zcontrol.zcomploc && bpmem.zmode.testenable && bpmem.zmode.updateenable) || g_ActiveConfig.bEnablePerPixelDepth ; - // Declare samplers - - if(ApiType != API_D3D11) - { - WRITE(p, "uniform sampler2D "); - } - else - { - WRITE(p, "sampler "); - } - - bool bfirst = true; - for (int i = 0; i < 8; ++i) - { - WRITE(p, "%s samp%d : register(s%d)", bfirst?"":",", i, i); - bfirst = false; - } - WRITE(p, ";\n"); - if(ApiType == API_D3D11) - { - WRITE(p, "Texture2D "); - bfirst = true; - for (int i = 0; i < 8; ++i) - { - WRITE(p, "%s Tex%d : register(t%d)", bfirst?"":",", i, i); - bfirst = false; - } - WRITE(p, ";\n"); - } - - WRITE(p, "\n"); - - WRITE(p, "uniform float4 "I_COLORS"[4] : register(c%d);\n", C_COLORS); - WRITE(p, "uniform float4 "I_KCOLORS"[4] : register(c%d);\n", C_KCOLORS); - WRITE(p, "uniform float4 "I_ALPHA"[1] : register(c%d);\n", C_ALPHA); - WRITE(p, "uniform float4 "I_TEXDIMS"[8] : register(c%d);\n", C_TEXDIMS); - WRITE(p, "uniform float4 "I_ZBIAS"[2] : register(c%d);\n", C_ZBIAS); - WRITE(p, "uniform float4 "I_INDTEXSCALE"[2] : register(c%d);\n", C_INDTEXSCALE); - WRITE(p, "uniform float4 "I_INDTEXMTX"[6] : register(c%d);\n", C_INDTEXMTX); - WRITE(p, "uniform float4 "I_FOG"[3] : register(c%d);\n", C_FOG); - - if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) - { - WRITE(p,"typedef struct { float4 col; float4 cosatt; float4 distatt; float4 pos; float4 dir; } Light;\n"); - WRITE(p,"typedef struct { Light lights[8]; } s_"I_PLIGHTS";\n"); - WRITE(p, "uniform s_"I_PLIGHTS" "I_PLIGHTS" : register(c%d);\n", C_PLIGHTS); - WRITE(p, "typedef struct { float4 C0, C1, C2, C3; } s_"I_PMATERIALS";\n"); - WRITE(p, "uniform s_"I_PMATERIALS" "I_PMATERIALS" : register(c%d);\n", C_PMATERIALS); - } - - WRITE(p, "void main(\n"); - if(ApiType != API_D3D11) - { - WRITE(p, " out float4 ocol0 : COLOR0,%s%s\n in float4 rawpos : %s,\n", - dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND ? "\n out float4 ocol1 : COLOR1," : "", - DepthTextureEnable ? "\n out float depth : DEPTH," : "", - ApiType & API_OPENGL ? "WPOS" : ApiType & API_D3D9_SM20 ? "POSITION" : "VPOS"); - } - else - { - WRITE(p, " out float4 ocol0 : SV_Target0,%s%s\n in float4 rawpos : SV_Position,\n", - dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND ? "\n out float4 ocol1 : SV_Target1," : "", - DepthTextureEnable ? "\n out float depth : SV_Depth," : ""); - } - - WRITE(p, " in float4 colors_0 : COLOR0,\n"); - WRITE(p, " in float4 colors_1 : COLOR1"); - - // compute window position if needed because binding semantic WPOS is not widely supported - if (numTexgen < 7) - { - for (int i = 0; i < numTexgen; ++i) - WRITE(p, ",\n in float3 uv%d : TEXCOORD%d", i, i); - WRITE(p, ",\n in float4 clipPos : TEXCOORD%d", numTexgen); - if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) - WRITE(p, ",\n in float4 Normal : TEXCOORD%d", numTexgen + 1); - } - else - { - // wpos is in w of first 4 texcoords - if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) - { - for (int i = 0; i < 8; ++i) - WRITE(p, ",\n in float4 uv%d : TEXCOORD%d", i, i); - } - else - { - for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i) - WRITE(p, ",\n in float%d uv%d : TEXCOORD%d", i < 4 ? 4 : 3 , i, i); - } - } - WRITE(p, " ) {\n"); - - char* pmainstart = p; - int Pretest = AlphaPreTest(); - if (dstAlphaMode == DSTALPHA_ALPHA_PASS && !DepthTextureEnable && Pretest >= 0) - { - if (!Pretest) - { - // alpha test will always fail, so restart the shader and just make it an empty function - WRITE(p, "ocol0 = 0;\n"); - WRITE(p, "discard;\n"); - if(ApiType != API_D3D11) - WRITE(p, "return;\n"); - } - else - { - WRITE(p, " ocol0 = "I_ALPHA"[0].aaaa;\n"); - } - WRITE(p, "}\n"); - return text; - } - - WRITE(p, " float4 c0 = "I_COLORS"[1], c1 = "I_COLORS"[2], c2 = "I_COLORS"[3], prev = float4(0.0f, 0.0f, 0.0f, 0.0f), textemp = float4(0.0f, 0.0f, 0.0f, 0.0f), rastemp = float4(0.0f, 0.0f, 0.0f, 0.0f), konsttemp = float4(0.0f, 0.0f, 0.0f, 0.0f);\n" - " float3 comp16 = float3(1.0f, 255.0f, 0.0f), comp24 = float3(1.0f, 255.0f, 255.0f*255.0f);\n" - " float4 alphabump=0;\n" - " float3 tevcoord;\n" - " float2 wrappedcoord, tempcoord;\n" - " float4 cc0, cc1, cc2, cprev,crastemp,ckonsttemp;\n\n"); - - if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) - { - if (xfregs.numTexGen.numTexGens < 7) - { - WRITE(p,"float3 _norm0 = normalize(Normal.xyz);\n\n"); - WRITE(p,"float3 pos = float3(clipPos.x,clipPos.y,Normal.w);\n"); - } - else - { - WRITE(p," float3 _norm0 = normalize(float3(uv4.w,uv5.w,uv6.w));\n\n"); - WRITE(p,"float3 pos = float3(uv0.w,uv1.w,uv7.w);\n"); - } - - - WRITE(p, "float4 mat, lacc;\n" - "float3 ldir, h;\n" - "float dist, dist2, attn;\n"); - - p = GenerateLightingShader(p, components, I_PMATERIALS, I_PLIGHTS, "colors_", "colors_"); - } - - if (numTexgen < 7) - WRITE(p, "clipPos = float4(rawpos.x, rawpos.y, clipPos.z, clipPos.w);\n"); - else - WRITE(p, "float4 clipPos = float4(rawpos.x, rawpos.y, uv2.w, uv3.w);\n"); - - // HACK to handle cases where the tex gen is not enabled - if (numTexgen == 0) - { - WRITE(p, "float3 uv0 = float3(0.0f, 0.0f, 0.0f);\n"); - } - else - { - for (int i = 0; i < numTexgen; ++i) - { - // optional perspective divides - if (xfregs.texMtxInfo[i].projection == XF_TEXPROJ_STQ) - { - WRITE(p, "if (uv%d.z)", i); - WRITE(p, " uv%d.xy = uv%d.xy / uv%d.z;\n", i, i, i); - } - - WRITE(p, "uv%d.xy = uv%d.xy * "I_TEXDIMS"[%d].zw;\n", i, i, i); - } - } - - // indirect texture map lookup - for(u32 i = 0; i < bpmem.genMode.numindstages; ++i) - { - if (nIndirectStagesUsed & (1< +#include +#include +#include + +#include "LightingShaderGen.h" +#include "PixelShaderGen.h" +#include "XFMemory.h" // for texture projection mode +#include "BPMemory.h" +#include "VideoConfig.h" +#include "NativeVertexFormat.h" + +PIXELSHADERUID last_pixel_shader_uid; + +static int AlphaPreTest(); + +static void StageHash(int stage, u32* out) +{ + out[0] |= bpmem.combiners[stage].colorC.hex & 0xFFFFFF; // 24 + u32 alphaC = bpmem.combiners[stage].alphaC.hex & 0xFFFFF0; // 24, strip out tswap and rswap for now + out[0] |= (alphaC&0xF0) << 24; // 8 + out[1] |= alphaC >> 8; // 16 + + // reserve 3 bits for bpmem.tevorders[stage/2].getTexMap + out[1] |= bpmem.tevorders[stage/2].getTexCoord(stage&1) << 19; // 3 + out[1] |= bpmem.tevorders[stage/2].getEnable(stage&1) << 22; // 1 + // reserve 3 bits for bpmem.tevorders[stage/2].getColorChan + + bool bHasIndStage = bpmem.tevind[stage].IsActive() && bpmem.tevind[stage].bt < bpmem.genMode.numindstages; + out[2] |= bHasIndStage << 2; // 1 + + bool needstexcoord = false; + + if (bHasIndStage) + { + out[2] |= (bpmem.tevind[stage].hex & 0x17FFFF) << 3; // 21, TODO: needs an explanation + needstexcoord = true; + } + + + TevStageCombiner::ColorCombiner& cc = bpmem.combiners[stage].colorC; + TevStageCombiner::AlphaCombiner& ac = bpmem.combiners[stage].alphaC; + + if(cc.a == TEVCOLORARG_RASA || cc.a == TEVCOLORARG_RASC + || cc.b == TEVCOLORARG_RASA || cc.b == TEVCOLORARG_RASC + || cc.c == TEVCOLORARG_RASA || cc.c == TEVCOLORARG_RASC + || cc.d == TEVCOLORARG_RASA || cc.d == TEVCOLORARG_RASC + || ac.a == TEVALPHAARG_RASA || ac.b == TEVALPHAARG_RASA + || ac.c == TEVALPHAARG_RASA || ac.d == TEVALPHAARG_RASA) + { + out[0] |= bpmem.combiners[stage].alphaC.rswap; + out[2] |= bpmem.tevksel[bpmem.combiners[stage].alphaC.rswap*2].swap1 << 24; // 2 + out[2] |= bpmem.tevksel[bpmem.combiners[stage].alphaC.rswap*2].swap2 << 26; // 2 + out[2] |= bpmem.tevksel[bpmem.combiners[stage].alphaC.rswap*2+1].swap1 << 28; // 2 + out[2] |= bpmem.tevksel[bpmem.combiners[stage].alphaC.rswap*2+1].swap2 << 30; // 2 + out[1] |= (bpmem.tevorders[stage/2].getColorChan(stage&1)&1) << 23; + out[2] |= (bpmem.tevorders[stage/2].getColorChan(stage&1)&0x6) >> 1; + } + + out[3] |= bpmem.tevorders[stage/2].getEnable(stage&1); + if (bpmem.tevorders[stage/2].getEnable(stage&1)) + { + if (bHasIndStage) needstexcoord = true; + + out[0] |= bpmem.combiners[stage].alphaC.tswap; + out[3] |= bpmem.tevksel[bpmem.combiners[stage].alphaC.tswap*2].swap1 << 1; // 2 + out[3] |= bpmem.tevksel[bpmem.combiners[stage].alphaC.tswap*2].swap2 << 3; // 2 + out[3] |= bpmem.tevksel[bpmem.combiners[stage].alphaC.tswap*2+1].swap1 << 5; // 2 + out[3] |= bpmem.tevksel[bpmem.combiners[stage].alphaC.tswap*2+1].swap2 << 7; // 2 + out[1] |= bpmem.tevorders[stage/2].getTexMap(stage&1) << 16; + } + + if (cc.a == TEVCOLORARG_KONST || cc.b == TEVCOLORARG_KONST || cc.c == TEVCOLORARG_KONST || cc.d == TEVCOLORARG_KONST + || ac.a == TEVALPHAARG_KONST || ac.b == TEVALPHAARG_KONST || ac.c == TEVALPHAARG_KONST || ac.d == TEVALPHAARG_KONST) + { + out[3] |= bpmem.tevksel[stage/2].getKC(stage&1) << 9; // 5 + out[3] |= bpmem.tevksel[stage/2].getKA(stage&1) << 14; // 5 + } + + if (needstexcoord) + { + out[1] |= bpmem.tevorders[stage/2].getTexCoord(stage&1) << 16; + } +} + +void GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode) +{ + uid->values[0] |= bpmem.genMode.numtevstages; // 4 + uid->values[0] |= bpmem.genMode.numtexgens << 4; // 4 + uid->values[0] |= dstAlphaMode << 8; // 2 + + uid->tevstages = bpmem.genMode.numtevstages; + + bool DepthTextureEnable = (bpmem.ztex2.op != ZTEXTURE_DISABLE && !bpmem.zcontrol.zcomploc && bpmem.zmode.testenable && bpmem.zmode.updateenable) || g_ActiveConfig.bEnablePerPixelDepth; + + uid->values[0] |= DepthTextureEnable << 10; // 1 + + bool enablePL = g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting; + uid->values[0] |= enablePL << 11; // 1 + + if (!enablePL) uid->values[0] |= xfregs.numTexGen.numTexGens << 12; // 4 + u32 alphaPreTest = AlphaPreTest()+1; + + uid->values[0] |= alphaPreTest << 16; // 2 + + if (alphaPreTest == 1 || (alphaPreTest && !DepthTextureEnable && dstAlphaMode == DSTALPHA_ALPHA_PASS)) + { + // Courtesy of PreAlphaTest, we're done already ;) + // TODO: There's a comment including bpmem.genmode.numindstages.. shouldnt really bother about that though. + return; + } + + if (enablePL) + { + // TODO: Include register states for lighting shader + } + + for (unsigned int i = 0; i < bpmem.genMode.numtexgens; ++i) + { + if (18+i < 32) + uid->values[0] |= xfregs.texMtxInfo[i].projection << (18+i); // 1 + else + uid->values[1] |= xfregs.texMtxInfo[i].projection << (i - 14); // 1 + } + + uid->indstages = bpmem.genMode.numindstages; + + uid->values[1] = bpmem.genMode.numindstages << 2; // 3 + u32 indirectStagesUsed = 0; + for (unsigned int i = 0; i < bpmem.genMode.numindstages; ++i) + if (bpmem.tevind[i].IsActive() && bpmem.tevind[i].bt < bpmem.genMode.numindstages) + indirectStagesUsed |= (1 << bpmem.tevind[i].bt); + + assert(indirectStagesUsed == (indirectStagesUsed & 0xF)); + + uid->values[1] |= indirectStagesUsed << 5; // 4; + + for (unsigned int i = 0; i < bpmem.genMode.numindstages; ++i) + { + if (indirectStagesUsed & (1 << i)) + { + uid->values[1] |= (bpmem.tevindref.getTexCoord(i) < bpmem.genMode.numtexgens) << (9 + 3*i); // 1 + if (bpmem.tevindref.getTexCoord(i) < bpmem.genMode.numtexgens) + uid->values[1] |= bpmem.tevindref.getTexCoord(i) << (10 + 3*i); // 2 + } + } + + u32* ptr = &uid->values[2]; + for (unsigned int i = 0; i < bpmem.genMode.numtevstages+1; ++i) + { + StageHash(i, ptr); + ptr += 4; // max: ptr = &uid->values[66] + } + + if (alphaPreTest == 0 || alphaPreTest == 2) + { + ptr[0] |= bpmem.fog.c_proj_fsel.fsel; // 3 + if (DepthTextureEnable) + { + ptr[0] |= bpmem.ztex2.op << 3; // 2 + ptr[0] |= bpmem.zcontrol.zcomploc << 5; // 1 + ptr[0] |= bpmem.zmode.testenable << 6; // 1 + ptr[0] |= bpmem.zmode.updateenable << 7; // 1 + } + } + + if (dstAlphaMode != DSTALPHA_ALPHA_PASS) + { + if (bpmem.fog.c_proj_fsel.fsel != 0) + { + ptr[0] |= bpmem.fog.c_proj_fsel.proj << 8; // 1 + ptr[0] |= bpmem.fogRange.Base.Enabled << 9; // 1 + } + } + uid->tevstages = (ptr+1) - uid->values; +} + +// Mash together all the inputs that contribute to the code of a generated pixel shader into +// a unique identifier, basically containing all the bits. Yup, it's a lot .... +// It would likely be a lot more efficient to build this incrementally as the attributes +// are set... +void _GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode) +{ + u32 numstages = bpmem.genMode.numtevstages + 1; + u32 projtexcoords = 0; + for (u32 i = 0; i < numstages; i++) + { + if (bpmem.tevorders[i/2].getEnable(i & 1)) + { + int texcoord = bpmem.tevorders[i / 2].getTexCoord(i & 1); + if (xfregs.texMtxInfo[i].projection) + projtexcoords |= 1 << texcoord; + } + } + uid->values[0] = (u32)bpmem.genMode.numtevstages | + ((u32)bpmem.genMode.numindstages << 4) | + ((u32)bpmem.genMode.numtexgens << 7) | + ((u32)dstAlphaMode << 11) | + ((u32)((bpmem.alphaFunc.hex >> 16) & 0xff) << 13) | + (projtexcoords << 21) | + ((u32)bpmem.ztex2.op << 29); + + // swap table + for (int i = 0; i < 8; i += 2) + ((u8*)&uid->values[1])[i / 2] = (bpmem.tevksel[i].hex & 0xf) | ((bpmem.tevksel[i + 1].hex & 0xf) << 4); + + u32 enableZTexture = (bpmem.ztex2.op != ZTEXTURE_DISABLE && !bpmem.zcontrol.zcomploc && bpmem.zmode.testenable && bpmem.zmode.updateenable) || g_ActiveConfig.bEnablePerPixelDepth ? 1 : 0; + + uid->values[2] = (u32)bpmem.fog.c_proj_fsel.fsel | + ((u32)bpmem.fog.c_proj_fsel.proj << 3) | + ((u32)enableZTexture << 4) | ((u32)bpmem.fogRange.Base.Enabled << 5); + + if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) + { + for (int i = 0; i < 2; ++i) { + uid->values[3 + i] = xfregs.color[i].enablelighting ? + (u32)xfregs.color[i].hex : + (u32)xfregs.color[i].matsource; + uid->values[3 + i] |= (xfregs.alpha[i].enablelighting ? + (u32)xfregs.alpha[i].hex : + (u32)xfregs.alpha[i].matsource) << 15; + } + } + uid->values[4] |= (g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) << 31; + + int hdr = 5; + u32 *pcurvalue = &uid->values[hdr]; + for (u32 i = 0; i < numstages; ++i) + { + TevStageCombiner::ColorCombiner &cc = bpmem.combiners[i].colorC; + TevStageCombiner::AlphaCombiner &ac = bpmem.combiners[i].alphaC; + + u32 val0 = cc.hex & 0xffffff; + u32 val1 = ac.hex & 0xffffff; + val0 |= bpmem.tevksel[i / 2].getKC(i & 1) << 24; + val1 |= bpmem.tevksel[i / 2].getKA(i & 1) << 24; + pcurvalue[0] = val0; + pcurvalue[1] = val1; + pcurvalue += 2; + } + + for (u32 i = 0; i < numstages / 2; ++i) + { + u32 val0, val1; + if (bpmem.tevorders[i].hex & 0x40) + val0 = bpmem.tevorders[i].hex & 0x3ff; + else + val0 = bpmem.tevorders[i].hex & 0x380; + if (bpmem.tevorders[i].hex & 0x40000) + val1 = (bpmem.tevorders[i].hex & 0x3ff000) >> 12; + else + val1 = (bpmem.tevorders[i].hex & 0x380000) >> 12; + + switch (i % 3) { + case 0: pcurvalue[0] = val0|(val1<<10); break; + case 1: pcurvalue[0] |= val0<<20; pcurvalue[1] = val1; pcurvalue++; break; + case 2: pcurvalue[1] |= (val0<<10)|(val1<<20); pcurvalue++; break; + default: PanicAlert("Unknown case for Tev Stages / 2: %08x", (i % 3)); + } + } + + if (numstages & 1) { // odd + u32 val0; + if (bpmem.tevorders[bpmem.genMode.numtevstages/2].hex & 0x40) + val0 = bpmem.tevorders[bpmem.genMode.numtevstages/2].hex & 0x3ff; + else + val0 = bpmem.tevorders[bpmem.genMode.numtevstages/2].hex & 0x380; + + switch (bpmem.genMode.numtevstages % 3) + { + case 0: pcurvalue[0] = val0; break; + case 1: pcurvalue[0] |= val0 << 20; break; + case 2: pcurvalue[1] |= val0 << 10; pcurvalue++; break; + default: PanicAlert("Unknown case for Tev Stages: %08x", bpmem.genMode.numtevstages % 3); + } + } + + if ((bpmem.genMode.numtevstages % 3) != 2) + ++pcurvalue; + + uid->tevstages = (u32)(pcurvalue - &uid->values[0] - hdr); + + for (u32 i = 0; i < bpmem.genMode.numindstages; ++i) + { + u32 val = bpmem.tevind[i].hex & 0x1fffff; // 21 bits + switch (i % 3) + { + case 0: pcurvalue[0] = val; break; + case 1: pcurvalue[0] |= val << 21; pcurvalue[1] = val >> 11; ++pcurvalue; break; + case 2: pcurvalue[0] |= val << 10; ++pcurvalue; break; + default: PanicAlert("Unknown case for Ind Stages: %08x", (i % 3)); + } + } + + // yeah, well .... + uid->indstages = (u32)(pcurvalue - &uid->values[0] - (hdr - 1) - uid->tevstages); + +} + +// old tev->pixelshader notes +// +// color for this stage (alpha, color) is given by bpmem.tevorders[0].colorchan0 +// konstant for this stage (alpha, color) is given by bpmem.tevksel +// inputs are given by bpmem.combiners[0].colorC.a/b/c/d << could be current chan color +// according to GXTevColorArg table above +// output is given by .outreg +// tevtemp is set according to swapmodetables and + +static void WriteStage(char *&p, int n, API_TYPE ApiType); +static void SampleTexture(char *&p, const char *destination, const char *texcoords, const char *texswap, int texmap, API_TYPE ApiType); +// static void WriteAlphaCompare(char *&p, int num, int comp); +static bool WriteAlphaTest(char *&p, API_TYPE ApiType,DSTALPHA_MODE dstAlphaMode); +static void WriteFog(char *&p); + +static const char *tevKSelTableC[] = // KCSEL +{ + "1.0f,1.0f,1.0f", // 1 = 0x00 + "0.875f,0.875f,0.875f", // 7_8 = 0x01 + "0.75f,0.75f,0.75f", // 3_4 = 0x02 + "0.625f,0.625f,0.625f", // 5_8 = 0x03 + "0.5f,0.5f,0.5f", // 1_2 = 0x04 + "0.375f,0.375f,0.375f", // 3_8 = 0x05 + "0.25f,0.25f,0.25f", // 1_4 = 0x06 + "0.125f,0.125f,0.125f", // 1_8 = 0x07 + "ERROR", // 0x08 + "ERROR", // 0x09 + "ERROR", // 0x0a + "ERROR", // 0x0b + I_KCOLORS"[0].rgb", // K0 = 0x0C + I_KCOLORS"[1].rgb", // K1 = 0x0D + I_KCOLORS"[2].rgb", // K2 = 0x0E + I_KCOLORS"[3].rgb", // K3 = 0x0F + I_KCOLORS"[0].rrr", // K0_R = 0x10 + I_KCOLORS"[1].rrr", // K1_R = 0x11 + I_KCOLORS"[2].rrr", // K2_R = 0x12 + I_KCOLORS"[3].rrr", // K3_R = 0x13 + I_KCOLORS"[0].ggg", // K0_G = 0x14 + I_KCOLORS"[1].ggg", // K1_G = 0x15 + I_KCOLORS"[2].ggg", // K2_G = 0x16 + I_KCOLORS"[3].ggg", // K3_G = 0x17 + I_KCOLORS"[0].bbb", // K0_B = 0x18 + I_KCOLORS"[1].bbb", // K1_B = 0x19 + I_KCOLORS"[2].bbb", // K2_B = 0x1A + I_KCOLORS"[3].bbb", // K3_B = 0x1B + I_KCOLORS"[0].aaa", // K0_A = 0x1C + I_KCOLORS"[1].aaa", // K1_A = 0x1D + I_KCOLORS"[2].aaa", // K2_A = 0x1E + I_KCOLORS"[3].aaa", // K3_A = 0x1F +}; + +static const char *tevKSelTableA[] = // KASEL +{ + "1.0f", // 1 = 0x00 + "0.875f",// 7_8 = 0x01 + "0.75f", // 3_4 = 0x02 + "0.625f",// 5_8 = 0x03 + "0.5f", // 1_2 = 0x04 + "0.375f",// 3_8 = 0x05 + "0.25f", // 1_4 = 0x06 + "0.125f",// 1_8 = 0x07 + "ERROR", // 0x08 + "ERROR", // 0x09 + "ERROR", // 0x0a + "ERROR", // 0x0b + "ERROR", // 0x0c + "ERROR", // 0x0d + "ERROR", // 0x0e + "ERROR", // 0x0f + I_KCOLORS"[0].r", // K0_R = 0x10 + I_KCOLORS"[1].r", // K1_R = 0x11 + I_KCOLORS"[2].r", // K2_R = 0x12 + I_KCOLORS"[3].r", // K3_R = 0x13 + I_KCOLORS"[0].g", // K0_G = 0x14 + I_KCOLORS"[1].g", // K1_G = 0x15 + I_KCOLORS"[2].g", // K2_G = 0x16 + I_KCOLORS"[3].g", // K3_G = 0x17 + I_KCOLORS"[0].b", // K0_B = 0x18 + I_KCOLORS"[1].b", // K1_B = 0x19 + I_KCOLORS"[2].b", // K2_B = 0x1A + I_KCOLORS"[3].b", // K3_B = 0x1B + I_KCOLORS"[0].a", // K0_A = 0x1C + I_KCOLORS"[1].a", // K1_A = 0x1D + I_KCOLORS"[2].a", // K2_A = 0x1E + I_KCOLORS"[3].a", // K3_A = 0x1F +}; + +static const char *tevScaleTable[] = // CS +{ + "1.0f", // SCALE_1 + "2.0f", // SCALE_2 + "4.0f", // SCALE_4 + "0.5f", // DIVIDE_2 +}; + +static const char *tevBiasTable[] = // TB +{ + "", // ZERO, + "+0.5f", // ADDHALF, + "-0.5f", // SUBHALF, + "", +}; + +static const char *tevOpTable[] = { // TEV + "+", // TEVOP_ADD = 0, + "-", // TEVOP_SUB = 1, +}; + +static const char *tevCInputTable[] = // CC +{ + "(prev.rgb)", // CPREV, + "(prev.aaa)", // APREV, + "(c0.rgb)", // C0, + "(c0.aaa)", // A0, + "(c1.rgb)", // C1, + "(c1.aaa)", // A1, + "(c2.rgb)", // C2, + "(c2.aaa)", // A2, + "(textemp.rgb)", // TEXC, + "(textemp.aaa)", // TEXA, + "(rastemp.rgb)", // RASC, + "(rastemp.aaa)", // RASA, + "float3(1.0f, 1.0f, 1.0f)", // ONE + "float3(0.5f, 0.5f, 0.5f)", // HALF + "(konsttemp.rgb)", //"konsttemp.rgb", // KONST + "float3(0.0f, 0.0f, 0.0f)", // ZERO + ///aded extra values to map clamped values + "(cprev.rgb)", // CPREV, + "(cprev.aaa)", // APREV, + "(cc0.rgb)", // C0, + "(cc0.aaa)", // A0, + "(cc1.rgb)", // C1, + "(cc1.aaa)", // A1, + "(cc2.rgb)", // C2, + "(cc2.aaa)", // A2, + "(textemp.rgb)", // TEXC, + "(textemp.aaa)", // TEXA, + "(crastemp.rgb)", // RASC, + "(crastemp.aaa)", // RASA, + "float3(1.0f, 1.0f, 1.0f)", // ONE + "float3(0.5f, 0.5f, 0.5f)", // HALF + "(ckonsttemp.rgb)", //"konsttemp.rgb", // KONST + "float3(0.0f, 0.0f, 0.0f)", // ZERO + "PADERROR", "PADERROR", "PADERROR", "PADERROR" +}; + +static const char *tevAInputTable[] = // CA +{ + "prev", // APREV, + "c0", // A0, + "c1", // A1, + "c2", // A2, + "textemp", // TEXA, + "rastemp", // RASA, + "konsttemp", // KONST, (hw1 had quarter) + "float4(0.0f, 0.0f, 0.0f, 0.0f)", // ZERO + ///aded extra values to map clamped values + "cprev", // APREV, + "cc0", // A0, + "cc1", // A1, + "cc2", // A2, + "textemp", // TEXA, + "crastemp", // RASA, + "ckonsttemp", // KONST, (hw1 had quarter) + "float4(0.0f, 0.0f, 0.0f, 0.0f)", // ZERO + "PADERROR", "PADERROR", "PADERROR", "PADERROR", + "PADERROR", "PADERROR", "PADERROR", "PADERROR", +}; + +static const char *tevRasTable[] = +{ + "colors_0", + "colors_1", + "ERROR", //2 + "ERROR", //3 + "ERROR", //4 + "alphabump", // use bump alpha + "(alphabump*(255.0f/248.0f))", //normalized + "float4(0.0f, 0.0f, 0.0f, 0.0f)", // zero +}; + +//static const char *tevTexFunc[] = { "tex2D", "texRECT" }; + +static const char *tevCOutputTable[] = { "prev.rgb", "c0.rgb", "c1.rgb", "c2.rgb" }; +static const char *tevAOutputTable[] = { "prev.a", "c0.a", "c1.a", "c2.a" }; +static const char *tevIndAlphaSel[] = {"", "x", "y", "z"}; +//static const char *tevIndAlphaScale[] = {"", "*32", "*16", "*8"}; +static const char *tevIndAlphaScale[] = {"*(248.0f/255.0f)", "*(224.0f/255.0f)", "*(240.0f/255.0f)", "*(248.0f/255.0f)"}; +static const char *tevIndBiasField[] = {"", "x", "y", "xy", "z", "xz", "yz", "xyz"}; // indexed by bias +static const char *tevIndBiasAdd[] = {"-128.0f", "1.0f", "1.0f", "1.0f" }; // indexed by fmt +static const char *tevIndWrapStart[] = {"0.0f", "256.0f", "128.0f", "64.0f", "32.0f", "16.0f", "0.001f" }; +static const char *tevIndFmtScale[] = {"255.0f", "31.0f", "15.0f", "7.0f" }; + +#define WRITE p+=sprintf + +static char swapModeTable[4][5]; + +static char text[16384]; +static bool DepthTextureEnable; + +static void BuildSwapModeTable() +{ + static const char *swapColors = "rgba"; + for (int i = 0; i < 4; i++) + { + swapModeTable[i][0] = swapColors[bpmem.tevksel[i*2].swap1]; + swapModeTable[i][1] = swapColors[bpmem.tevksel[i*2].swap2]; + swapModeTable[i][2] = swapColors[bpmem.tevksel[i*2+1].swap1]; + swapModeTable[i][3] = swapColors[bpmem.tevksel[i*2+1].swap2]; + swapModeTable[i][4] = 0; + } +} + +const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType, u32 components) +{ + setlocale(LC_NUMERIC, "C"); // Reset locale for compilation + text[sizeof(text) - 1] = 0x7C; // canary + + BuildSwapModeTable(); // Needed for WriteStage + int numStages = bpmem.genMode.numtevstages + 1; + int numTexgen = bpmem.genMode.numtexgens; + + char *p = text; + WRITE(p, "//Pixel Shader for TEV stages\n"); + WRITE(p, "//%i TEV stages, %i texgens, %i IND stages\n", + numStages, numTexgen, bpmem.genMode.numindstages); + + int nIndirectStagesUsed = 0; + if (bpmem.genMode.numindstages > 0) + { + for (int i = 0; i < numStages; ++i) + { + if (bpmem.tevind[i].IsActive() && bpmem.tevind[i].bt < bpmem.genMode.numindstages) + nIndirectStagesUsed |= 1 << bpmem.tevind[i].bt; + } + } + DepthTextureEnable = (bpmem.ztex2.op != ZTEXTURE_DISABLE && !bpmem.zcontrol.zcomploc && bpmem.zmode.testenable && bpmem.zmode.updateenable) || g_ActiveConfig.bEnablePerPixelDepth ; + // Declare samplers + + if(ApiType != API_D3D11) + { + WRITE(p, "uniform sampler2D "); + } + else + { + WRITE(p, "sampler "); + } + + bool bfirst = true; + for (int i = 0; i < 8; ++i) + { + WRITE(p, "%s samp%d : register(s%d)", bfirst?"":",", i, i); + bfirst = false; + } + WRITE(p, ";\n"); + if(ApiType == API_D3D11) + { + WRITE(p, "Texture2D "); + bfirst = true; + for (int i = 0; i < 8; ++i) + { + WRITE(p, "%s Tex%d : register(t%d)", bfirst?"":",", i, i); + bfirst = false; + } + WRITE(p, ";\n"); + } + + WRITE(p, "\n"); + + WRITE(p, "uniform float4 "I_COLORS"[4] : register(c%d);\n", C_COLORS); + WRITE(p, "uniform float4 "I_KCOLORS"[4] : register(c%d);\n", C_KCOLORS); + WRITE(p, "uniform float4 "I_ALPHA"[1] : register(c%d);\n", C_ALPHA); + WRITE(p, "uniform float4 "I_TEXDIMS"[8] : register(c%d);\n", C_TEXDIMS); + WRITE(p, "uniform float4 "I_ZBIAS"[2] : register(c%d);\n", C_ZBIAS); + WRITE(p, "uniform float4 "I_INDTEXSCALE"[2] : register(c%d);\n", C_INDTEXSCALE); + WRITE(p, "uniform float4 "I_INDTEXMTX"[6] : register(c%d);\n", C_INDTEXMTX); + WRITE(p, "uniform float4 "I_FOG"[3] : register(c%d);\n", C_FOG); + + if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) + { + WRITE(p,"typedef struct { float4 col; float4 cosatt; float4 distatt; float4 pos; float4 dir; } Light;\n"); + WRITE(p,"typedef struct { Light lights[8]; } s_"I_PLIGHTS";\n"); + WRITE(p, "uniform s_"I_PLIGHTS" "I_PLIGHTS" : register(c%d);\n", C_PLIGHTS); + WRITE(p, "typedef struct { float4 C0, C1, C2, C3; } s_"I_PMATERIALS";\n"); + WRITE(p, "uniform s_"I_PMATERIALS" "I_PMATERIALS" : register(c%d);\n", C_PMATERIALS); + } + + WRITE(p, "void main(\n"); + if(ApiType != API_D3D11) + { + WRITE(p, " out float4 ocol0 : COLOR0,%s%s\n in float4 rawpos : %s,\n", + dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND ? "\n out float4 ocol1 : COLOR1," : "", + DepthTextureEnable ? "\n out float depth : DEPTH," : "", + ApiType & API_OPENGL ? "WPOS" : ApiType & API_D3D9_SM20 ? "POSITION" : "VPOS"); + } + else + { + WRITE(p, " out float4 ocol0 : SV_Target0,%s%s\n in float4 rawpos : SV_Position,\n", + dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND ? "\n out float4 ocol1 : SV_Target1," : "", + DepthTextureEnable ? "\n out float depth : SV_Depth," : ""); + } + + WRITE(p, " in float4 colors_0 : COLOR0,\n"); + WRITE(p, " in float4 colors_1 : COLOR1"); + + // compute window position if needed because binding semantic WPOS is not widely supported + if (numTexgen < 7) + { + for (int i = 0; i < numTexgen; ++i) + WRITE(p, ",\n in float3 uv%d : TEXCOORD%d", i, i); + WRITE(p, ",\n in float4 clipPos : TEXCOORD%d", numTexgen); + if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) + WRITE(p, ",\n in float4 Normal : TEXCOORD%d", numTexgen + 1); + } + else + { + // wpos is in w of first 4 texcoords + if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) + { + for (int i = 0; i < 8; ++i) + WRITE(p, ",\n in float4 uv%d : TEXCOORD%d", i, i); + } + else + { + for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i) + WRITE(p, ",\n in float%d uv%d : TEXCOORD%d", i < 4 ? 4 : 3 , i, i); + } + } + WRITE(p, " ) {\n"); + + char* pmainstart = p; + int Pretest = AlphaPreTest(); + if (dstAlphaMode == DSTALPHA_ALPHA_PASS && !DepthTextureEnable && Pretest >= 0) + { + if (!Pretest) + { + // alpha test will always fail, so restart the shader and just make it an empty function + WRITE(p, "ocol0 = 0;\n"); + WRITE(p, "discard;\n"); + if(ApiType != API_D3D11) + WRITE(p, "return;\n"); + } + else + { + WRITE(p, " ocol0 = "I_ALPHA"[0].aaaa;\n"); + } + WRITE(p, "}\n"); + return text; + } + + WRITE(p, " float4 c0 = "I_COLORS"[1], c1 = "I_COLORS"[2], c2 = "I_COLORS"[3], prev = float4(0.0f, 0.0f, 0.0f, 0.0f), textemp = float4(0.0f, 0.0f, 0.0f, 0.0f), rastemp = float4(0.0f, 0.0f, 0.0f, 0.0f), konsttemp = float4(0.0f, 0.0f, 0.0f, 0.0f);\n" + " float3 comp16 = float3(1.0f, 255.0f, 0.0f), comp24 = float3(1.0f, 255.0f, 255.0f*255.0f);\n" + " float4 alphabump=0;\n" + " float3 tevcoord;\n" + " float2 wrappedcoord, tempcoord;\n" + " float4 cc0, cc1, cc2, cprev,crastemp,ckonsttemp;\n\n"); + + if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) + { + if (xfregs.numTexGen.numTexGens < 7) + { + WRITE(p,"float3 _norm0 = normalize(Normal.xyz);\n\n"); + WRITE(p,"float3 pos = float3(clipPos.x,clipPos.y,Normal.w);\n"); + } + else + { + WRITE(p," float3 _norm0 = normalize(float3(uv4.w,uv5.w,uv6.w));\n\n"); + WRITE(p,"float3 pos = float3(uv0.w,uv1.w,uv7.w);\n"); + } + + + WRITE(p, "float4 mat, lacc;\n" + "float3 ldir, h;\n" + "float dist, dist2, attn;\n"); + + p = GenerateLightingShader(p, components, I_PMATERIALS, I_PLIGHTS, "colors_", "colors_"); + } + + if (numTexgen < 7) + WRITE(p, "clipPos = float4(rawpos.x, rawpos.y, clipPos.z, clipPos.w);\n"); + else + WRITE(p, "float4 clipPos = float4(rawpos.x, rawpos.y, uv2.w, uv3.w);\n"); + + // HACK to handle cases where the tex gen is not enabled + if (numTexgen == 0) + { + WRITE(p, "float3 uv0 = float3(0.0f, 0.0f, 0.0f);\n"); + } + else + { + for (int i = 0; i < numTexgen; ++i) + { + // optional perspective divides + if (xfregs.texMtxInfo[i].projection == XF_TEXPROJ_STQ) + { + WRITE(p, "if (uv%d.z)", i); + WRITE(p, " uv%d.xy = uv%d.xy / uv%d.z;\n", i, i, i); + } + + WRITE(p, "uv%d.xy = uv%d.xy * "I_TEXDIMS"[%d].zw;\n", i, i, i); + } + } + + // indirect texture map lookup + for(u32 i = 0; i < bpmem.genMode.numindstages; ++i) + { + if (nIndirectStagesUsed & (1<= %s.r + (0.25f/255.0f)) ? %s : float3(0.0f, 0.0f, 0.0f))",//#define TEVCMP_R8_GT 8 - " %s + ((abs(%s.r - %s.r) < (0.5f/255.0f)) ? %s : float3(0.0f, 0.0f, 0.0f))",//#define TEVCMP_R8_EQ 9 - " %s + (( dot(%s.rgb, comp16) >= (dot(%s.rgb, comp16) + (0.25f/255.0f))) ? %s : float3(0.0f, 0.0f, 0.0f))",//#define TEVCMP_GR16_GT 10 - " %s + (abs(dot(%s.rgb, comp16) - dot(%s.rgb, comp16)) < (0.5f/255.0f) ? %s : float3(0.0f, 0.0f, 0.0f))",//#define TEVCMP_GR16_EQ 11 - " %s + (( dot(%s.rgb, comp24) >= (dot(%s.rgb, comp24) + (0.25f/255.0f))) ? %s : float3(0.0f, 0.0f, 0.0f))",//#define TEVCMP_BGR24_GT 12 - " %s + (abs(dot(%s.rgb, comp24) - dot(%s.rgb, comp24)) < (0.5f/255.0f) ? %s : float3(0.0f, 0.0f, 0.0f))",//#define TEVCMP_BGR24_EQ 13 - " %s + (max(sign(%s.rgb - %s.rgb - (0.25f/255.0f)), float3(0.0f, 0.0f, 0.0f)) * %s)",//#define TEVCMP_RGB8_GT 14 - " %s + ((float3(1.0f, 1.0f, 1.0f) - max(sign(abs(%s.rgb - %s.rgb) - (0.5f/255.0f)), float3(0.0f, 0.0f, 0.0f))) * %s)"//#define TEVCMP_RGB8_EQ 15 -}; - -//table with the alpha compare operations -static const char *TEVCMPAlphaOPTable[16] = -{ - "0.0f",//0 - "0.0f",//1 - "0.0f",//2 - "0.0f",//3 - "0.0f",//4 - "0.0f",//5 - "0.0f",//6 - "0.0f",//7 - " %s.a + ((%s.r >= (%s.r + (0.25f/255.0f))) ? %s.a : 0.0f)",//#define TEVCMP_R8_GT 8 - " %s.a + (abs(%s.r - %s.r) < (0.5f/255.0f) ? %s.a : 0.0f)",//#define TEVCMP_R8_EQ 9 - " %s.a + ((dot(%s.rgb, comp16) >= (dot(%s.rgb, comp16) + (0.25f/255.0f))) ? %s.a : 0.0f)",//#define TEVCMP_GR16_GT 10 - " %s.a + (abs(dot(%s.rgb, comp16) - dot(%s.rgb, comp16)) < (0.5f/255.0f) ? %s.a : 0.0f)",//#define TEVCMP_GR16_EQ 11 - " %s.a + ((dot(%s.rgb, comp24) >= (dot(%s.rgb, comp24) + (0.25f/255.0f))) ? %s.a : 0.0f)",//#define TEVCMP_BGR24_GT 12 - " %s.a + (abs(dot(%s.rgb, comp24) - dot(%s.rgb, comp24)) < (0.5f/255.0f) ? %s.a : 0.0f)",//#define TEVCMP_BGR24_EQ 13 - " %s.a + ((%s.a >= (%s.a + (0.25f/255.0f))) ? %s.a : 0.0f)",//#define TEVCMP_A8_GT 14 - " %s.a + (abs(%s.a - %s.a) < (0.5f/255.0f) ? %s.a : 0.0f)"//#define TEVCMP_A8_EQ 15 - -}; - - -static void WriteStage(char *&p, int n, API_TYPE ApiType) -{ - int texcoord = bpmem.tevorders[n/2].getTexCoord(n&1); - bool bHasTexCoord = (u32)texcoord < bpmem.genMode.numtexgens; - bool bHasIndStage = bpmem.tevind[n].IsActive() && bpmem.tevind[n].bt < bpmem.genMode.numindstages; - - // HACK to handle cases where the tex gen is not enabled - if (!bHasTexCoord) - texcoord = 0; - - if (bHasIndStage) - { - // perform the indirect op on the incoming regular coordinates using indtex%d as the offset coords - if (bpmem.tevind[n].bs != ITBA_OFF) - { - WRITE(p, "alphabump = indtex%d.%s %s;\n", - bpmem.tevind[n].bt, - tevIndAlphaSel[bpmem.tevind[n].bs], - tevIndAlphaScale[bpmem.tevind[n].fmt]); - } - // format - WRITE(p, "float3 indtevcrd%d = indtex%d * %s;\n", n, bpmem.tevind[n].bt, tevIndFmtScale[bpmem.tevind[n].fmt]); - - // bias - if (bpmem.tevind[n].bias != ITB_NONE ) - WRITE(p, "indtevcrd%d.%s += %s;\n", n, tevIndBiasField[bpmem.tevind[n].bias], tevIndBiasAdd[bpmem.tevind[n].fmt]); - - // multiply by offset matrix and scale - if (bpmem.tevind[n].mid != 0) - { - if (bpmem.tevind[n].mid <= 3) - { - int mtxidx = 2*(bpmem.tevind[n].mid-1); - WRITE(p, "float2 indtevtrans%d = float2(dot("I_INDTEXMTX"[%d].xyz, indtevcrd%d), dot("I_INDTEXMTX"[%d].xyz, indtevcrd%d));\n", - n, mtxidx, n, mtxidx+1, n); - } - else if (bpmem.tevind[n].mid <= 7 && bHasTexCoord) - { // s matrix - // TODO: Might become negative? - int mtxidx = 2*(bpmem.tevind[n].mid-5); - WRITE(p, "float2 indtevtrans%d = "I_INDTEXMTX"[%d].ww * uv%d.xy * indtevcrd%d.xx;\n", n, mtxidx, texcoord, n); - } - else if (bpmem.tevind[n].mid <= 11 && bHasTexCoord) - { // t matrix - // TODO: Might become negative? - int mtxidx = 2*(bpmem.tevind[n].mid-9); - WRITE(p, "float2 indtevtrans%d = "I_INDTEXMTX"[%d].ww * uv%d.xy * indtevcrd%d.yy;\n", n, mtxidx, texcoord, n); - } - else - WRITE(p, "float2 indtevtrans%d = 0;\n", n); - } - else - WRITE(p, "float2 indtevtrans%d = 0;\n", n); - - // --------- - // Wrapping - // --------- - - // wrap S - if (bpmem.tevind[n].sw == ITW_OFF) - WRITE(p, "wrappedcoord.x = uv%d.x;\n", texcoord); - else if (bpmem.tevind[n].sw == ITW_0) - WRITE(p, "wrappedcoord.x = 0.0f;\n"); - else - WRITE(p, "wrappedcoord.x = fmod( uv%d.x, %s );\n", texcoord, tevIndWrapStart[bpmem.tevind[n].sw]); - - // wrap T - if (bpmem.tevind[n].tw == ITW_OFF) - WRITE(p, "wrappedcoord.y = uv%d.y;\n", texcoord); - else if (bpmem.tevind[n].tw == ITW_0) - WRITE(p, "wrappedcoord.y = 0.0f;\n"); - else - WRITE(p, "wrappedcoord.y = fmod( uv%d.y, %s );\n", texcoord, tevIndWrapStart[bpmem.tevind[n].tw]); - - if (bpmem.tevind[n].fb_addprev) // add previous tevcoord - WRITE(p, "tevcoord.xy += wrappedcoord + indtevtrans%d;\n", n); - else - WRITE(p, "tevcoord.xy = wrappedcoord + indtevtrans%d;\n", n); - } - - TevStageCombiner::ColorCombiner &cc = bpmem.combiners[n].colorC; - TevStageCombiner::AlphaCombiner &ac = bpmem.combiners[n].alphaC; - - if(cc.a == TEVCOLORARG_RASA || cc.a == TEVCOLORARG_RASC - || cc.b == TEVCOLORARG_RASA || cc.b == TEVCOLORARG_RASC - || cc.c == TEVCOLORARG_RASA || cc.c == TEVCOLORARG_RASC - || cc.d == TEVCOLORARG_RASA || cc.d == TEVCOLORARG_RASC - || ac.a == TEVALPHAARG_RASA || ac.b == TEVALPHAARG_RASA - || ac.c == TEVALPHAARG_RASA || ac.d == TEVALPHAARG_RASA) - { - char *rasswap = swapModeTable[bpmem.combiners[n].alphaC.rswap]; - WRITE(p, "rastemp = %s.%s;\n", tevRasTable[bpmem.tevorders[n / 2].getColorChan(n & 1)], rasswap); - WRITE(p, "crastemp = frac(rastemp * (255.0f/256.0f)) * (256.0f/255.0f);\n"); - } - - - if (bpmem.tevorders[n/2].getEnable(n&1)) - { - if(!bHasIndStage) - { - // calc tevcord - if(bHasTexCoord) - WRITE(p, "tevcoord.xy = uv%d.xy;\n", texcoord); - else - WRITE(p, "tevcoord.xy = float2(0.0f, 0.0f);\n"); - } - - char *texswap = swapModeTable[bpmem.combiners[n].alphaC.tswap]; - int texmap = bpmem.tevorders[n/2].getTexMap(n&1); - SampleTexture(p, "textemp", "tevcoord", texswap, texmap, ApiType); - } - else - WRITE(p, "textemp = float4(1.0f, 1.0f, 1.0f, 1.0f);\n"); - - - if (cc.a == TEVCOLORARG_KONST || cc.b == TEVCOLORARG_KONST || cc.c == TEVCOLORARG_KONST || cc.d == TEVCOLORARG_KONST - || ac.a == TEVALPHAARG_KONST || ac.b == TEVALPHAARG_KONST || ac.c == TEVALPHAARG_KONST || ac.d == TEVALPHAARG_KONST) - { - int kc = bpmem.tevksel[n / 2].getKC(n & 1); - int ka = bpmem.tevksel[n / 2].getKA(n & 1); - WRITE(p, "konsttemp = float4(%s, %s);\n", tevKSelTableC[kc], tevKSelTableA[ka]); - if(kc > 7 || ka > 7) - { - WRITE(p, "ckonsttemp = frac(konsttemp * (255.0f/256.0f)) * (256.0f/255.0f);\n"); - } - else - { - WRITE(p, "ckonsttemp = konsttemp;\n"); - } - } - - if(cc.a == TEVCOLORARG_CPREV || cc.a == TEVCOLORARG_APREV - || cc.b == TEVCOLORARG_CPREV || cc.b == TEVCOLORARG_APREV - || cc.c == TEVCOLORARG_CPREV || cc.c == TEVCOLORARG_APREV - || ac.a == TEVALPHAARG_APREV || ac.b == TEVALPHAARG_APREV || ac.c == TEVALPHAARG_APREV) - WRITE(p, "cprev = frac(prev * (255.0f/256.0f)) * (256.0f/255.0f);\n"); - - - if(cc.a == TEVCOLORARG_C0 || cc.a == TEVCOLORARG_A0 - || cc.b == TEVCOLORARG_C0 || cc.b == TEVCOLORARG_A0 - || cc.c == TEVCOLORARG_C0 || cc.c == TEVCOLORARG_A0 - || ac.a == TEVALPHAARG_A0 || ac.b == TEVALPHAARG_A0 || ac.c == TEVALPHAARG_A0) - WRITE(p, "cc0 = frac(c0 * (255.0f/256.0f)) * (256.0f/255.0f);\n"); - - - if(cc.a == TEVCOLORARG_C1 || cc.a == TEVCOLORARG_A1 - || cc.b == TEVCOLORARG_C1 || cc.b == TEVCOLORARG_A1 - || cc.c == TEVCOLORARG_C1 || cc.c == TEVCOLORARG_A1 - || ac.a == TEVALPHAARG_A1 || ac.b == TEVALPHAARG_A1 || ac.c == TEVALPHAARG_A1) - WRITE(p, "cc1 = frac(c1 * (255.0f/256.0f)) * (256.0f/255.0f);\n"); - - - if(cc.a == TEVCOLORARG_C2 || cc.a == TEVCOLORARG_A2 - || cc.b == TEVCOLORARG_C2 || cc.b == TEVCOLORARG_A2 - || cc.c == TEVCOLORARG_C2 || cc.c == TEVCOLORARG_A2 - || ac.a == TEVALPHAARG_A2 || ac.b == TEVALPHAARG_A2 || ac.c == TEVALPHAARG_A2) - WRITE(p, "cc2 = frac(c2 * (255.0f/256.0f)) * (256.0f/255.0f);\n"); - - - if (cc.clamp) - WRITE(p, "%s = saturate(", tevCOutputTable[cc.dest]); - else - WRITE(p, "%s = ", tevCOutputTable[cc.dest]); - - // combine the color channel - if (cc.bias != TevBias_COMPARE) // if not compare - { - //normal color combiner goes here - if (cc.shift > TEVSCALE_1) - WRITE(p, "%s*(", tevScaleTable[cc.shift]); - - if(!(cc.d == TEVCOLORARG_ZERO && cc.op == TEVOP_ADD)) - WRITE(p, "%s%s", tevCInputTable[cc.d], tevOpTable[cc.op]); - - if (cc.a == cc.b) - WRITE(p, "%s", tevCInputTable[cc.a + 16]); - else if (cc.c == TEVCOLORARG_ZERO) - WRITE(p, "%s", tevCInputTable[cc.a + 16]); - else if (cc.c == TEVCOLORARG_ONE) - WRITE(p, "%s", tevCInputTable[cc.b + 16]); - else if (cc.a == TEVCOLORARG_ZERO) - WRITE(p, "%s*%s", tevCInputTable[cc.b + 16], tevCInputTable[cc.c + 16]); - else if (cc.b == TEVCOLORARG_ZERO) - WRITE(p, "%s*(float3(1.0f, 1.0f, 1.0f)-%s)", tevCInputTable[cc.a + 16], tevCInputTable[cc.c + 16]); - else - WRITE(p, "lerp(%s, %s, %s)", tevCInputTable[cc.a + 16], tevCInputTable[cc.b + 16], tevCInputTable[cc.c + 16]); - - WRITE(p, "%s", tevBiasTable[cc.bias]); - - if (cc.shift > TEVSCALE_1) - WRITE(p, ")"); - } - else - { - int cmp = (cc.shift<<1)|cc.op|8; // comparemode stored here - WRITE(p, TEVCMPColorOPTable[cmp],//lookup the function from the op table - tevCInputTable[cc.d], - tevCInputTable[cc.a + 16], - tevCInputTable[cc.b + 16], - tevCInputTable[cc.c + 16]); - } - if (cc.clamp) - WRITE(p, ")"); - WRITE(p,";\n"); - - // combine the alpha channel - if (ac.clamp) - WRITE(p, "%s = saturate(", tevAOutputTable[ac.dest]); - else - WRITE(p, "%s = ", tevAOutputTable[ac.dest]); - - if (ac.bias != TevBias_COMPARE) // if not compare - { - //normal alpha combiner goes here - if (ac.shift > TEVSCALE_1) - WRITE(p, "%s*(", tevScaleTable[ac.shift]); - - if(!(ac.d == TEVALPHAARG_ZERO && ac.op == TEVOP_ADD)) - WRITE(p, "%s.a%s", tevAInputTable[ac.d], tevOpTable[ac.op]); - - if (ac.a == ac.b) - WRITE(p, "%s.a", tevAInputTable[ac.a + 8]); - else if (ac.c == TEVALPHAARG_ZERO) - WRITE(p, "%s.a", tevAInputTable[ac.a + 8]); - else if (ac.a == TEVALPHAARG_ZERO) - WRITE(p, "%s.a*%s.a", tevAInputTable[ac.b + 8], tevAInputTable[ac.c + 8]); - else if (ac.b == TEVALPHAARG_ZERO) - WRITE(p, "%s.a*(1.0f-%s.a)", tevAInputTable[ac.a + 8], tevAInputTable[ac.c + 8]); - else - WRITE(p, "lerp(%s.a, %s.a, %s.a)", tevAInputTable[ac.a + 8], tevAInputTable[ac.b + 8], tevAInputTable[ac.c + 8]); - - WRITE(p, "%s",tevBiasTable[ac.bias]); - - if (ac.shift>0) - WRITE(p, ")"); - - } - else - { - //compare alpha combiner goes here - int cmp = (ac.shift<<1)|ac.op|8; // comparemode stored here - WRITE(p, TEVCMPAlphaOPTable[cmp], - tevAInputTable[ac.d], - tevAInputTable[ac.a + 8], - tevAInputTable[ac.b + 8], - tevAInputTable[ac.c + 8]); - } - if (ac.clamp) - WRITE(p, ")"); - WRITE(p, ";\n\n"); -} - -void SampleTexture(char *&p, const char *destination, const char *texcoords, const char *texswap, int texmap, API_TYPE ApiType) -{ - if (ApiType == API_D3D11) - WRITE(p, "%s=Tex%d.Sample(samp%d,%s.xy * "I_TEXDIMS"[%d].xy).%s;\n", destination, texmap,texmap, texcoords, texmap, texswap); - else - WRITE(p, "%s=tex2D(samp%d,%s.xy * "I_TEXDIMS"[%d].xy).%s;\n", destination, texmap, texcoords, texmap, texswap); -} - -static const char *tevAlphaFuncsTable[] = -{ - "(false)", //ALPHACMP_NEVER 0 - "(prev.a <= %s - (0.25f/255.0f))", //ALPHACMP_LESS 1 - "(abs( prev.a - %s ) < (0.5f/255.0f))", //ALPHACMP_EQUAL 2 - "(prev.a < %s + (0.25f/255.0f))", //ALPHACMP_LEQUAL 3 - "(prev.a >= %s + (0.25f/255.0f))", //ALPHACMP_GREATER 4 - "(abs( prev.a - %s ) >= (0.5f/255.0f))", //ALPHACMP_NEQUAL 5 - "(prev.a > %s - (0.25f/255.0f))", //ALPHACMP_GEQUAL 6 - "(true)" //ALPHACMP_ALWAYS 7 -}; - -static const char *tevAlphaFunclogicTable[] = -{ - " && ", // and - " || ", // or - " != ", // xor - " == " // xnor -}; -static int AlphaPreTest() -{ - u32 op = bpmem.alphaFunc.logic; - u32 comp[2] = {bpmem.alphaFunc.comp0, bpmem.alphaFunc.comp1}; - - // First kill all the simple cases - switch(op) - { - case 0: // AND - if (comp[0] == ALPHACMP_ALWAYS && comp[1] == ALPHACMP_ALWAYS) return true; - if (comp[0] == ALPHACMP_NEVER || comp[1] == ALPHACMP_NEVER) return false; - break; - case 1: // OR - if (comp[0] == ALPHACMP_ALWAYS || comp[1] == ALPHACMP_ALWAYS) return true; - if (comp[0] == ALPHACMP_NEVER && comp[1] == ALPHACMP_NEVER)return false; - break; - case 2: // XOR - if ((comp[0] == ALPHACMP_ALWAYS && comp[1] == ALPHACMP_NEVER) || (comp[0] == ALPHACMP_NEVER && comp[1] == ALPHACMP_ALWAYS)) - return true; - if ((comp[0] == ALPHACMP_ALWAYS && comp[1] == ALPHACMP_ALWAYS) || (comp[0] == ALPHACMP_NEVER && comp[1] == ALPHACMP_NEVER)) - return false; - break; - case 3: // XNOR - if ((comp[0] == ALPHACMP_ALWAYS && comp[1] == ALPHACMP_NEVER) || (comp[0] == ALPHACMP_NEVER && comp[1] == ALPHACMP_ALWAYS)) - return false; - if ((comp[0] == ALPHACMP_ALWAYS && comp[1] == ALPHACMP_ALWAYS) || (comp[0] == ALPHACMP_NEVER && comp[1] == ALPHACMP_NEVER)) - return true; - break; - default: PanicAlert("bad logic for alpha test? %08x", op); - } - return -1; -} - - -static bool WriteAlphaTest(char *&p, API_TYPE ApiType,DSTALPHA_MODE dstAlphaMode) -{ - static const char *alphaRef[2] = - { - I_ALPHA"[0].r", - I_ALPHA"[0].g" - }; - - int Pretest = AlphaPreTest(); - if(Pretest >= 0) - { - return Pretest != 0; - } - - // using discard then return works the same in cg and dx9 but not in dx11 - WRITE(p, "if(!( "); - - int compindex = bpmem.alphaFunc.comp0 % 8; - WRITE(p, tevAlphaFuncsTable[compindex],alphaRef[0]);//lookup the first component from the alpha function table - - WRITE(p, "%s", tevAlphaFunclogicTable[bpmem.alphaFunc.logic % 4]);//lookup the logic op - - compindex = bpmem.alphaFunc.comp1 % 8; - WRITE(p, tevAlphaFuncsTable[compindex],alphaRef[1]);//lookup the second component from the alpha function table - WRITE(p, ")){ocol0 = 0;%s%s discard;%s}\n", - dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND ? "ocol1 = 0;" : "", - DepthTextureEnable ? "depth = 1.f;" : "", - (ApiType != API_D3D11) ? "return;" : ""); - return true; -} - -static const char *tevFogFuncsTable[] = -{ - "", //No Fog - "", //? - "", //Linear - "", //? - " fog = 1.0f - pow(2.0f, -8.0f * fog);\n", //exp - " fog = 1.0f - pow(2.0f, -8.0f * fog * fog);\n", //exp2 - " fog = pow(2.0f, -8.0f * (1.0f - fog));\n", //backward exp - " fog = 1.0f - fog;\n fog = pow(2.0f, -8.0f * fog * fog);\n" //backward exp2 -}; - -static void WriteFog(char *&p) -{ - if(bpmem.fog.c_proj_fsel.fsel == 0)return;//no Fog - - if (bpmem.fog.c_proj_fsel.proj == 0) - { - // perspective - // ze = A/(B - (Zs >> B_SHF) - WRITE (p, " float ze = "I_FOG"[1].x / ("I_FOG"[1].y - (zCoord / "I_FOG"[1].w));\n"); - } - else - { - // orthographic - // ze = a*Zs (here, no B_SHF) - WRITE (p, " float ze = "I_FOG"[1].x * zCoord;\n"); - } - - // x_adjust = sqrt((x-center)^2 + k^2)/k - // ze *= x_adjust - //this is complitly teorical as the real hard seems to use a table intead of calculate the values. - if(bpmem.fogRange.Base.Enabled) - { - WRITE (p, " float x_adjust = (2.0f * (clipPos.x / "I_FOG"[2].y)) - 1.0f - "I_FOG"[2].x;\n"); - WRITE (p, " x_adjust = sqrt(x_adjust * x_adjust + "I_FOG"[2].z * "I_FOG"[2].z) / "I_FOG"[2].z;\n"); - WRITE (p, " ze *= x_adjust;\n"); - } - - WRITE (p, " float fog = saturate(ze - "I_FOG"[1].z);\n"); - - if(bpmem.fog.c_proj_fsel.fsel > 3) - { - WRITE(p, "%s", tevFogFuncsTable[bpmem.fog.c_proj_fsel.fsel]); - } - else - { - if(bpmem.fog.c_proj_fsel.fsel != 2) - WARN_LOG(VIDEO, "Unknown Fog Type! %08x", bpmem.fog.c_proj_fsel.fsel); - } - - WRITE(p, " prev.rgb = lerp(prev.rgb,"I_FOG"[0].rgb,fog);\n"); - - + WRITE(p, "prev = frac(4.0f + prev * (255.0f/256.0f)) * (256.0f/255.0f);\n"); + + // TODO: Why are we doing a second alpha pretest here? + if (!WriteAlphaTest(p, ApiType, dstAlphaMode)) + { + // alpha test will always fail, so restart the shader and just make it an empty function + p = pmainstart; + WRITE(p, "ocol0 = 0;\n"); + if(DepthTextureEnable) + WRITE(p, "depth = 1.f;\n"); + if(dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND) + WRITE(p, "ocol1 = 0;\n"); + WRITE(p, "discard;\n"); + if(ApiType != API_D3D11) + WRITE(p, "return;\n"); + } + else + { + if((bpmem.fog.c_proj_fsel.fsel != 0) || DepthTextureEnable) + { + + // the screen space depth value = far z + (clip z / clip w) * z range + WRITE(p, "float zCoord = "I_ZBIAS"[1].x + (clipPos.z / clipPos.w) * "I_ZBIAS"[1].y;\n"); + } + + if (DepthTextureEnable) + { + // use the texture input of the last texture stage (textemp), hopefully this has been read and is in correct format... + if (bpmem.ztex2.op != ZTEXTURE_DISABLE && !bpmem.zcontrol.zcomploc && bpmem.zmode.testenable && bpmem.zmode.updateenable) + { + if (bpmem.ztex2.op == ZTEXTURE_ADD) + WRITE(p, "zCoord = dot("I_ZBIAS"[0].xyzw, textemp.xyzw) + "I_ZBIAS"[1].w + zCoord;\n"); + else + WRITE(p, "zCoord = dot("I_ZBIAS"[0].xyzw, textemp.xyzw) + "I_ZBIAS"[1].w;\n"); + + // scale to make result from frac correct + WRITE(p, "zCoord = zCoord * (16777215.0f/16777216.0f);\n"); + WRITE(p, "zCoord = frac(zCoord);\n"); + WRITE(p, "zCoord = zCoord * (16777216.0f/16777215.0f);\n"); + } + WRITE(p, "depth = zCoord;\n"); + } + + if (dstAlphaMode == DSTALPHA_ALPHA_PASS) + WRITE(p, " ocol0 = float4(prev.rgb, "I_ALPHA"[0].a);\n"); + else + { + WriteFog(p); + WRITE(p, " ocol0 = prev;\n"); + } + + // On D3D11, use dual-source color blending to perform dst alpha in a + // single pass + if (dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND) + { + // Colors will be blended against the alpha from ocol1... + WRITE(p, " ocol1 = ocol0;\n"); + // ...and the alpha from ocol0 will be written to the framebuffer. + WRITE(p, " ocol0.a = "I_ALPHA"[0].a;\n"); + } + } + WRITE(p, "}\n"); + if (text[sizeof(text) - 1] != 0x7C) + PanicAlert("PixelShader generator - buffer too small, canary has been eaten!"); + + setlocale(LC_NUMERIC, ""); // restore locale + return text; +} + + + +//table with the color compare operations +static const char *TEVCMPColorOPTable[16] = +{ + "float3(0.0f, 0.0f, 0.0f)",//0 + "float3(0.0f, 0.0f, 0.0f)",//1 + "float3(0.0f, 0.0f, 0.0f)",//2 + "float3(0.0f, 0.0f, 0.0f)",//3 + "float3(0.0f, 0.0f, 0.0f)",//4 + "float3(0.0f, 0.0f, 0.0f)",//5 + "float3(0.0f, 0.0f, 0.0f)",//6 + "float3(0.0f, 0.0f, 0.0f)",//7 + " %s + ((%s.r >= %s.r + (0.25f/255.0f)) ? %s : float3(0.0f, 0.0f, 0.0f))",//#define TEVCMP_R8_GT 8 + " %s + ((abs(%s.r - %s.r) < (0.5f/255.0f)) ? %s : float3(0.0f, 0.0f, 0.0f))",//#define TEVCMP_R8_EQ 9 + " %s + (( dot(%s.rgb, comp16) >= (dot(%s.rgb, comp16) + (0.25f/255.0f))) ? %s : float3(0.0f, 0.0f, 0.0f))",//#define TEVCMP_GR16_GT 10 + " %s + (abs(dot(%s.rgb, comp16) - dot(%s.rgb, comp16)) < (0.5f/255.0f) ? %s : float3(0.0f, 0.0f, 0.0f))",//#define TEVCMP_GR16_EQ 11 + " %s + (( dot(%s.rgb, comp24) >= (dot(%s.rgb, comp24) + (0.25f/255.0f))) ? %s : float3(0.0f, 0.0f, 0.0f))",//#define TEVCMP_BGR24_GT 12 + " %s + (abs(dot(%s.rgb, comp24) - dot(%s.rgb, comp24)) < (0.5f/255.0f) ? %s : float3(0.0f, 0.0f, 0.0f))",//#define TEVCMP_BGR24_EQ 13 + " %s + (max(sign(%s.rgb - %s.rgb - (0.25f/255.0f)), float3(0.0f, 0.0f, 0.0f)) * %s)",//#define TEVCMP_RGB8_GT 14 + " %s + ((float3(1.0f, 1.0f, 1.0f) - max(sign(abs(%s.rgb - %s.rgb) - (0.5f/255.0f)), float3(0.0f, 0.0f, 0.0f))) * %s)"//#define TEVCMP_RGB8_EQ 15 +}; + +//table with the alpha compare operations +static const char *TEVCMPAlphaOPTable[16] = +{ + "0.0f",//0 + "0.0f",//1 + "0.0f",//2 + "0.0f",//3 + "0.0f",//4 + "0.0f",//5 + "0.0f",//6 + "0.0f",//7 + " %s.a + ((%s.r >= (%s.r + (0.25f/255.0f))) ? %s.a : 0.0f)",//#define TEVCMP_R8_GT 8 + " %s.a + (abs(%s.r - %s.r) < (0.5f/255.0f) ? %s.a : 0.0f)",//#define TEVCMP_R8_EQ 9 + " %s.a + ((dot(%s.rgb, comp16) >= (dot(%s.rgb, comp16) + (0.25f/255.0f))) ? %s.a : 0.0f)",//#define TEVCMP_GR16_GT 10 + " %s.a + (abs(dot(%s.rgb, comp16) - dot(%s.rgb, comp16)) < (0.5f/255.0f) ? %s.a : 0.0f)",//#define TEVCMP_GR16_EQ 11 + " %s.a + ((dot(%s.rgb, comp24) >= (dot(%s.rgb, comp24) + (0.25f/255.0f))) ? %s.a : 0.0f)",//#define TEVCMP_BGR24_GT 12 + " %s.a + (abs(dot(%s.rgb, comp24) - dot(%s.rgb, comp24)) < (0.5f/255.0f) ? %s.a : 0.0f)",//#define TEVCMP_BGR24_EQ 13 + " %s.a + ((%s.a >= (%s.a + (0.25f/255.0f))) ? %s.a : 0.0f)",//#define TEVCMP_A8_GT 14 + " %s.a + (abs(%s.a - %s.a) < (0.5f/255.0f) ? %s.a : 0.0f)"//#define TEVCMP_A8_EQ 15 + +}; + + +static void WriteStage(char *&p, int n, API_TYPE ApiType) +{ + int texcoord = bpmem.tevorders[n/2].getTexCoord(n&1); + bool bHasTexCoord = (u32)texcoord < bpmem.genMode.numtexgens; + bool bHasIndStage = bpmem.tevind[n].IsActive() && bpmem.tevind[n].bt < bpmem.genMode.numindstages; + + // HACK to handle cases where the tex gen is not enabled + if (!bHasTexCoord) + texcoord = 0; + + WRITE(p, "// TEV stage %d\n", n); + + if (bHasIndStage) + { + WRITE(p, "// indirect op\n", n); + // perform the indirect op on the incoming regular coordinates using indtex%d as the offset coords + if (bpmem.tevind[n].bs != ITBA_OFF) + { + WRITE(p, "alphabump = indtex%d.%s %s;\n", + bpmem.tevind[n].bt, + tevIndAlphaSel[bpmem.tevind[n].bs], + tevIndAlphaScale[bpmem.tevind[n].fmt]); + } + // format + WRITE(p, "float3 indtevcrd%d = indtex%d * %s;\n", n, bpmem.tevind[n].bt, tevIndFmtScale[bpmem.tevind[n].fmt]); + + // bias + if (bpmem.tevind[n].bias != ITB_NONE ) + WRITE(p, "indtevcrd%d.%s += %s;\n", n, tevIndBiasField[bpmem.tevind[n].bias], tevIndBiasAdd[bpmem.tevind[n].fmt]); + + // multiply by offset matrix and scale + if (bpmem.tevind[n].mid != 0) + { + if (bpmem.tevind[n].mid <= 3) + { + int mtxidx = 2*(bpmem.tevind[n].mid-1); + WRITE(p, "float2 indtevtrans%d = float2(dot("I_INDTEXMTX"[%d].xyz, indtevcrd%d), dot("I_INDTEXMTX"[%d].xyz, indtevcrd%d));\n", + n, mtxidx, n, mtxidx+1, n); + } + else if (bpmem.tevind[n].mid <= 7 && bHasTexCoord) + { // s matrix + // TODO: Might become negative? + int mtxidx = 2*(bpmem.tevind[n].mid-5); + WRITE(p, "float2 indtevtrans%d = "I_INDTEXMTX"[%d].ww * uv%d.xy * indtevcrd%d.xx;\n", n, mtxidx, texcoord, n); + } + else if (bpmem.tevind[n].mid <= 11 && bHasTexCoord) + { // t matrix + // TODO: Might become negative? + int mtxidx = 2*(bpmem.tevind[n].mid-9); + WRITE(p, "float2 indtevtrans%d = "I_INDTEXMTX"[%d].ww * uv%d.xy * indtevcrd%d.yy;\n", n, mtxidx, texcoord, n); + } + else + WRITE(p, "float2 indtevtrans%d = 0;\n", n); + } + else + WRITE(p, "float2 indtevtrans%d = 0;\n", n); + + // --------- + // Wrapping + // --------- + + // wrap S + if (bpmem.tevind[n].sw == ITW_OFF) + WRITE(p, "wrappedcoord.x = uv%d.x;\n", texcoord); + else if (bpmem.tevind[n].sw == ITW_0) + WRITE(p, "wrappedcoord.x = 0.0f;\n"); + else + WRITE(p, "wrappedcoord.x = fmod( uv%d.x, %s );\n", texcoord, tevIndWrapStart[bpmem.tevind[n].sw]); + + // wrap T + if (bpmem.tevind[n].tw == ITW_OFF) + WRITE(p, "wrappedcoord.y = uv%d.y;\n", texcoord); + else if (bpmem.tevind[n].tw == ITW_0) + WRITE(p, "wrappedcoord.y = 0.0f;\n"); + else + WRITE(p, "wrappedcoord.y = fmod( uv%d.y, %s );\n", texcoord, tevIndWrapStart[bpmem.tevind[n].tw]); + + if (bpmem.tevind[n].fb_addprev) // add previous tevcoord + WRITE(p, "tevcoord.xy += wrappedcoord + indtevtrans%d;\n", n); + else + WRITE(p, "tevcoord.xy = wrappedcoord + indtevtrans%d;\n", n); + } + + TevStageCombiner::ColorCombiner &cc = bpmem.combiners[n].colorC; + TevStageCombiner::AlphaCombiner &ac = bpmem.combiners[n].alphaC; + + // blah1 + if(cc.a == TEVCOLORARG_RASA || cc.a == TEVCOLORARG_RASC + || cc.b == TEVCOLORARG_RASA || cc.b == TEVCOLORARG_RASC + || cc.c == TEVCOLORARG_RASA || cc.c == TEVCOLORARG_RASC + || cc.d == TEVCOLORARG_RASA || cc.d == TEVCOLORARG_RASC + || ac.a == TEVALPHAARG_RASA || ac.b == TEVALPHAARG_RASA + || ac.c == TEVALPHAARG_RASA || ac.d == TEVALPHAARG_RASA) + { + char *rasswap = swapModeTable[bpmem.combiners[n].alphaC.rswap]; + WRITE(p, "rastemp = %s.%s;\n", tevRasTable[bpmem.tevorders[n / 2].getColorChan(n & 1)], rasswap); + WRITE(p, "crastemp = frac(rastemp * (255.0f/256.0f)) * (256.0f/255.0f);\n"); + } + + + if (bpmem.tevorders[n/2].getEnable(n&1)) + { + if(!bHasIndStage) + { + // calc tevcord + if(bHasTexCoord) + WRITE(p, "tevcoord.xy = uv%d.xy;\n", texcoord); + else + WRITE(p, "tevcoord.xy = float2(0.0f, 0.0f);\n"); + } + + char *texswap = swapModeTable[bpmem.combiners[n].alphaC.tswap]; + int texmap = bpmem.tevorders[n/2].getTexMap(n&1); + SampleTexture(p, "textemp", "tevcoord", texswap, texmap, ApiType); + } + else + WRITE(p, "textemp = float4(1.0f, 1.0f, 1.0f, 1.0f);\n"); + + + // blah2 + if (cc.a == TEVCOLORARG_KONST || cc.b == TEVCOLORARG_KONST || cc.c == TEVCOLORARG_KONST || cc.d == TEVCOLORARG_KONST + || ac.a == TEVALPHAARG_KONST || ac.b == TEVALPHAARG_KONST || ac.c == TEVALPHAARG_KONST || ac.d == TEVALPHAARG_KONST) + { + int kc = bpmem.tevksel[n / 2].getKC(n & 1); + int ka = bpmem.tevksel[n / 2].getKA(n & 1); + WRITE(p, "konsttemp = float4(%s, %s);\n", tevKSelTableC[kc], tevKSelTableA[ka]); + if(kc > 7 || ka > 7) + { + WRITE(p, "ckonsttemp = frac(konsttemp * (255.0f/256.0f)) * (256.0f/255.0f);\n"); + } + else + { + WRITE(p, "ckonsttemp = konsttemp;\n"); + } + } + + if(cc.a == TEVCOLORARG_CPREV || cc.a == TEVCOLORARG_APREV + || cc.b == TEVCOLORARG_CPREV || cc.b == TEVCOLORARG_APREV + || cc.c == TEVCOLORARG_CPREV || cc.c == TEVCOLORARG_APREV + || ac.a == TEVALPHAARG_APREV || ac.b == TEVALPHAARG_APREV || ac.c == TEVALPHAARG_APREV) + WRITE(p, "cprev = frac(prev * (255.0f/256.0f)) * (256.0f/255.0f);\n"); + + + if(cc.a == TEVCOLORARG_C0 || cc.a == TEVCOLORARG_A0 + || cc.b == TEVCOLORARG_C0 || cc.b == TEVCOLORARG_A0 + || cc.c == TEVCOLORARG_C0 || cc.c == TEVCOLORARG_A0 + || ac.a == TEVALPHAARG_A0 || ac.b == TEVALPHAARG_A0 || ac.c == TEVALPHAARG_A0) + WRITE(p, "cc0 = frac(c0 * (255.0f/256.0f)) * (256.0f/255.0f);\n"); + + + if(cc.a == TEVCOLORARG_C1 || cc.a == TEVCOLORARG_A1 + || cc.b == TEVCOLORARG_C1 || cc.b == TEVCOLORARG_A1 + || cc.c == TEVCOLORARG_C1 || cc.c == TEVCOLORARG_A1 + || ac.a == TEVALPHAARG_A1 || ac.b == TEVALPHAARG_A1 || ac.c == TEVALPHAARG_A1) + WRITE(p, "cc1 = frac(c1 * (255.0f/256.0f)) * (256.0f/255.0f);\n"); + + + if(cc.a == TEVCOLORARG_C2 || cc.a == TEVCOLORARG_A2 + || cc.b == TEVCOLORARG_C2 || cc.b == TEVCOLORARG_A2 + || cc.c == TEVCOLORARG_C2 || cc.c == TEVCOLORARG_A2 + || ac.a == TEVALPHAARG_A2 || ac.b == TEVALPHAARG_A2 || ac.c == TEVALPHAARG_A2) + WRITE(p, "cc2 = frac(c2 * (255.0f/256.0f)) * (256.0f/255.0f);\n"); + + + WRITE(p, "// color combine\n", n); + if (cc.clamp) + WRITE(p, "%s = saturate(", tevCOutputTable[cc.dest]); + else + WRITE(p, "%s = ", tevCOutputTable[cc.dest]); + + // combine the color channel + if (cc.bias != TevBias_COMPARE) // if not compare + { + //normal color combiner goes here + if (cc.shift > TEVSCALE_1) + WRITE(p, "%s*(", tevScaleTable[cc.shift]); + + if(!(cc.d == TEVCOLORARG_ZERO && cc.op == TEVOP_ADD)) + WRITE(p, "%s%s", tevCInputTable[cc.d], tevOpTable[cc.op]); + + if (cc.a == cc.b) + WRITE(p, "%s", tevCInputTable[cc.a + 16]); + else if (cc.c == TEVCOLORARG_ZERO) + WRITE(p, "%s", tevCInputTable[cc.a + 16]); + else if (cc.c == TEVCOLORARG_ONE) + WRITE(p, "%s", tevCInputTable[cc.b + 16]); + else if (cc.a == TEVCOLORARG_ZERO) + WRITE(p, "%s*%s", tevCInputTable[cc.b + 16], tevCInputTable[cc.c + 16]); + else if (cc.b == TEVCOLORARG_ZERO) + WRITE(p, "%s*(float3(1.0f, 1.0f, 1.0f)-%s)", tevCInputTable[cc.a + 16], tevCInputTable[cc.c + 16]); + else + WRITE(p, "lerp(%s, %s, %s)", tevCInputTable[cc.a + 16], tevCInputTable[cc.b + 16], tevCInputTable[cc.c + 16]); + + WRITE(p, "%s", tevBiasTable[cc.bias]); + + if (cc.shift > TEVSCALE_1) + WRITE(p, ")"); + } + else + { + int cmp = (cc.shift<<1)|cc.op|8; // comparemode stored here + WRITE(p, TEVCMPColorOPTable[cmp],//lookup the function from the op table + tevCInputTable[cc.d], + tevCInputTable[cc.a + 16], + tevCInputTable[cc.b + 16], + tevCInputTable[cc.c + 16]); + } + if (cc.clamp) + WRITE(p, ")"); + WRITE(p,";\n"); + + WRITE(p, "// alpha combine\n", n); + // combine the alpha channel + if (ac.clamp) + WRITE(p, "%s = saturate(", tevAOutputTable[ac.dest]); + else + WRITE(p, "%s = ", tevAOutputTable[ac.dest]); + + if (ac.bias != TevBias_COMPARE) // if not compare + { + //normal alpha combiner goes here + if (ac.shift > TEVSCALE_1) + WRITE(p, "%s*(", tevScaleTable[ac.shift]); + + if(!(ac.d == TEVALPHAARG_ZERO && ac.op == TEVOP_ADD)) + WRITE(p, "%s.a%s", tevAInputTable[ac.d], tevOpTable[ac.op]); + + if (ac.a == ac.b) + WRITE(p, "%s.a", tevAInputTable[ac.a + 8]); + else if (ac.c == TEVALPHAARG_ZERO) + WRITE(p, "%s.a", tevAInputTable[ac.a + 8]); + else if (ac.a == TEVALPHAARG_ZERO) + WRITE(p, "%s.a*%s.a", tevAInputTable[ac.b + 8], tevAInputTable[ac.c + 8]); + else if (ac.b == TEVALPHAARG_ZERO) + WRITE(p, "%s.a*(1.0f-%s.a)", tevAInputTable[ac.a + 8], tevAInputTable[ac.c + 8]); + else + WRITE(p, "lerp(%s.a, %s.a, %s.a)", tevAInputTable[ac.a + 8], tevAInputTable[ac.b + 8], tevAInputTable[ac.c + 8]); + + WRITE(p, "%s",tevBiasTable[ac.bias]); + + if (ac.shift>0) + WRITE(p, ")"); + + } + else + { + //compare alpha combiner goes here + int cmp = (ac.shift<<1)|ac.op|8; // comparemode stored here + WRITE(p, TEVCMPAlphaOPTable[cmp], + tevAInputTable[ac.d], + tevAInputTable[ac.a + 8], + tevAInputTable[ac.b + 8], + tevAInputTable[ac.c + 8]); + } + if (ac.clamp) + WRITE(p, ")"); + WRITE(p, ";\n\n"); + WRITE(p, "// TEV done\n", n); +} + +void SampleTexture(char *&p, const char *destination, const char *texcoords, const char *texswap, int texmap, API_TYPE ApiType) +{ + if (ApiType == API_D3D11) + WRITE(p, "%s=Tex%d.Sample(samp%d,%s.xy * "I_TEXDIMS"[%d].xy).%s;\n", destination, texmap,texmap, texcoords, texmap, texswap); + else + WRITE(p, "%s=tex2D(samp%d,%s.xy * "I_TEXDIMS"[%d].xy).%s;\n", destination, texmap, texcoords, texmap, texswap); +} + +static const char *tevAlphaFuncsTable[] = +{ + "(false)", //ALPHACMP_NEVER 0 + "(prev.a <= %s - (0.25f/255.0f))", //ALPHACMP_LESS 1 + "(abs( prev.a - %s ) < (0.5f/255.0f))", //ALPHACMP_EQUAL 2 + "(prev.a < %s + (0.25f/255.0f))", //ALPHACMP_LEQUAL 3 + "(prev.a >= %s + (0.25f/255.0f))", //ALPHACMP_GREATER 4 + "(abs( prev.a - %s ) >= (0.5f/255.0f))", //ALPHACMP_NEQUAL 5 + "(prev.a > %s - (0.25f/255.0f))", //ALPHACMP_GEQUAL 6 + "(true)" //ALPHACMP_ALWAYS 7 +}; + +static const char *tevAlphaFunclogicTable[] = +{ + " && ", // and + " || ", // or + " != ", // xor + " == " // xnor +}; +static int AlphaPreTest() +{ + u32 op = bpmem.alphaFunc.logic; + u32 comp[2] = {bpmem.alphaFunc.comp0, bpmem.alphaFunc.comp1}; + + // First kill all the simple cases + switch(op) + { + case 0: // AND + if (comp[0] == ALPHACMP_ALWAYS && comp[1] == ALPHACMP_ALWAYS) return true; + if (comp[0] == ALPHACMP_NEVER || comp[1] == ALPHACMP_NEVER) return false; + break; + case 1: // OR + if (comp[0] == ALPHACMP_ALWAYS || comp[1] == ALPHACMP_ALWAYS) return true; + if (comp[0] == ALPHACMP_NEVER && comp[1] == ALPHACMP_NEVER)return false; + break; + case 2: // XOR + if ((comp[0] == ALPHACMP_ALWAYS && comp[1] == ALPHACMP_NEVER) || (comp[0] == ALPHACMP_NEVER && comp[1] == ALPHACMP_ALWAYS)) + return true; + if ((comp[0] == ALPHACMP_ALWAYS && comp[1] == ALPHACMP_ALWAYS) || (comp[0] == ALPHACMP_NEVER && comp[1] == ALPHACMP_NEVER)) + return false; + break; + case 3: // XNOR + if ((comp[0] == ALPHACMP_ALWAYS && comp[1] == ALPHACMP_NEVER) || (comp[0] == ALPHACMP_NEVER && comp[1] == ALPHACMP_ALWAYS)) + return false; + if ((comp[0] == ALPHACMP_ALWAYS && comp[1] == ALPHACMP_ALWAYS) || (comp[0] == ALPHACMP_NEVER && comp[1] == ALPHACMP_NEVER)) + return true; + break; + default: PanicAlert("bad logic for alpha test? %08x", op); + } + return -1; +} + + +static bool WriteAlphaTest(char *&p, API_TYPE ApiType,DSTALPHA_MODE dstAlphaMode) +{ + static const char *alphaRef[2] = + { + I_ALPHA"[0].r", + I_ALPHA"[0].g" + }; + + int Pretest = AlphaPreTest(); + if(Pretest >= 0) + { + return Pretest != 0; + } + + // using discard then return works the same in cg and dx9 but not in dx11 + WRITE(p, "if(!( "); + + int compindex = bpmem.alphaFunc.comp0 % 8; + WRITE(p, tevAlphaFuncsTable[compindex],alphaRef[0]);//lookup the first component from the alpha function table + + WRITE(p, "%s", tevAlphaFunclogicTable[bpmem.alphaFunc.logic % 4]);//lookup the logic op + + compindex = bpmem.alphaFunc.comp1 % 8; + WRITE(p, tevAlphaFuncsTable[compindex],alphaRef[1]);//lookup the second component from the alpha function table + WRITE(p, ")){ocol0 = 0;%s%s discard;%s}\n", + dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND ? "ocol1 = 0;" : "", + DepthTextureEnable ? "depth = 1.f;" : "", + (ApiType != API_D3D11) ? "return;" : ""); + return true; +} + +static const char *tevFogFuncsTable[] = +{ + "", //No Fog + "", //? + "", //Linear + "", //? + " fog = 1.0f - pow(2.0f, -8.0f * fog);\n", //exp + " fog = 1.0f - pow(2.0f, -8.0f * fog * fog);\n", //exp2 + " fog = pow(2.0f, -8.0f * (1.0f - fog));\n", //backward exp + " fog = 1.0f - fog;\n fog = pow(2.0f, -8.0f * fog * fog);\n" //backward exp2 +}; + +static void WriteFog(char *&p) +{ + if(bpmem.fog.c_proj_fsel.fsel == 0)return;//no Fog + + if (bpmem.fog.c_proj_fsel.proj == 0) + { + // perspective + // ze = A/(B - (Zs >> B_SHF) + WRITE (p, " float ze = "I_FOG"[1].x / ("I_FOG"[1].y - (zCoord / "I_FOG"[1].w));\n"); + } + else + { + // orthographic + // ze = a*Zs (here, no B_SHF) + WRITE (p, " float ze = "I_FOG"[1].x * zCoord;\n"); + } + + // x_adjust = sqrt((x-center)^2 + k^2)/k + // ze *= x_adjust + //this is complitly teorical as the real hard seems to use a table intead of calculate the values. + if(bpmem.fogRange.Base.Enabled) + { + WRITE (p, " float x_adjust = (2.0f * (clipPos.x / "I_FOG"[2].y)) - 1.0f - "I_FOG"[2].x;\n"); + WRITE (p, " x_adjust = sqrt(x_adjust * x_adjust + "I_FOG"[2].z * "I_FOG"[2].z) / "I_FOG"[2].z;\n"); + WRITE (p, " ze *= x_adjust;\n"); + } + + WRITE (p, " float fog = saturate(ze - "I_FOG"[1].z);\n"); + + if(bpmem.fog.c_proj_fsel.fsel > 3) + { + WRITE(p, "%s", tevFogFuncsTable[bpmem.fog.c_proj_fsel.fsel]); + } + else + { + if(bpmem.fog.c_proj_fsel.fsel != 2) + WARN_LOG(VIDEO, "Unknown Fog Type! %08x", bpmem.fog.c_proj_fsel.fsel); + } + + WRITE(p, " prev.rgb = lerp(prev.rgb,"I_FOG"[0].rgb,fog);\n"); + + } \ No newline at end of file diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.h b/Source/Core/VideoCommon/Src/PixelShaderGen.h index b495703a13..0ebdd0e42f 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderGen.h +++ b/Source/Core/VideoCommon/Src/PixelShaderGen.h @@ -44,7 +44,7 @@ #define C_PLIGHTS (C_FOG + 3) #define C_PMATERIALS (C_PLIGHTS + 40) #define C_PENVCONST_END (C_PMATERIALS + 4) -#define PIXELSHADERUID_MAX_VALUES (5 + 32 + 6 + 11 + 2) +#define PIXELSHADERUID_MAX_VALUES 67 // DO NOT make anything in this class virtual. class PIXELSHADERUID @@ -71,7 +71,7 @@ public: int GetNumValues() const { - return tevstages + indstages + 4; + return tevstages; } bool operator <(const PIXELSHADERUID& _Right) const From 4137f287fd4d8778967bb8a82eafe5450687e2b7 Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Wed, 31 Aug 2011 19:45:28 +0200 Subject: [PATCH 04/36] Fix a critical bug which caused shaders to be redundantly recompiled when disabling per-pixel depth. As a nice side effect, the number of redundant shader compilations is now next to zero ;) --- Source/Core/VideoCommon/Src/PixelShaderGen.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp index 6d0cc64964..ff82438305 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp @@ -124,6 +124,7 @@ void GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode) { // Courtesy of PreAlphaTest, we're done already ;) // TODO: There's a comment including bpmem.genmode.numindstages.. shouldnt really bother about that though. + uid->tevstages = 1; return; } From bcb8d11c1b9f0493a29b4bc4ecf40ee75594e9df Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Wed, 31 Aug 2011 20:46:03 +0200 Subject: [PATCH 05/36] Reduced the number of redundant vertex shader compilations (possibly to zero). That one was almost too easy ;P --- Source/Core/VideoCommon/Src/VertexShaderGen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Core/VideoCommon/Src/VertexShaderGen.cpp b/Source/Core/VideoCommon/Src/VertexShaderGen.cpp index 747b95c0da..7a1d5eb555 100644 --- a/Source/Core/VideoCommon/Src/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/VertexShaderGen.cpp @@ -37,7 +37,7 @@ void GetVertexShaderId(VERTEXSHADERUID *uid, u32 components) (xfregs.numChan.numColorChans << 27) | (xfregs.dualTexTrans.enabled << 29); - for (int i = 0; i < 2; ++i) { + for (int i = 0; i < xfregs.numChan.numColorChans; ++i) { uid->values[1+i] = xfregs.color[i].enablelighting ? (u32)xfregs.color[i].hex : (u32)xfregs.color[i].matsource; From 231c13d6cec11c1326ab21f567ab6a58a521043d Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Sun, 4 Sep 2011 00:47:45 +0200 Subject: [PATCH 06/36] Added safe vertex shader UIDs for debugging purposes. --- .../Core/VideoCommon/Src/VertexShaderGen.cpp | 21 +++++++++++++++++++ Source/Core/VideoCommon/Src/VertexShaderGen.h | 21 ++++++++++++------- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/Source/Core/VideoCommon/Src/VertexShaderGen.cpp b/Source/Core/VideoCommon/Src/VertexShaderGen.cpp index 7a1d5eb555..d15cef0c70 100644 --- a/Source/Core/VideoCommon/Src/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/VertexShaderGen.cpp @@ -69,6 +69,27 @@ void GetVertexShaderId(VERTEXSHADERUID *uid, u32 components) } } +void GetSafeVertexShaderId(VERTEXSHADERUIDSAFE *uid, u32 components) +{ + // Just store all used registers here without caring whether we need all bits or less. + u32* ptr = uid->values; + *ptr++ = components; + *ptr++ = xfregs.numTexGen.hex; + *ptr++ = xfregs.numChan.hex; + *ptr++ = xfregs.dualTexTrans.hex; + + for (int i = 0; i < 2; ++i) { + *ptr++ = xfregs.color[i].hex; + *ptr++ = xfregs.alpha[i].hex; + } + *ptr++ = g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting; + for (unsigned int i = 0; i < 8; ++i) { + *ptr++ = xfregs.texMtxInfo[i].hex; + *ptr++ = xfregs.postMtxInfo[i].hex; + } + _assert_((ptr - uid->values) == uid->GetNumValues()); +} + static char text[16384]; #define WRITE p+=sprintf diff --git a/Source/Core/VideoCommon/Src/VertexShaderGen.h b/Source/Core/VideoCommon/Src/VertexShaderGen.h index d7bf362213..50e9c5fc3b 100644 --- a/Source/Core/VideoCommon/Src/VertexShaderGen.h +++ b/Source/Core/VideoCommon/Src/VertexShaderGen.h @@ -48,17 +48,19 @@ #define C_DEPTHPARAMS (C_POSTTRANSFORMMATRICES + 64) #define C_VENVCONST_END (C_DEPTHPARAMS + 4) -class VERTEXSHADERUID +template +class _VERTEXSHADERUID { +#define NUM_VSUID_VALUES_SAFE 25 public: - u32 values[9]; + u32 values[safe ? NUM_VSUID_VALUES_SAFE : 9]; - VERTEXSHADERUID() + _VERTEXSHADERUID() { memset(values, 0, sizeof(values)); } - VERTEXSHADERUID(const VERTEXSHADERUID& r) + _VERTEXSHADERUID(const _VERTEXSHADERUID& r) { for (size_t i = 0; i < sizeof(values) / sizeof(u32); ++i) values[i] = r.values[i]; @@ -66,10 +68,11 @@ public: int GetNumValues() const { - return (((values[0] >> 23) & 0xf) * 3 + 3) / 4 + 3; // numTexGens*3/4+1 + if (safe) return NUM_VSUID_VALUES_SAFE; + else return (((values[0] >> 23) & 0xf) * 3 + 3) / 4 + 3; // numTexGens*3/4+1 } - bool operator <(const VERTEXSHADERUID& _Right) const + bool operator <(const _VERTEXSHADERUID& _Right) const { if (values[0] < _Right.values[0]) return true; @@ -86,7 +89,7 @@ public: return false; } - bool operator ==(const VERTEXSHADERUID& _Right) const + bool operator ==(const _VERTEXSHADERUID& _Right) const { if (values[0] != _Right.values[0]) return false; @@ -99,13 +102,15 @@ public: return true; } }; - +typedef _VERTEXSHADERUID VERTEXSHADERUID; +typedef _VERTEXSHADERUID VERTEXSHADERUIDSAFE; // components is included in the uid. char* GenerateVSOutputStruct(char* p, u32 components, API_TYPE api_type); const char *GenerateVertexShaderCode(u32 components, API_TYPE api_type); void GetVertexShaderId(VERTEXSHADERUID *uid, u32 components); +void GetSafeVertexShaderId(VERTEXSHADERUIDSAFE *uid, u32 components); extern VERTEXSHADERUID last_vertex_shader_uid; From 4702de591eb69e815398b21c5b4321b1ac133552 Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Sun, 4 Sep 2011 02:10:07 +0200 Subject: [PATCH 07/36] Added safe pixel shader UIDs for debugging purposes. --- .../Core/VideoCommon/Src/PixelShaderGen.cpp | 54 ++++++++++++++++--- Source/Core/VideoCommon/Src/PixelShaderGen.h | 24 +++++---- Source/Core/VideoCommon/Src/VertexShaderGen.h | 2 +- 3 files changed, 63 insertions(+), 17 deletions(-) diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp index ff82438305..9913ea7c5a 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp @@ -164,7 +164,7 @@ void GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode) } u32* ptr = &uid->values[2]; - for (unsigned int i = 0; i < bpmem.genMode.numtevstages+1; ++i) + for (int i = 0; i < bpmem.genMode.numtevstages+1; ++i) { StageHash(i, ptr); ptr += 4; // max: ptr = &uid->values[66] @@ -315,6 +315,46 @@ void _GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode) } +void GetSafePixelShaderId(PIXELSHADERUIDSAFE *uid, DSTALPHA_MODE dstAlphaMode) +{ + u32* ptr = uid->values; + *ptr++ = dstAlphaMode; + *ptr++ = bpmem.genMode.hex; + *ptr++ = bpmem.ztex2.hex; + *ptr++ = bpmem.zcontrol.hex; + *ptr++ = bpmem.zmode.hex; + *ptr++ = g_ActiveConfig.bEnablePerPixelDepth; + *ptr++ = g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting; + *ptr++ = xfregs.numTexGen.hex; + + if (g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) + { + // TODO: Include register states for lighting shader + } + + for (unsigned int i = 0; i < 8; ++i) + *ptr++ = xfregs.texMtxInfo[i].hex; + + for (unsigned int i = 0; i < 16; ++i) + *ptr++ = bpmem.tevind[i].hex; + + *ptr++ = bpmem.tevindref.hex; + + for (int i = 0; i < bpmem.genMode.numtevstages+1; ++i) + { + // TODO ... + StageHash(i, ptr); + ptr += 4; // max: ptr = &uid->values[66] + } + + *ptr++ = bpmem.fog.c_proj_fsel.hex; + + *ptr++ = bpmem.fogRange.Base.hex; + + _assert_((ptr - uid->values) == uid->GetNumValues()); +} + + // old tev->pixelshader notes // // color for this stage (alpha, color) is given by bpmem.tevorders[0].colorchan0 @@ -539,8 +579,8 @@ const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType char *p = text; WRITE(p, "//Pixel Shader for TEV stages\n"); - WRITE(p, "//%i TEV stages, %i texgens, %i IND stages\n", - numStages, numTexgen, bpmem.genMode.numindstages); + WRITE(p, "//%i TEV stages, %i texgens, XXX IND stages\n", + numStages, numTexgen/*, bpmem.genMode.numindstages*/); int nIndirectStagesUsed = 0; if (bpmem.genMode.numindstages > 0) @@ -876,7 +916,7 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType) if (bHasIndStage) { - WRITE(p, "// indirect op\n", n); + WRITE(p, "// indirect op\n"); // perform the indirect op on the incoming regular coordinates using indtex%d as the offset coords if (bpmem.tevind[n].bs != ITBA_OFF) { @@ -1026,7 +1066,7 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType) WRITE(p, "cc2 = frac(c2 * (255.0f/256.0f)) * (256.0f/255.0f);\n"); - WRITE(p, "// color combine\n", n); + WRITE(p, "// color combine\n"); if (cc.clamp) WRITE(p, "%s = saturate(", tevCOutputTable[cc.dest]); else @@ -1073,7 +1113,7 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType) WRITE(p, ")"); WRITE(p,";\n"); - WRITE(p, "// alpha combine\n", n); + WRITE(p, "// alpha combine\n"); // combine the alpha channel if (ac.clamp) WRITE(p, "%s = saturate(", tevAOutputTable[ac.dest]); @@ -1119,7 +1159,7 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType) if (ac.clamp) WRITE(p, ")"); WRITE(p, ";\n\n"); - WRITE(p, "// TEV done\n", n); + WRITE(p, "// TEV done\n"); } void SampleTexture(char *&p, const char *destination, const char *texcoords, const char *texswap, int texmap, API_TYPE ApiType) diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.h b/Source/Core/VideoCommon/Src/PixelShaderGen.h index 0ebdd0e42f..6ed39e7e74 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderGen.h +++ b/Source/Core/VideoCommon/Src/PixelShaderGen.h @@ -45,36 +45,39 @@ #define C_PMATERIALS (C_PLIGHTS + 40) #define C_PENVCONST_END (C_PMATERIALS + 4) #define PIXELSHADERUID_MAX_VALUES 67 +#define PIXELSHADERUID_MAX_VALUES_SAFE 100 // DO NOT make anything in this class virtual. -class PIXELSHADERUID +template +class _PIXELSHADERUID { public: - u32 values[PIXELSHADERUID_MAX_VALUES]; + u32 values[safe ? PIXELSHADERUID_MAX_VALUES_SAFE : PIXELSHADERUID_MAX_VALUES]; u16 tevstages, indstages; - PIXELSHADERUID() + _PIXELSHADERUID() { - memset(values, 0, PIXELSHADERUID_MAX_VALUES * 4); + memset(values, 0, sizeof(values)); tevstages = indstages = 0; } - PIXELSHADERUID(const PIXELSHADERUID& r) + _PIXELSHADERUID(const _PIXELSHADERUID& r) { tevstages = r.tevstages; indstages = r.indstages; int N = GetNumValues(); - _assert_(N <= PIXELSHADERUID_MAX_VALUES); + _assert_(N <= GetNumValues()); for (int i = 0; i < N; ++i) values[i] = r.values[i]; } int GetNumValues() const { - return tevstages; + if (safe) return (sizeof(values) / sizeof(u32)); + else return tevstages; } - bool operator <(const PIXELSHADERUID& _Right) const + bool operator <(const _PIXELSHADERUID& _Right) const { if (values[0] < _Right.values[0]) return true; @@ -91,7 +94,7 @@ public: return false; } - bool operator ==(const PIXELSHADERUID& _Right) const + bool operator ==(const _PIXELSHADERUID& _Right) const { if (values[0] != _Right.values[0]) return false; @@ -104,6 +107,8 @@ public: return true; } }; +typedef _PIXELSHADERUID PIXELSHADERUID; +typedef _PIXELSHADERUID PIXELSHADERUIDSAFE; // Different ways to achieve rendering with destination alpha enum DSTALPHA_MODE @@ -115,6 +120,7 @@ enum DSTALPHA_MODE const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType, u32 components); void GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode); +void GetSafePixelShaderId(PIXELSHADERUIDSAFE *uid, DSTALPHA_MODE dstAlphaMode); extern PIXELSHADERUID last_pixel_shader_uid; diff --git a/Source/Core/VideoCommon/Src/VertexShaderGen.h b/Source/Core/VideoCommon/Src/VertexShaderGen.h index 50e9c5fc3b..1ab696acc2 100644 --- a/Source/Core/VideoCommon/Src/VertexShaderGen.h +++ b/Source/Core/VideoCommon/Src/VertexShaderGen.h @@ -57,7 +57,7 @@ public: _VERTEXSHADERUID() { - memset(values, 0, sizeof(values)); + memset(values, 0, sizeof(values)); } _VERTEXSHADERUID(const _VERTEXSHADERUID& r) From 3939f9595a87393482df617465888f4ed46b6d94 Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Wed, 7 Sep 2011 20:20:29 +0200 Subject: [PATCH 08/36] Add runtime checks to make sure we aren't overoptimizing the pixel shader cache. --- Source/Core/Common/Src/MsgHandler.cpp | 4 +- .../Core/VideoCommon/Src/PixelShaderGen.cpp | 49 ++++++++++--------- Source/Core/VideoCommon/Src/PixelShaderGen.h | 2 + .../Plugin_VideoOGL/Src/PixelShaderCache.cpp | 37 +++++++++++++- .../Plugin_VideoOGL/Src/PixelShaderCache.h | 2 + 5 files changed, 68 insertions(+), 26 deletions(-) diff --git a/Source/Core/Common/Src/MsgHandler.cpp b/Source/Core/Common/Src/MsgHandler.cpp index 3f68e1d29a..17c40d76f8 100644 --- a/Source/Core/Common/Src/MsgHandler.cpp +++ b/Source/Core/Common/Src/MsgHandler.cpp @@ -53,7 +53,7 @@ bool MsgAlert(bool yes_no, int Style, const char* format, ...) { // Read message and write it to the log std::string caption; - char buffer[2048]; + char buffer[4096]; static std::string info_caption; static std::string warn_caption; @@ -86,7 +86,7 @@ bool MsgAlert(bool yes_no, int Style, const char* format, ...) va_list args; va_start(args, format); - CharArrayFromFormatV(buffer, 2047, str_translator(format).c_str(), args); + CharArrayFromFormatV(buffer, sizeof(buffer)-1, str_translator(format).c_str(), args); va_end(args); ERROR_LOG(MASTER_LOG, "%s: %s", caption.c_str(), buffer); diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp index 9913ea7c5a..8bdfc3db28 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp @@ -172,13 +172,13 @@ void GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode) if (alphaPreTest == 0 || alphaPreTest == 2) { - ptr[0] |= bpmem.fog.c_proj_fsel.fsel; // 3 + ptr[0] |= bpmem.fog.c_proj_fsel.fsel << 8; // 3 if (DepthTextureEnable) { - ptr[0] |= bpmem.ztex2.op << 3; // 2 - ptr[0] |= bpmem.zcontrol.zcomploc << 5; // 1 - ptr[0] |= bpmem.zmode.testenable << 6; // 1 - ptr[0] |= bpmem.zmode.updateenable << 7; // 1 + ptr[0] |= bpmem.ztex2.op << 11; // 2 + ptr[0] |= bpmem.zcontrol.zcomploc << 13; // 1 + ptr[0] |= bpmem.zmode.testenable << 14; // 1 + ptr[0] |= bpmem.zmode.updateenable << 15; // 1 } } @@ -186,8 +186,8 @@ void GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode) { if (bpmem.fog.c_proj_fsel.fsel != 0) { - ptr[0] |= bpmem.fog.c_proj_fsel.proj << 8; // 1 - ptr[0] |= bpmem.fogRange.Base.Enabled << 9; // 1 + ptr[0] |= bpmem.fog.c_proj_fsel.proj << 16; // 1 + ptr[0] |= bpmem.fogRange.Base.Enabled << 17; // 1 } } uid->tevstages = (ptr+1) - uid->values; @@ -318,14 +318,14 @@ void _GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode) void GetSafePixelShaderId(PIXELSHADERUIDSAFE *uid, DSTALPHA_MODE dstAlphaMode) { u32* ptr = uid->values; - *ptr++ = dstAlphaMode; - *ptr++ = bpmem.genMode.hex; - *ptr++ = bpmem.ztex2.hex; - *ptr++ = bpmem.zcontrol.hex; - *ptr++ = bpmem.zmode.hex; - *ptr++ = g_ActiveConfig.bEnablePerPixelDepth; - *ptr++ = g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting; - *ptr++ = xfregs.numTexGen.hex; + *ptr++ = dstAlphaMode; // 0 + *ptr++ = bpmem.genMode.hex; // 1 + *ptr++ = bpmem.ztex2.hex; // 2 + *ptr++ = bpmem.zcontrol.hex; // 3 + *ptr++ = bpmem.zmode.hex; // 4 + *ptr++ = g_ActiveConfig.bEnablePerPixelDepth; // 5 + *ptr++ = g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting; // 6 + *ptr++ = xfregs.numTexGen.hex; // 7 if (g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) { @@ -333,25 +333,28 @@ void GetSafePixelShaderId(PIXELSHADERUIDSAFE *uid, DSTALPHA_MODE dstAlphaMode) } for (unsigned int i = 0; i < 8; ++i) - *ptr++ = xfregs.texMtxInfo[i].hex; + *ptr++ = xfregs.texMtxInfo[i].hex; // 8-15 for (unsigned int i = 0; i < 16; ++i) - *ptr++ = bpmem.tevind[i].hex; + *ptr++ = bpmem.tevind[i].hex; // 16-31 - *ptr++ = bpmem.tevindref.hex; + *ptr++ = bpmem.tevindref.hex; // 32 - for (int i = 0; i < bpmem.genMode.numtevstages+1; ++i) + for (int i = 0; i < bpmem.genMode.numtevstages+1; ++i) // up to 16 times { // TODO ... StageHash(i, ptr); - ptr += 4; // max: ptr = &uid->values[66] + ptr += 4; // max: ptr = &uid->values[33+63] } - *ptr++ = bpmem.fog.c_proj_fsel.hex; + ptr = &uid->values[97]; - *ptr++ = bpmem.fogRange.Base.hex; + *ptr++ = bpmem.alphaFunc.hex; // 97 - _assert_((ptr - uid->values) == uid->GetNumValues()); + *ptr++ = bpmem.fog.c_proj_fsel.hex; // 98 + *ptr++ = bpmem.fogRange.Base.hex; // 99 + + _assert_((ptr - uid->values) <= uid->GetNumValues()); } diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.h b/Source/Core/VideoCommon/Src/PixelShaderGen.h index 6ed39e7e74..c66635e12b 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderGen.h +++ b/Source/Core/VideoCommon/Src/PixelShaderGen.h @@ -119,6 +119,8 @@ enum DSTALPHA_MODE }; const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType, u32 components); + +// TODO: Wtf, those need components as well! -.- void GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode); void GetSafePixelShaderId(PIXELSHADERUIDSAFE *uid, DSTALPHA_MODE dstAlphaMode); diff --git a/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.cpp b/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.cpp index fb4c226f77..f0a640a114 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.cpp @@ -184,12 +184,30 @@ void PixelShaderCache::Shutdown() FRAGMENTSHADER* PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components) { PIXELSHADERUID uid; + PIXELSHADERUIDSAFE safe_uid; GetPixelShaderId(&uid, dstAlphaMode); + GetSafePixelShaderId(&safe_uid, dstAlphaMode); - // Check if the shader is already set + // Check if the shader is already set - TODO: Use pShaderLast instead of PixelShaders[uid]? if (uid == last_pixel_shader_uid && PixelShaders[uid].frameCount == frameCount) { GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); + + if (!(safe_uid == PixelShaders[uid].safe_uid)) + { + std::string code(GeneratePixelShaderCode(dstAlphaMode, API_OPENGL, components)); + if (code != PixelShaders[uid].code) + { + char msg[4096]; + char* ptr = msg; + ptr += sprintf(ptr, "Mismatch!\nUnique IDs:\n"); + for (int i = 0; i < PixelShaders[uid].safe_uid.GetNumValues()/2; ++i) + ptr += sprintf(ptr, "%02d, %08X %08X | %08X %08X\n", 2*i, PixelShaders[uid].safe_uid.values[2*i], PixelShaders[uid].safe_uid.values[2*i+1], + safe_uid.values[2*i], safe_uid.values[2*i+1]); + PanicAlert(msg); + } + } + return pShaderLast; } @@ -207,14 +225,31 @@ FRAGMENTSHADER* PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 comp } GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); + if (!(safe_uid == entry.safe_uid)) + { + std::string code(GeneratePixelShaderCode(dstAlphaMode, API_OPENGL, components)); + if (code != entry.code) + { + char msg[4096]; + char *ptr = msg; + ptr += sprintf(ptr, "Mismatch!\nUnique IDs:\n"); + for (int i = 0; i < entry.safe_uid.GetNumValues()/2; ++i) + ptr += sprintf(ptr, "%02d\t%08X %08X | %08X %08X\n", 2*i, entry.safe_uid.values[2*i], entry.safe_uid.values[2*i+1], + safe_uid.values[2*i], safe_uid.values[2*i+1]); + PanicAlert(msg); + } + } + return pShaderLast; } // Make an entry in the table PSCacheEntry& newentry = PixelShaders[uid]; newentry.frameCount = frameCount; + newentry.safe_uid = safe_uid; pShaderLast = &newentry.shader; const char *code = GeneratePixelShaderCode(dstAlphaMode, API_OPENGL, components); + newentry.code = code; #if defined(_DEBUG) || defined(DEBUGFAST) if (g_ActiveConfig.iLog & CONF_SAVESHADERS && code) { diff --git a/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.h b/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.h index f404b206a2..63f71ddc13 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.h @@ -56,6 +56,8 @@ class PixelShaderCache { shader.Destroy(); } + PIXELSHADERUIDSAFE safe_uid; + std::string code; }; typedef std::map PSCache; From 98b62d836290ff0ea46f73a6f6bdb0d3c91df923 Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Wed, 7 Sep 2011 21:12:17 +0200 Subject: [PATCH 09/36] Track alpha blending paramaters in the pixel shader UID. --- Source/Core/VideoCommon/Src/PixelShaderGen.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp index 8bdfc3db28..46f139f105 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp @@ -170,6 +170,10 @@ void GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode) ptr += 4; // max: ptr = &uid->values[66] } + ptr[0] |= bpmem.alphaFunc.comp0; // 3 + ptr[0] |= bpmem.alphaFunc.comp1 << 3; // 3 + ptr[0] |= bpmem.alphaFunc.logic << 6; // 2 + if (alphaPreTest == 0 || alphaPreTest == 2) { ptr[0] |= bpmem.fog.c_proj_fsel.fsel << 8; // 3 From 6c7bda6851b39d358f9b951739156e07345ccfa4 Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Thu, 8 Sep 2011 02:09:44 +0200 Subject: [PATCH 10/36] Various fixes and cleanups. --- Source/Core/Common/Src/LinearDiskCache.h | 6 +- .../Core/VideoCommon/Src/PixelShaderGen.cpp | 152 ++---------------- Source/Core/VideoCommon/Src/PixelShaderGen.h | 35 ++-- .../Plugin_VideoDX11/Src/PixelShaderCache.h | 5 +- .../Plugin_VideoDX11/Src/VertexShaderCache.h | 4 +- 5 files changed, 40 insertions(+), 162 deletions(-) diff --git a/Source/Core/Common/Src/LinearDiskCache.h b/Source/Core/Common/Src/LinearDiskCache.h index 7a124aaa7b..a2f758b416 100644 --- a/Source/Core/Common/Src/LinearDiskCache.h +++ b/Source/Core/Common/Src/LinearDiskCache.h @@ -21,12 +21,10 @@ #include "Common.h" #include -// Update this to the current SVN revision every time you change shader generation code. -// We don't automatically get this from SVN_REV because that would mean regenerating the -// shader cache for every revision, graphics-related or not, which is simply annoying. +// Increment this every time you change shader generation code. enum { - LINEAR_DISKCACHE_VER = 6964 + LINEAR_DISKCACHE_VER = 6965 }; // On disk format: diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp index 46f139f105..464c16fa58 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp @@ -100,14 +100,16 @@ static void StageHash(int stage, u32* out) } } +// Mash together all the inputs that contribute to the code of a generated pixel shader into +// a unique identifier, basically containing all the bits. Yup, it's a lot .... +// It would likely be a lot more efficient to build this incrementally as the attributes +// are set... void GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode) { uid->values[0] |= bpmem.genMode.numtevstages; // 4 uid->values[0] |= bpmem.genMode.numtexgens << 4; // 4 uid->values[0] |= dstAlphaMode << 8; // 2 - uid->tevstages = bpmem.genMode.numtevstages; - bool DepthTextureEnable = (bpmem.ztex2.op != ZTEXTURE_DISABLE && !bpmem.zcontrol.zcomploc && bpmem.zmode.testenable && bpmem.zmode.updateenable) || g_ActiveConfig.bEnablePerPixelDepth; uid->values[0] |= DepthTextureEnable << 10; // 1 @@ -124,7 +126,7 @@ void GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode) { // Courtesy of PreAlphaTest, we're done already ;) // TODO: There's a comment including bpmem.genmode.numindstages.. shouldnt really bother about that though. - uid->tevstages = 1; + uid->num_values = 1; return; } @@ -141,8 +143,6 @@ void GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode) uid->values[1] |= xfregs.texMtxInfo[i].projection << (i - 14); // 1 } - uid->indstages = bpmem.genMode.numindstages; - uid->values[1] = bpmem.genMode.numindstages << 2; // 3 u32 indirectStagesUsed = 0; for (unsigned int i = 0; i < bpmem.genMode.numindstages; ++i) @@ -194,129 +194,7 @@ void GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode) ptr[0] |= bpmem.fogRange.Base.Enabled << 17; // 1 } } - uid->tevstages = (ptr+1) - uid->values; -} - -// Mash together all the inputs that contribute to the code of a generated pixel shader into -// a unique identifier, basically containing all the bits. Yup, it's a lot .... -// It would likely be a lot more efficient to build this incrementally as the attributes -// are set... -void _GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode) -{ - u32 numstages = bpmem.genMode.numtevstages + 1; - u32 projtexcoords = 0; - for (u32 i = 0; i < numstages; i++) - { - if (bpmem.tevorders[i/2].getEnable(i & 1)) - { - int texcoord = bpmem.tevorders[i / 2].getTexCoord(i & 1); - if (xfregs.texMtxInfo[i].projection) - projtexcoords |= 1 << texcoord; - } - } - uid->values[0] = (u32)bpmem.genMode.numtevstages | - ((u32)bpmem.genMode.numindstages << 4) | - ((u32)bpmem.genMode.numtexgens << 7) | - ((u32)dstAlphaMode << 11) | - ((u32)((bpmem.alphaFunc.hex >> 16) & 0xff) << 13) | - (projtexcoords << 21) | - ((u32)bpmem.ztex2.op << 29); - - // swap table - for (int i = 0; i < 8; i += 2) - ((u8*)&uid->values[1])[i / 2] = (bpmem.tevksel[i].hex & 0xf) | ((bpmem.tevksel[i + 1].hex & 0xf) << 4); - - u32 enableZTexture = (bpmem.ztex2.op != ZTEXTURE_DISABLE && !bpmem.zcontrol.zcomploc && bpmem.zmode.testenable && bpmem.zmode.updateenable) || g_ActiveConfig.bEnablePerPixelDepth ? 1 : 0; - - uid->values[2] = (u32)bpmem.fog.c_proj_fsel.fsel | - ((u32)bpmem.fog.c_proj_fsel.proj << 3) | - ((u32)enableZTexture << 4) | ((u32)bpmem.fogRange.Base.Enabled << 5); - - if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) - { - for (int i = 0; i < 2; ++i) { - uid->values[3 + i] = xfregs.color[i].enablelighting ? - (u32)xfregs.color[i].hex : - (u32)xfregs.color[i].matsource; - uid->values[3 + i] |= (xfregs.alpha[i].enablelighting ? - (u32)xfregs.alpha[i].hex : - (u32)xfregs.alpha[i].matsource) << 15; - } - } - uid->values[4] |= (g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) << 31; - - int hdr = 5; - u32 *pcurvalue = &uid->values[hdr]; - for (u32 i = 0; i < numstages; ++i) - { - TevStageCombiner::ColorCombiner &cc = bpmem.combiners[i].colorC; - TevStageCombiner::AlphaCombiner &ac = bpmem.combiners[i].alphaC; - - u32 val0 = cc.hex & 0xffffff; - u32 val1 = ac.hex & 0xffffff; - val0 |= bpmem.tevksel[i / 2].getKC(i & 1) << 24; - val1 |= bpmem.tevksel[i / 2].getKA(i & 1) << 24; - pcurvalue[0] = val0; - pcurvalue[1] = val1; - pcurvalue += 2; - } - - for (u32 i = 0; i < numstages / 2; ++i) - { - u32 val0, val1; - if (bpmem.tevorders[i].hex & 0x40) - val0 = bpmem.tevorders[i].hex & 0x3ff; - else - val0 = bpmem.tevorders[i].hex & 0x380; - if (bpmem.tevorders[i].hex & 0x40000) - val1 = (bpmem.tevorders[i].hex & 0x3ff000) >> 12; - else - val1 = (bpmem.tevorders[i].hex & 0x380000) >> 12; - - switch (i % 3) { - case 0: pcurvalue[0] = val0|(val1<<10); break; - case 1: pcurvalue[0] |= val0<<20; pcurvalue[1] = val1; pcurvalue++; break; - case 2: pcurvalue[1] |= (val0<<10)|(val1<<20); pcurvalue++; break; - default: PanicAlert("Unknown case for Tev Stages / 2: %08x", (i % 3)); - } - } - - if (numstages & 1) { // odd - u32 val0; - if (bpmem.tevorders[bpmem.genMode.numtevstages/2].hex & 0x40) - val0 = bpmem.tevorders[bpmem.genMode.numtevstages/2].hex & 0x3ff; - else - val0 = bpmem.tevorders[bpmem.genMode.numtevstages/2].hex & 0x380; - - switch (bpmem.genMode.numtevstages % 3) - { - case 0: pcurvalue[0] = val0; break; - case 1: pcurvalue[0] |= val0 << 20; break; - case 2: pcurvalue[1] |= val0 << 10; pcurvalue++; break; - default: PanicAlert("Unknown case for Tev Stages: %08x", bpmem.genMode.numtevstages % 3); - } - } - - if ((bpmem.genMode.numtevstages % 3) != 2) - ++pcurvalue; - - uid->tevstages = (u32)(pcurvalue - &uid->values[0] - hdr); - - for (u32 i = 0; i < bpmem.genMode.numindstages; ++i) - { - u32 val = bpmem.tevind[i].hex & 0x1fffff; // 21 bits - switch (i % 3) - { - case 0: pcurvalue[0] = val; break; - case 1: pcurvalue[0] |= val << 21; pcurvalue[1] = val >> 11; ++pcurvalue; break; - case 2: pcurvalue[0] |= val << 10; ++pcurvalue; break; - default: PanicAlert("Unknown case for Ind Stages: %08x", (i % 3)); - } - } - - // yeah, well .... - uid->indstages = (u32)(pcurvalue - &uid->values[0] - (hdr - 1) - uid->tevstages); - + uid->num_values = (ptr+1) - uid->values; } void GetSafePixelShaderId(PIXELSHADERUIDSAFE *uid, DSTALPHA_MODE dstAlphaMode) @@ -346,19 +224,21 @@ void GetSafePixelShaderId(PIXELSHADERUIDSAFE *uid, DSTALPHA_MODE dstAlphaMode) for (int i = 0; i < bpmem.genMode.numtevstages+1; ++i) // up to 16 times { - // TODO ... - StageHash(i, ptr); - ptr += 4; // max: ptr = &uid->values[33+63] + *ptr++ = bpmem.combiners[i].colorC.hex; // 33+5*i + *ptr++ = bpmem.combiners[i].alphaC.hex; // 34+5*i + *ptr++ = bpmem.tevind[i].hex; // 35+5*i + *ptr++ = bpmem.tevksel[i/2].hex; // 36+5*i + *ptr++ = bpmem.tevorders[i/2].hex; // 37+5*i } - ptr = &uid->values[97]; + ptr = &uid->values[113]; - *ptr++ = bpmem.alphaFunc.hex; // 97 + *ptr++ = bpmem.alphaFunc.hex; // 113 - *ptr++ = bpmem.fog.c_proj_fsel.hex; // 98 - *ptr++ = bpmem.fogRange.Base.hex; // 99 + *ptr++ = bpmem.fog.c_proj_fsel.hex; // 114 + *ptr++ = bpmem.fogRange.Base.hex; // 115 - _assert_((ptr - uid->values) <= uid->GetNumValues()); + _assert_((ptr - uid->values) == uid->GetNumValues()); } diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.h b/Source/Core/VideoCommon/Src/PixelShaderGen.h index c66635e12b..d20f43c711 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderGen.h +++ b/Source/Core/VideoCommon/Src/PixelShaderGen.h @@ -45,7 +45,7 @@ #define C_PMATERIALS (C_PLIGHTS + 40) #define C_PENVCONST_END (C_PMATERIALS + 4) #define PIXELSHADERUID_MAX_VALUES 67 -#define PIXELSHADERUID_MAX_VALUES_SAFE 100 +#define PIXELSHADERUID_MAX_VALUES_SAFE 115 // DO NOT make anything in this class virtual. template @@ -53,38 +53,37 @@ class _PIXELSHADERUID { public: u32 values[safe ? PIXELSHADERUID_MAX_VALUES_SAFE : PIXELSHADERUID_MAX_VALUES]; - u16 tevstages, indstages; + u16 num_values; _PIXELSHADERUID() { memset(values, 0, sizeof(values)); - tevstages = indstages = 0; + + if (safe) num_values = sizeof(values) / sizeof(values[0]); + else num_values = 0; } _PIXELSHADERUID(const _PIXELSHADERUID& r) { - tevstages = r.tevstages; - indstages = r.indstages; - int N = GetNumValues(); - _assert_(N <= GetNumValues()); - for (int i = 0; i < N; ++i) - values[i] = r.values[i]; + num_values = r.num_values; + if (safe) memcpy(values, r.values, PIXELSHADERUID_MAX_VALUES_SAFE); + else memcpy(values, r.values, r.GetNumValues() * sizeof(values[0])); } int GetNumValues() const { if (safe) return (sizeof(values) / sizeof(u32)); - else return tevstages; + else return num_values; } bool operator <(const _PIXELSHADERUID& _Right) const { - if (values[0] < _Right.values[0]) - return true; - else if (values[0] > _Right.values[0]) - return false; int N = GetNumValues(); - for (int i = 1; i < N; ++i) + if (N < _Right.GetNumValues()) + return true; + else if (N > _Right.GetNumValues()) + return false; + for (int i = 0; i < N; ++i) { if (values[i] < _Right.values[i]) return true; @@ -96,10 +95,10 @@ public: bool operator ==(const _PIXELSHADERUID& _Right) const { - if (values[0] != _Right.values[0]) - return false; int N = GetNumValues(); - for (int i = 1; i < N; ++i) + if (N != _Right.GetNumValues()) + return false; + for (int i = 0; i < N; ++i) { if (values[i] != _Right.values[i]) return false; diff --git a/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.h b/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.h index 046f551657..3b9c537a7a 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.h +++ b/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.h @@ -17,11 +17,12 @@ #pragma once -#include +#include "PixelShaderGen.h" #include -class PIXELSHADERUID; +#include + enum DSTALPHA_MODE; namespace DX11 diff --git a/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.h b/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.h index 3c7dadd3e7..24be4e6c1c 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.h +++ b/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.h @@ -18,12 +18,12 @@ #ifndef _VERTEXSHADERCACHE_H #define _VERTEXSHADERCACHE_H -#include +#include "VertexShaderGen.h" #include "D3DBase.h" #include "D3DBlob.h" -class VERTEXSHADERUID; +#include namespace DX11 { From b28348066e083d532d5ab62c93ce0f1dc5c217ed Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Fri, 9 Sep 2011 00:32:04 +0200 Subject: [PATCH 11/36] Improve the shader UID debugging stuff and merge it to VideoCommon, effectively enabling it in D3D9 and D3D11 as well. --- Source/Core/Common/Src/MsgHandler.cpp | 2 +- .../Core/VideoCommon/Src/PixelShaderGen.cpp | 45 +- Source/Core/VideoCommon/Src/PixelShaderGen.h | 3 + .../Core/VideoCommon/Src/VertexShaderGen.cpp | 968 +++++++++--------- Source/Core/VideoCommon/Src/VertexShaderGen.h | 4 + .../Plugin_VideoDX11/Src/PixelShaderCache.cpp | 13 +- .../Plugin_VideoDX11/Src/PixelShaderCache.h | 3 + .../Src/VertexShaderCache.cpp | 13 +- .../Plugin_VideoDX11/Src/VertexShaderCache.h | 3 + .../Plugin_VideoDX9/Src/PixelShaderCache.cpp | 13 +- .../Plugin_VideoDX9/Src/PixelShaderCache.h | 3 + .../Plugin_VideoDX9/Src/VertexShaderCache.cpp | 11 +- .../Plugin_VideoDX9/Src/VertexShaderCache.h | 5 +- .../Plugin_VideoOGL/Src/PixelShaderCache.cpp | 41 +- .../Plugin_VideoOGL/Src/VertexShaderCache.cpp | 9 +- .../Plugin_VideoOGL/Src/VertexShaderCache.h | 5 +- 16 files changed, 614 insertions(+), 527 deletions(-) diff --git a/Source/Core/Common/Src/MsgHandler.cpp b/Source/Core/Common/Src/MsgHandler.cpp index 17c40d76f8..7c666227aa 100644 --- a/Source/Core/Common/Src/MsgHandler.cpp +++ b/Source/Core/Common/Src/MsgHandler.cpp @@ -53,7 +53,7 @@ bool MsgAlert(bool yes_no, int Style, const char* format, ...) { // Read message and write it to the log std::string caption; - char buffer[4096]; + char buffer[2048]; static std::string info_caption; static std::string warn_caption; diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp index 8aa3a0a56e..25007be93b 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp @@ -241,6 +241,39 @@ void GetSafePixelShaderId(PIXELSHADERUIDSAFE *uid, DSTALPHA_MODE dstAlphaMode) _assert_((ptr - uid->values) == uid->GetNumValues()); } +void ValidatePixelShaderIDs(API_TYPE api, PIXELSHADERUIDSAFE old_id, const std::string& old_code, DSTALPHA_MODE dstAlphaMode, u32 components) +{ + PIXELSHADERUIDSAFE new_id; + GetSafePixelShaderId(&new_id, dstAlphaMode); + + if (!(old_id == new_id)) + { + std::string new_code(GeneratePixelShaderCode(dstAlphaMode, api, components)); + if (old_code != new_code) + { + _assert_(old_id.GetNumValues() == new_id.GetNumValues()); + + char msg[8192]; + char* ptr = msg; + ptr += sprintf(ptr, "Pixel shader IDs matched but unique IDs did not!\nUnique IDs (old <-> new):\n"); + const int N = new_id.GetNumValues(); + for (int i = 0; i < N/2; ++i) + ptr += sprintf(ptr, "%02d, %08X %08X | %08X %08X\n", 2*i, old_id.values[2*i], old_id.values[2*i+1], + new_id.values[2*i], new_id.values[2*i+1]); + if (N % 2) + ptr += sprintf(ptr, "%02d, %08X | %08X\n", N-1, old_id.values[N-1], new_id.values[N-1]); + + static int num_failures = 0; + char szTemp[MAX_PATH]; + sprintf(szTemp, "%spsuid_mismatch_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++); + std::ofstream file(szTemp); + file << msg; + file.close(); + + PanicAlert("Unique pixel shader ID mismatch!\n\nReport this to the devs, along with the contents of %s.", szTemp); + } + } +} // old tev->pixelshader notes // @@ -594,12 +627,12 @@ const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType WRITE(p, " float4 c0 = "I_COLORS"[1], c1 = "I_COLORS"[2], c2 = "I_COLORS"[3], prev = float4(0.0f, 0.0f, 0.0f, 0.0f), textemp = float4(0.0f, 0.0f, 0.0f, 0.0f), rastemp = float4(0.0f, 0.0f, 0.0f, 0.0f), konsttemp = float4(0.0f, 0.0f, 0.0f, 0.0f);\n" " float3 comp16 = float3(1.0f, 255.0f, 0.0f), comp24 = float3(1.0f, 255.0f, 255.0f*255.0f);\n" - " float4 alphabump=float4(0.0f,0.0f,0.0f,0.0f);\n" - " float3 tevcoord=float3(0.0f, 0.0f, 0.0f);\n" - " float2 wrappedcoord=float2(0.0f,0.0f), tempcoord=float2(0.0f,0.0f);\n" - " float4 cc0=float4(0.0f,0.0f,0.0f,0.0f), cc1=float4(0.0f,0.0f,0.0f,0.0f);\n" - " float4 cc2=float4(0.0f,0.0f,0.0f,0.0f), cprev=float4(0.0f,0.0f,0.0f,0.0f);\n" - " float4 crastemp=float4(0.0f,0.0f,0.0f,0.0f),ckonsttemp=float4(0.0f,0.0f,0.0f,0.0f);\n\n"); + " float4 alphabump=float4(0.0f,0.0f,0.0f,0.0f);\n" + " float3 tevcoord=float3(0.0f, 0.0f, 0.0f);\n" + " float2 wrappedcoord=float2(0.0f,0.0f), tempcoord=float2(0.0f,0.0f);\n" + " float4 cc0=float4(0.0f,0.0f,0.0f,0.0f), cc1=float4(0.0f,0.0f,0.0f,0.0f);\n" + " float4 cc2=float4(0.0f,0.0f,0.0f,0.0f), cprev=float4(0.0f,0.0f,0.0f,0.0f);\n" + " float4 crastemp=float4(0.0f,0.0f,0.0f,0.0f),ckonsttemp=float4(0.0f,0.0f,0.0f,0.0f);\n\n"); if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) { diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.h b/Source/Core/VideoCommon/Src/PixelShaderGen.h index d20f43c711..8031fdfbb2 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderGen.h +++ b/Source/Core/VideoCommon/Src/PixelShaderGen.h @@ -123,6 +123,9 @@ const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType void GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode); void GetSafePixelShaderId(PIXELSHADERUIDSAFE *uid, DSTALPHA_MODE dstAlphaMode); +// Used to make sure that our optimized pixel shader IDs don't lose any possible shader code changes +void ValidatePixelShaderIDs(API_TYPE api, PIXELSHADERUIDSAFE old_id, const std::string& old_code, DSTALPHA_MODE dstAlphaMode, u32 components); + extern PIXELSHADERUID last_pixel_shader_uid; #endif // GCOGL_PIXELSHADER_H diff --git a/Source/Core/VideoCommon/Src/VertexShaderGen.cpp b/Source/Core/VideoCommon/Src/VertexShaderGen.cpp index d15cef0c70..902f645bec 100644 --- a/Source/Core/VideoCommon/Src/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/VertexShaderGen.cpp @@ -1,466 +1,502 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include -#include - -#include "NativeVertexFormat.h" - -#include "BPMemory.h" -#include "CPMemory.h" -#include "LightingShaderGen.h" -#include "VertexShaderGen.h" -#include "VideoConfig.h" - -VERTEXSHADERUID last_vertex_shader_uid; - -// Mash together all the inputs that contribute to the code of a generated vertex shader into -// a unique identifier, basically containing all the bits. Yup, it's a lot .... -void GetVertexShaderId(VERTEXSHADERUID *uid, u32 components) -{ - uid->values[0] = components | - (xfregs.numTexGen.numTexGens << 23) | - (xfregs.numChan.numColorChans << 27) | - (xfregs.dualTexTrans.enabled << 29); - - for (int i = 0; i < xfregs.numChan.numColorChans; ++i) { - uid->values[1+i] = xfregs.color[i].enablelighting ? - (u32)xfregs.color[i].hex : - (u32)xfregs.color[i].matsource; - uid->values[1+i] |= (xfregs.alpha[i].enablelighting ? - (u32)xfregs.alpha[i].hex : - (u32)xfregs.alpha[i].matsource) << 15; - } - uid->values[2] |= (g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) << 31; - u32 *pcurvalue = &uid->values[3]; - for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i) { - TexMtxInfo tinfo = xfregs.texMtxInfo[i]; - if (tinfo.texgentype != XF_TEXGEN_EMBOSS_MAP) - tinfo.hex &= 0x7ff; - if (tinfo.texgentype != XF_TEXGEN_REGULAR) - tinfo.projection = 0; - - u32 val = ((tinfo.hex >> 1) & 0x1ffff); - if (xfregs.dualTexTrans.enabled && tinfo.texgentype == XF_TEXGEN_REGULAR) { - // rewrite normalization and post index - val |= ((u32)xfregs.postMtxInfo[i].index << 17) | ((u32)xfregs.postMtxInfo[i].normalize << 23); - } - - switch (i & 3) { - case 0: pcurvalue[0] |= val; break; - case 1: pcurvalue[0] |= val << 24; pcurvalue[1] = val >> 8; ++pcurvalue; break; - case 2: pcurvalue[0] |= val << 16; pcurvalue[1] = val >> 16; ++pcurvalue; break; - case 3: pcurvalue[0] |= val << 8; ++pcurvalue; break; - } - } -} - -void GetSafeVertexShaderId(VERTEXSHADERUIDSAFE *uid, u32 components) -{ - // Just store all used registers here without caring whether we need all bits or less. - u32* ptr = uid->values; - *ptr++ = components; - *ptr++ = xfregs.numTexGen.hex; - *ptr++ = xfregs.numChan.hex; - *ptr++ = xfregs.dualTexTrans.hex; - - for (int i = 0; i < 2; ++i) { - *ptr++ = xfregs.color[i].hex; - *ptr++ = xfregs.alpha[i].hex; - } - *ptr++ = g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting; - for (unsigned int i = 0; i < 8; ++i) { - *ptr++ = xfregs.texMtxInfo[i].hex; - *ptr++ = xfregs.postMtxInfo[i].hex; - } - _assert_((ptr - uid->values) == uid->GetNumValues()); -} - -static char text[16384]; - -#define WRITE p+=sprintf - -char* GenerateVSOutputStruct(char* p, u32 components, API_TYPE api_type) -{ - WRITE(p, "struct VS_OUTPUT {\n"); - WRITE(p, " float4 pos : POSITION;\n"); - WRITE(p, " float4 colors_0 : COLOR0;\n"); - WRITE(p, " float4 colors_1 : COLOR1;\n"); - - if (xfregs.numTexGen.numTexGens < 7) { - for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i) - WRITE(p, " float3 tex%d : TEXCOORD%d;\n", i, i); - WRITE(p, " float4 clipPos : TEXCOORD%d;\n", xfregs.numTexGen.numTexGens); - if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) - WRITE(p, " float4 Normal : TEXCOORD%d;\n", xfregs.numTexGen.numTexGens + 1); - } else { - // clip position is in w of first 4 texcoords - if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) - { - for (int i = 0; i < 8; ++i) - WRITE(p, " float4 tex%d : TEXCOORD%d;\n", i, i); - } - else - { - for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i) - WRITE(p, " float%d tex%d : TEXCOORD%d;\n", i < 4 ? 4 : 3 , i, i); - } - } - WRITE(p, "};\n"); - - return p; -} - -const char *GenerateVertexShaderCode(u32 components, API_TYPE api_type) -{ - setlocale(LC_NUMERIC, "C"); // Reset locale for compilation - text[sizeof(text) - 1] = 0x7C; // canary - - _assert_(bpmem.genMode.numtexgens == xfregs.numTexGen.numTexGens); - _assert_(bpmem.genMode.numcolchans == xfregs.numChan.numColorChans); - - bool is_d3d = (api_type & API_D3D9 || api_type == API_D3D11); - u32 lightMask = 0; - if (xfregs.numChan.numColorChans > 0) - lightMask |= xfregs.color[0].GetFullLightMask() | xfregs.alpha[0].GetFullLightMask(); - if (xfregs.numChan.numColorChans > 1) - lightMask |= xfregs.color[1].GetFullLightMask() | xfregs.alpha[1].GetFullLightMask(); - - char *p = text; - WRITE(p, "//Vertex Shader: comp:%x, \n", components); - WRITE(p, "typedef struct { float4 T0, T1, T2; float4 N0, N1, N2; } s_"I_POSNORMALMATRIX";\n" - "typedef struct { float4 t; } FLT4;\n" - "typedef struct { FLT4 T[24]; } s_"I_TEXMATRICES";\n" - "typedef struct { FLT4 T[64]; } s_"I_TRANSFORMMATRICES";\n" - "typedef struct { FLT4 T[32]; } s_"I_NORMALMATRICES";\n" - "typedef struct { FLT4 T[64]; } s_"I_POSTTRANSFORMMATRICES";\n" - "typedef struct { float4 col; float4 cosatt; float4 distatt; float4 pos; float4 dir; } Light;\n" - "typedef struct { Light lights[8]; } s_"I_LIGHTS";\n" - "typedef struct { float4 C0, C1, C2, C3; } s_"I_MATERIALS";\n" - "typedef struct { float4 T0, T1, T2, T3; } s_"I_PROJECTION";\n" - ); - - p = GenerateVSOutputStruct(p, components, api_type); - - // uniforms - - WRITE(p, "uniform s_"I_TRANSFORMMATRICES" "I_TRANSFORMMATRICES" : register(c%d);\n", C_TRANSFORMMATRICES); - WRITE(p, "uniform s_"I_TEXMATRICES" "I_TEXMATRICES" : register(c%d);\n", C_TEXMATRICES); // also using tex matrices - WRITE(p, "uniform s_"I_NORMALMATRICES" "I_NORMALMATRICES" : register(c%d);\n", C_NORMALMATRICES); - WRITE(p, "uniform s_"I_POSNORMALMATRIX" "I_POSNORMALMATRIX" : register(c%d);\n", C_POSNORMALMATRIX); - WRITE(p, "uniform s_"I_POSTTRANSFORMMATRICES" "I_POSTTRANSFORMMATRICES" : register(c%d);\n", C_POSTTRANSFORMMATRICES); - WRITE(p, "uniform s_"I_LIGHTS" "I_LIGHTS" : register(c%d);\n", C_LIGHTS); - WRITE(p, "uniform s_"I_MATERIALS" "I_MATERIALS" : register(c%d);\n", C_MATERIALS); - WRITE(p, "uniform s_"I_PROJECTION" "I_PROJECTION" : register(c%d);\n", C_PROJECTION); - WRITE(p, "uniform float4 "I_DEPTHPARAMS" : register(c%d);\n", C_DEPTHPARAMS); - - WRITE(p, "VS_OUTPUT main(\n"); - - // inputs - if (components & VB_HAS_NRM0) - WRITE(p, " float3 rawnorm0 : NORMAL0,\n"); - if (components & VB_HAS_NRM1) { - if (is_d3d) - WRITE(p, " float3 rawnorm1 : NORMAL1,\n"); - else - WRITE(p, " float3 rawnorm1 : ATTR%d,\n", SHADER_NORM1_ATTRIB); - } - if (components & VB_HAS_NRM2) { - if (is_d3d) - WRITE(p, " float3 rawnorm2 : NORMAL2,\n"); - else - WRITE(p, " float3 rawnorm2 : ATTR%d,\n", SHADER_NORM2_ATTRIB); - } - if (components & VB_HAS_COL0) - WRITE(p, " float4 color0 : COLOR0,\n"); - if (components & VB_HAS_COL1) - WRITE(p, " float4 color1 : COLOR1,\n"); - for (int i = 0; i < 8; ++i) { - u32 hastexmtx = (components & (VB_HAS_TEXMTXIDX0<= 32 ? (posmtx-32) : posmtx;\n"); - WRITE(p, "float3 N0 = "I_NORMALMATRICES".T[normidx].t.xyz, N1 = "I_NORMALMATRICES".T[normidx+1].t.xyz, N2 = "I_NORMALMATRICES".T[normidx+2].t.xyz;\n"); - } - - if (components & VB_HAS_NRM0) - WRITE(p, "float3 _norm0 = normalize(float3(dot(N0, rawnorm0), dot(N1, rawnorm0), dot(N2, rawnorm0)));\n"); - if (components & VB_HAS_NRM1) - WRITE(p, "float3 _norm1 = float3(dot(N0, rawnorm1), dot(N1, rawnorm1), dot(N2, rawnorm1));\n"); - if (components & VB_HAS_NRM2) - WRITE(p, "float3 _norm2 = float3(dot(N0, rawnorm2), dot(N1, rawnorm2), dot(N2, rawnorm2));\n"); - } - else - { - WRITE(p, "float4 pos = float4(dot("I_POSNORMALMATRIX".T0, rawpos), dot("I_POSNORMALMATRIX".T1, rawpos), dot("I_POSNORMALMATRIX".T2, rawpos), 1.0f);\n"); - if (components & VB_HAS_NRM0) - WRITE(p, "float3 _norm0 = normalize(float3(dot("I_POSNORMALMATRIX".N0.xyz, rawnorm0), dot("I_POSNORMALMATRIX".N1.xyz, rawnorm0), dot("I_POSNORMALMATRIX".N2.xyz, rawnorm0)));\n"); - if (components & VB_HAS_NRM1) - WRITE(p, "float3 _norm1 = float3(dot("I_POSNORMALMATRIX".N0.xyz, rawnorm1), dot("I_POSNORMALMATRIX".N1.xyz, rawnorm1), dot("I_POSNORMALMATRIX".N2.xyz, rawnorm1));\n"); - if (components & VB_HAS_NRM2) - WRITE(p, "float3 _norm2 = float3(dot("I_POSNORMALMATRIX".N0.xyz, rawnorm2), dot("I_POSNORMALMATRIX".N1.xyz, rawnorm2), dot("I_POSNORMALMATRIX".N2.xyz, rawnorm2));\n"); - } - - if (!(components & VB_HAS_NRM0)) - WRITE(p, "float3 _norm0 = float3(0.0f, 0.0f, 0.0f);\n"); - - - - WRITE(p, "o.pos = float4(dot("I_PROJECTION".T0, pos), dot("I_PROJECTION".T1, pos), dot("I_PROJECTION".T2, pos), dot("I_PROJECTION".T3, pos));\n"); - - WRITE(p, "float4 mat, lacc;\n" - "float3 ldir, h;\n" - "float dist, dist2, attn;\n"); - - if(xfregs.numChan.numColorChans == 0) - { - if (components & VB_HAS_COL0) - WRITE(p, "o.colors_0 = color0;\n"); - else - WRITE(p, "o.colors_0 = float4(1.0f, 1.0f, 1.0f, 1.0f);\n"); - } - - p = GenerateLightingShader(p, components, I_MATERIALS, I_LIGHTS, "color", "o.colors_"); - - if(xfregs.numChan.numColorChans < 2) - { - if (components & VB_HAS_COL1) - WRITE(p, "o.colors_1 = color1;\n"); - else - WRITE(p, "o.colors_1 = o.colors_0;\n"); - } - // special case if only pos and tex coord 0 and tex coord input is AB11 - // donko - this has caused problems in some games. removed for now. - bool texGenSpecialCase = false; - /*bool texGenSpecialCase = - ((g_VtxDesc.Hex & 0x60600L) == g_VtxDesc.Hex) && // only pos and tex coord 0 - (g_VtxDesc.Tex0Coord != NOT_PRESENT) && - (xfregs.texcoords[0].texmtxinfo.inputform == XF_TEXINPUT_AB11); - */ - - // transform texcoords - WRITE(p, "float4 coord = float4(0.0f, 0.0f, 1.0f, 1.0f);\n"); - for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i) { - TexMtxInfo& texinfo = xfregs.texMtxInfo[i]; - - WRITE(p, "{\n"); - WRITE(p, "coord = float4(0.0f, 0.0f, 1.0f, 1.0f);\n"); - switch (texinfo.sourcerow) { - case XF_SRCGEOM_INROW: - _assert_( texinfo.inputform == XF_TEXINPUT_ABC1 ); - WRITE(p, "coord = rawpos;\n"); // pos.w is 1 - break; - case XF_SRCNORMAL_INROW: - if (components & VB_HAS_NRM0) { - _assert_( texinfo.inputform == XF_TEXINPUT_ABC1 ); - WRITE(p, "coord = float4(rawnorm0.xyz, 1.0f);\n"); - } - break; - case XF_SRCCOLORS_INROW: - _assert_( texinfo.texgentype == XF_TEXGEN_COLOR_STRGBC0 || texinfo.texgentype == XF_TEXGEN_COLOR_STRGBC1 ); - break; - case XF_SRCBINORMAL_T_INROW: - if (components & VB_HAS_NRM1) { - _assert_( texinfo.inputform == XF_TEXINPUT_ABC1 ); - WRITE(p, "coord = float4(rawnorm1.xyz, 1.0f);\n"); - } - break; - case XF_SRCBINORMAL_B_INROW: - if (components & VB_HAS_NRM2) { - _assert_( texinfo.inputform == XF_TEXINPUT_ABC1 ); - WRITE(p, "coord = float4(rawnorm2.xyz, 1.0f);\n"); - } - break; - default: - _assert_(texinfo.sourcerow <= XF_SRCTEX7_INROW); - if (components & (VB_HAS_UV0<<(texinfo.sourcerow - XF_SRCTEX0_INROW)) ) - WRITE(p, "coord = float4(tex%d.x, tex%d.y, 1.0f, 1.0f);\n", texinfo.sourcerow - XF_SRCTEX0_INROW, texinfo.sourcerow - XF_SRCTEX0_INROW); - break; - } - - // first transformation - switch (texinfo.texgentype) { - case XF_TEXGEN_EMBOSS_MAP: // calculate tex coords into bump map - - if (components & (VB_HAS_NRM1|VB_HAS_NRM2)) { - // transform the light dir into tangent space - WRITE(p, "ldir = normalize("I_LIGHTS".lights[%d].pos.xyz - pos.xyz);\n", texinfo.embosslightshift); - WRITE(p, "o.tex%d.xyz = o.tex%d.xyz + float3(dot(ldir, _norm1), dot(ldir, _norm2), 0.0f);\n", i, texinfo.embosssourceshift); - } - else - { - _assert_(0); // should have normals - WRITE(p, "o.tex%d.xyz = o.tex%d.xyz;\n", i, texinfo.embosssourceshift); - } - - break; - case XF_TEXGEN_COLOR_STRGBC0: - _assert_(texinfo.sourcerow == XF_SRCCOLORS_INROW); - WRITE(p, "o.tex%d.xyz = float3(o.colors_0.x, o.colors_0.y, 1);\n", i); - break; - case XF_TEXGEN_COLOR_STRGBC1: - _assert_(texinfo.sourcerow == XF_SRCCOLORS_INROW); - WRITE(p, "o.tex%d.xyz = float3(o.colors_1.x, o.colors_1.y, 1);\n", i); - break; - case XF_TEXGEN_REGULAR: - default: - if (components & (VB_HAS_TEXMTXIDX0< +#include + +#include "NativeVertexFormat.h" + +#include "BPMemory.h" +#include "CPMemory.h" +#include "LightingShaderGen.h" +#include "VertexShaderGen.h" +#include "VideoConfig.h" + +VERTEXSHADERUID last_vertex_shader_uid; + +// Mash together all the inputs that contribute to the code of a generated vertex shader into +// a unique identifier, basically containing all the bits. Yup, it's a lot .... +void GetVertexShaderId(VERTEXSHADERUID *uid, u32 components) +{ + uid->values[0] = components | + (xfregs.numTexGen.numTexGens << 23) | + (xfregs.numChan.numColorChans << 27) | + (xfregs.dualTexTrans.enabled << 29); + + for (int i = 0; i < xfregs.numChan.numColorChans; ++i) { + uid->values[1+i] = xfregs.color[i].enablelighting ? + (u32)xfregs.color[i].hex : + (u32)xfregs.color[i].matsource; + uid->values[1+i] |= (xfregs.alpha[i].enablelighting ? + (u32)xfregs.alpha[i].hex : + (u32)xfregs.alpha[i].matsource) << 15; + } + uid->values[2] |= (g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) << 31; + u32 *pcurvalue = &uid->values[3]; + for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i) { + TexMtxInfo tinfo = xfregs.texMtxInfo[i]; + if (tinfo.texgentype != XF_TEXGEN_EMBOSS_MAP) + tinfo.hex &= 0x7ff; + if (tinfo.texgentype != XF_TEXGEN_REGULAR) + tinfo.projection = 0; + + u32 val = ((tinfo.hex >> 1) & 0x1ffff); + if (xfregs.dualTexTrans.enabled && tinfo.texgentype == XF_TEXGEN_REGULAR) { + // rewrite normalization and post index + val |= ((u32)xfregs.postMtxInfo[i].index << 17) | ((u32)xfregs.postMtxInfo[i].normalize << 23); + } + + switch (i & 3) { + case 0: pcurvalue[0] |= val; break; + case 1: pcurvalue[0] |= val << 24; pcurvalue[1] = val >> 8; ++pcurvalue; break; + case 2: pcurvalue[0] |= val << 16; pcurvalue[1] = val >> 16; ++pcurvalue; break; + case 3: pcurvalue[0] |= val << 8; ++pcurvalue; break; + } + } +} + +void GetSafeVertexShaderId(VERTEXSHADERUIDSAFE *uid, u32 components) +{ + // Just store all used registers here without caring whether we need all bits or less. + u32* ptr = uid->values; + *ptr++ = components; + *ptr++ = xfregs.numTexGen.hex; + *ptr++ = xfregs.numChan.hex; + *ptr++ = xfregs.dualTexTrans.hex; + + for (int i = 0; i < 2; ++i) { + *ptr++ = xfregs.color[i].hex; + *ptr++ = xfregs.alpha[i].hex; + } + *ptr++ = g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting; + for (unsigned int i = 0; i < 8; ++i) { + *ptr++ = xfregs.texMtxInfo[i].hex; + *ptr++ = xfregs.postMtxInfo[i].hex; + } + _assert_((ptr - uid->values) == uid->GetNumValues()); +} + + +void ValidateVertexShaderIDs(API_TYPE api, VERTEXSHADERUIDSAFE old_id, const std::string& old_code, u32 components) +{ + VERTEXSHADERUIDSAFE new_id; + GetSafeVertexShaderId(&new_id, components); + + if (!(old_id == new_id)) + { + std::string new_code(GenerateVertexShaderCode(components, api)); + if (old_code != new_code) + { + _assert_(old_id.GetNumValues() == new_id.GetNumValues()); + + char msg[8192]; + char* ptr = msg; + ptr += sprintf(ptr, "Vertex shader IDs matched but unique IDs did not!\nUnique IDs (old <-> new):\n"); + const int N = new_id.GetNumValues(); + for (int i = 0; i < N/2; ++i) + ptr += sprintf(ptr, "%02d, %08X %08X | %08X %08X\n", 2*i, old_id.values[2*i], old_id.values[2*i+1], + new_id.values[2*i], new_id.values[2*i+1]); + if (N % 2) + ptr += sprintf(ptr, "%02d, %08X | %08X\n", N-1, old_id.values[N-1], new_id.values[N-1]); + + static int num_failures = 0; + char szTemp[MAX_PATH]; + sprintf(szTemp, "%svsuid_mismatch_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++); + std::ofstream file(szTemp); + file << msg; + file.close(); + + PanicAlert("Unique pixel shader ID mismatch!\n\nReport this to the devs, along with the contents of %s.", szTemp); + } + } +} + + +static char text[16384]; + +#define WRITE p+=sprintf + +char* GenerateVSOutputStruct(char* p, u32 components, API_TYPE api_type) +{ + WRITE(p, "struct VS_OUTPUT {\n"); + WRITE(p, " float4 pos : POSITION;\n"); + WRITE(p, " float4 colors_0 : COLOR0;\n"); + WRITE(p, " float4 colors_1 : COLOR1;\n"); + + if (xfregs.numTexGen.numTexGens < 7) { + for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i) + WRITE(p, " float3 tex%d : TEXCOORD%d;\n", i, i); + WRITE(p, " float4 clipPos : TEXCOORD%d;\n", xfregs.numTexGen.numTexGens); + if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) + WRITE(p, " float4 Normal : TEXCOORD%d;\n", xfregs.numTexGen.numTexGens + 1); + } else { + // clip position is in w of first 4 texcoords + if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) + { + for (int i = 0; i < 8; ++i) + WRITE(p, " float4 tex%d : TEXCOORD%d;\n", i, i); + } + else + { + for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i) + WRITE(p, " float%d tex%d : TEXCOORD%d;\n", i < 4 ? 4 : 3 , i, i); + } + } + WRITE(p, "};\n"); + + return p; +} + +const char *GenerateVertexShaderCode(u32 components, API_TYPE api_type) +{ + setlocale(LC_NUMERIC, "C"); // Reset locale for compilation + text[sizeof(text) - 1] = 0x7C; // canary + + _assert_(bpmem.genMode.numtexgens == xfregs.numTexGen.numTexGens); + _assert_(bpmem.genMode.numcolchans == xfregs.numChan.numColorChans); + + bool is_d3d = (api_type & API_D3D9 || api_type == API_D3D11); + u32 lightMask = 0; + if (xfregs.numChan.numColorChans > 0) + lightMask |= xfregs.color[0].GetFullLightMask() | xfregs.alpha[0].GetFullLightMask(); + if (xfregs.numChan.numColorChans > 1) + lightMask |= xfregs.color[1].GetFullLightMask() | xfregs.alpha[1].GetFullLightMask(); + + char *p = text; + WRITE(p, "//Vertex Shader: comp:%x, \n", components); + WRITE(p, "typedef struct { float4 T0, T1, T2; float4 N0, N1, N2; } s_"I_POSNORMALMATRIX";\n" + "typedef struct { float4 t; } FLT4;\n" + "typedef struct { FLT4 T[24]; } s_"I_TEXMATRICES";\n" + "typedef struct { FLT4 T[64]; } s_"I_TRANSFORMMATRICES";\n" + "typedef struct { FLT4 T[32]; } s_"I_NORMALMATRICES";\n" + "typedef struct { FLT4 T[64]; } s_"I_POSTTRANSFORMMATRICES";\n" + "typedef struct { float4 col; float4 cosatt; float4 distatt; float4 pos; float4 dir; } Light;\n" + "typedef struct { Light lights[8]; } s_"I_LIGHTS";\n" + "typedef struct { float4 C0, C1, C2, C3; } s_"I_MATERIALS";\n" + "typedef struct { float4 T0, T1, T2, T3; } s_"I_PROJECTION";\n" + ); + + p = GenerateVSOutputStruct(p, components, api_type); + + // uniforms + + WRITE(p, "uniform s_"I_TRANSFORMMATRICES" "I_TRANSFORMMATRICES" : register(c%d);\n", C_TRANSFORMMATRICES); + WRITE(p, "uniform s_"I_TEXMATRICES" "I_TEXMATRICES" : register(c%d);\n", C_TEXMATRICES); // also using tex matrices + WRITE(p, "uniform s_"I_NORMALMATRICES" "I_NORMALMATRICES" : register(c%d);\n", C_NORMALMATRICES); + WRITE(p, "uniform s_"I_POSNORMALMATRIX" "I_POSNORMALMATRIX" : register(c%d);\n", C_POSNORMALMATRIX); + WRITE(p, "uniform s_"I_POSTTRANSFORMMATRICES" "I_POSTTRANSFORMMATRICES" : register(c%d);\n", C_POSTTRANSFORMMATRICES); + WRITE(p, "uniform s_"I_LIGHTS" "I_LIGHTS" : register(c%d);\n", C_LIGHTS); + WRITE(p, "uniform s_"I_MATERIALS" "I_MATERIALS" : register(c%d);\n", C_MATERIALS); + WRITE(p, "uniform s_"I_PROJECTION" "I_PROJECTION" : register(c%d);\n", C_PROJECTION); + WRITE(p, "uniform float4 "I_DEPTHPARAMS" : register(c%d);\n", C_DEPTHPARAMS); + + WRITE(p, "VS_OUTPUT main(\n"); + + // inputs + if (components & VB_HAS_NRM0) + WRITE(p, " float3 rawnorm0 : NORMAL0,\n"); + if (components & VB_HAS_NRM1) { + if (is_d3d) + WRITE(p, " float3 rawnorm1 : NORMAL1,\n"); + else + WRITE(p, " float3 rawnorm1 : ATTR%d,\n", SHADER_NORM1_ATTRIB); + } + if (components & VB_HAS_NRM2) { + if (is_d3d) + WRITE(p, " float3 rawnorm2 : NORMAL2,\n"); + else + WRITE(p, " float3 rawnorm2 : ATTR%d,\n", SHADER_NORM2_ATTRIB); + } + if (components & VB_HAS_COL0) + WRITE(p, " float4 color0 : COLOR0,\n"); + if (components & VB_HAS_COL1) + WRITE(p, " float4 color1 : COLOR1,\n"); + for (int i = 0; i < 8; ++i) { + u32 hastexmtx = (components & (VB_HAS_TEXMTXIDX0<= 32 ? (posmtx-32) : posmtx;\n"); + WRITE(p, "float3 N0 = "I_NORMALMATRICES".T[normidx].t.xyz, N1 = "I_NORMALMATRICES".T[normidx+1].t.xyz, N2 = "I_NORMALMATRICES".T[normidx+2].t.xyz;\n"); + } + + if (components & VB_HAS_NRM0) + WRITE(p, "float3 _norm0 = normalize(float3(dot(N0, rawnorm0), dot(N1, rawnorm0), dot(N2, rawnorm0)));\n"); + if (components & VB_HAS_NRM1) + WRITE(p, "float3 _norm1 = float3(dot(N0, rawnorm1), dot(N1, rawnorm1), dot(N2, rawnorm1));\n"); + if (components & VB_HAS_NRM2) + WRITE(p, "float3 _norm2 = float3(dot(N0, rawnorm2), dot(N1, rawnorm2), dot(N2, rawnorm2));\n"); + } + else + { + WRITE(p, "float4 pos = float4(dot("I_POSNORMALMATRIX".T0, rawpos), dot("I_POSNORMALMATRIX".T1, rawpos), dot("I_POSNORMALMATRIX".T2, rawpos), 1.0f);\n"); + if (components & VB_HAS_NRM0) + WRITE(p, "float3 _norm0 = normalize(float3(dot("I_POSNORMALMATRIX".N0.xyz, rawnorm0), dot("I_POSNORMALMATRIX".N1.xyz, rawnorm0), dot("I_POSNORMALMATRIX".N2.xyz, rawnorm0)));\n"); + if (components & VB_HAS_NRM1) + WRITE(p, "float3 _norm1 = float3(dot("I_POSNORMALMATRIX".N0.xyz, rawnorm1), dot("I_POSNORMALMATRIX".N1.xyz, rawnorm1), dot("I_POSNORMALMATRIX".N2.xyz, rawnorm1));\n"); + if (components & VB_HAS_NRM2) + WRITE(p, "float3 _norm2 = float3(dot("I_POSNORMALMATRIX".N0.xyz, rawnorm2), dot("I_POSNORMALMATRIX".N1.xyz, rawnorm2), dot("I_POSNORMALMATRIX".N2.xyz, rawnorm2));\n"); + } + + if (!(components & VB_HAS_NRM0)) + WRITE(p, "float3 _norm0 = float3(0.0f, 0.0f, 0.0f);\n"); + + + + WRITE(p, "o.pos = float4(dot("I_PROJECTION".T0, pos), dot("I_PROJECTION".T1, pos), dot("I_PROJECTION".T2, pos), dot("I_PROJECTION".T3, pos));\n"); + + WRITE(p, "float4 mat, lacc;\n" + "float3 ldir, h;\n" + "float dist, dist2, attn;\n"); + + if(xfregs.numChan.numColorChans == 0) + { + if (components & VB_HAS_COL0) + WRITE(p, "o.colors_0 = color0;\n"); + else + WRITE(p, "o.colors_0 = float4(1.0f, 1.0f, 1.0f, 1.0f);\n"); + } + + p = GenerateLightingShader(p, components, I_MATERIALS, I_LIGHTS, "color", "o.colors_"); + + if(xfregs.numChan.numColorChans < 2) + { + if (components & VB_HAS_COL1) + WRITE(p, "o.colors_1 = color1;\n"); + else + WRITE(p, "o.colors_1 = o.colors_0;\n"); + } + // special case if only pos and tex coord 0 and tex coord input is AB11 + // donko - this has caused problems in some games. removed for now. + bool texGenSpecialCase = false; + /*bool texGenSpecialCase = + ((g_VtxDesc.Hex & 0x60600L) == g_VtxDesc.Hex) && // only pos and tex coord 0 + (g_VtxDesc.Tex0Coord != NOT_PRESENT) && + (xfregs.texcoords[0].texmtxinfo.inputform == XF_TEXINPUT_AB11); + */ + + // transform texcoords + WRITE(p, "float4 coord = float4(0.0f, 0.0f, 1.0f, 1.0f);\n"); + for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i) { + TexMtxInfo& texinfo = xfregs.texMtxInfo[i]; + + WRITE(p, "{\n"); + WRITE(p, "coord = float4(0.0f, 0.0f, 1.0f, 1.0f);\n"); + switch (texinfo.sourcerow) { + case XF_SRCGEOM_INROW: + _assert_( texinfo.inputform == XF_TEXINPUT_ABC1 ); + WRITE(p, "coord = rawpos;\n"); // pos.w is 1 + break; + case XF_SRCNORMAL_INROW: + if (components & VB_HAS_NRM0) { + _assert_( texinfo.inputform == XF_TEXINPUT_ABC1 ); + WRITE(p, "coord = float4(rawnorm0.xyz, 1.0f);\n"); + } + break; + case XF_SRCCOLORS_INROW: + _assert_( texinfo.texgentype == XF_TEXGEN_COLOR_STRGBC0 || texinfo.texgentype == XF_TEXGEN_COLOR_STRGBC1 ); + break; + case XF_SRCBINORMAL_T_INROW: + if (components & VB_HAS_NRM1) { + _assert_( texinfo.inputform == XF_TEXINPUT_ABC1 ); + WRITE(p, "coord = float4(rawnorm1.xyz, 1.0f);\n"); + } + break; + case XF_SRCBINORMAL_B_INROW: + if (components & VB_HAS_NRM2) { + _assert_( texinfo.inputform == XF_TEXINPUT_ABC1 ); + WRITE(p, "coord = float4(rawnorm2.xyz, 1.0f);\n"); + } + break; + default: + _assert_(texinfo.sourcerow <= XF_SRCTEX7_INROW); + if (components & (VB_HAS_UV0<<(texinfo.sourcerow - XF_SRCTEX0_INROW)) ) + WRITE(p, "coord = float4(tex%d.x, tex%d.y, 1.0f, 1.0f);\n", texinfo.sourcerow - XF_SRCTEX0_INROW, texinfo.sourcerow - XF_SRCTEX0_INROW); + break; + } + + // first transformation + switch (texinfo.texgentype) { + case XF_TEXGEN_EMBOSS_MAP: // calculate tex coords into bump map + + if (components & (VB_HAS_NRM1|VB_HAS_NRM2)) { + // transform the light dir into tangent space + WRITE(p, "ldir = normalize("I_LIGHTS".lights[%d].pos.xyz - pos.xyz);\n", texinfo.embosslightshift); + WRITE(p, "o.tex%d.xyz = o.tex%d.xyz + float3(dot(ldir, _norm1), dot(ldir, _norm2), 0.0f);\n", i, texinfo.embosssourceshift); + } + else + { + _assert_(0); // should have normals + WRITE(p, "o.tex%d.xyz = o.tex%d.xyz;\n", i, texinfo.embosssourceshift); + } + + break; + case XF_TEXGEN_COLOR_STRGBC0: + _assert_(texinfo.sourcerow == XF_SRCCOLORS_INROW); + WRITE(p, "o.tex%d.xyz = float3(o.colors_0.x, o.colors_0.y, 1);\n", i); + break; + case XF_TEXGEN_COLOR_STRGBC1: + _assert_(texinfo.sourcerow == XF_SRCCOLORS_INROW); + WRITE(p, "o.tex%d.xyz = float3(o.colors_1.x, o.colors_1.y, 1);\n", i); + break; + case XF_TEXGEN_REGULAR: + default: + if (components & (VB_HAS_TEXMTXIDX0< VERTEXSHADERUIDSAFE; // components is included in the uid. char* GenerateVSOutputStruct(char* p, u32 components, API_TYPE api_type); const char *GenerateVertexShaderCode(u32 components, API_TYPE api_type); + void GetVertexShaderId(VERTEXSHADERUID *uid, u32 components); void GetSafeVertexShaderId(VERTEXSHADERUIDSAFE *uid, u32 components); +// Used to make sure that our optimized vertex shader IDs don't lose any possible shader code changes +void ValidateVertexShaderIDs(API_TYPE api, VERTEXSHADERUIDSAFE old_id, const std::string& old_code, u32 components); + extern VERTEXSHADERUID last_vertex_shader_uid; #endif // GCOGL_VERTEXSHADER_H diff --git a/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.cpp b/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.cpp index 5418923bf8..950aaf5ef1 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.cpp @@ -461,6 +461,7 @@ bool PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components) { PSCache::const_iterator iter = PixelShaders.find(uid); GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE,true); + ValidatePixelShaderIDs(API_D3D11, PixelShaders[uid].safe_uid, PixelShaders[uid].code, dstAlphaMode, components); return (iter != PixelShaders.end() && iter->second.shader); } @@ -476,6 +477,7 @@ bool PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components) last_entry = &entry; GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE,true); + ValidatePixelShaderIDs(API_D3D11, entry.safe_uid, entry.code, dstAlphaMode, components); return (entry.shader != NULL); } @@ -494,10 +496,17 @@ bool PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components) g_ps_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size()); g_ps_disk_cache.Sync(); - bool result = InsertByteCode(uid, pbytecode->Data(), pbytecode->Size()); + bool success = InsertByteCode(uid, pbytecode->Data(), pbytecode->Size()); pbytecode->Release(); + + if (success) + { + PixelShaders[uid].code = code; + GetSafePixelShaderId(&PixelShaders[uid].safe_uid, dstAlphaMode); + } + GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); - return result; + return success; } bool PixelShaderCache::InsertByteCode(const PIXELSHADERUID &uid, const void* bytecode, unsigned int bytecodelen) diff --git a/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.h b/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.h index 3b9c537a7a..f5a9cf34b8 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.h +++ b/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.h @@ -55,6 +55,9 @@ private: ID3D11PixelShader* shader; int frameCount; + PIXELSHADERUIDSAFE safe_uid; + std::string code; + PSCacheEntry() : shader(NULL), frameCount(0) {} void Destroy() { SAFE_RELEASE(shader); } }; diff --git a/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.cpp b/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.cpp index 041caba28c..68326e1c60 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.cpp @@ -205,6 +205,7 @@ bool VertexShaderCache::SetShader(u32 components) if (uid == last_vertex_shader_uid && vshaders[uid].frameCount == frameCount) { GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); + ValidateVertexShaderIDs(API_D3D11, vshaders[uid].safe_uid, vshaders[uid].code, components); return (vshaders[uid].shader != NULL); } @@ -218,6 +219,7 @@ bool VertexShaderCache::SetShader(u32 components) last_entry = &entry; GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); + ValidateVertexShaderIDs(API_D3D11, entry.safe_uid, entry.code, components); return (entry.shader != NULL); } @@ -235,10 +237,17 @@ bool VertexShaderCache::SetShader(u32 components) g_vs_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size()); g_vs_disk_cache.Sync(); - bool result = InsertByteCode(uid, pbytecode); + bool success = InsertByteCode(uid, pbytecode); pbytecode->Release(); + + if (success) + { + vshaders[uid].code = code; + GetSafeVertexShaderId(&vshaders[uid].safe_uid, components); + } + GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); - return result; + return success; } bool VertexShaderCache::InsertByteCode(const VERTEXSHADERUID &uid, D3DBlob* bcodeblob) diff --git a/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.h b/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.h index 24be4e6c1c..d614989b0a 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.h +++ b/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.h @@ -53,6 +53,9 @@ private: D3DBlob* bytecode; // needed to initialize the input layout int frameCount; + VERTEXSHADERUIDSAFE safe_uid; + std::string code; + VSCacheEntry() : shader(NULL), bytecode(NULL), frameCount(0) {} void SetByteCode(D3DBlob* blob) { diff --git a/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp b/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp index f76837837d..d69f943546 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp @@ -334,6 +334,7 @@ bool PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components) { PSCache::const_iterator iter = PixelShaders.find(uid); GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); + ValidatePixelShaderIDs(API_D3D9, PixelShaders[uid].safe_uid, PixelShaders[uid].code, dstAlphaMode, components); return (iter != PixelShaders.end() && iter->second.shader); } @@ -350,11 +351,11 @@ bool PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components) if (entry.shader) D3D::SetPixelShader(entry.shader); GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); + ValidatePixelShaderIDs(API_D3D9, entry.safe_uid, entry.code, dstAlphaMode, components); return (entry.shader != NULL); } - // Need to compile a new shader const char *code = GeneratePixelShaderCode(dstAlphaMode, ((D3D::GetCaps().PixelShaderVersion >> 8) & 0xFF) < 3 ? API_D3D9_SM20 : API_D3D9_SM30, components); @@ -384,11 +385,17 @@ bool PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components) g_ps_disk_cache.Sync(); // And insert it into the shader cache. - bool result = InsertByteCode(uid, bytecode, bytecodelen, true); + bool success = InsertByteCode(uid, bytecode, bytecodelen, true); delete [] bytecode; + if (success) + { + PixelShaders[uid].code = code; + GetSafePixelShaderId(&PixelShaders[uid].safe_uid, dstAlphaMode); + } + GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); - return result; + return success; } bool PixelShaderCache::InsertByteCode(const PIXELSHADERUID &uid, const u8 *bytecode, int bytecodelen, bool activate) diff --git a/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.h b/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.h index 2f3c552e2a..d323311fe0 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.h +++ b/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.h @@ -42,6 +42,9 @@ private: bool owns_shader; int frameCount; + PIXELSHADERUIDSAFE safe_uid; + std::string code; + PSCacheEntry() : shader(NULL), owns_shader(true), frameCount(0) {} void Destroy() { diff --git a/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.cpp b/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.cpp index 5fc2b6dee2..854da9d4c2 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.cpp @@ -187,6 +187,7 @@ bool VertexShaderCache::SetShader(u32 components) if (uid == last_vertex_shader_uid && vshaders[uid].frameCount == frameCount) { GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); + ValidateVertexShaderIDs(API_D3D9, vshaders[uid].safe_uid, vshaders[uid].code, components); return (vshaders[uid].shader != NULL); } @@ -201,6 +202,7 @@ bool VertexShaderCache::SetShader(u32 components) if (entry.shader) D3D::SetVertexShader(entry.shader); GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); + ValidateVertexShaderIDs(API_D3D9, entry.safe_uid, entry.code, components); return (entry.shader != NULL); } @@ -215,10 +217,15 @@ bool VertexShaderCache::SetShader(u32 components) g_vs_disk_cache.Append(uid, bytecode, bytecodelen); g_vs_disk_cache.Sync(); - bool result = InsertByteCode(uid, bytecode, bytecodelen, true); + bool success = InsertByteCode(uid, bytecode, bytecodelen, true); + if (success) + { + vshaders[uid].code = code; + GetSafeVertexShaderId(&vshaders[uid].safe_uid, components); + } delete [] bytecode; GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); - return result; + return success; } bool VertexShaderCache::InsertByteCode(const VERTEXSHADERUID &uid, const u8 *bytecode, int bytecodelen, bool activate) { diff --git a/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.h b/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.h index b516f46f9a..686f8b7c6d 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.h +++ b/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.h @@ -35,9 +35,10 @@ private: { LPDIRECT3DVERTEXSHADER9 shader; int frameCount; -#if defined(_DEBUG) || defined(DEBUGFAST) +//#if defined(_DEBUG) || defined(DEBUGFAST) std::string code; -#endif + VERTEXSHADERUIDSAFE safe_uid; +//#endif VSCacheEntry() : shader(NULL), frameCount(0) {} void Destroy() { diff --git a/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.cpp b/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.cpp index f0a640a114..25099d4793 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.cpp @@ -184,30 +184,13 @@ void PixelShaderCache::Shutdown() FRAGMENTSHADER* PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components) { PIXELSHADERUID uid; - PIXELSHADERUIDSAFE safe_uid; GetPixelShaderId(&uid, dstAlphaMode); - GetSafePixelShaderId(&safe_uid, dstAlphaMode); - + // Check if the shader is already set - TODO: Use pShaderLast instead of PixelShaders[uid]? if (uid == last_pixel_shader_uid && PixelShaders[uid].frameCount == frameCount) { GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); - - if (!(safe_uid == PixelShaders[uid].safe_uid)) - { - std::string code(GeneratePixelShaderCode(dstAlphaMode, API_OPENGL, components)); - if (code != PixelShaders[uid].code) - { - char msg[4096]; - char* ptr = msg; - ptr += sprintf(ptr, "Mismatch!\nUnique IDs:\n"); - for (int i = 0; i < PixelShaders[uid].safe_uid.GetNumValues()/2; ++i) - ptr += sprintf(ptr, "%02d, %08X %08X | %08X %08X\n", 2*i, PixelShaders[uid].safe_uid.values[2*i], PixelShaders[uid].safe_uid.values[2*i+1], - safe_uid.values[2*i], safe_uid.values[2*i+1]); - PanicAlert(msg); - } - } - + ValidatePixelShaderIDs(API_OPENGL, PixelShaders[uid].safe_uid, PixelShaders[uid].code, dstAlphaMode, components); return pShaderLast; } @@ -220,35 +203,19 @@ FRAGMENTSHADER* PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 comp iter->second.frameCount = frameCount; PSCacheEntry &entry = iter->second; if (&entry.shader != pShaderLast) - { pShaderLast = &entry.shader; - } GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); - if (!(safe_uid == entry.safe_uid)) - { - std::string code(GeneratePixelShaderCode(dstAlphaMode, API_OPENGL, components)); - if (code != entry.code) - { - char msg[4096]; - char *ptr = msg; - ptr += sprintf(ptr, "Mismatch!\nUnique IDs:\n"); - for (int i = 0; i < entry.safe_uid.GetNumValues()/2; ++i) - ptr += sprintf(ptr, "%02d\t%08X %08X | %08X %08X\n", 2*i, entry.safe_uid.values[2*i], entry.safe_uid.values[2*i+1], - safe_uid.values[2*i], safe_uid.values[2*i+1]); - PanicAlert(msg); - } - } - + ValidatePixelShaderIDs(API_OPENGL, entry.safe_uid, entry.code, dstAlphaMode, components); return pShaderLast; } // Make an entry in the table PSCacheEntry& newentry = PixelShaders[uid]; newentry.frameCount = frameCount; - newentry.safe_uid = safe_uid; pShaderLast = &newentry.shader; const char *code = GeneratePixelShaderCode(dstAlphaMode, API_OPENGL, components); + GetSafePixelShaderId(&newentry.safe_uid, dstAlphaMode); newentry.code = code; #if defined(_DEBUG) || defined(DEBUGFAST) diff --git a/Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.cpp b/Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.cpp index 96f2d5a2ae..82455a84e1 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.cpp @@ -77,6 +77,7 @@ VERTEXSHADER* VertexShaderCache::SetShader(u32 components) if (uid == last_vertex_shader_uid && vshaders[uid].frameCount == frameCount) { GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); + ValidateVertexShaderIDs(API_OPENGL, vshaders[uid].safe_uid, vshaders[uid].shader.strprog, components); return pShaderLast; } memcpy(&last_vertex_shader_uid, &uid, sizeof(VERTEXSHADERUID)); @@ -86,11 +87,11 @@ VERTEXSHADER* VertexShaderCache::SetShader(u32 components) { iter->second.frameCount = frameCount; VSCacheEntry &entry = iter->second; - if (&entry.shader != pShaderLast) { + if (&entry.shader != pShaderLast) pShaderLast = &entry.shader; - } GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); + ValidateVertexShaderIDs(API_OPENGL, entry.safe_uid, entry.shader.strprog, components); return pShaderLast; } @@ -182,9 +183,9 @@ bool VertexShaderCache::CompileVertexShader(VERTEXSHADER& vs, const char* pstrpr cgDestroyProgram(tempprog); #endif -#if defined(_DEBUG) || defined(DEBUGFAST) +//#if defined(_DEBUG) || defined(DEBUGFAST) vs.strprog = pstrprogram; -#endif +//#endif return true; } diff --git a/Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.h b/Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.h index e311fde77b..1711d42a63 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.h @@ -32,9 +32,9 @@ struct VERTEXSHADER VERTEXSHADER() : glprogid(0) {} GLuint glprogid; // opengl program id -#if defined(_DEBUG) || defined(DEBUGFAST) +//#if defined(_DEBUG) || defined(DEBUGFAST) std::string strprog; -#endif +//#endif }; class VertexShaderCache @@ -42,6 +42,7 @@ class VertexShaderCache struct VSCacheEntry { VERTEXSHADER shader; + VERTEXSHADERUIDSAFE safe_uid; int frameCount; VSCacheEntry() : frameCount(0) {} void Destroy() { From 5c14a24ce115a85d9edfdd11bbf6d78ccd9eddaa Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Fri, 9 Sep 2011 21:34:46 +0200 Subject: [PATCH 12/36] Make shader ID validation optional by adding a gfx setting called "EnableShaderDebugging". Setting this to True will enable additional checks if the shader cache misses any relevant register changes. --- Source/Core/VideoCommon/Src/VideoConfig.cpp | 4 ++++ Source/Core/VideoCommon/Src/VideoConfig.h | 3 +++ .../Plugin_VideoDX11/Src/PixelShaderCache.cpp | 2 +- .../Plugin_VideoDX11/Src/VertexShaderCache.cpp | 2 +- .../Plugin_VideoDX9/Src/PixelShaderCache.cpp | 11 +++++++---- .../Plugin_VideoDX9/Src/VertexShaderCache.cpp | 2 +- .../Plugin_VideoOGL/Src/PixelShaderCache.cpp | 15 ++++++++------- .../Plugin_VideoOGL/Src/PixelShaderCache.h | 3 --- .../Plugin_VideoOGL/Src/VertexShaderCache.cpp | 6 +++--- 9 files changed, 28 insertions(+), 20 deletions(-) diff --git a/Source/Core/VideoCommon/Src/VideoConfig.cpp b/Source/Core/VideoCommon/Src/VideoConfig.cpp index 8bad7b005a..2c7788c9cc 100644 --- a/Source/Core/VideoCommon/Src/VideoConfig.cpp +++ b/Source/Core/VideoCommon/Src/VideoConfig.cpp @@ -96,6 +96,8 @@ void VideoConfig::Load(const char *ini_file) iniFile.Get("Settings", "EnableOpenCL", &bEnableOpenCL, false); iniFile.Get("Settings", "OMPDecoder", &bOMPDecoder, false); + iniFile.Get("Settings", "EnableShaderDebugging", &bEnableShaderDebugging, false); + iniFile.Get("Enhancements", "ForceFiltering", &bForceFiltering, 0); iniFile.Get("Enhancements", "MaxAnisotropy", &iMaxAnisotropy, 0); // NOTE - this is x in (1 << x) iniFile.Get("Enhancements", "PostProcessingShader", &sPostProcessingShader, ""); @@ -231,6 +233,8 @@ void VideoConfig::Save(const char *ini_file) iniFile.Set("Settings", "EnableOpenCL", bEnableOpenCL); iniFile.Set("Settings", "OMPDecoder", bOMPDecoder); + iniFile.Set("Settings", "EnableShaderDebugging", bEnableShaderDebugging); + iniFile.Set("Enhancements", "ForceFiltering", bForceFiltering); iniFile.Set("Enhancements", "MaxAnisotropy", iMaxAnisotropy); iniFile.Set("Enhancements", "PostProcessingShader", sPostProcessingShader); diff --git a/Source/Core/VideoCommon/Src/VideoConfig.h b/Source/Core/VideoCommon/Src/VideoConfig.h index 92a8b67741..83ec08784d 100644 --- a/Source/Core/VideoCommon/Src/VideoConfig.h +++ b/Source/Core/VideoCommon/Src/VideoConfig.h @@ -147,6 +147,9 @@ struct VideoConfig // D3D only config, mostly to be merged into the above int iAdapter; + // Debugging + bool bEnableShaderDebugging; + // Static config per API // TODO: Move this out of VideoConfig struct diff --git a/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.cpp b/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.cpp index 950aaf5ef1..6dec1977b1 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.cpp @@ -499,7 +499,7 @@ bool PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components) bool success = InsertByteCode(uid, pbytecode->Data(), pbytecode->Size()); pbytecode->Release(); - if (success) + if (g_ActiveConfig.bEnableShaderDebugging && success) { PixelShaders[uid].code = code; GetSafePixelShaderId(&PixelShaders[uid].safe_uid, dstAlphaMode); diff --git a/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.cpp b/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.cpp index 68326e1c60..bbddd21bb1 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.cpp @@ -240,7 +240,7 @@ bool VertexShaderCache::SetShader(u32 components) bool success = InsertByteCode(uid, pbytecode); pbytecode->Release(); - if (success) + if (g_ActiveConfig.bEnableShaderDebugging && success) { vshaders[uid].code = code; GetSafeVertexShaderId(&vshaders[uid].safe_uid, components); diff --git a/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp b/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp index d69f943546..712bbadfb7 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp @@ -359,9 +359,12 @@ bool PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components) // Need to compile a new shader const char *code = GeneratePixelShaderCode(dstAlphaMode, ((D3D::GetCaps().PixelShaderVersion >> 8) & 0xFF) < 3 ? API_D3D9_SM20 : API_D3D9_SM30, components); - u32 code_hash = HashAdler32((const u8 *)code, strlen(code)); - unique_shaders.insert(code_hash); - SETSTAT(stats.numUniquePixelShaders, unique_shaders.size()); + if (g_ActiveConfig.bEnableShaderDebugging) + { + u32 code_hash = HashAdler32((const u8 *)code, strlen(code)); + unique_shaders.insert(code_hash); + SETSTAT(stats.numUniquePixelShaders, unique_shaders.size()); + } #if defined(_DEBUG) || defined(DEBUGFAST) if (g_ActiveConfig.iLog & CONF_SAVESHADERS && code) { @@ -388,7 +391,7 @@ bool PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components) bool success = InsertByteCode(uid, bytecode, bytecodelen, true); delete [] bytecode; - if (success) + if (g_ActiveConfig.bEnableShaderDebugging && success) { PixelShaders[uid].code = code; GetSafePixelShaderId(&PixelShaders[uid].safe_uid, dstAlphaMode); diff --git a/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.cpp b/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.cpp index 854da9d4c2..81f4af0392 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.cpp @@ -218,7 +218,7 @@ bool VertexShaderCache::SetShader(u32 components) g_vs_disk_cache.Sync(); bool success = InsertByteCode(uid, bytecode, bytecodelen, true); - if (success) + if (g_ActiveConfig.bEnableShaderDebugging && success) { vshaders[uid].code = code; GetSafeVertexShaderId(&vshaders[uid].safe_uid, components); diff --git a/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.cpp b/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.cpp index 25099d4793..b76ce4ca9a 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.cpp @@ -190,7 +190,7 @@ FRAGMENTSHADER* PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 comp if (uid == last_pixel_shader_uid && PixelShaders[uid].frameCount == frameCount) { GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); - ValidatePixelShaderIDs(API_OPENGL, PixelShaders[uid].safe_uid, PixelShaders[uid].code, dstAlphaMode, components); + ValidatePixelShaderIDs(API_OPENGL, PixelShaders[uid].safe_uid, PixelShaders[uid].shader.strprog, dstAlphaMode, components); return pShaderLast; } @@ -206,7 +206,7 @@ FRAGMENTSHADER* PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 comp pShaderLast = &entry.shader; GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); - ValidatePixelShaderIDs(API_OPENGL, entry.safe_uid, entry.code, dstAlphaMode, components); + ValidatePixelShaderIDs(API_OPENGL, entry.safe_uid, entry.shader.strprog, dstAlphaMode, components); return pShaderLast; } @@ -215,8 +215,12 @@ FRAGMENTSHADER* PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 comp newentry.frameCount = frameCount; pShaderLast = &newentry.shader; const char *code = GeneratePixelShaderCode(dstAlphaMode, API_OPENGL, components); - GetSafePixelShaderId(&newentry.safe_uid, dstAlphaMode); - newentry.code = code; + + if (g_ActiveConfig.bEnableShaderDebugging && code) + { + GetSafePixelShaderId(&newentry.safe_uid, dstAlphaMode); + newentry.shader.strprog = code; + } #if defined(_DEBUG) || defined(DEBUGFAST) if (g_ActiveConfig.iLog & CONF_SAVESHADERS && code) { @@ -320,9 +324,6 @@ bool PixelShaderCache::CompilePixelShader(FRAGMENTSHADER& ps, const char* pstrpr cgDestroyProgram(tempprog); #endif -#if defined(_DEBUG) || defined(DEBUGFAST) - ps.strprog = pstrprogram; -#endif return true; } diff --git a/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.h b/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.h index 63f71ddc13..2aac23a7e5 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.h @@ -39,9 +39,7 @@ struct FRAGMENTSHADER } } GLuint glprogid; // opengl program id -#if defined(_DEBUG) || defined(DEBUGFAST) std::string strprog; -#endif }; class PixelShaderCache @@ -57,7 +55,6 @@ class PixelShaderCache shader.Destroy(); } PIXELSHADERUIDSAFE safe_uid; - std::string code; }; typedef std::map PSCache; diff --git a/Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.cpp b/Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.cpp index 82455a84e1..d922ef63db 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.cpp @@ -100,6 +100,7 @@ VERTEXSHADER* VertexShaderCache::SetShader(u32 components) entry.frameCount = frameCount; pShaderLast = &entry.shader; const char *code = GenerateVertexShaderCode(components, API_OPENGL); + GetSafeVertexShaderId(&entry.safe_uid, components); #if defined(_DEBUG) || defined(DEBUGFAST) if (g_ActiveConfig.iLog & CONF_SAVESHADERS && code) { @@ -183,9 +184,8 @@ bool VertexShaderCache::CompileVertexShader(VERTEXSHADER& vs, const char* pstrpr cgDestroyProgram(tempprog); #endif -//#if defined(_DEBUG) || defined(DEBUGFAST) - vs.strprog = pstrprogram; -//#endif + if (g_ActiveConfig.bEnableShaderDebugging) + vs.strprog = pstrprogram; return true; } From a021dd7b79062d20552852d32387cf6b36ab06e6 Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Fri, 9 Sep 2011 21:45:11 +0200 Subject: [PATCH 13/36] Small fix to the previous commit. --- Source/Core/VideoCommon/Src/PixelShaderGen.cpp | 3 +++ Source/Core/VideoCommon/Src/VertexShaderGen.cpp | 3 +++ 2 files changed, 6 insertions(+) diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp index 25007be93b..1ea7479990 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp @@ -243,6 +243,9 @@ void GetSafePixelShaderId(PIXELSHADERUIDSAFE *uid, DSTALPHA_MODE dstAlphaMode) void ValidatePixelShaderIDs(API_TYPE api, PIXELSHADERUIDSAFE old_id, const std::string& old_code, DSTALPHA_MODE dstAlphaMode, u32 components) { + if (!g_ActiveConfig.bEnableShaderDebugging) + return; + PIXELSHADERUIDSAFE new_id; GetSafePixelShaderId(&new_id, dstAlphaMode); diff --git a/Source/Core/VideoCommon/Src/VertexShaderGen.cpp b/Source/Core/VideoCommon/Src/VertexShaderGen.cpp index 902f645bec..f3dab89173 100644 --- a/Source/Core/VideoCommon/Src/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/VertexShaderGen.cpp @@ -93,6 +93,9 @@ void GetSafeVertexShaderId(VERTEXSHADERUIDSAFE *uid, u32 components) void ValidateVertexShaderIDs(API_TYPE api, VERTEXSHADERUIDSAFE old_id, const std::string& old_code, u32 components) { + if (!g_ActiveConfig.bEnableShaderDebugging) + return; + VERTEXSHADERUIDSAFE new_id; GetSafeVertexShaderId(&new_id, components); From 5d075ce507c180dc89b9731eaa2f52e729caf8f6 Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Sat, 10 Sep 2011 03:10:28 +0200 Subject: [PATCH 14/36] - D3D9: pass the correct API type to ValidatePixelShaderIDs - don't load shader cache from disk in d3d9/11 if shader debugging is enabled (we won't have any info about the source shader code otherwise, etc) - dump shader source codes on safe UIDs mismatch Thanks to LordMark and [SS] for reporting those to me ;) --- Source/Core/VideoCommon/Src/PixelShaderGen.cpp | 2 ++ Source/Core/VideoCommon/Src/VertexShaderGen.cpp | 2 ++ .../Plugins/Plugin_VideoDX11/Src/PixelShaderCache.cpp | 3 +++ .../Plugins/Plugin_VideoDX11/Src/VertexShaderCache.cpp | 3 +++ .../Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp | 10 +++++++--- .../Plugins/Plugin_VideoDX9/Src/VertexShaderCache.cpp | 3 +++ 6 files changed, 20 insertions(+), 3 deletions(-) diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp index 1ea7479990..7937c695ce 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp @@ -271,6 +271,8 @@ void ValidatePixelShaderIDs(API_TYPE api, PIXELSHADERUIDSAFE old_id, const std:: sprintf(szTemp, "%spsuid_mismatch_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++); std::ofstream file(szTemp); file << msg; + file << "\n\nOld shader code:\n" << old_code; + file << "\n\nNew shader code:\n" << new_code; file.close(); PanicAlert("Unique pixel shader ID mismatch!\n\nReport this to the devs, along with the contents of %s.", szTemp); diff --git a/Source/Core/VideoCommon/Src/VertexShaderGen.cpp b/Source/Core/VideoCommon/Src/VertexShaderGen.cpp index f3dab89173..5c6c12887a 100644 --- a/Source/Core/VideoCommon/Src/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/VertexShaderGen.cpp @@ -121,6 +121,8 @@ void ValidateVertexShaderIDs(API_TYPE api, VERTEXSHADERUIDSAFE old_id, const std sprintf(szTemp, "%svsuid_mismatch_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++); std::ofstream file(szTemp); file << msg; + file << "\n\nOld shader code:\n" << old_code; + file << "\n\nNew shader code:\n" << new_code; file.close(); PanicAlert("Unique pixel shader ID mismatch!\n\nReport this to the devs, along with the contents of %s.", szTemp); diff --git a/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.cpp b/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.cpp index 6dec1977b1..c278ae1d81 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.cpp @@ -412,6 +412,9 @@ void PixelShaderCache::Init() SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str()); PixelShaderCacheInserter inserter; g_ps_disk_cache.OpenAndRead(cache_filename, inserter); + + if (g_Config.bEnableShaderDebugging) // TODO: Hacks.. + Clear(); } // ONLY to be used during shutdown. diff --git a/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.cpp b/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.cpp index bbddd21bb1..f46881b16b 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.cpp @@ -174,6 +174,9 @@ void VertexShaderCache::Init() SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str()); VertexShaderCacheInserter inserter; g_vs_disk_cache.OpenAndRead(cache_filename, inserter); + + if (g_Config.bEnableShaderDebugging) // TODO: Hacks.. + Clear(); } void VertexShaderCache::Clear() diff --git a/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp b/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp index 712bbadfb7..7f2cdfceee 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp @@ -283,6 +283,9 @@ void PixelShaderCache::Init() SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str()); PixelShaderCacheInserter inserter; g_ps_disk_cache.OpenAndRead(cache_filename, inserter); + + if (g_Config.bEnableShaderDebugging) // TODO: Hacks.. + Clear(); } // ONLY to be used during shutdown. @@ -326,6 +329,7 @@ void PixelShaderCache::Shutdown() bool PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components) { + const API_TYPE api = ((D3D::GetCaps().PixelShaderVersion >> 8) & 0xFF) < 3 ? API_D3D9_SM20 : API_D3D9_SM30; PIXELSHADERUID uid; GetPixelShaderId(&uid, dstAlphaMode); @@ -334,7 +338,7 @@ bool PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components) { PSCache::const_iterator iter = PixelShaders.find(uid); GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); - ValidatePixelShaderIDs(API_D3D9, PixelShaders[uid].safe_uid, PixelShaders[uid].code, dstAlphaMode, components); + ValidatePixelShaderIDs(api, PixelShaders[uid].safe_uid, PixelShaders[uid].code, dstAlphaMode, components); return (iter != PixelShaders.end() && iter->second.shader); } @@ -351,13 +355,13 @@ bool PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components) if (entry.shader) D3D::SetPixelShader(entry.shader); GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); - ValidatePixelShaderIDs(API_D3D9, entry.safe_uid, entry.code, dstAlphaMode, components); + ValidatePixelShaderIDs(api, entry.safe_uid, entry.code, dstAlphaMode, components); return (entry.shader != NULL); } // Need to compile a new shader - const char *code = GeneratePixelShaderCode(dstAlphaMode, ((D3D::GetCaps().PixelShaderVersion >> 8) & 0xFF) < 3 ? API_D3D9_SM20 : API_D3D9_SM30, components); + const char *code = GeneratePixelShaderCode(dstAlphaMode, api, components); if (g_ActiveConfig.bEnableShaderDebugging) { diff --git a/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.cpp b/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.cpp index 81f4af0392..3ef18ffba8 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.cpp @@ -151,6 +151,9 @@ void VertexShaderCache::Init() SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str()); VertexShaderCacheInserter inserter; g_vs_disk_cache.OpenAndRead(cache_filename, inserter); + + if (g_Config.bEnableShaderDebugging) // TODO: Hacks.. + Clear(); } void VertexShaderCache::Clear() From 8c691767da71d041580d362b3b822d50e85d46da Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Sat, 27 Aug 2011 20:42:11 +0200 Subject: [PATCH 15/36] Various changes which improve FreeBSD support. Patches by martymac, all credits go to him ;) --- CMakeLists.txt | 2 +- Source/Core/Common/Src/CPUDetect.cpp | 9 +++++ Source/Core/Common/Src/CommonFuncs.h | 6 ++++ Source/Core/Common/Src/MemoryUtil.cpp | 48 +++++++++++++++++++++---- Source/Core/Core/Src/MemTools.cpp | 2 +- Source/Core/DolphinWX/CMakeLists.txt | 3 ++ Source/Core/VideoCommon/Src/AVIDump.cpp | 4 +++ 7 files changed, 66 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d0d6a3ae8f..e870304dc4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -463,7 +463,7 @@ if(GETTEXT_FOUND AND NOT DISABLE_WX) file(GLOB LINGUAS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} Languages/po/*.po) GETTEXT_CREATE_TRANSLATIONS(Languages/po/dolphin-emu.pot ALL ${LINGUAS}) endif() -if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Linux") +if((NOT ${CMAKE_SYSTEM_NAME} MATCHES "Linux") AND (NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")) install(FILES Data/license.txt DESTINATION ${datadir}) endif() diff --git a/Source/Core/Common/Src/CPUDetect.cpp b/Source/Core/Common/Src/CPUDetect.cpp index 810c5d2a59..7c231b0a69 100644 --- a/Source/Core/Common/Src/CPUDetect.cpp +++ b/Source/Core/Common/Src/CPUDetect.cpp @@ -32,6 +32,10 @@ //#include #include +#if defined __FreeBSD__ +#include +#include +#else static inline void do_cpuid(unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx) { @@ -65,15 +69,20 @@ static inline void do_cpuid(unsigned int *eax, unsigned int *ebx, ); #endif } +#endif /* defined __FreeBSD__ */ static void __cpuid(int info[4], int x) { +#if defined __FreeBSD__ + do_cpuid((unsigned int)x, (unsigned int*)info); +#else unsigned int eax = x, ebx = 0, ecx = 0, edx = 0; do_cpuid(&eax, &ebx, &ecx, &edx); info[0] = eax; info[1] = ebx; info[2] = ecx; info[3] = edx; +#endif } #endif diff --git a/Source/Core/Common/Src/CommonFuncs.h b/Source/Core/Common/Src/CommonFuncs.h index 7dd156f42e..c79137780d 100644 --- a/Source/Core/Common/Src/CommonFuncs.h +++ b/Source/Core/Common/Src/CommonFuncs.h @@ -45,6 +45,8 @@ _mm_shuffle_epi8(__m128i a, __m128i mask) #include #ifdef __linux__ #include +#elif defined __FreeBSD__ +#include #endif // go to debugger mode @@ -137,6 +139,10 @@ inline __attribute__((always_inline)) u32 swap32(u32 _data) {return __builtin_bswap32(_data);} inline __attribute__((always_inline)) u64 swap64(u64 _data) {return __builtin_bswap64(_data);} +#elif __FreeBSD__ +inline u16 swap16(u16 _data) {return bswap16(_data);} +inline u32 swap32(u32 _data) {return bswap32(_data);} +inline u64 swap64(u64 _data) {return bswap64(_data);} #else // Slow generic implementation. inline u16 swap16(u16 data) {return (data >> 8) | (data << 8);} diff --git a/Source/Core/Common/Src/MemoryUtil.cpp b/Source/Core/Common/Src/MemoryUtil.cpp index bc65f856f4..65c70e0c5e 100644 --- a/Source/Core/Common/Src/MemoryUtil.cpp +++ b/Source/Core/Common/Src/MemoryUtil.cpp @@ -27,28 +27,64 @@ #include #endif +#if !defined(MAP_32BIT) +#include +#define PAGE_MASK (getpagesize() - 1) +#define round_page(x) ((((unsigned long)(x)) + PAGE_MASK) & ~(PAGE_MASK)) +#endif + // This is purposely not a full wrapper for virtualalloc/mmap, but it // provides exactly the primitive operations that Dolphin needs. void* AllocateExecutableMemory(size_t size, bool low) { -#ifdef _WIN32 + static char *map_hint = 0; +#if defined(__x86_64__) && !defined(MAP_32BIT) + if (low && (!map_hint)) + map_hint = (char*)round_page(512*1024*1024); /* 0.5 GB rounded up to the next page */ +#endif + +#if defined(_WIN32) void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); #else - void* ptr = mmap(0, size, PROT_READ | PROT_WRITE | PROT_EXEC, + void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE -#if defined __linux__ && defined __x86_64__ +#if defined(__x86_64__) +#if defined(MAP_32BIT) | (low ? MAP_32BIT : 0) -#endif +#else + | (low ? MAP_FIXED : 0) +#endif /* defined(MAP_32BIT) */ +#endif /* defined(__x86_64__) */ , -1, 0); -#endif +#endif /* defined(_WIN32) */ // printf("Mapped executable memory at %p (size %ld)\n", ptr, // (unsigned long)size); +#if defined(__FreeBSD__) + if (ptr == MAP_FAILED) + { + ptr = NULL; +#else if (ptr == NULL) + { +#endif PanicAlert("Failed to allocate executable memory"); -#ifdef _M_X64 + } +#if defined(__x86_64__) && !defined(MAP_32BIT) + else + { + if (low) + { + map_hint += size; + map_hint = (char*)round_page(map_hint); /* round up to the next page */ + // printf("Next map will (hopefully) be at %p\n", map_hint); + } + } +#endif + +#if defined(_M_X64) if ((u64)ptr >= 0x80000000 && low == true) PanicAlert("Executable memory ended up above 2GB!"); #endif diff --git a/Source/Core/Core/Src/MemTools.cpp b/Source/Core/Core/Src/MemTools.cpp index 469ae32684..bb6fef6439 100644 --- a/Source/Core/Core/Src/MemTools.cpp +++ b/Source/Core/Core/Src/MemTools.cpp @@ -160,7 +160,7 @@ void InstallExceptionHandler() #else // _WIN32 -#if defined __APPLE__ || defined __linux__ || defined _WIN32 +#if defined __APPLE__ || defined __linux__ || defined __FreeBSD__ || defined _WIN32 #ifndef _WIN32 #include #endif diff --git a/Source/Core/DolphinWX/CMakeLists.txt b/Source/Core/DolphinWX/CMakeLists.txt index 7890c9fe96..5fc433009f 100644 --- a/Source/Core/DolphinWX/CMakeLists.txt +++ b/Source/Core/DolphinWX/CMakeLists.txt @@ -9,6 +9,9 @@ set(LIBS core sfml-network SDL GL + avcodec + avformat + swscale ${XRANDR_LIBRARIES} ${X11_LIBRARIES}) diff --git a/Source/Core/VideoCommon/Src/AVIDump.cpp b/Source/Core/VideoCommon/Src/AVIDump.cpp index cfd34e5cdb..a5a6098489 100644 --- a/Source/Core/VideoCommon/Src/AVIDump.cpp +++ b/Source/Core/VideoCommon/Src/AVIDump.cpp @@ -15,6 +15,10 @@ // Official SVN repository and contact information can be found at // http://code.google.com/p/dolphin-emu/ +#if defined(__FreeBSD__) +#define __STDC_CONSTANT_MACROS 1 +#endif + #include "AVIDump.h" #include "HW/VideoInterface.h" //for TargetRefreshRate #include "VideoConfig.h" From 5dcb212fc7b65dcc25829b1ee42ef03898023f1e Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Tue, 6 Sep 2011 14:45:05 +0200 Subject: [PATCH 16/36] Fix Windows build. --- Source/Core/Common/Src/MemoryUtil.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Source/Core/Common/Src/MemoryUtil.cpp b/Source/Core/Common/Src/MemoryUtil.cpp index 65c70e0c5e..2d64a434f1 100644 --- a/Source/Core/Common/Src/MemoryUtil.cpp +++ b/Source/Core/Common/Src/MemoryUtil.cpp @@ -27,7 +27,7 @@ #include #endif -#if !defined(MAP_32BIT) +#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT) #include #define PAGE_MASK (getpagesize() - 1) #define round_page(x) ((((unsigned long)(x)) + PAGE_MASK) & ~(PAGE_MASK)) @@ -38,15 +38,14 @@ void* AllocateExecutableMemory(size_t size, bool low) { +#if defined(_WIN32) + void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); +#else static char *map_hint = 0; #if defined(__x86_64__) && !defined(MAP_32BIT) if (low && (!map_hint)) map_hint = (char*)round_page(512*1024*1024); /* 0.5 GB rounded up to the next page */ #endif - -#if defined(_WIN32) - void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); -#else void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE #if defined(__x86_64__) @@ -72,7 +71,7 @@ void* AllocateExecutableMemory(size_t size, bool low) #endif PanicAlert("Failed to allocate executable memory"); } -#if defined(__x86_64__) && !defined(MAP_32BIT) +#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT) else { if (low) From bd4a5b5ef692bce25dcfc60e13df3f08edc84bf8 Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Thu, 8 Sep 2011 15:39:03 +0200 Subject: [PATCH 17/36] Implement frame dumping in D3D11. Fixes issue 4831. --- Source/Core/VideoCommon/Src/RenderBase.cpp | 2 +- Source/Core/VideoCommon/Src/RenderBase.h | 2 +- .../Plugins/Plugin_VideoDX11/Src/Render.cpp | 115 ++++++++++++++++-- Source/Plugins/Plugin_VideoDX9/Src/Render.cpp | 28 +++-- Source/Plugins/Plugin_VideoOGL/Src/Render.cpp | 18 +-- 5 files changed, 133 insertions(+), 32 deletions(-) diff --git a/Source/Core/VideoCommon/Src/RenderBase.cpp b/Source/Core/VideoCommon/Src/RenderBase.cpp index d89e582860..06f4c81ab6 100644 --- a/Source/Core/VideoCommon/Src/RenderBase.cpp +++ b/Source/Core/VideoCommon/Src/RenderBase.cpp @@ -52,7 +52,7 @@ int OSDChoice, OSDTime; Renderer *g_renderer = NULL; -bool s_bLastFrameDumped = false; +bool bLastFrameDumped = false; std::mutex Renderer::s_criticalScreenshot; std::string Renderer::s_sScreenshotName; diff --git a/Source/Core/VideoCommon/Src/RenderBase.h b/Source/Core/VideoCommon/Src/RenderBase.h index b2c2c7ecfb..48f096851f 100644 --- a/Source/Core/VideoCommon/Src/RenderBase.h +++ b/Source/Core/VideoCommon/Src/RenderBase.h @@ -41,7 +41,7 @@ extern int frameCount; extern int OSDChoice, OSDTime; -extern bool s_bLastFrameDumped; +extern bool bLastFrameDumped; // Renderer really isn't a very good name for this class - it's more like "Misc". // The long term goal is to get rid of this class and replace it with others that make diff --git a/Source/Plugins/Plugin_VideoDX11/Src/Render.cpp b/Source/Plugins/Plugin_VideoDX11/Src/Render.cpp index bbf2a966dd..368fec357c 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoDX11/Src/Render.cpp @@ -43,6 +43,7 @@ #include "Television.h" #include "Host.h" #include "BPFunctions.h" +#include "AVIDump.h" namespace DX11 { @@ -62,6 +63,10 @@ ID3D11BlendState* resetblendstate = NULL; ID3D11DepthStencilState* resetdepthstate = NULL; ID3D11RasterizerState* resetraststate = NULL; +static ID3D11Texture2D* s_screenshot_texture = NULL; +static bool s_bAVIDumping; +static char *s_frame_data = NULL; + // GX pipeline state struct { @@ -296,9 +301,14 @@ void SetupDeviceObjects() hr = D3D::device->CreateRasterizerState(&rastdesc, &resetraststate); CHECK(hr==S_OK, "Create rasterizer state for Renderer::ResetAPIState"); D3D::SetDebugObjectName((ID3D11DeviceChild*)resetraststate, "rasterizer state for Renderer::ResetAPIState"); + + D3D11_TEXTURE2D_DESC scrtex_desc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, D3D::GetBackBufferWidth(), D3D::GetBackBufferHeight(), 1, 1, 0, D3D11_USAGE_STAGING, D3D11_CPU_ACCESS_READ|D3D11_CPU_ACCESS_WRITE); + hr = D3D::device->CreateTexture2D(&scrtex_desc, NULL, &s_screenshot_texture); + CHECK(hr==S_OK, "Create screenshot staging texture"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)s_screenshot_texture, "staging screenshot texture"); } -// Kill off all POOL_DEFAULT device objects. +// Kill off all device objects void TeardownDeviceObjects() { delete g_framebuffer_manager; @@ -314,6 +324,7 @@ void TeardownDeviceObjects() SAFE_RELEASE(resetblendstate); SAFE_RELEASE(resetdepthstate); SAFE_RELEASE(resetraststate); + SAFE_RELEASE(s_screenshot_texture); s_television.Shutdown(); } @@ -344,6 +355,10 @@ Renderer::Renderer() SetupDeviceObjects(); + bLastFrameDumped = false; + s_bAVIDumping = false; + + // Setup GX pipeline state memset(&gx_state.blenddc, 0, sizeof(gx_state.blenddc)); gx_state.blenddc.AlphaToCoverageEnable = FALSE; @@ -391,6 +406,15 @@ Renderer::Renderer() Renderer::~Renderer() { + if (g_ActiveConfig.bDumpFrames && bLastFrameDumped && s_bAVIDumping) + { + SAFE_DELETE_ARRAY(s_frame_data); + + AVIDump::Stop(); + s_bAVIDumping = false; + bLastFrameDumped = false; + } + TeardownDeviceObjects(); D3D::EndFrame(); D3D::Present(); @@ -835,15 +859,11 @@ void Renderer::SetBlendMode(bool forceUpdate) bool Renderer::SaveScreenshot(const std::string &filename, const TargetRectangle &rc) { // copy back buffer to system memory - ID3D11Texture2D* buftex; - D3D11_TEXTURE2D_DESC tex_desc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, D3D::GetBackBufferWidth(), D3D::GetBackBufferHeight(), 1, 1, 0, D3D11_USAGE_STAGING, D3D11_CPU_ACCESS_READ|D3D11_CPU_ACCESS_WRITE); - HRESULT hr = D3D::device->CreateTexture2D(&tex_desc, NULL, &buftex); - if (FAILED(hr)) PanicAlert("Failed to create screenshot buffer texture"); - D3D::context->CopyResource(buftex, (ID3D11Resource*)D3D::GetBackBuffer()->GetTex()); + D3D::context->CopyResource(s_screenshot_texture, (ID3D11Resource*)D3D::GetBackBuffer()->GetTex()); // D3DX11SaveTextureToFileA doesn't allow us to ignore the alpha channel, so we need to strip it out ourselves D3D11_MAPPED_SUBRESOURCE map; - D3D::context->Map(buftex, 0, D3D11_MAP_READ_WRITE, 0, &map); + D3D::context->Map(s_screenshot_texture, 0, D3D11_MAP_READ_WRITE, 0, &map); for (unsigned int y = 0; y < D3D::GetBackBufferHeight(); ++y) { u8* ptr = (u8*)map.pData + y * map.RowPitch + 3; @@ -853,21 +873,36 @@ bool Renderer::SaveScreenshot(const std::string &filename, const TargetRectangle ptr += 4; } } - D3D::context->Unmap(buftex, 0); + D3D::context->Unmap(s_screenshot_texture, 0); // ready to be saved - hr = PD3DX11SaveTextureToFileA(D3D::context, buftex, D3DX11_IFF_PNG, filename.c_str()); - buftex->Release(); + HRESULT hr = PD3DX11SaveTextureToFileA(D3D::context, s_screenshot_texture, D3DX11_IFF_PNG, filename.c_str()); return SUCCEEDED(hr); } +void formatBufferDump(const char *in, char *out, int w, int h, int p) +{ + for (int y = 0; y < h; ++y) + { + const u32 *line = (u32*)(in + (h - y - 1) * p); + for (int x = 0; x < w; ++x) + { + memcpy(out, line, 3); + out += 3; + line += 4; + } + } +} // This function has the final picture. We adjust the aspect ratio here. void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,const EFBRectangle& rc,float Gamma) { if (g_bSkipCurrentFrame || (!XFBWrited && (!g_ActiveConfig.bUseXFB || !g_ActiveConfig.bUseRealXFB)) || !fbWidth || !fbHeight) { + if (g_ActiveConfig.bDumpFrames) + AVIDump::AddFrame(s_frame_data); + Core::Callback_VideoCopiedToXFB(false); return; } @@ -879,6 +914,9 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons const XFBSourceBase* const* xfbSourceList = FramebufferManager::GetXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount); if ((!xfbSourceList || xfbCount == 0) && g_ActiveConfig.bUseXFB && !g_ActiveConfig.bUseRealXFB) { + if (g_ActiveConfig.bDumpFrames) + AVIDump::AddFrame(s_frame_data); + Core::Callback_VideoCopiedToXFB(false); return; } @@ -984,6 +1022,63 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons s_bScreenshot = false; } + // Dump frames + static int w = 0, h = 0; + if (g_ActiveConfig.bDumpFrames) + { + static int s_recordWidth; + static int s_recordHeight; + + D3D::context->CopyResource(s_screenshot_texture, (ID3D11Resource*)D3D::GetBackBuffer()->GetTex()); + if (!bLastFrameDumped) + { + s_recordWidth = dst_rect.GetWidth(); + s_recordHeight = dst_rect.GetHeight(); + s_bAVIDumping = AVIDump::Start(EmuWindow::GetParentWnd(), s_recordWidth, s_recordHeight); + if (!s_bAVIDumping) + { + PanicAlert("Error dumping frames to AVI."); + } + else + { + char msg [255]; + sprintf_s(msg,255, "Dumping Frames to \"%sframedump0.avi\" (%dx%d RGB24)", + File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), s_recordWidth, s_recordHeight); + OSD::AddMessage(msg, 2000); + } + } + if (s_bAVIDumping) + { + D3D11_MAPPED_SUBRESOURCE map; + D3D::context->Map(s_screenshot_texture, 0, D3D11_MAP_READ, 0, &map); + + if (!s_frame_data || w != s_recordWidth || h != s_recordHeight) + { + delete[] s_frame_data; + s_frame_data = new char[3 * s_recordWidth * s_recordHeight]; + w = s_recordWidth; + h = s_recordHeight; + } + formatBufferDump((char*)map.pData, s_frame_data, s_recordWidth, s_recordHeight, map.RowPitch); + AVIDump::AddFrame(s_frame_data); + D3D::context->Unmap(s_screenshot_texture, 0); + } + bLastFrameDumped = true; + } + else + { + if (bLastFrameDumped && s_bAVIDumping) + { + SAFE_DELETE_ARRAY(s_frame_data); + w = h = 0; + + AVIDump::Stop(); + s_bAVIDumping = false; + OSD::AddMessage("Stop dumping frames to AVI", 2000); + } + bLastFrameDumped = false; + } + // Finish up the current frame, print some stats if (g_ActiveConfig.bShowFPS) { diff --git a/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp b/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp index 15b592e800..e7177be396 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp @@ -60,12 +60,6 @@ namespace DX9 static int s_fps = 0; -static int s_recordWidth; -static int s_recordHeight; - -static bool s_bLastFrameDumped; -static bool s_bAVIDumping; - static u32 s_blendMode; static u32 s_LastAA; static bool IS_AMD; @@ -73,6 +67,7 @@ static bool IS_AMD; static char *st; static LPDIRECT3DSURFACE9 ScreenShootMEMSurface = NULL; +static bool s_bAVIDumping; // State translation lookup tables @@ -297,7 +292,7 @@ Renderer::Renderer() // Make sure to use valid texture sizes D3D::FixTextureSize(s_target_width, s_target_height); - s_bLastFrameDumped = false; + bLastFrameDumped = false; s_bAVIDumping = false; // We're not using fixed function. @@ -845,11 +840,11 @@ bool Renderer::SaveScreenshot(const std::string &filename, const TargetRectangle void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,const EFBRectangle& rc,float Gamma) { static char* data = 0; - static int w = 0, h = 0; if (g_bSkipCurrentFrame || (!XFBWrited && (!g_ActiveConfig.bUseXFB || !g_ActiveConfig.bUseRealXFB)) || !fbWidth || !fbHeight) { if (g_ActiveConfig.bDumpFrames && data) AVIDump::AddFrame(data); + Core::Callback_VideoCopiedToXFB(false); return; } @@ -862,6 +857,9 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons const XFBSourceBase* const* xfbSourceList = FramebufferManager::GetXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount); if ((!xfbSourceList || xfbCount == 0) && g_ActiveConfig.bUseXFB && !g_ActiveConfig.bUseRealXFB) { + if (g_ActiveConfig.bDumpFrames && data) + AVIDump::AddFrame(data); + Core::Callback_VideoCopiedToXFB(false); return; } @@ -1027,10 +1025,16 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons SaveScreenshot(s_sScreenshotName, dst_rect); s_bScreenshot = false; } + + // Dump frames + static int w = 0, h = 0; if (g_ActiveConfig.bDumpFrames) { + static int s_recordWidth; + static int s_recordHeight; + HRESULT hr = D3D::dev->GetRenderTargetData(D3D::GetBackBufferSurface(),ScreenShootMEMSurface); - if (!s_bLastFrameDumped) + if (!bLastFrameDumped) { s_recordWidth = dst_rect.GetWidth(); s_recordHeight = dst_rect.GetHeight(); @@ -1064,11 +1068,11 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons ScreenShootMEMSurface->UnlockRect(); } } - s_bLastFrameDumped = true; + bLastFrameDumped = true; } else { - if (s_bLastFrameDumped && s_bAVIDumping) + if (bLastFrameDumped && s_bAVIDumping) { if (data) { @@ -1080,7 +1084,7 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons s_bAVIDumping = false; OSD::AddMessage("Stop dumping frames to AVI", 2000); } - s_bLastFrameDumped = false; + bLastFrameDumped = false; } // Finish up the current frame, print some stats diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp index ca3280673e..8b2d08eecc 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp @@ -521,7 +521,7 @@ Renderer::~Renderer() if(s_bAVIDumping) { AVIDump::Stop(); - s_bLastFrameDumped = false; + bLastFrameDumped = false; s_bAVIDumping = false; } #else @@ -970,11 +970,13 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons if ((!xfbSourceList || xfbCount == 0) && g_ActiveConfig.bUseXFB && !g_ActiveConfig.bUseRealXFB) { if (g_ActiveConfig.bDumpFrames && data) - #ifdef _WIN32 + { +#ifdef _WIN32 AVIDump::AddFrame((char *) data); - #elif defined HAVE_LIBAV +#elif defined HAVE_LIBAV AVIDump::AddFrame(data, w, h); - #endif +#endif + } Core::Callback_VideoCopiedToXFB(false); return; } @@ -1145,7 +1147,7 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons glReadPixels(dst_rect.left, dst_rect.bottom, w, h, GL_BGR, GL_UNSIGNED_BYTE, data); if (GL_REPORT_ERROR() == GL_NO_ERROR && w > 0 && h > 0) { - if (!s_bLastFrameDumped) + if (!bLastFrameDumped) { #ifdef _WIN32 s_bAVIDumping = AVIDump::Start(EmuWindow::GetParentWnd(), w, h); @@ -1171,14 +1173,14 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons #endif } - s_bLastFrameDumped = true; + bLastFrameDumped = true; } else NOTICE_LOG(VIDEO, "Error reading framebuffer"); } else { - if (s_bLastFrameDumped && s_bAVIDumping) + if (bLastFrameDumped && s_bAVIDumping) { if (data) { @@ -1190,7 +1192,7 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons s_bAVIDumping = false; OSD::AddMessage("Stop dumping frames", 2000); } - s_bLastFrameDumped = false; + bLastFrameDumped = false; } #else if (g_ActiveConfig.bDumpFrames) From c710ea33f97b5b64eef1c56c2f67a666146d41f6 Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Thu, 8 Sep 2011 17:09:24 +0200 Subject: [PATCH 18/36] Merge some frame dumping code to VideoCommon, fixes a memory leak in D3D9 and OpenGL if emulation is stopped while dumping frames. Breaks D3D11 frame dumping for some weird reason (memory corruption or whatever?). --- Source/Core/VideoCommon/Src/RenderBase.cpp | 17 +++- Source/Core/VideoCommon/Src/RenderBase.h | 13 ++- .../Plugins/Plugin_VideoDX11/Src/Render.cpp | 44 +++------ Source/Plugins/Plugin_VideoDX9/Src/Render.cpp | 43 ++++----- Source/Plugins/Plugin_VideoOGL/Src/Render.cpp | 95 +++++++------------ 5 files changed, 93 insertions(+), 119 deletions(-) diff --git a/Source/Core/VideoCommon/Src/RenderBase.cpp b/Source/Core/VideoCommon/Src/RenderBase.cpp index 06f4c81ab6..fa6ba018c7 100644 --- a/Source/Core/VideoCommon/Src/RenderBase.cpp +++ b/Source/Core/VideoCommon/Src/RenderBase.cpp @@ -42,6 +42,7 @@ #include "Host.h" #include "XFMemory.h" #include "FifoPlayer/FifoRecorder.h" +#include "AVIDump.h" #include #include @@ -52,7 +53,6 @@ int OSDChoice, OSDTime; Renderer *g_renderer = NULL; -bool bLastFrameDumped = false; std::mutex Renderer::s_criticalScreenshot; std::string Renderer::s_sScreenshotName; @@ -81,15 +81,28 @@ bool Renderer::s_EnableDLCachingAfterRecording; unsigned int Renderer::prev_efb_format = (unsigned int)-1; -Renderer::Renderer() +Renderer::Renderer() : frame_data(NULL), bLastFrameDumped(false) { UpdateActiveConfig(); + +#if defined _WIN32 || defined HAVE_LIBAV + bAVIDumping = false; +#endif } Renderer::~Renderer() { // invalidate previous efb format prev_efb_format = (unsigned int)-1; + +#if defined _WIN32 || defined HAVE_LIBAV + if (g_ActiveConfig.bDumpFrames && bLastFrameDumped && bAVIDumping) + AVIDump::Stop(); +#else + if (f_pFrameDump.IsOpen()) + f_pFrameDump.Close(); +#endif + delete[] frame_data; } void Renderer::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, float Gamma) diff --git a/Source/Core/VideoCommon/Src/RenderBase.h b/Source/Core/VideoCommon/Src/RenderBase.h index 48f096851f..e8d4c55a20 100644 --- a/Source/Core/VideoCommon/Src/RenderBase.h +++ b/Source/Core/VideoCommon/Src/RenderBase.h @@ -132,9 +132,6 @@ public: protected: - static std::mutex s_criticalScreenshot; - static std::string s_sScreenshotName; - static void CalculateTargetScale(int x, int y, int &scaledX, int &scaledY); static bool CalculateTargetSize(int multiplier = 1); static void CalculateXYScale(const TargetRectangle& dst_rect); @@ -143,6 +140,16 @@ protected: static void RecordVideoMemory(); static volatile bool s_bScreenshot; + static std::mutex s_criticalScreenshot; + static std::string s_sScreenshotName; + +#if defined _WIN32 || defined HAVE_LIBAV + bool bAVIDumping; +#else + File::IOFile pFrameDump; +#endif + char* frame_data; + bool bLastFrameDumped; // The framebuffer size static int s_target_width; diff --git a/Source/Plugins/Plugin_VideoDX11/Src/Render.cpp b/Source/Plugins/Plugin_VideoDX11/Src/Render.cpp index 368fec357c..9de763bf37 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoDX11/Src/Render.cpp @@ -64,8 +64,6 @@ ID3D11DepthStencilState* resetdepthstate = NULL; ID3D11RasterizerState* resetraststate = NULL; static ID3D11Texture2D* s_screenshot_texture = NULL; -static bool s_bAVIDumping; -static char *s_frame_data = NULL; // GX pipeline state struct @@ -355,9 +353,6 @@ Renderer::Renderer() SetupDeviceObjects(); - bLastFrameDumped = false; - s_bAVIDumping = false; - // Setup GX pipeline state memset(&gx_state.blenddc, 0, sizeof(gx_state.blenddc)); @@ -406,15 +401,6 @@ Renderer::Renderer() Renderer::~Renderer() { - if (g_ActiveConfig.bDumpFrames && bLastFrameDumped && s_bAVIDumping) - { - SAFE_DELETE_ARRAY(s_frame_data); - - AVIDump::Stop(); - s_bAVIDumping = false; - bLastFrameDumped = false; - } - TeardownDeviceObjects(); D3D::EndFrame(); D3D::Present(); @@ -900,8 +886,8 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons { if (g_bSkipCurrentFrame || (!XFBWrited && (!g_ActiveConfig.bUseXFB || !g_ActiveConfig.bUseRealXFB)) || !fbWidth || !fbHeight) { - if (g_ActiveConfig.bDumpFrames) - AVIDump::AddFrame(s_frame_data); + if (g_ActiveConfig.bDumpFrames && frame_data) + AVIDump::AddFrame(frame_data); Core::Callback_VideoCopiedToXFB(false); return; @@ -914,8 +900,8 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons const XFBSourceBase* const* xfbSourceList = FramebufferManager::GetXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount); if ((!xfbSourceList || xfbCount == 0) && g_ActiveConfig.bUseXFB && !g_ActiveConfig.bUseRealXFB) { - if (g_ActiveConfig.bDumpFrames) - AVIDump::AddFrame(s_frame_data); + if (g_ActiveConfig.bDumpFrames && frame_data) + AVIDump::AddFrame(frame_data); Core::Callback_VideoCopiedToXFB(false); return; @@ -1034,8 +1020,8 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons { s_recordWidth = dst_rect.GetWidth(); s_recordHeight = dst_rect.GetHeight(); - s_bAVIDumping = AVIDump::Start(EmuWindow::GetParentWnd(), s_recordWidth, s_recordHeight); - if (!s_bAVIDumping) + bAVIDumping = AVIDump::Start(EmuWindow::GetParentWnd(), s_recordWidth, s_recordHeight); + if (!bAVIDumping) { PanicAlert("Error dumping frames to AVI."); } @@ -1047,33 +1033,33 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons OSD::AddMessage(msg, 2000); } } - if (s_bAVIDumping) + if (bAVIDumping) { D3D11_MAPPED_SUBRESOURCE map; D3D::context->Map(s_screenshot_texture, 0, D3D11_MAP_READ, 0, &map); - if (!s_frame_data || w != s_recordWidth || h != s_recordHeight) + if (!frame_data || w != s_recordWidth || h != s_recordHeight) { - delete[] s_frame_data; - s_frame_data = new char[3 * s_recordWidth * s_recordHeight]; + delete[] frame_data; + frame_data = new char[3 * s_recordWidth * s_recordHeight]; w = s_recordWidth; h = s_recordHeight; } - formatBufferDump((char*)map.pData, s_frame_data, s_recordWidth, s_recordHeight, map.RowPitch); - AVIDump::AddFrame(s_frame_data); + formatBufferDump((char*)map.pData, frame_data, s_recordWidth, s_recordHeight, map.RowPitch); + AVIDump::AddFrame(frame_data); D3D::context->Unmap(s_screenshot_texture, 0); } bLastFrameDumped = true; } else { - if (bLastFrameDumped && s_bAVIDumping) + if (bLastFrameDumped && bAVIDumping) { - SAFE_DELETE_ARRAY(s_frame_data); + SAFE_DELETE_ARRAY(frame_data); w = h = 0; AVIDump::Stop(); - s_bAVIDumping = false; + bAVIDumping = false; OSD::AddMessage("Stop dumping frames to AVI", 2000); } bLastFrameDumped = false; diff --git a/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp b/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp index e7177be396..93b37e211a 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp @@ -67,7 +67,6 @@ static bool IS_AMD; static char *st; static LPDIRECT3DSURFACE9 ScreenShootMEMSurface = NULL; -static bool s_bAVIDumping; // State translation lookup tables @@ -292,9 +291,6 @@ Renderer::Renderer() // Make sure to use valid texture sizes D3D::FixTextureSize(s_target_width, s_target_height); - bLastFrameDumped = false; - s_bAVIDumping = false; - // We're not using fixed function. // Let's just set the matrices to identity to be sure. D3DXMATRIX mtx; @@ -337,10 +333,6 @@ Renderer::~Renderer() D3D::Present(); D3D::Close(); - if (s_bAVIDumping) - { - AVIDump::Stop(); - } delete[] st; } @@ -839,11 +831,10 @@ bool Renderer::SaveScreenshot(const std::string &filename, const TargetRectangle // This function has the final picture. We adjust the aspect ratio here. void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,const EFBRectangle& rc,float Gamma) { - static char* data = 0; if (g_bSkipCurrentFrame || (!XFBWrited && (!g_ActiveConfig.bUseXFB || !g_ActiveConfig.bUseRealXFB)) || !fbWidth || !fbHeight) { - if (g_ActiveConfig.bDumpFrames && data) - AVIDump::AddFrame(data); + if (g_ActiveConfig.bDumpFrames && frame_data) + AVIDump::AddFrame(frame_data); Core::Callback_VideoCopiedToXFB(false); return; @@ -857,8 +848,8 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons const XFBSourceBase* const* xfbSourceList = FramebufferManager::GetXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount); if ((!xfbSourceList || xfbCount == 0) && g_ActiveConfig.bUseXFB && !g_ActiveConfig.bUseRealXFB) { - if (g_ActiveConfig.bDumpFrames && data) - AVIDump::AddFrame(data); + if (g_ActiveConfig.bDumpFrames && frame_data) + AVIDump::AddFrame(frame_data); Core::Callback_VideoCopiedToXFB(false); return; @@ -1038,8 +1029,8 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons { s_recordWidth = dst_rect.GetWidth(); s_recordHeight = dst_rect.GetHeight(); - s_bAVIDumping = AVIDump::Start(EmuWindow::GetParentWnd(), s_recordWidth, s_recordHeight); - if (!s_bAVIDumping) + bAVIDumping = AVIDump::Start(EmuWindow::GetParentWnd(), s_recordWidth, s_recordHeight); + if (!bAVIDumping) { PanicAlert("Error dumping frames to AVI."); } @@ -1051,20 +1042,20 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons OSD::AddMessage(msg, 2000); } } - if (s_bAVIDumping) + if (bAVIDumping) { D3DLOCKED_RECT rect; if (SUCCEEDED(ScreenShootMEMSurface->LockRect(&rect, dst_rect.AsRECT(), D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_NOSYSLOCK | D3DLOCK_READONLY))) { - if (!data || w != s_recordWidth || h != s_recordHeight) + if (!frame_data || w != s_recordWidth || h != s_recordHeight) { - free(data); - data = (char*)malloc(3 * s_recordWidth * s_recordHeight); + delete[] frame_data; + frame_data = new char[3 * s_recordWidth * s_recordHeight]; w = s_recordWidth; h = s_recordHeight; } - formatBufferDump((const char*)rect.pBits, data, s_recordWidth, s_recordHeight, rect.Pitch); - AVIDump::AddFrame(data); + formatBufferDump((const char*)rect.pBits, frame_data, s_recordWidth, s_recordHeight, rect.Pitch); + AVIDump::AddFrame(frame_data); ScreenShootMEMSurface->UnlockRect(); } } @@ -1072,16 +1063,16 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons } else { - if (bLastFrameDumped && s_bAVIDumping) + if (bLastFrameDumped && bAVIDumping) { - if (data) + if (frame_data) { - free(data); - data = 0; + delete[] frame_data; + frame_data = 0; w = h = 0; } AVIDump::Stop(); - s_bAVIDumping = false; + bAVIDumping = false; OSD::AddMessage("Stop dumping frames to AVI", 2000); } bLastFrameDumped = false; diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp index 8b2d08eecc..415d1986b3 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp @@ -110,12 +110,6 @@ int s_fps=0; RasterFont* s_pfont = NULL; -#if defined _WIN32 || defined HAVE_LIBAV -static bool s_bAVIDumping = false; -#else -static File::IOFile f_pFrameDump; -#endif - // 1 for no MSAA. Use s_MSAASamples > 1 to check for MSAA. static int s_MSAASamples = 1; static int s_MSAACoverageSamples = 0; @@ -250,9 +244,6 @@ Renderer::Renderer() s_fps=0; s_blendMode = 0; -#if defined _WIN32 || defined HAVE_LIBAV - s_bAVIDumping = false; -#endif #if defined HAVE_CG && HAVE_CG g_cgcontext = cgCreateContext(); @@ -516,19 +507,6 @@ Renderer::~Renderer() #endif delete g_framebuffer_manager; - -#if defined _WIN32 || defined HAVE_LIBAV - if(s_bAVIDumping) - { - AVIDump::Stop(); - bLastFrameDumped = false; - s_bAVIDumping = false; - } -#else - if (f_pFrameDump.IsOpen()) - f_pFrameDump.Close(); - s_bLastFrameDumped = false; -#endif } // Create On-Screen-Messages @@ -947,15 +925,14 @@ void Renderer::SetBlendMode(bool forceUpdate) // This function has the final picture. We adjust the aspect ratio here. void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,const EFBRectangle& rc,float Gamma) { - static u8 *data = NULL; static int w = 0, h = 0; if (g_bSkipCurrentFrame || (!XFBWrited && (!g_ActiveConfig.bUseXFB || !g_ActiveConfig.bUseRealXFB)) || !fbWidth || !fbHeight) { - if (g_ActiveConfig.bDumpFrames && data) + if (g_ActiveConfig.bDumpFrames && frame_data) #ifdef _WIN32 - AVIDump::AddFrame((char *) data); + AVIDump::AddFrame(frame_data); #elif defined HAVE_LIBAV - AVIDump::AddFrame(data, w, h); + AVIDump::AddFrame(frame_data, w, h); #endif Core::Callback_VideoCopiedToXFB(false); return; @@ -969,12 +946,12 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons const XFBSourceBase* const* xfbSourceList = FramebufferManager::GetXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount); if ((!xfbSourceList || xfbCount == 0) && g_ActiveConfig.bUseXFB && !g_ActiveConfig.bUseRealXFB) { - if (g_ActiveConfig.bDumpFrames && data) + if (g_ActiveConfig.bDumpFrames && frame_data) { #ifdef _WIN32 - AVIDump::AddFrame((char *) data); + AVIDump::AddFrame(frame_data); #elif defined HAVE_LIBAV - AVIDump::AddFrame(data, w, h); + AVIDump::AddFrame(frame_data, w, h); #endif } Core::Callback_VideoCopiedToXFB(false); @@ -1135,26 +1112,26 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons if (g_ActiveConfig.bDumpFrames) { std::lock_guard lk(s_criticalScreenshot); - if (!data || w != dst_rect.GetWidth() || + if (!frame_data || w != dst_rect.GetWidth() || h != dst_rect.GetHeight()) { - if (data) delete[] data; + if (frame_data) delete[] frame_data; w = dst_rect.GetWidth(); h = dst_rect.GetHeight(); - data = new u8[3 * w * h]; + frame_data = new char[3 * w * h]; } glPixelStorei(GL_PACK_ALIGNMENT, 1); - glReadPixels(dst_rect.left, dst_rect.bottom, w, h, GL_BGR, GL_UNSIGNED_BYTE, data); + glReadPixels(dst_rect.left, dst_rect.bottom, w, h, GL_BGR, GL_UNSIGNED_BYTE, frame_data); if (GL_REPORT_ERROR() == GL_NO_ERROR && w > 0 && h > 0) { if (!bLastFrameDumped) { #ifdef _WIN32 - s_bAVIDumping = AVIDump::Start(EmuWindow::GetParentWnd(), w, h); + bAVIDumping = AVIDump::Start(EmuWindow::GetParentWnd(), w, h); #else - s_bAVIDumping = AVIDump::Start(w, h); + bAVIDumping = AVIDump::Start(w, h); #endif - if (!s_bAVIDumping) + if (!bAVIDumping) OSD::AddMessage("AVIDump Start failed", 2000); else { @@ -1163,13 +1140,13 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), w, h).c_str(), 2000); } } - if (s_bAVIDumping) + if (bAVIDumping) { #ifdef _WIN32 - AVIDump::AddFrame((char *) data); + AVIDump::AddFrame(frame_data); #else - FlipImageData(data, w, h); - AVIDump::AddFrame(data, w, h); + FlipImageData(frame_data, w, h); + AVIDump::AddFrame(frame_data, w, h); #endif } @@ -1180,16 +1157,16 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons } else { - if (bLastFrameDumped && s_bAVIDumping) + if (bLastFrameDumped && bAVIDumping) { - if (data) + if (frame_data) { - delete[] data; - data = NULL; + delete[] frame_data; + frame_data = NULL; w = h = 0; } AVIDump::Stop(); - s_bAVIDumping = false; + bAVIDumping = false; OSD::AddMessage("Stop dumping frames", 2000); } bLastFrameDumped = false; @@ -1201,16 +1178,16 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons std::string movie_file_name; w = dst_rect.GetWidth(); h = dst_rect.GetHeight(); - data = new u8[3 * w * h]; + frame_data = new u8[3 * w * h]; glPixelStorei(GL_PACK_ALIGNMENT, 1); - glReadPixels(dst_rect.left, dst_rect.bottom, w, h, GL_BGR, GL_UNSIGNED_BYTE, data); + glReadPixels(dst_rect.left, dst_rect.bottom, w, h, GL_BGR, GL_UNSIGNED_BYTE, frame_data); if (GL_REPORT_ERROR() == GL_NO_ERROR) { - if (!s_bLastFrameDumped) + if (!bLastFrameDumped) { movie_file_name = File::GetUserPath(D_DUMPFRAMES_IDX) + "framedump.raw"; - f_pFrameDump.Open(movie_file_name, "wb"); - if (!f_pFrameDump) + pFrameDump.Open(movie_file_name, "wb"); + if (!pFrameDump) OSD::AddMessage("Error opening framedump.raw for writing.", 2000); else { @@ -1219,22 +1196,22 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons OSD::AddMessage(msg, 2000); } } - if (f_pFrameDump) + if (pFrameDump) { - FlipImageData(data, w, h); - f_pFrameDump.WriteBytes(data, w * 3 * h); - f_pFrameDump.Flush(); + FlipImageData(frame_data, w, h); + pFrameDump.WriteBytes(frame_data, w * 3 * h); + pFrameDump.Flush(); } - s_bLastFrameDumped = true; + bLastFrameDumped = true; } - delete[] data; + delete[] frame_data; } else { - if (s_bLastFrameDumped) - f_pFrameDump.Close(); - s_bLastFrameDumped = false; + if (bLastFrameDumped) + pFrameDump.Close(); + bLastFrameDumped = false; } #endif From 6d8f641cc901fd82b053f18cca43a3f940d35b1a Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Thu, 8 Sep 2011 17:52:01 +0200 Subject: [PATCH 19/36] Fix D3D11 frame dumping. --- Source/Plugins/Plugin_VideoDX11/Src/Render.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Source/Plugins/Plugin_VideoDX11/Src/Render.cpp b/Source/Plugins/Plugin_VideoDX11/Src/Render.cpp index 9de763bf37..53cf9fd4d9 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoDX11/Src/Render.cpp @@ -871,13 +871,15 @@ void formatBufferDump(const char *in, char *out, int w, int h, int p) { for (int y = 0; y < h; ++y) { - const u32 *line = (u32*)(in + (h - y - 1) * p); + const u8 *line = (u8*)(in + (h - y - 1) * p); for (int x = 0; x < w; ++x) { - memcpy(out, line, 3); + out[0] = line[2]; + out[1] = line[1]; + out[2] = line[0]; out += 3; line += 4; - } + } } } @@ -1045,7 +1047,8 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons w = s_recordWidth; h = s_recordHeight; } - formatBufferDump((char*)map.pData, frame_data, s_recordWidth, s_recordHeight, map.RowPitch); + char* source_ptr = (char*)map.pData + dst_rect.left*4 + dst_rect.top*map.RowPitch; + formatBufferDump(source_ptr, frame_data, s_recordWidth, s_recordHeight, map.RowPitch); AVIDump::AddFrame(frame_data); D3D::context->Unmap(s_screenshot_texture, 0); } From 913bc6d15f3ddc91a8f924227490f7b9e4b6d0cf Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Thu, 8 Sep 2011 22:59:34 +0200 Subject: [PATCH 20/36] D3D11: Disable some redundant shader compilation errors. --- Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.cpp | 5 +---- Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.cpp | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.cpp b/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.cpp index c278ae1d81..0a67584409 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.cpp @@ -490,7 +490,6 @@ bool PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components) D3DBlob* pbytecode; if (!D3D::CompilePixelShader(code, (unsigned int)strlen(code), &pbytecode)) { - PanicAlert("Failed to compile Pixel Shader:\n\n%s", code); GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); return false; } @@ -516,10 +515,8 @@ bool PixelShaderCache::InsertByteCode(const PIXELSHADERUID &uid, const void* byt { ID3D11PixelShader* shader = D3D::CreatePixelShaderFromByteCode(bytecode, bytecodelen); if (shader == NULL) - { - PanicAlert("Failed to create pixel shader at %s %d\n", __FILE__, __LINE__); return false; - } + // TODO: Somehow make the debug name a bit more specific D3D::SetDebugObjectName((ID3D11DeviceChild*)shader, "a pixel shader of PixelShaderCache"); diff --git a/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.cpp b/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.cpp index f46881b16b..c81993e5e1 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.cpp @@ -233,7 +233,6 @@ bool VertexShaderCache::SetShader(u32 components) if (pbytecode == NULL) { - PanicAlert("Failed to compile Vertex Shader %s %d:\n\n%s", __FILE__, __LINE__, code); GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); return false; } @@ -257,10 +256,8 @@ bool VertexShaderCache::InsertByteCode(const VERTEXSHADERUID &uid, D3DBlob* bcod { ID3D11VertexShader* shader = D3D::CreateVertexShaderFromByteCode(bcodeblob); if (shader == NULL) - { - PanicAlert("Failed to create vertex shader from %p size %d at %s %d\n", bcodeblob->Data(), bcodeblob->Size(), __FILE__, __LINE__); return false; - } + // TODO: Somehow make the debug name a bit more specific D3D::SetDebugObjectName((ID3D11DeviceChild*)shader, "a vertex shader of VertexShaderCache"); From 6ccfd85f42cd5aa4da9a328e65e81cd3da478d01 Mon Sep 17 00:00:00 2001 From: Glenn Rice Date: Thu, 8 Sep 2011 22:24:11 -0500 Subject: [PATCH 21/36] Build fix for the linux libav build. --- Source/Plugins/Plugin_VideoOGL/Src/Render.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp index 415d1986b3..1870a64f8b 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp @@ -932,7 +932,7 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons #ifdef _WIN32 AVIDump::AddFrame(frame_data); #elif defined HAVE_LIBAV - AVIDump::AddFrame(frame_data, w, h); + AVIDump::AddFrame((u8*)frame_data, w, h); #endif Core::Callback_VideoCopiedToXFB(false); return; @@ -951,7 +951,7 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons #ifdef _WIN32 AVIDump::AddFrame(frame_data); #elif defined HAVE_LIBAV - AVIDump::AddFrame(frame_data, w, h); + AVIDump::AddFrame((u8*)frame_data, w, h); #endif } Core::Callback_VideoCopiedToXFB(false); @@ -1145,8 +1145,8 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons #ifdef _WIN32 AVIDump::AddFrame(frame_data); #else - FlipImageData(frame_data, w, h); - AVIDump::AddFrame(frame_data, w, h); + FlipImageData((u8*)frame_data, w, h); + AVIDump::AddFrame((u8*)frame_data, w, h); #endif } From f041eee23b51b11f198b993b81820597af13a30b Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Fri, 9 Sep 2011 16:30:29 +0200 Subject: [PATCH 22/36] Compile fix. --- Source/Core/VideoCommon/Src/RenderBase.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Core/VideoCommon/Src/RenderBase.cpp b/Source/Core/VideoCommon/Src/RenderBase.cpp index fa6ba018c7..3b06bbb1c0 100644 --- a/Source/Core/VideoCommon/Src/RenderBase.cpp +++ b/Source/Core/VideoCommon/Src/RenderBase.cpp @@ -99,8 +99,8 @@ Renderer::~Renderer() if (g_ActiveConfig.bDumpFrames && bLastFrameDumped && bAVIDumping) AVIDump::Stop(); #else - if (f_pFrameDump.IsOpen()) - f_pFrameDump.Close(); + if (pFrameDump.IsOpen()) + pFrameDump.Close(); #endif delete[] frame_data; } From 08af37509e3fcbc3b1ed4c72b588e267449b9568 Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Mon, 12 Sep 2011 17:58:05 +0200 Subject: [PATCH 23/36] More buildfixes.. --- Source/Plugins/Plugin_VideoOGL/Src/Render.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp index 1870a64f8b..19142e44bb 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp @@ -1178,7 +1178,7 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons std::string movie_file_name; w = dst_rect.GetWidth(); h = dst_rect.GetHeight(); - frame_data = new u8[3 * w * h]; + frame_data = new char[3 * w * h]; glPixelStorei(GL_PACK_ALIGNMENT, 1); glReadPixels(dst_rect.left, dst_rect.bottom, w, h, GL_BGR, GL_UNSIGNED_BYTE, frame_data); if (GL_REPORT_ERROR() == GL_NO_ERROR) @@ -1198,7 +1198,7 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons } if (pFrameDump) { - FlipImageData(frame_data, w, h); + FlipImageData((u8*)frame_data, w, h); pFrameDump.WriteBytes(frame_data, w * 3 * h); pFrameDump.Flush(); } From cfba35f7e573257e527d1f90a64a56e7400d919e Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Mon, 12 Sep 2011 18:01:45 +0200 Subject: [PATCH 24/36] Only link against libav if it's available. --- Source/Core/DolphinWX/CMakeLists.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Source/Core/DolphinWX/CMakeLists.txt b/Source/Core/DolphinWX/CMakeLists.txt index 5fc433009f..f38e791cd0 100644 --- a/Source/Core/DolphinWX/CMakeLists.txt +++ b/Source/Core/DolphinWX/CMakeLists.txt @@ -9,12 +9,13 @@ set(LIBS core sfml-network SDL GL - avcodec - avformat - swscale ${XRANDR_LIBRARIES} ${X11_LIBRARIES}) +if(LIBAV_FOUND) + set(LIBS ${LIBS} ${LIBAV_LIBRARIES}) +endif() + if(wxWidgets_FOUND) set(SRCS Src/ARCodeAddEdit.cpp Src/AboutDolphin.cpp From 0a0cf0e0646705d4421370d2307c7cafb39c5fdd Mon Sep 17 00:00:00 2001 From: Runo Date: Mon, 12 Sep 2011 22:44:03 -0300 Subject: [PATCH 25/36] Update Pt_BR Translation to POT file revision 60. This is also a testing commit, as this is my first one on this repository ^^ --- Languages/po/pt_BR.po | 610 +++++++++++++----------------------------- 1 file changed, 191 insertions(+), 419 deletions(-) diff --git a/Languages/po/pt_BR.po b/Languages/po/pt_BR.po index 1ac0c7a002..d7d782547c 100644 --- a/Languages/po/pt_BR.po +++ b/Languages/po/pt_BR.po @@ -8,13 +8,13 @@ msgstr "" "Project-Id-Version: Dolphin Emu\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2011-08-10 08:30-0500\n" -"PO-Revision-Date: 2011-07-09 19:12-0300\n" +"PO-Revision-Date: 2011-09-11 23:35-0300\n" "Last-Translator: Runo \n" "Language-Team: Portuguese (BR) \n" -"Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: \n" #: Source/Core/DolphinWX/Src/CheatsWindow.cpp:510 msgid " (too many to display)" @@ -42,8 +42,7 @@ msgstr "" #: Source/Core/Core/Src/CoreParameter.cpp:144 #, c-format msgid "\"%s\" is an invalid GCM/ISO file, or is not a GC/Wii ISO." -msgstr "" -"\"%s\" é um arquivo GCM/ISO inválido, ou não é um arquivo ISO de GC/Wii." +msgstr "\"%s\" é um arquivo GCM/ISO inválido, ou não é um arquivo ISO de GC/Wii." #: Source/Core/DolphinWX/Src/MemcardManager.cpp:193 #, c-format @@ -58,9 +57,9 @@ msgid "%d Hz" msgstr "%d Hz" #: Source/Core/DolphinWX/Src/WiimoteConfigDiag.cpp:12 -#, fuzzy, c-format +#, c-format msgid "%i connected" -msgstr "Desconectado" +msgstr "%i conectado" #: Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.cpp:128 #: Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.cpp:296 @@ -74,22 +73,22 @@ msgid "%s failed to be scrubbed. Probably the image is corrupt." msgstr "%s não pôde ser \"limpo\". A imagem provavelmente está corrompida." #: Source/Core/DolphinWX/Src/MemoryCards/GCMemcard.cpp:97 -#, fuzzy, c-format +#, c-format msgid "" "%s failed to load as a memorycard \n" " Card file size is invalid (0x%x bytes)" msgstr "" -"Falha ao carregar o Memory Card\n" -" O tamanho é inválido (%04X)" +"%s falhou ao ser carregado como Memory Card\n" +" O tamanho é inválido (0x%x bytes)" #: Source/Core/DolphinWX/Src/MemoryCards/GCMemcard.cpp:112 -#, fuzzy, c-format +#, c-format msgid "" "%s failed to load as a memorycard \n" " Card size is invalid (0x%x bytes)" msgstr "" -"Falha ao carregar o Memory Card\n" -" O tamanho é inválido (%04X)" +"%s falhou ao ser carregado como Memory Card\n" +" O tamanho é inválido (0x%x bytes)" #: Source/Core/DolphinWX/Src/MemoryCards/GCMemcard.cpp:92 #, c-format @@ -97,6 +96,8 @@ msgid "" "%s failed to load as a memorycard \n" "file is not large enough to be a valid memory card file (0x%x bytes)" msgstr "" +"%s não pôde ser carregado como um MemoryCard \n" +"o arquivo não é grande o bastante para ser um arquivo de Memory Card (0x%x bytes)" #: Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.cpp:367 #, c-format @@ -367,13 +368,11 @@ msgstr "" msgid "" "ALERT:\n" "\n" -"NetPlay will currently only work properly when using the following " -"settings:\n" +"NetPlay will currently only work properly when using the following settings:\n" " - Dual Core [OFF]\n" " - Audio Throttle [OFF]\n" " - DSP-HLE with \"Null Audio\" or DSP-LLE\n" -" - Manually set the exact number of controllers that will be used to " -"[Standard Controller]\n" +" - Manually set the exact number of controllers that will be used to [Standard Controller]\n" "\n" "All players should try to use the same Dolphin version and settings.\n" "Disable all memory cards or send them to all players before starting.\n" @@ -383,18 +382,14 @@ msgid "" msgstr "" "ALERTA:\n" "\n" -"O NetPlay atualmente irá funcionar corretamente apenas usando as " -"configurações a seguir:\n" +"O NetPlay atualmente irá funcionar corretamente apenas usando as configurações a seguir:\n" " - Dual Core [DESLIGADO]\n" " - Aceleração de Audio [Desligado]\n" " - DSP-HLE com \"Audio Nulo\" ou DSP-LLE\n" -" - Manualmente configurar o número exato de controles a serem usados para " -"[Controle Padrão]\n" +" - Manualmente configurar o número exato de controles a serem usados para [Controle Padrão]\n" "\n" -"Todos os jogadores devem tentar usar a mesma versão e configuração do " -"Dolphin.\n" -"Desative todos os cartões de memórias ou mande eles para todos os jogadores " -"antes de começar .\n" +"Todos os jogadores devem tentar usar a mesma versão e configuração do Dolphin.\n" +"Desative todos os cartões de memórias ou mande eles para todos os jogadores antes de começar .\n" "Suport ao wiimote não foi implementado.\n" "\n" "Você deve redirecionar as portas TCP para ser o Host!!" @@ -424,14 +419,12 @@ msgstr "Emulção precisa de VBeam" #: Source/Core/DolphinWX/Src/VideoConfigDiag.cpp:95 msgid "" "Accurately emulate EFB copies.\n" -"Some games depend on this for certain graphical effects or gameplay " -"functionality.\n" +"Some games depend on this for certain graphical effects or gameplay functionality.\n" "\n" "If unsure, leave this checked." msgstr "" "Emula as Cópias do EFB com precisão.\n" -"Alguns jogos dependem disso para certos efeitos visuais ou funções de " -"jogabilidade.\n" +"Alguns jogos dependem disso para certos efeitos visuais ou funções de jogabilidade.\n" "\n" "Se estiver em dúvida, deixe isto ativado." @@ -456,38 +449,23 @@ msgstr "" #: Source/Core/Core/Src/ActionReplay.cpp:669 #, c-format -msgid "" -"Action Replay Error: Invalid size (%08x : address = %08x) in Add Code (%s)" -msgstr "" -"Erro no Action Replay: Tamanho inválido (%08x : address = %08x) em Add Code " -"(%s)" +msgid "Action Replay Error: Invalid size (%08x : address = %08x) in Add Code (%s)" +msgstr "Erro no Action Replay: Tamanho inválido (%08x : address = %08x) em Add Code (%s)" #: Source/Core/Core/Src/ActionReplay.cpp:756 #, c-format -msgid "" -"Action Replay Error: Invalid size (%08x : address = %08x) in Fill and Slide " -"(%s)" -msgstr "" -"Erro no Action Replay: Tamanho inválido (%08x : address = %08x) em Fill e " -"Slide (%s)" +msgid "Action Replay Error: Invalid size (%08x : address = %08x) in Fill and Slide (%s)" +msgstr "Erro no Action Replay: Tamanho inválido (%08x : address = %08x) em Fill e Slide (%s)" #: Source/Core/Core/Src/ActionReplay.cpp:549 #, c-format -msgid "" -"Action Replay Error: Invalid size (%08x : address = %08x) in Ram Write And " -"Fill (%s)" -msgstr "" -"Erro no Action Replay: Tamanho inválido (%08x : address = %08x) em RAM Write " -"e Fill (%s)" +msgid "Action Replay Error: Invalid size (%08x : address = %08x) in Ram Write And Fill (%s)" +msgstr "Erro no Action Replay: Tamanho inválido (%08x : address = %08x) em RAM Write e Fill (%s)" #: Source/Core/Core/Src/ActionReplay.cpp:609 #, c-format -msgid "" -"Action Replay Error: Invalid size (%08x : address = %08x) in Write To " -"Pointer (%s)" -msgstr "" -"Erro no Action Replay: Tamanho inválido (%08x : address = %08x) em Write to " -"Pointer (%s)" +msgid "Action Replay Error: Invalid size (%08x : address = %08x) in Write To Pointer (%s)" +msgstr "Erro no Action Replay: Tamanho inválido (%08x : address = %08x) em Write to Pointer (%s)" #: Source/Core/Core/Src/ActionReplay.cpp:803 #, c-format @@ -496,11 +474,8 @@ msgstr "Erro no Action Replay: Valor inválido (%08x) na Cópia de Memória (%s) #: Source/Core/Core/Src/ActionReplay.cpp:684 #, c-format -msgid "" -"Action Replay Error: Master Code and Write To CCXXXXXX not implemented (%s)" -msgstr "" -"Erro no Action Replay: Master Code e Write To CCXXXXXX não está implementado " -"(%s)" +msgid "Action Replay Error: Master Code and Write To CCXXXXXX not implemented (%s)" +msgstr "Erro no Action Replay: Master Code e Write To CCXXXXXX não está implementado (%s)" #: Source/Core/Core/Src/ActionReplay.cpp:196 #, c-format @@ -562,16 +537,14 @@ msgstr "Endereço:" msgid "" "Adds the specified value to zFar Parameter.\n" "Two ways to express the floating point values.\n" -"Example: entering ''200'' or ''0.0002'' directly, it produces equal effects, " -"the acquired value will be ''0.0002''.\n" +"Example: entering ''200'' or ''0.0002'' directly, it produces equal effects, the acquired value will be ''0.0002''.\n" "Values: (0->+/-Integer) or (0->+/-FP[6 digits of precision])\n" "\n" "NOTE: Check LogWindow/Console for the acquired values." msgstr "" "Adiciona o valor especificado ao Parâmetro do zFar.\n" "Duas formas de expressar os valores flutuantes do ponteiro.\n" -"Exemplo: Digitar ''200'' ou ''0.0002'' diretamente, isso vai produzir " -"efeitos iguais, o valor adquirido será ''0.0002''.\n" +"Exemplo: Digitar ''200'' ou ''0.0002'' diretamente, isso vai produzir efeitos iguais, o valor adquirido será ''0.0002''.\n" "Valores: (0->+/-Inteiro) ou (0->+/-FP[6 dígitos precisos])\n" "\n" "NOTA: Confira a Janela de Log/Console para ver os valores adquiridos." @@ -580,16 +553,14 @@ msgstr "" msgid "" "Adds the specified value to zNear Parameter.\n" "Two ways to express the floating point values.\n" -"Example: entering ''200'' or ''0.0002'' directly, it produces equal effects, " -"the acquired value will be ''0.0002''.\n" +"Example: entering ''200'' or ''0.0002'' directly, it produces equal effects, the acquired value will be ''0.0002''.\n" "Values: (0->+/-Integer) or (0->+/-FP[6 digits of precision])\n" "\n" "NOTE: Check LogWindow/Console for the acquired values." msgstr "" "Adiciona o valor especificado ao Parâmetro do zNear.\n" "Duas formas de expressar os valores flutuantes do ponteiro.\n" -"Exemplo: Digitar ''200'' ou ''0.0002'' diretamente, isso vai produzir " -"efeitos iguais, o valor adquirido será ''0.0002''.\n" +"Exemplo: Digitar ''200'' ou ''0.0002'' diretamente, isso vai produzir efeitos iguais, o valor adquirido será ''0.0002''.\n" "Valores: (0->+/-Inteiro) ou (0->+/-FP[6 dígitos precisos])\n" "\n" "NOTA: Confira a Janela de Log/Console para ver os valores adquiridos." @@ -637,13 +608,11 @@ msgstr "Todos os arquivos (*.*)|*.*" #: Source/Core/DolphinWX/Src/VideoConfigDiag.cpp:121 msgid "" -"Allows toggling certain options via the hotkeys 3, 4, 5, 6 and 7 within the " -"emulation window.\n" +"Allows toggling certain options via the hotkeys 3, 4, 5, 6 and 7 within the emulation window.\n" "\n" "If unsure, leave this unchecked." msgstr "" -"Permite Ligar/Desligar algumas opções através das teclas 3, 4, 5, 6 e 7 " -"enquanto o emulador está funcionando.\n" +"Permite Ligar/Desligar algumas opções através das teclas 3, 4, 5, 6 e 7 enquanto o emulador está funcionando.\n" "\n" "Se estiver em dúvida, deixe isto desativado." @@ -700,9 +669,7 @@ msgstr "" #: Source/Core/DolphinWX/Src/GameListCtrl.cpp:1112 msgid "Are you sure you want to delete this file? It will be gone forever!" -msgstr "" -"Você tem certeza que quer deletar este arquivo? Ele ficará perdido para " -"sempre!" +msgstr "Você tem certeza que quer deletar este arquivo? Ele ficará perdido para sempre!" #: Source/Core/DolphinWX/Src/ConfigMain.cpp:725 #: Source/Core/DolphinWX/Src/VideoConfigDiag.cpp:280 @@ -886,17 +853,12 @@ msgstr "Cache das Listas de Display" #: Source/Core/DolphinWX/Src/VideoConfigDiag.cpp:87 msgid "" "Calculate depth values of 3D graphics per-pixel rather than per vertex.\n" -"In contrast to pixel lighting (which is merely an enhancement), per-pixel " -"depth calculations are necessary to properly emulate a small number of " -"games.\n" +"In contrast to pixel lighting (which is merely an enhancement), per-pixel depth calculations are necessary to properly emulate a small number of games.\n" "\n" "If unsure, leave this checked." msgstr "" -"Calcula os valores de profundidade dos gráficos 3D por Pixel ao invés de por " -"vetor.\n" -"Ao contrário da Iluminação por Pixels (que é meramente uma melhoria), o " -"cálculo da Profundidade por Pixel é necessário para emular própriamente um " -"pequeno número de jogos.\n" +"Calcula os valores de profundidade dos gráficos 3D por Pixel ao invés de por vetor.\n" +"Ao contrário da Iluminação por Pixels (que é meramente uma melhoria), o cálculo da Profundidade por Pixel é necessário para emular própriamente um pequeno número de jogos.\n" "\n" "Se estiver em dúvida, deixe isto desativado." @@ -928,21 +890,22 @@ msgstr "Não é possível abrir %s" #: Source/Core/DolphinWX/Src/FrameTools.cpp:721 msgid "Cannot record movies in read-only mode." -msgstr "" +msgstr "Não é possível gravar vídeos no modo Apenas Leitura" #: Source/Core/Core/Src/CoreTiming.cpp:122 msgid "Cannot unregister events with events pending" msgstr "Não é possível cancelar o registro de evnetos com eventos pendentes" #: Source/Core/DolphinWX/Src/ConfigMain.cpp:1016 -#, fuzzy, c-format +#, c-format msgid "" "Cannot use that file as a memory card.\n" "%s\n" "is not a valid gamecube memory card file" msgstr "" "Não é possível usar aquele arquivo como um Memory Card.\n" -"Você está tentando usar o mesmo arquivo nos dois slots?" +"%s\n" +"não é um arquivo de Memory Card válido" #: Source/Core/DolphinWX/Src/ConfigMain.cpp:1039 msgid "" @@ -955,14 +918,12 @@ msgstr "" #: Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_usb.cpp:1858 #, c-format msgid "Cant find WiiMote by bd: %02x:%02x:%02x:%02x:%02x:%02x" -msgstr "" -"Não foi possível encontrar o Wiimote pelo bd: %02x:%02x:%02x:%02x:%02x:%02x" +msgstr "Não foi possível encontrar o Wiimote pelo bd: %02x:%02x:%02x:%02x:%02x:%02x" #: Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_usb.cpp:1872 #, c-format msgid "Cant find WiiMote by connection handle %02x" -msgstr "" -"Não foi possível encontrar o Wiimote pelo identificador de conexão %02x" +msgstr "Não foi possível encontrar o Wiimote pelo identificador de conexão %02x" #: Source/Core/Core/Src/HW/DVDInterface.cpp:643 #: Source/Core/Core/Src/HW/DVDInterface.cpp:653 @@ -1069,12 +1030,8 @@ msgid "Choose a memory card:" msgstr "Escolher um cartão de memória:" #: Source/Core/DolphinWX/Src/ConfigMain.cpp:755 -msgid "" -"Choose file to use as apploader: (applies to discs constructed from " -"directories only)" -msgstr "" -"Escolher um arquivo para ser usado como apploader: (aplicável somente para " -"discos construídos de diretórios)" +msgid "Choose file to use as apploader: (applies to discs constructed from directories only)" +msgstr "Escolher um arquivo para ser usado como apploader: (aplicável somente para discos construídos de diretórios)" #: Source/Core/DolphinWX/Src/ISOProperties.cpp:764 #: Source/Core/DolphinWX/Src/ISOProperties.cpp:803 @@ -1101,12 +1058,8 @@ msgid "Clear failed." msgstr "Falha na liberação." #: Source/Core/Core/Src/NetPlayServer.cpp:259 -msgid "" -"Client disconnect while game is running!! NetPlay is disabled. You must " -"manually stop the game." -msgstr "" -"O Client desconectou-se enquanto o jogo rodava!! O NetPlay foi desativado. " -"Você deve parar o jogo manualmente." +msgid "Client disconnect while game is running!! NetPlay is disabled. You must manually stop the game." +msgstr "O Client desconectou-se enquanto o jogo rodava!! O NetPlay foi desativado. Você deve parar o jogo manualmente." #: Source/Core/DolphinWX/Src/VideoConfigDiag.cpp:558 #: Source/Core/DolphinWX/Src/MemcardManager.cpp:244 @@ -1256,14 +1209,8 @@ msgstr "Não foi possível inicializar o Backend 5s. %s" #: Source/Core/Core/Src/CoreParameter.cpp:139 #, c-format -msgid "" -"Could not read \"%s\". There is no disc in the drive, or it is not a GC/Wii " -"backup. Please note that original Gamecube and Wii discs cannot be read by " -"most PC DVD drives." -msgstr "" -"Não foi possível ler \"%s\". Não há nenhum disco no leitor, ou não é uma " -"cópia de GC/Wii. Note que os discos originais de Gamecube e Wii não podem " -"ser lidos pela maioria dos leitores de DVD dos PCs." +msgid "Could not read \"%s\". There is no disc in the drive, or it is not a GC/Wii backup. Please note that original Gamecube and Wii discs cannot be read by most PC DVD drives." +msgstr "Não foi possível ler \"%s\". Não há nenhum disco no leitor, ou não é uma cópia de GC/Wii. Note que os discos originais de Gamecube e Wii não podem ser lidos pela maioria dos leitores de DVD dos PCs." #: Source/Core/Core/Src/CoreParameter.cpp:294 #, c-format @@ -1280,8 +1227,7 @@ msgid "" "Could not set pads. The player left or the game is currently running!\n" "(setting pads while the game is running is not yet supported)" msgstr "" -"Não foi possível definir os controles. O jogador saiu ou o jogo está rodando " -"no momento!\n" +"Não foi possível definir os controles. O jogador saiu ou o jogo está rodando no momento!\n" "(Definir os controles durante o jogo ainda não é suportado)" #: Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp:118 @@ -1289,13 +1235,11 @@ msgstr "" msgid "" "Could not write memory card file %s.\n" "\n" -"Are you running Dolphin from a CD/DVD, or is the save file maybe write " -"protected?" +"Are you running Dolphin from a CD/DVD, or is the save file maybe write protected?" msgstr "" "Não foi possível escrever no arquivo de Memory Card %s.\n" "\n" -"Você está executando o Dolphin de um CD/DVD, ou talvez o arquivo de salva " -"seja somente-leitura?" +"Você está executando o Dolphin de um CD/DVD, ou talvez o arquivo de salva seja somente-leitura?" #: Source/Core/DolphinWX/Src/ISOProperties.cpp:1044 msgid "Couldn't find open command for extension 'ini'!" @@ -1333,10 +1277,8 @@ msgid "Created by KDE-Look.org" msgstr "Criado por KDE-Look.org" #: Source/Core/DolphinWX/Src/ConfigMain.cpp:491 -msgid "" -"Created by Milosz Wlazlo [miloszwl@miloszwl.com, miloszwl.deviantart.com]" -msgstr "" -"Criado por Milosz Wlazlo [miloszwl@miloszwl.com, miloszwl.deviantart.com]" +msgid "Created by Milosz Wlazlo [miloszwl@miloszwl.com, miloszwl.deviantart.com]" +msgstr "Criado por Milosz Wlazlo [miloszwl@miloszwl.com, miloszwl.deviantart.com]" #: Source/Core/DolphinWX/Src/ConfigMain.cpp:492 msgid "Created by VistaIcons.com" @@ -1352,7 +1294,7 @@ msgstr "Criador:" #: Source/Core/Common/Src/MsgHandler.cpp:68 msgid "Critical" -msgstr "" +msgstr "Crítico" #: Source/Core/DolphinWX/Src/VideoConfigDiag.cpp:527 msgid "Crop" @@ -1512,12 +1454,8 @@ msgstr "Detectar" #: Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_DI.cpp:230 #: Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_DI.cpp:325 -msgid "" -"Detected attempt to read more data from the DVD than fit inside the out " -"buffer. Clamp." -msgstr "" -"Foi detectada a tentativa de ler mais dados do DVD do que cabem no buffer de " -"saída. Segurando." +msgid "Detected attempt to read more data from the DVD than fit inside the out buffer. Clamp." +msgstr "Foi detectada a tentativa de ler mais dados do DVD do que cabem no buffer de saída. Segurando." #: Source/Core/DolphinWX/Src/InputConfigDiag.cpp:131 #: Source/Core/DolphinWX/Src/InputConfigDiag.cpp:902 @@ -1577,30 +1515,24 @@ msgstr "Desabilitar o Auto-Falante do Wiimote" #: Source/Core/DolphinWX/Src/VideoConfigDiag.cpp:106 msgid "" "Disable any XFB emulation.\n" -"Speeds up emulation a lot but causes heavy glitches in many games which rely " -"on them (especially homebrew applications).\n" +"Speeds up emulation a lot but causes heavy glitches in many games which rely on them (especially homebrew applications).\n" "\n" "If unsure, leave this checked." msgstr "" "Desativa a emulação do XFB.\n" -"Aumenta bastante a performance mas pode causar problemas em vários jogos que " -"precisam dela (especialmente aplicativos amadores/homebrew).\n" +"Aumenta bastante a performance mas pode causar problemas em vários jogos que precisam dela (especialmente aplicativos amadores/homebrew).\n" "\n" "Se estiver em dúvida, deixe isto ativado." #: Source/Core/DolphinWX/Src/VideoConfigDiag.cpp:93 msgid "" "Disable emulation of EFB copies.\n" -"These are often used for post-processing or render-to-texture effects, so " -"while checking this setting gives a great speedup it almost always also " -"causes issues.\n" +"These are often used for post-processing or render-to-texture effects, so while checking this setting gives a great speedup it almost always also causes issues.\n" "\n" "If unsure, leave this unchecked." msgstr "" "Desativa a emulação de cópias do EFB.\n" -"Elas são usadas com frequência para efeitos pós-processamento ou efeitos de " -"textura, portanto apesar de esta opção aumentar bastante a velocidade, ela " -"quase sempre causa problemas.\n" +"Elas são usadas com frequência para efeitos pós-processamento ou efeitos de textura, portanto apesar de esta opção aumentar bastante a velocidade, ela quase sempre causa problemas.\n" "\n" "Se estiver em dúvida, deixe isto desativado." @@ -1688,20 +1620,12 @@ msgid "Dolphin at &Google Code" msgstr "Dolphin no &Google Code" #: Source/Core/DolphinWX/Src/GameListCtrl.cpp:303 -msgid "" -"Dolphin could not find any GC/Wii ISOs. Doubleclick here to browse for " -"files..." -msgstr "" -"Dolphin não pôde encontrar ISOs GC/Wii. Duplo-clique aqui para procurar por " -"arquivos..." +msgid "Dolphin could not find any GC/Wii ISOs. Doubleclick here to browse for files..." +msgstr "Dolphin não pôde encontrar ISOs GC/Wii. Duplo-clique aqui para procurar por arquivos..." #: Source/Core/DolphinWX/Src/GameListCtrl.cpp:307 -msgid "" -"Dolphin is currently set to hide all games. Doubleclick here to show all " -"games..." -msgstr "" -"Dolphin atualmente está configurado para esconder todos os jogos. Duplo-" -"clique aqui para mostrar todos os jogos..." +msgid "Dolphin is currently set to hide all games. Doubleclick here to show all games..." +msgstr "Dolphin atualmente está configurado para esconder todos os jogos. Duplo-clique aqui para mostrar todos os jogos..." #: Source/Core/DolphinWX/Src/WXInputBase.cpp:55 #: Source/Core/InputCommon/Src/ControllerEmu.cpp:275 @@ -1747,8 +1671,7 @@ msgid "" "\n" "If unsure, leave this unchecked." msgstr "" -"Transfere todos os quadros renderizados para um arquivo AVI em User/Dump/" -"Frames/\n" +"Transfere todos os quadros renderizados para um arquivo AVI em User/Dump/Frames/\n" "\n" "Se estiver em dúvida, deixe isto desativado." @@ -1787,16 +1710,8 @@ msgstr "Cópias de EFB" #: Source/Core/Core/Src/HW/BBA-TAP/TAP_Win32.cpp:249 #, c-format -msgid "" -"ERROR: This version of Dolphin requires a TAP-Win32 driver that is at least " -"version %d.%d -- If you recently upgraded your Dolphin distribution, a " -"reboot is probably required at this point to get Windows to see the new " -"driver." -msgstr "" -"ERRO: Esta versão do Dolphin precisa de um driver TAP-Win32 no mínimo com a " -"versão %d.%d -- Se você mudou a versão do Dolphin recentemente, reiniciar o " -"PC é provavelmente necessário no momento para que o Windows veja o novo " -"driver." +msgid "ERROR: This version of Dolphin requires a TAP-Win32 driver that is at least version %d.%d -- If you recently upgraded your Dolphin distribution, a reboot is probably required at this point to get Windows to see the new driver." +msgstr "ERRO: Esta versão do Dolphin precisa de um driver TAP-Win32 no mínimo com a versão %d.%d -- Se você mudou a versão do Dolphin recentemente, reiniciar o PC é provavelmente necessário no momento para que o Windows veja o novo driver." #: Source/Core/DolphinWX/Src/ISOProperties.cpp:162 msgid "EUROPE" @@ -1846,30 +1761,24 @@ msgstr "Este Segmento de Emulação já está rodando" #: Source/Core/DolphinWX/Src/VideoConfigDiag.cpp:108 msgid "" "Emulate XFBs accurately.\n" -"Slows down emulation a lot and prohibits high-resolution rendering but is " -"necessary to emulate a number of games properly.\n" +"Slows down emulation a lot and prohibits high-resolution rendering but is necessary to emulate a number of games properly.\n" "\n" "If unsure, check virtual XFB emulation instead." msgstr "" "Emula os XFBs com precisão.\n" -"Diminui muito a performance e impossibilita a renderização em resoluções " -"altas mas é necessário para emular corretamente um certo número de jogos.\n" +"Diminui muito a performance e impossibilita a renderização em resoluções altas mas é necessário para emular corretamente um certo número de jogos.\n" "\n" "Se estiver em dúvida, selecione Virtual." #: Source/Core/DolphinWX/Src/VideoConfigDiag.cpp:107 msgid "" "Emulate XFBs using GPU texture objects.\n" -"Fixes many games which don't work without XFB emulation while not being as " -"slow as real XFB emulation. However, it may still fail for a lot of other " -"games (especially homebrew applications).\n" +"Fixes many games which don't work without XFB emulation while not being as slow as real XFB emulation. However, it may still fail for a lot of other games (especially homebrew applications).\n" "\n" "If unsure, leave this checked." msgstr "" "Emula os XFBs usando objetos de textura da GPU.\n" -"Corrige vários jogos que dependem da emulação do XFB e é bem mais rápido que " -"o XFB real. No entanto, ele ainda não funciona para muitos outros jogos (em " -"especial aplicativos homebrew/amadores).\n" +"Corrige vários jogos que dependem da emulação do XFB e é bem mais rápido que o XFB real. No entanto, ele ainda não funciona para muitos outros jogos (em especial aplicativos homebrew/amadores).\n" "\n" "Se estiver em dúvida, deixe isto ativado." @@ -1887,15 +1796,13 @@ msgstr "Ativar" #: Source/Core/DolphinWX/Src/VideoConfigDiag.cpp:89 msgid "" -"Enable 3D effects via stereoscopy using Nvidia 3D Vision technology if it's " -"supported by your GPU.\n" +"Enable 3D effects via stereoscopy using Nvidia 3D Vision technology if it's supported by your GPU.\n" "Possibly causes issues.\n" "Requires fullscreen to work.\n" "\n" "If unsure, leave this unchecked." msgstr "" -"Ativa efeitos 3D através de estereoscopia usando a tecnologia Nvidia 3D " -"Vision se isto for suportado pela sua GPU.\n" +"Ativa efeitos 3D através de estereoscopia usando a tecnologia Nvidia 3D Vision se isto for suportado pela sua GPU.\n" "Pode causar problemas.\n" "Pecisa estar em Tela Cheia para funcionar.\n" "\n" @@ -1975,19 +1882,14 @@ msgid "" "If unsure, select 1x." msgstr "" "Ativar Filtro Anisotrópico.\n" -"Melhora a qualidade visual das texturas quando são vistas de ângulos " -"oblíquos.\n" +"Melhora a qualidade visual das texturas quando são vistas de ângulos oblíquos.\n" "Pode causar problemas em um número pequeno de jogos. \n" "\n" "Se estiver em dúvida, selecione 1x." #: Source/Core/DolphinWX/Src/ISOProperties.cpp:317 -msgid "" -"Enable fast disc access. Needed for a few games. (ON = Fast, OFF = " -"Compatible)" -msgstr "" -"Ativar acesso rápido de disco. Necessário para alguns jogos.(ON = Rapido, " -"OFF = Compativel)" +msgid "Enable fast disc access. Needed for a few games. (ON = Fast, OFF = Compatible)" +msgstr "Ativar acesso rápido de disco. Necessário para alguns jogos.(ON = Rapido, OFF = Compativel)" #: Source/Core/DolphinWX/Src/MemcardManager.cpp:799 msgid "Enable pages" @@ -2007,33 +1909,21 @@ msgstr "" #: Source/Core/DolphinWX/Src/VideoConfigDiag.cpp:79 msgid "" -"Enable this if you want to use the main Dolphin window for rendering rather " -"than a separate render window.\n" +"Enable this if you want to use the main Dolphin window for rendering rather than a separate render window.\n" "\n" "If unsure, leave this unchecked." msgstr "" -"Tive esta opção se você quiser usar a janela principal do Dolphin para " -"mostrar o jogo em vez de uma janela separada para a renderização.\n" +"Tive esta opção se você quiser usar a janela principal do Dolphin para mostrar o jogo em vez de uma janela separada para a renderização.\n" "\n" "Se estiver em dúvida, deixe isto desativado." #: Source/Core/DolphinWX/Src/ISOProperties.cpp:329 -msgid "" -"Enable this to speed up The Legend of Zelda: Twilight Princess. Disable for " -"ANY other game." -msgstr "" -"Ative isso para ter ganho de velocidade em The legend of Zelda: Twilight " -"Princess. Disative para QUALQUER UM outro jogo." +msgid "Enable this to speed up The Legend of Zelda: Twilight Princess. Disable for ANY other game." +msgstr "Ative isso para ter ganho de velocidade em The legend of Zelda: Twilight Princess. Disative para QUALQUER UM outro jogo." #: Source/Core/DolphinWX/Src/ISOProperties.cpp:311 -msgid "" -"Enables Block Address Translation (BAT); a function of the Memory Management " -"Unit. Accurate to the hardware, but slow to emulate. (ON = Compatible, OFF = " -"Fast)" -msgstr "" -"Ativar Block Address Translation (BAT); uma função da unidade de " -"gerenciamento de memoria. Precisão para o hardware, mas devagar para ser " -"emulado (ON = Compativel, OFF = Rapido)" +msgid "Enables Block Address Translation (BAT); a function of the Memory Management Unit. Accurate to the hardware, but slow to emulate. (ON = Compatible, OFF = Fast)" +msgstr "Ativar Block Address Translation (BAT); uma função da unidade de gerenciamento de memoria. Precisão para o hardware, mas devagar para ser emulado (ON = Compativel, OFF = Rapido)" #: Source/Core/DolphinWX/Src/ISOProperties.cpp:334 msgid "Enables Custom Projection Hack" @@ -2052,12 +1942,8 @@ msgstr "" "Se estiver em dúvida, deixe isto desativado" #: Source/Core/DolphinWX/Src/ISOProperties.cpp:309 -msgid "" -"Enables the Memory Management Unit, needed for some games. (ON = Compatible, " -"OFF = Fast)" -msgstr "" -"Ativar unidade de gerenciamento de memoria, necessário para alguns jogos. " -"(ON = Compativel, OFF = Rapido)" +msgid "Enables the Memory Management Unit, needed for some games. (ON = Compatible, OFF = Fast)" +msgstr "Ativar unidade de gerenciamento de memoria, necessário para alguns jogos. (ON = Compativel, OFF = Rapido)" #: Source/Core/DolphinWX/Src/VideoConfigDiag.cpp:114 msgid "" @@ -2114,12 +2000,8 @@ msgstr "Erro ao carregar o idioma selecionado. Voltando ao padrão do sistema." #: Source/Core/Core/Src/HW/EXI_DeviceIPL.cpp:273 #, c-format -msgid "" -"Error: Trying to access %s fonts but they are not loaded. Games may not show " -"fonts correctly, or crash." -msgstr "" -"Erro: Tentando acessar as fontes %s mas elas não estão carregadas. Os jogos " -"podem não mostrar as fontes corretamente, ou travar." +msgid "Error: Trying to access %s fonts but they are not loaded. Games may not show fonts correctly, or crash." +msgstr "Erro: Tentando acessar as fontes %s mas elas não estão carregadas. Os jogos podem não mostrar as fontes corretamente, ou travar." #: Source/Core/DolphinWX/Src/WXInputBase.cpp:30 msgid "Escape" @@ -2132,8 +2014,7 @@ msgstr "Euphoria" #: Source/Core/Core/Src/MemTools.cpp:214 #, c-format msgid "Exception handler - access below memory space. %08llx%08llx" -msgstr "" -"Manipulador de Exceções - Acesso abaixo do espaço da memória. %08llx%08llx" +msgstr "Manipulador de Exceções - Acesso abaixo do espaço da memória. %08llx%08llx" #: Source/Core/DolphinWX/Src/WXInputBase.cpp:58 msgid "Execute" @@ -2262,7 +2143,7 @@ msgstr "Não foi possível Ouvir!!" #: Source/Core/DolphinWX/Src/GeckoCodeDiag.cpp:286 msgid "Failed to download codes." -msgstr "Fa" +msgstr "Falha ao dazer o download de códigos." #: Source/Core/DolphinWX/Src/ISOProperties.cpp:824 #, c-format @@ -2470,8 +2351,7 @@ msgid "" "\n" "If unsure, leave this unchecked." msgstr "" -"Força filtro de texturas mesmo que o jogo tenha desativado-o " -"explicitamente.\n" +"Força filtro de texturas mesmo que o jogo tenha desativado-o explicitamente.\n" "Melhora um pouco a qualidade das texturas mas causa erros em certos jogos.\n" "\n" "Se estiver em dúvida, deixe isto desativado." @@ -2491,12 +2371,10 @@ msgstr "" #: Source/Core/DolphinWX/Src/ConfigMain.cpp:484 msgid "" "Forces NTSC-J mode for using the Japanese ROM font.\n" -"Left unchecked, dolphin defaults to NTSC-U and automatically enables this " -"setting when playing Japanese games." +"Left unchecked, dolphin defaults to NTSC-U and automatically enables this setting when playing Japanese games." msgstr "" "Força o modo NTSC-J para usar a fonte da ROM Japonesa.\n" -"Se isto ficar desativado, o Dolphin usa NTSC-U e ativa esta opção " -"automaticamente quando você jogar jogos japoneses." +"Se isto ficar desativado, o Dolphin usa NTSC-U e ativa esta opção automaticamente quando você jogar jogos japoneses." #: Source/Core/DolphinWX/Src/MemoryCards/GCMemcard.cpp:73 msgid "" @@ -2641,7 +2519,7 @@ msgstr "Geral" #: Source/Core/DolphinWX/Src/WiimoteConfigDiag.cpp:144 msgid "General Settings" -msgstr "Opções Gerais" +msgstr "Configurações Gerais" #: Source/Core/DolphinWX/Src/ConfigMain.cpp:263 #: Source/Core/DolphinWX/Src/ConfigMain.cpp:297 @@ -2668,14 +2546,12 @@ msgstr "Maior do que" #: Source/Core/DolphinWX/Src/VideoConfigDiag.cpp:94 msgid "" -"Greatly increases quality of textures generated using render-to-texture " -"effects.\n" +"Greatly increases quality of textures generated using render-to-texture effects.\n" "Raising the internal resolution will improve the effect of this setting.\n" "\n" "If unsure, leave this checked." msgstr "" -"Aumenta muito a qualidade das texturas geradas usando efeitos de " -"renderização.\n" +"Aumenta muito a qualidade das texturas geradas usando efeitos de renderização.\n" "Aumentar a Resolução Interna vai melhorar o efeito desta opção.\n" "\n" "Se estiver em dúvida, deixe isto ativado." @@ -2736,8 +2612,7 @@ msgstr "" "Olá\n" "\n" "O Dolphin precisa que a sua CPU tenha suporte a extensões SSE2. \n" -"Infelizmente a sua CPU não tem este suporte, e portanto o Dolphin não " -"funcionará.\n" +"Infelizmente a sua CPU não tem este suporte, e portanto o Dolphin não funcionará.\n" "\n" "Sayonara!\n" @@ -2788,19 +2663,16 @@ msgstr "Wiimote Hibrido" #: Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp:523 #, c-format msgid "IOCTL_ES_GETVIEWS: Tried to get data from an unknown ticket: %08x/%08x" -msgstr "" -"IOCTL_ES_GETVIEWS:Tentou adiquirir dados de um ticket desconhecido: %08x/%08x" +msgstr "IOCTL_ES_GETVIEWS:Tentou adiquirir dados de um ticket desconhecido: %08x/%08x" #: Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp:795 #, c-format msgid "" -"IOCTL_ES_LAUNCH: Game tried to reload ios or a title that is not available " -"in your nand dump\n" +"IOCTL_ES_LAUNCH: Game tried to reload ios or a title that is not available in your nand dump\n" "TitleID %016llx.\n" " Dolphin will likely hang now" msgstr "" -"IOCTL_ES_LAUNCH: O jogo tentou recarregar a ios ou um título que não está " -"disponível no dump do seu NAND\n" +"IOCTL_ES_LAUNCH: O jogo tentou recarregar a ios ou um título que não está disponível no dump do seu NAND\n" "TitleID %016llx.\n" " O Dolphin vai provavelmente travar agora" @@ -2841,20 +2713,12 @@ msgid "Icon" msgstr "Icone" #: Source/Core/DolphinWX/Src/ISOProperties.cpp:315 -msgid "" -"If the FPS is erratic, this option may help. (ON = Compatible, OFF = Fast)" -msgstr "" -"Se a taxa de FPS estiver instável, esta opção pode ajudar. (ON = Compatível, " -"OFF = Rápido)" +msgid "If the FPS is erratic, this option may help. (ON = Compatible, OFF = Fast)" +msgstr "Se a taxa de FPS estiver instável, esta opção pode ajudar. (ON = Compatível, OFF = Rápido)" #: Source/Core/DolphinWX/Src/ConfigMain.cpp:481 -msgid "" -"If you set Framelimit higher than game full speed (NTSC:60, PAL:50), you " -"also have to disable Audio Throttle in DSP to make it effective." -msgstr "" -"Se você colocar o Limitador de FPS em um valor maior que a velocidade máxima " -"do jogo (NTSC:60, PAL:50), você também vai precisar desativar o Throttle de " -"Áudio no DSP para que funcione." +msgid "If you set Framelimit higher than game full speed (NTSC:60, PAL:50), you also have to disable Audio Throttle in DSP to make it effective." +msgstr "Se você colocar o Limitador de FPS em um valor maior que a velocidade máxima do jogo (NTSC:60, PAL:50), você também vai precisar desativar o Throttle de Áudio no DSP para que funcione." #: Source/Core/DolphinWX/Src/VideoConfigDiag.cpp:427 msgid "Ignore Format Changes" @@ -2863,28 +2727,24 @@ msgstr "Ignorar Mudanças de Formato" #: Source/Core/DolphinWX/Src/VideoConfigDiag.cpp:92 msgid "" "Ignore any changes to the EFB format.\n" -"Improves performance in many games without any negative effect. Causes " -"graphical defects in a small number of other games though.\n" +"Improves performance in many games without any negative effect. Causes graphical defects in a small number of other games though.\n" "\n" "If unsure, leave this checked." msgstr "" "Ignora qualquer mudança no formato do EFB.\n" -"Melhora a Performance em vários jogos sem qualquer efeito negativo. Causa " -"defeitos gráficos em um pequeno número de jogos, no entanto.\n" +"Melhora a Performance em vários jogos sem qualquer efeito negativo. Causa defeitos gráficos em um pequeno número de jogos, no entanto.\n" "\n" "Se estiver em dúvida, deixe isto ativado." #: Source/Core/DolphinWX/Src/VideoConfigDiag.cpp:91 msgid "" "Ignore any requests of the CPU to read from or write to the EFB.\n" -"Improves performance in some games, but might disable some gameplay-related " -"features or graphical effects.\n" +"Improves performance in some games, but might disable some gameplay-related features or graphical effects.\n" "\n" "If unsure, leave this unchecked." msgstr "" "Ignora quaisquer pedidos da CPU de ler ou escrever no EFB.\n" -"Melhora a performance em alguns jogos, mas pode desativar algumas funções " -"dos jogos ou efeitos gráficos.\n" +"Melhora a performance em alguns jogos, mas pode desativar algumas funções dos jogos ou efeitos gráficos.\n" "\n" "Se estiver em dúvida, deixe isto desativado." @@ -2918,13 +2778,11 @@ msgstr "" #: Source/Core/DolphinWX/Src/VideoConfigDiag.cpp:99 msgid "" -"Improves performance but causes glitches in most games which rely on proper " -"fog emulation.\n" +"Improves performance but causes glitches in most games which rely on proper fog emulation.\n" "\n" "If unsure, leave this unchecked." msgstr "" -"Aumenta a performance mas causa problemas em jogos que dependem da emulação " -"apropriada da névoa.\n" +"Aumenta a performance mas causa problemas em jogos que dependem da emulação apropriada da névoa.\n" "\n" "Se estiver em dúvida, deixe esta opção desativada." @@ -2934,8 +2792,7 @@ msgid "" "\n" "If unsure, leave this unchecked." msgstr "" -"Melhora a performance mas faz a iluminação desaparecer na maioria dos " -"jogos.\n" +"Melhora a performance mas faz a iluminação desaparecer na maioria dos jogos.\n" "\n" "Se estiver em dúvida, deixe esta opção desativada." @@ -2985,11 +2842,8 @@ msgid "Install to Wii Menu" msgstr "Instalar para o menu do WII" #: Source/Core/Core/Src/MemTools.cpp:248 -msgid "" -"InstallExceptionHandler called, but this platform does not yet support it." -msgstr "" -"InstallExceptionHandler foi chamado, mas esta plataforma ainda não tem " -"suporte a ele." +msgid "InstallExceptionHandler called, but this platform does not yet support it." +msgstr "InstallExceptionHandler foi chamado, mas esta plataforma ainda não tem suporte a ele." #: Source/Core/DolphinWX/Src/FrameTools.cpp:1361 msgid "Installing WAD..." @@ -3238,8 +3092,7 @@ msgid "" "\n" "If unsure, leave this unchecked." msgstr "" -"Carrega texturas de alta definição do diretório User/Load/Textures//\n" +"Carrega texturas de alta definição do diretório User/Load/Textures//\n" "\n" "Se estiver em dúvida, deixe isto desativado." @@ -3346,12 +3199,8 @@ msgid "Memory Card" msgstr "Cartão de memoria" #: Source/Core/DolphinWX/Src/MemcardManager.h:36 -msgid "" -"Memory Card Manager WARNING-Make backups before using, should be fixed but " -"could mangle stuff!" -msgstr "" -"AVISO do Gerenciador de- Memory Card - Faça backupsantes de usar, deve estar " -"funcionando mas pode corromper coisas!" +msgid "Memory Card Manager WARNING-Make backups before using, should be fixed but could mangle stuff!" +msgstr "AVISO do Gerenciador de- Memory Card - Faça backupsantes de usar, deve estar funcionando mas pode corromper coisas!" #: Source/Core/Core/Src/CoreParameter.cpp:369 #, c-format @@ -3372,7 +3221,7 @@ msgstr "" #: Source/Core/DolphinWX/Src/MemoryCards/GCMemcard.cpp:126 msgid "Memorycard filesize does not match the header size" -msgstr "" +msgstr "O tamanho do arquivo do Memory Card é diferente do tamanho do header" #: Source/Core/DolphinWX/Src/WXInputBase.cpp:47 msgid "Menu" @@ -3402,14 +3251,11 @@ msgstr "Modificador" #: Source/Core/DolphinWX/Src/VideoConfigDiag.cpp:104 msgid "" -"Modify textures to show the format they're encoded in. Needs an emulation " -"reset in most cases.\n" +"Modify textures to show the format they're encoded in. Needs an emulation reset in most cases.\n" "\n" "If unsure, leave this unchecked." msgstr "" -"Modifica as texturas para que elas mostrem o formato em que elas estão " -"codificadas. Ao ativar isto, é preciso reiniciar a emulação na maioria das " -"vezes.\n" +"Modifica as texturas para que elas mostrem o formato em que elas estão codificadas. Ao ativar isto, é preciso reiniciar a emulação na maioria das vezes.\n" "\n" "Se estiver em dúvida, deixe isto desativado." @@ -3449,12 +3295,8 @@ msgid "Multiply" msgstr "Multiplicar" #: Source/Core/DolphinWX/Src/ISOProperties.cpp:325 -msgid "" -"Mutes the Wiimote speaker. Fixes random disconnections on real wiimotes. No " -"effect on emulated wiimotes." -msgstr "" -"Desliga o som que sai do Wiimote. Corrige desconexões imprevisíveis em " -"Wiimotes Reais. Não faz efeito em Wiimotes Emulados." +msgid "Mutes the Wiimote speaker. Fixes random disconnections on real wiimotes. No effect on emulated wiimotes." +msgstr "Desliga o som que sai do Wiimote. Corrige desconexões imprevisíveis em Wiimotes Reais. Não faz efeito em Wiimotes Emulados." #: Source/Core/DolphinWX/Src/WXInputBase.cpp:126 msgid "NP Add" @@ -3758,12 +3600,8 @@ msgid "Other" msgstr "Outros" #: Source/Core/Core/Src/NetPlayClient.cpp:206 -msgid "" -"Other client disconnected while game is running!! NetPlay is disabled. You " -"manually stop the game." -msgstr "" -"Outro Client desconectou enquanto o jogo rodava!! O Netplay foi " -"desabilitado. Você deve parar o jogo manualmente." +msgid "Other client disconnected while game is running!! NetPlay is disabled. You manually stop the game." +msgstr "Outro Client desconectou enquanto o jogo rodava!! O Netplay foi desabilitado. Você deve parar o jogo manualmente." #: Source/Core/DolphinWX/Src/InputConfigDiag.cpp:485 msgid "Output" @@ -3993,9 +3831,8 @@ msgid "Real Wiimote" msgstr "Wiimote Real" #: Source/Core/DolphinWX/Src/WiimoteConfigDiag.cpp:81 -#, fuzzy msgid "Real Wiimotes" -msgstr "Wiimote Real" +msgstr "Wiimotes Reais" #: Source/Core/DolphinWX/Src/Frame.cpp:163 msgid "Reconnect Wiimote Confirm" @@ -4220,8 +4057,10 @@ msgstr "Filtro de Busca" msgid "Search Subfolders" msgstr "Procurar em sub-pastas" -#: Source/Core/Common/Src/SysConf.h:104 Source/Core/Common/Src/SysConf.h:127 -#: Source/Core/Common/Src/SysConf.h:147 Source/Core/Common/Src/SysConf.h:168 +#: Source/Core/Common/Src/SysConf.h:104 +#: Source/Core/Common/Src/SysConf.h:127 +#: Source/Core/Common/Src/SysConf.h:147 +#: Source/Core/Common/Src/SysConf.h:168 #, c-format msgid "Section %s not found in SYSCONF" msgstr "A seção %s não foi encontrada no SYSCONF" @@ -4298,15 +4137,13 @@ msgstr "Fonte Selecionada" #: Source/Core/DolphinWX/Src/VideoConfigDiag.cpp:75 msgid "" "Selects the display resolution used in fullscreen mode.\n" -"This should always be bigger than or equal to the internal resolution. " -"Performance impact is negligible.\n" +"This should always be bigger than or equal to the internal resolution. Performance impact is negligible.\n" "\n" "If unsure, use your desktop resolution.\n" "If still unsure, use the highest resolution which works for you." msgstr "" "Seleciona que resolução será usada no modo Tela Cheia.\n" -"Isto deve ser sempre maior ou igual à Resolução Interna. O impacto na " -"performance é insignificante.\n" +"Isto deve ser sempre maior ou igual à Resolução Interna. O impacto na performance é insignificante.\n" "\n" "Se estiver em dúvida, use a resolução da sua Área de Trabalho.\n" "Se ainda estiver em dúvida, use a maior disponível.." @@ -4314,15 +4151,13 @@ msgstr "" #: Source/Core/DolphinWX/Src/VideoConfigDiag.cpp:73 msgid "" "Selects what graphics API to use internally.\n" -"Direct3D 9 usually is the fastest one. OpenGL is more accurate though. " -"Direct3D 11 is somewhere between the two.\n" +"Direct3D 9 usually is the fastest one. OpenGL is more accurate though. Direct3D 11 is somewhere between the two.\n" "Note that the Direct3D backends are only available on Windows.\n" "\n" "If unsure, use Direct3D 9." msgstr "" "Seleciona qual API gráfico será usado internamente.\n" -"Direct3D 9 é geralmente o mais rápido. O OpenGL tem menos erros, no entanto. " -"O Direct3D 11 está entre os dois.\n" +"Direct3D 9 é geralmente o mais rápido. O OpenGL tem menos erros, no entanto. O Direct3D 11 está entre os dois.\n" "Note que os Backends Direct3D só podem ser usados no Windows.\n" "\n" "Se estiver em dúvida, use o Direct3D 9." @@ -4344,11 +4179,8 @@ msgid "Serbian" msgstr "Sérvio" #: Source/Core/DolphinWX/Src/ConfigMain.cpp:506 -msgid "" -"Serial Port 1 - This is the port which devices such as the net adapter use" -msgstr "" -"Porta Serial 1 - Esta é a porta usada por dispositivos como o adaptador de " -"rede" +msgid "Serial Port 1 - This is the port which devices such as the net adapter use" +msgstr "Porta Serial 1 - Esta é a porta usada por dispositivos como o adaptador de rede" #: Source/Core/DolphinWX/Src/InputConfigDiag.cpp:492 msgid "Set" @@ -4366,8 +4198,7 @@ msgstr "Definir como Memory Card padrão%c" #: Source/Core/Core/Src/ActionReplay.cpp:462 #, c-format msgid "SetARCode_IsActive: Index is greater than ar code list size %lu" -msgstr "" -"SetARCode_IsActive: O índice é maior que a lista de códigos AR de tamanho %lu" +msgstr "SetARCode_IsActive: O índice é maior que a lista de códigos AR de tamanho %lu" #: Source/Core/DolphinWX/Src/ISOProperties.cpp:335 msgid "Settings..." @@ -4488,12 +4319,10 @@ msgstr "Mostrar uma janela de confirmação antes de parar um jogo." #: Source/Core/DolphinWX/Src/ConfigMain.cpp:488 msgid "" "Show a message box when a potentially serious error has occured.\n" -"Disabling this may avoid annoying and non-fatal messages, but it may also " -"mean that Dolphin suddenly crashes without any explanation at all." +"Disabling this may avoid annoying and non-fatal messages, but it may also mean that Dolphin suddenly crashes without any explanation at all." msgstr "" "Mostra uma menssagem quando erros potencialmente sérios ocorreram. \n" -"Desabilitar isso pode evitar menssagens irritantes e não-fatais, mas também " -"pode fazer com que o Dolphin trave sem nenhuma explicação." +"Desabilitar isso pode evitar menssagens irritantes e não-fatais, mas também pode fazer com que o Dolphin trave sem nenhuma explicação." #: Source/Core/DolphinWX/Src/MemcardManager.cpp:812 msgid "Show first block" @@ -4517,13 +4346,11 @@ msgstr "Mostrar título do salva" #: Source/Core/DolphinWX/Src/VideoConfigDiag.cpp:101 msgid "" -"Show the number of frames rendered per second as a measure of emulation " -"speed.\n" +"Show the number of frames rendered per second as a measure of emulation speed.\n" "\n" "If unsure, leave this unchecked." msgstr "" -"Mostra o número de quadros renderizados por segundo como uma forma de medir " -"a velocidade da emulação.\n" +"Mostra o número de quadros renderizados por segundo como uma forma de medir a velocidade da emulação.\n" "\n" "Se estiver em dúvida, deixe isto desativado." @@ -4571,13 +4398,11 @@ msgstr "Não permite o acesso da CPU ao EFB" #: Source/Core/DolphinWX/Src/VideoConfigDiag.cpp:100 msgid "" -"Skip the destination alpha pass used in many games for various graphical " -"effects.\n" +"Skip the destination alpha pass used in many games for various graphical effects.\n" "\n" "If unsure, leave this unchecked." msgstr "" -"Não faz o passe de destino Alfa usado em muitos jogos para vários efeitos " -"gráficos.\n" +"Não faz o passe de destino Alfa usado em muitos jogos para vários efeitos gráficos.\n" "\n" "Se estiver em dúvida, deixe isto desativado." @@ -4605,15 +4430,13 @@ msgstr "Renderizador por Software" #: Source/Core/DolphinWX/Src/VideoConfigDiag.h:83 msgid "" -"Software rendering is an order of magnitude slower than using the other " -"backends.\n" +"Software rendering is an order of magnitude slower than using the other backends.\n" "It's only useful for debugging purposes.\n" "Do you really want to enable software rendering? If unsure, select 'No'." msgstr "" "O Renderizador por Software é bem mais lento que os outros backends.\n" "É útil apenas para a depuração de problemas.\n" -"Você realmente quer utilizar o Renderizador por Software? Se estiver em " -"dúvida, pressione 'Não'." +"Você realmente quer utilizar o Renderizador por Software? Se estiver em dúvida, pressione 'Não'." #: Source/Core/DolphinWX/Src/ConfigMain.cpp:618 msgid "Sound Settings" @@ -4645,21 +4468,13 @@ msgstr "Volume do Auto-Falante:" #: Source/Core/DolphinWX/Src/VideoConfigDiag.cpp:90 msgid "" -"Specifies the resolution used to render at. A high resolution will improve " -"visual quality a lot but is also quite heavy on performance and might cause " -"glitches in certain games.\n" -"\"Multiple of 640x528\" is a bit slower than \"Window Size\" but yields less " -"issues. Generally speaking, the lower the internal resolution is, the better " -"your performance will be.\n" +"Specifies the resolution used to render at. A high resolution will improve visual quality a lot but is also quite heavy on performance and might cause glitches in certain games.\n" +"\"Multiple of 640x528\" is a bit slower than \"Window Size\" but yields less issues. Generally speaking, the lower the internal resolution is, the better your performance will be.\n" "\n" "If unsure, select 640x528." msgstr "" -"Especifica a resolução a renderizar. Uma resolução mais alta aumenta a " -"qualidade visual mas é bastante pesada e pode causar problemas em alguns " -"jogos.\n" -"\"Múltiplo de 640x528\" é um pouco mais lento que \"Window Size\" mas causa " -"menos problemas. De forma geral, quanto menor for a resolução interna, maior " -"será a performance.\n" +"Especifica a resolução a renderizar. Uma resolução mais alta aumenta a qualidade visual mas é bastante pesada e pode causar problemas em alguns jogos.\n" +"\"Múltiplo de 640x528\" é um pouco mais lento que \"Window Size\" mas causa menos problemas. De forma geral, quanto menor for a resolução interna, maior será a performance.\n" "\n" "Se estiver em dúvida, selecione 640x528." @@ -4814,12 +4629,8 @@ msgstr "" #: Source/Core/AudioCommon/Src/WaveFile.cpp:51 #, c-format -msgid "" -"The file %s could not be opened for writing. Please check if it's already " -"opened by another program." -msgstr "" -"O arquivo %s não pôde ser aberto para escrita. Por favor cheque se ele não " -"está aberto em outro programa." +msgid "The file %s could not be opened for writing. Please check if it's already opened by another program." +msgstr "O arquivo %s não pôde ser aberto para escrita. Por favor cheque se ele não está aberto em outro programa." #: Source/Core/AudioCommon/Src/WaveFile.cpp:44 #, c-format @@ -4845,16 +4656,11 @@ msgstr "O código AR resultante da derciptação não contém nenhuma linha." #: Source/Core/DolphinWX/Src/MemcardManager.cpp:447 msgid "The save you are trying to copy has an invalid file size" -msgstr "" -"O Salva que você está tentando copiar tem um tamanho de arquivo inválido" +msgstr "O Salva que você está tentando copiar tem um tamanho de arquivo inválido" #: Source/Core/DolphinWX/Src/Main.cpp:363 -msgid "" -"The selected language is not supported by your system. Falling back to " -"system default." -msgstr "" -"O idioma selecionado não é suportado pelo seu sistema. Voltando ao padrão do " -"sistema." +msgid "The selected language is not supported by your system. Falling back to system default." +msgstr "O idioma selecionado não é suportado pelo seu sistema. Voltando ao padrão do sistema." #: Source/Core/Core/Src/NetPlayClient.cpp:43 msgid "The server and client's NetPlay versions are incompatible!" @@ -4890,12 +4696,8 @@ msgid "Theme selection went wrong" msgstr "A seleção do tema deu errado" #: Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp:467 -msgid "" -"There must be a ticket for 00000001/00000002. Your NAND dump is probably " -"incomplete." -msgstr "" -"É necessário um ticket para 00000001/00000002. O seu Dump do NAND está " -"provavelmente incompleto." +msgid "There must be a ticket for 00000001/00000002. Your NAND dump is probably incomplete." +msgstr "É necessário um ticket para 00000001/00000002. O seu Dump do NAND está provavelmente incompleto." #: Source/Core/DolphinWX/Src/ISOProperties.cpp:304 msgid "" @@ -4906,34 +4708,23 @@ msgstr "" "Indeterminado significa que o jogo usa as configurações do Dolphin." #: Source/Core/Core/Src/ActionReplay.cpp:356 -msgid "" -"This action replay simulator does not support codes that modify Action " -"Replay itself." -msgstr "" -"Este simulador de Action Replay não suporta códigos que modifiquem o Action " -"Replay em si." +msgid "This action replay simulator does not support codes that modify Action Replay itself." +msgstr "Este simulador de Action Replay não suporta códigos que modifiquem o Action Replay em si." #: Source/Core/DolphinWX/Src/ConfigMain.cpp:509 msgid "This could cause slow down in Wii Menu and some games." -msgstr "" -"Isto pode causar diminuição da performance no Wii Menu e em alguns jogos." +msgstr "Isto pode causar diminuição da performance no Wii Menu e em alguns jogos." #: Source/Core/DolphinWX/Src/VideoConfigDiag.cpp:116 msgid "" "This feature allows you to change the game's camera.\n" -"Hold the right mouse button and move the mouse to pan the camera around. " -"Hold SHIFT and press one of the WASD keys to move the camera by a certain " -"step distance (SHIFT+0 to move faster and SHIFT+9 to move slower). Press " -"SHIFT+R to reset the camera.\n" +"Hold the right mouse button and move the mouse to pan the camera around. Hold SHIFT and press one of the WASD keys to move the camera by a certain step distance (SHIFT+0 to move faster and SHIFT+9 to move slower). Press SHIFT+R to reset the camera.\n" "\n" "If unsure, leave this unchecked." msgstr "" "Este recurso permite mexer na câmera do jogo.\n" "\n" -"Segure o botão direito e mova o mouse para mover a câmera em qualquer " -"direção. Segure SHIFT e pressione uma das teclas WASD para mover a câmera em " -"uma certa distância (SHIFT+0 para movê-la mais rápido e SHIFT+9 para movê-la " -"mais devagar). Pressione SHIFT+R para voltar a câmera à posição inicial.\n" +"Segure o botão direito e mova o mouse para mover a câmera em qualquer direção. Segure SHIFT e pressione uma das teclas WASD para mover a câmera em uma certa distância (SHIFT+0 para movê-la mais rápido e SHIFT+9 para movê-la mais devagar). Pressione SHIFT+R para voltar a câmera à posição inicial.\n" "\n" "Se estiver em dúvida, deixe isto desativado." @@ -4946,8 +4737,7 @@ msgid "" "Keyboard Shortcut : Hold down to instantly disable Throttle." msgstr "" "Isto é usado para controlar a velocidade do jogo por throttle de som.\n" -"Desativar isso pode causar velocidade de jogo anormal, ás vezes muito " -"rápido.\n" +"Desativar isso pode causar velocidade de jogo anormal, ás vezes muito rápido.\n" "Mas algumas vezes ativar isso pode causar ruído constante.\n" "\n" "Atalho de Teclado : Segure para instantaneamente desativar o Throttle." @@ -4958,15 +4748,11 @@ msgstr "Isto é usado para tocar trilhas sonoras de jogos, como BGM" #: Source/Core/DolphinWX/Src/ConfigMain.cpp:480 msgid "" -"This splits the Video and CPU threads, so they can be run on separate " -"cores.\n" -"Causes major speed improvements on PCs with more than one core, but can also " -"cause occasional crashes/glitches." +"This splits the Video and CPU threads, so they can be run on separate cores.\n" +"Causes major speed improvements on PCs with more than one core, but can also cause occasional crashes/glitches." msgstr "" -"Isto separa os segmentos de Áudio e Vídeo, para que eles possam ser rodados " -"em núcleos diferentes.\n" -"Dá um grande aumento de velocidade para PCs com mais de um núcleo, mas " -"também pode causar travamentos/erros ocasionais." +"Isto separa os segmentos de Áudio e Vídeo, para que eles possam ser rodados em núcleos diferentes.\n" +"Dá um grande aumento de velocidade para PCs com mais de um núcleo, mas também pode causar travamentos/erros ocasionais." #: Source/Core/DolphinWX/Src/ISOProperties.cpp:283 msgid "This will let you Manually Edit the INI config file" @@ -5017,7 +4803,8 @@ msgstr "Houve a tentativa de carregar um tipo de arquivo desconhecido." msgid "Triggers" msgstr "Gatilhos" -#: Source/Core/Common/Src/SysConf.h:92 Source/Core/Common/Src/SysConf.h:115 +#: Source/Core/Common/Src/SysConf.h:92 +#: Source/Core/Common/Src/SysConf.h:115 msgid "Trying to read from invalid SYSCONF" msgstr "Tentando ler de um SYSCONF inválido" @@ -5063,17 +4850,16 @@ msgid "" "Unable to create patch from given values.\n" "Entry not modified." msgstr "" +"Impossível criar patch com os valores dados. \n" +"Nada modificado." #: Source/Core/DolphinWX/Src/ARCodeAddEdit.cpp:123 #, c-format msgid "" -"Unable to parse line %lu of the entered AR code as a valid encrypted or " -"decrypted code. Make sure you typed it correctly.\n" +"Unable to parse line %lu of the entered AR code as a valid encrypted or decrypted code. Make sure you typed it correctly.\n" "Would you like to ignore this line and continue parsing?" msgstr "" -"Não foi possível analisar a linha %lu do código AR digitado como código " -"válido encriptado ou decriptad. Certifique-se de que você digitou " -"corretamente.\n" +"Não foi possível analisar a linha %lu do código AR digitado como código válido encriptado ou decriptad. Certifique-se de que você digitou corretamente.\n" "Você gostaria de ignorar esta linha e continuar a análise?" #: Source/Core/DolphinWX/Src/FrameTools.cpp:404 @@ -5107,8 +4893,7 @@ msgstr "Menssagem desconhecida recebida com identificação: %d" #: Source/Core/Core/Src/NetPlayServer.cpp:504 #, c-format msgid "Unknown message with id:%d received from player:%d Kicking player!" -msgstr "" -"Menssagem desconhecida com ID:%d recebida do jogador:%d Expulsando jogador!" +msgstr "Menssagem desconhecida com ID:%d recebida do jogador:%d Expulsando jogador!" #: Source/Core/Core/Src/HW/Memmap.cpp:633 #, c-format @@ -5157,23 +4942,19 @@ msgid "" "If unsure, leave this unchecked." msgstr "" "Usa múltiplos segmentos para decodificar texturas.\n" -"Pode resultar em um aumento de velocidade (especialmente em CPUs com mais de " -"dois núcleos).\n" +"Pode resultar em um aumento de velocidade (especialmente em CPUs com mais de dois núcleos).\n" "\n" "Se estiver em dúvida, deixe isto desativado." #: Source/Core/DolphinWX/Src/VideoConfigDiag.cpp:123 msgid "" "Usually if shader compilation fails, an error message is displayed.\n" -"However, one may skip the popups to allow interruption free gameplay by " -"checking this option.\n" +"However, one may skip the popups to allow interruption free gameplay by checking this option.\n" "\n" "If unsure, leave this unchecked." msgstr "" -"Normalmente se a compilação dos Shaders falha, uma mensagem de erro é " -"mostrada.\n" -"No entanto, é possível impedir estas mensagens de interromperem o jogo " -"ativando esta opção.\n" +"Normalmente se a compilação dos Shaders falha, uma mensagem de erro é mostrada.\n" +"No entanto, é possível impedir estas mensagens de interromperem o jogo ativando esta opção.\n" "\n" "Se estiver em dúvida, deixe isto desativado." @@ -5258,8 +5039,7 @@ msgid "" "%s\n" "Do you wish to continue?" msgstr "" -"Aviso! É recomendado que você tenha um backup de todos os arquivos na " -"pasta:\n" +"Aviso! É recomendado que você tenha um backup de todos os arquivos na pasta:\n" "%s\n" "Deseja continuar?" @@ -5271,8 +5051,7 @@ msgid "" "and have the same name as a file on your memcard\n" "Continue?" msgstr "" -"Aviso: Isso vai substituir quaisquer arquivos de salva existentes na " -"pasta :\n" +"Aviso: Isso vai substituir quaisquer arquivos de salva existentes na pasta :\n" "%s\n" "que tenham o mesmo nome de um arquivo do Memory Card\n" "Continuar?" @@ -5324,9 +5103,9 @@ msgid "Wiimote" msgstr "Wiimote" #: Source/Core/DolphinWX/Src/WiimoteConfigDiag.cpp:30 -#, fuzzy, c-format +#, c-format msgid "Wiimote %i" -msgstr "Wiimote" +msgstr "Wiimote %i" #: Source/Core/DolphinWX/Src/Frame.cpp:162 #, c-format @@ -5354,9 +5133,8 @@ msgid "Wiimote settings" msgstr "Configurações do Wiimote" #: Source/Core/DolphinWX/Src/WiimoteConfigDiag.cpp:57 -#, fuzzy msgid "Wiimotes" -msgstr "Wiimote" +msgstr "Wiimotes" #: Source/Core/DolphinWX/Src/WXInputBase.cpp:131 msgid "Windows Left" @@ -5416,6 +5194,8 @@ msgid "" "You are using free dsp roms made by Dolphin Team.\n" "Only Zelda ucode games will work correctly with them.\n" msgstr "" +"Você está usando roms do DSP grátis feitas pela Equipe do Dolphin.\n" +"Apenas o ucode dos jogos da série Zelda irão funcionar corretamente com elas. \n" #: Source/Core/DolphinWX/Src/FrameAui.cpp:72 msgid "You can't close panes that have pages in them." @@ -5497,19 +5277,14 @@ msgstr "[Personalizado]" #: Source/Core/DolphinWX/Src/VideoConfigDiag.cpp:118 msgid "" "[EXPERIMENTAL]\n" -"Aims to speed up emulation by offloading texture decoding to the GPU using " -"the OpenCL framework.\n" -"However, right now it's known to cause texture defects in various games. " -"Also it's slower than regular CPU texture decoding in most cases.\n" +"Aims to speed up emulation by offloading texture decoding to the GPU using the OpenCL framework.\n" +"However, right now it's known to cause texture defects in various games. Also it's slower than regular CPU texture decoding in most cases.\n" "\n" "If unsure, leave this unchecked." msgstr "" "[EXPERIMENTAL]\n" -"Tenta aumentar a velocidade de emulação dando o trabalho de decodificação de " -"texturas para a GPU usando o Framework OpenCL.\n" -"No entanto, em seu estado atual ele causa defeitos nas texturas em vários " -"jogos. Além disso, na maioria dos casos ele é mais lento que a decodificação " -"usual da CPU.\n" +"Tenta aumentar a velocidade de emulação dando o trabalho de decodificação de texturas para a GPU usando o Framework OpenCL.\n" +"No entanto, em seu estado atual ele causa defeitos nas texturas em vários jogos. Além disso, na maioria dos casos ele é mais lento que a decodificação usual da CPU.\n" "\n" "Se estiver em dúvida, deixe isto desativado." @@ -5522,8 +5297,7 @@ msgid "" "If unsure, leave this unchecked." msgstr "" "[EXPERIMENTAL]\n" -"Aumenta a velocidade da emulação fazendo um reservatório temporário de " -"Dysplay Lists.\n" +"Aumenta a velocidade da emulação fazendo um reservatório temporário de Dysplay Lists.\n" "Pode causar problemas.\n" "\n" "Se estiver em dúvida, deixe isto desativado." @@ -5557,9 +5331,7 @@ msgstr "iCacheJIT: Lendo Opcode de %x. Favor reportar." #: Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.cpp:108 #, c-format msgid "not a wii save or read failure for file header size %x" -msgstr "" -"Não é um salva de Wii ou houve erro de leitura no tamanho do header do " -"arquivo %x" +msgstr "Não é um salva de Wii ou houve erro de leitura no tamanho do header do arquivo %x" #: Source/Core/DolphinWX/Src/FifoPlayerDlg.cpp:461 msgid "s" From 75408fa9af9f81cbc5b798880f2b4dc865503b67 Mon Sep 17 00:00:00 2001 From: Runo Date: Mon, 12 Sep 2011 22:56:10 -0300 Subject: [PATCH 26/36] PT_BR Translation Update to revision 60. --- Languages/po/pt_BR.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Languages/po/pt_BR.po b/Languages/po/pt_BR.po index d7d782547c..0e55fbbb5e 100644 --- a/Languages/po/pt_BR.po +++ b/Languages/po/pt_BR.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: Dolphin Emu\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2011-08-10 08:30-0500\n" -"PO-Revision-Date: 2011-09-11 23:35-0300\n" +"PO-Revision-Date: 2011-09-12 22:54-0300\n" "Last-Translator: Runo \n" "Language-Team: Portuguese (BR) \n" "MIME-Version: 1.0\n" @@ -739,7 +739,7 @@ msgstr "Input em Background" #: Source/Core/InputCommon/Src/ControllerEmu.cpp:279 msgid "Backward" -msgstr "Para trás" +msgstr "Para Trás" #: Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.cpp:264 msgid "Bad File Header" From ce3e3339365486318b8970ccaa49a3f536b2dc1b Mon Sep 17 00:00:00 2001 From: Runo Date: Mon, 12 Sep 2011 23:16:26 -0300 Subject: [PATCH 27/36] Last attempt to update PT_BR.po --- Languages/po/pt_BR.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Languages/po/pt_BR.po b/Languages/po/pt_BR.po index 0e55fbbb5e..d7d782547c 100644 --- a/Languages/po/pt_BR.po +++ b/Languages/po/pt_BR.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: Dolphin Emu\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2011-08-10 08:30-0500\n" -"PO-Revision-Date: 2011-09-12 22:54-0300\n" +"PO-Revision-Date: 2011-09-11 23:35-0300\n" "Last-Translator: Runo \n" "Language-Team: Portuguese (BR) \n" "MIME-Version: 1.0\n" @@ -739,7 +739,7 @@ msgstr "Input em Background" #: Source/Core/InputCommon/Src/ControllerEmu.cpp:279 msgid "Backward" -msgstr "Para Trás" +msgstr "Para trás" #: Source/Core/DolphinWX/Src/MemoryCards/WiiSaveCrypted.cpp:264 msgid "Bad File Header" From 2f321524d894e3bed7b7a8147a976b4224b568e0 Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Tue, 13 Sep 2011 16:39:28 +0200 Subject: [PATCH 28/36] Add libav headers to the include directories. Fixes issue 4811. --- CMakeTests/CheckLib.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeTests/CheckLib.cmake b/CMakeTests/CheckLib.cmake index c1174ecb58..affc92ae8f 100644 --- a/CMakeTests/CheckLib.cmake +++ b/CMakeTests/CheckLib.cmake @@ -63,6 +63,7 @@ macro(check_libav) if(LIBAV_FOUND) message("libav found, enabling AVI frame dumps") add_definitions(-DHAVE_LIBAV) + include_directories(${LIBAV_INCLUDE_DIRS}) else() message("libav not found, disabling AVI frame dumps") endif() From 0abe19e31feabe26cab24710fa61731b83669a3f Mon Sep 17 00:00:00 2001 From: "kostamarino@hotmail.com" Date: Thu, 15 Sep 2011 23:11:40 +0300 Subject: [PATCH 29/36] Gameini database update. Fight Night Round 2 boots properly now, Mystery Case Files: The Malgrave Incident (PAL) addition with proper settings, fix a mistake in Xenoblade and addition/updates to emulation state for a couple of games. Also update for the Greek language. --- Data/User/GameConfig/G8FE8P.ini | 15 +++++++++++++ Data/User/GameConfig/GEYE69.ini | 12 +++++++++- Data/User/GameConfig/GKUE9G.ini | 2 +- Data/User/GameConfig/GNOE78.ini | 2 +- Data/User/GameConfig/RM6EEB.ini | 15 +++++++++++++ Data/User/GameConfig/SFIP01.ini | 22 ++++++++++++++++++ Data/User/GameConfig/SX4J01.ini | 6 ++--- Data/User/GameConfig/SX4P01.ini | 5 ++--- Languages/po/el.po | 40 ++++++++++++++++----------------- 9 files changed, 90 insertions(+), 29 deletions(-) create mode 100644 Data/User/GameConfig/G8FE8P.ini create mode 100644 Data/User/GameConfig/RM6EEB.ini create mode 100644 Data/User/GameConfig/SFIP01.ini diff --git a/Data/User/GameConfig/G8FE8P.ini b/Data/User/GameConfig/G8FE8P.ini new file mode 100644 index 0000000000..43eef9a46e --- /dev/null +++ b/Data/User/GameConfig/G8FE8P.ini @@ -0,0 +1,15 @@ +# G8FE8P - VIRTUA QUEST +[Core] Values set here will override the main dolphin settings. +[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set. +EmulationStateId = 5 +EmulationIssues = +[OnFrame] Add memory patches to be applied every frame here. +[ActionReplay] Add action replay cheats here. +[Video] +ProjectionHack = 0 +PH_SZNear = 0 +PH_SZFar = 0 +PH_ExtraParam = 0 +PH_ZNear = +PH_ZFar = +[Gecko] diff --git a/Data/User/GameConfig/GEYE69.ini b/Data/User/GameConfig/GEYE69.ini index 8c96330c60..ebf5159b27 100644 --- a/Data/User/GameConfig/GEYE69.ini +++ b/Data/User/GameConfig/GEYE69.ini @@ -1,6 +1,16 @@ # GEYE69 - EA SPORTS(TM) Fight Night Round 2 [Core] Values set here will override the main dolphin settings. +TLBHack = 1 [EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set. -EmulationStateId = 1 +EmulationStateId = 4 +EmulationIssues = Videos are messed up, needs LLE audio for proper sound. [OnFrame] Add memory patches to be applied every frame here. [ActionReplay] Add action replay cheats here. +[Video] +ProjectionHack = 0 +PH_SZNear = 0 +PH_SZFar = 0 +PH_ExtraParam = 0 +PH_ZNear = +PH_ZFar = +[Gecko] diff --git a/Data/User/GameConfig/GKUE9G.ini b/Data/User/GameConfig/GKUE9G.ini index 4fce1959df..3a0d9b7c08 100644 --- a/Data/User/GameConfig/GKUE9G.ini +++ b/Data/User/GameConfig/GKUE9G.ini @@ -2,7 +2,7 @@ [Core] Values set here will override the main dolphin settings. TLBHack = 1 [EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set. -EmulationStateId = 0 +EmulationStateId = 4 EmulationIssues = [OnFrame] Add memory patches to be applied every frame here. [ActionReplay] Add action replay cheats here. diff --git a/Data/User/GameConfig/GNOE78.ini b/Data/User/GameConfig/GNOE78.ini index cd8c06fa53..bf0d3f3f1f 100644 --- a/Data/User/GameConfig/GNOE78.ini +++ b/Data/User/GameConfig/GNOE78.ini @@ -3,7 +3,7 @@ TLBHack = 1 FastDiscSpeed = 1 [EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set. -EmulationStateId = 0 +EmulationStateId = 4 EmulationIssues = [OnFrame] Add memory patches to be applied every frame here. [ActionReplay] Add action replay cheats here. diff --git a/Data/User/GameConfig/RM6EEB.ini b/Data/User/GameConfig/RM6EEB.ini new file mode 100644 index 0000000000..8f78ac8ffa --- /dev/null +++ b/Data/User/GameConfig/RM6EEB.ini @@ -0,0 +1,15 @@ +# RM6EEB - BAROQUE +[Core] Values set here will override the main dolphin settings. +[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set. +EmulationStateId = 4 +EmulationIssues = +[OnFrame] Add memory patches to be applied every frame here. +[ActionReplay] Add action replay cheats here. +[Video] +ProjectionHack = 0 +PH_SZNear = 0 +PH_SZFar = 0 +PH_ExtraParam = 0 +PH_ZNear = +PH_ZFar = +[Gecko] diff --git a/Data/User/GameConfig/SFIP01.ini b/Data/User/GameConfig/SFIP01.ini new file mode 100644 index 0000000000..d655f59141 --- /dev/null +++ b/Data/User/GameConfig/SFIP01.ini @@ -0,0 +1,22 @@ +# SFIP01 - Mystery Case Files: The Malgrave Incident +[Core] Values set here will override the main dolphin settings. +[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set. +EmulationStateId = 4 +EmulationIssues = Needs real xfb for videos to show up. +[OnFrame] Add memory patches to be applied every frame here. +[ActionReplay] Add action replay cheats here. +[Wii] +DisableWiimoteSpeaker = 1 +[Video] +ProjectionHack = 0 +PH_SZNear = 0 +PH_SZFar = 0 +PH_ExtraParam = 0 +PH_ZNear = +PH_ZFar = +[Gecko] +[Video_Settings] +SafeTextureCache = True +SafeTextureCacheColorSamples = 512 +UseXFB = True +UseRealXFB = True diff --git a/Data/User/GameConfig/SX4J01.ini b/Data/User/GameConfig/SX4J01.ini index 1add4f0579..2e2169a190 100644 --- a/Data/User/GameConfig/SX4J01.ini +++ b/Data/User/GameConfig/SX4J01.ini @@ -1,11 +1,10 @@ # SX4J01 - Xenoblade [Core] Values set here will override the main dolphin settings. -SkipIdle = 0 BlockMerging = 1 -TLBHack = 1 +SkipIdle = 0 [EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Disable idle skipping to solve sound issues or use LLE audio. Per pixel lighting creates a glitch in ether cave with direct 3d 9. +EmulationIssues = Disable idle skipping to solve sound issues or use LLE audio. Per pixel lighting creates a glitch in ether cave with direct 3d 9. The game randomly freezes. [OnFrame] Add memory patches to be applied every frame here. [ActionReplay] Add action replay cheats here. [Video] @@ -20,3 +19,4 @@ PH_ZFar = DlistCachingEnable = False [Video_Settings] EnablePixelLighting = False + diff --git a/Data/User/GameConfig/SX4P01.ini b/Data/User/GameConfig/SX4P01.ini index d649b00050..b374dab682 100644 --- a/Data/User/GameConfig/SX4P01.ini +++ b/Data/User/GameConfig/SX4P01.ini @@ -1,11 +1,10 @@ # SX4P01 - Xenoblade Chronicles [Core] Values set here will override the main dolphin settings. -SkipIdle = 0 BlockMerging = 1 -TLBHack = 1 +SkipIdle = 0 [EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set. EmulationStateId = 4 -EmulationIssues = Disable idle skipping to solve sound issues or use LLE audio. Per pixel lighting creates a glitch in ether cave with direct 3d 9. +EmulationIssues = Disable idle skipping to solve sound issues or use LLE audio. Per pixel lighting creates a glitch in ether cave with direct 3d 9. The game randomly freezes. [OnFrame] Add memory patches to be applied every frame here. [ActionReplay] Add action replay cheats here. [Video] diff --git a/Languages/po/el.po b/Languages/po/el.po index 3f93e7d65a..9a746c96f1 100644 --- a/Languages/po/el.po +++ b/Languages/po/el.po @@ -8,13 +8,13 @@ msgstr "" "Project-Id-Version: Dolphin Emu\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2011-08-10 08:30-0500\n" -"PO-Revision-Date: 2011-08-25 20:16+0200\n" +"PO-Revision-Date: 2011-09-13 17:28+0200\n" "Last-Translator: Linktothepast \n" "Language-Team: Gpower2 \n" -"Language: Greek\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: Greek\n" "X-Poedit-Language: Greek\n" "X-Poedit-Country: GREECE\n" @@ -862,7 +862,7 @@ msgid "" msgstr "" "Υπολογίζει τον φωτισμό των 3D γραφικών ανά pixel αντί ανά vertex.\n" "Μειώνει την ταχύτητα εξομοίωσης κατά κάποιο ποσοστό (ανάλογα με την GPU).\n" -"Αυτή είναι συνήθως μια ασφαλής βελτίωση, αλλά μπορεί να προκαλέσει προβλήματα ορισμένες φορές.\n" +"Αυτή συνήθως είναι μια ασφαλής βελτίωση, αλλά μπορεί να προκαλέσει ορισμένες φορές προβλήματα.\n" "\n" "Αν δεν είστε σίγουροι, αφήστε το αποεπιλεγμένο." @@ -1116,7 +1116,7 @@ msgstr "Ρυθμίσεις Χειριστηρίων" #: Source/Core/DolphinWX/Src/FrameTools.cpp:442 msgid "Configure..." -msgstr "Γενικές Ρυθμίσεις......" +msgstr "Γενικές Ρυθμίσεις..." #: Source/Core/DolphinWX/Src/GameListCtrl.cpp:1229 #: Source/Core/DolphinWX/Src/GameListCtrl.cpp:1257 @@ -1741,7 +1741,7 @@ msgstr "Επεξεργασία..." #: Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Turntable.cpp:44 msgid "Effect" -msgstr "Εφφέ" +msgstr "Εφέ" #: Source/Core/DolphinWX/Src/VideoConfigDiag.cpp:424 msgid "Embedded Frame Buffer" @@ -1759,7 +1759,7 @@ msgid "" "If unsure, check virtual XFB emulation instead." msgstr "" "Εξομοιώνει τα XFBs με ακρίβεια.\n" -"Επιβραδύνει την εξομοίωση αρκετά και αποτρέπει την απόδοση γραφικών υψηλής ανάλυσης, αλλά είναι απαραίτητο για την σωστή εξομοίωση ορισμένου αριθμού παιχνιδιών.\n" +"Επιβραδύνει αρκετά την εξομοίωση και αποτρέπει την απόδοση γραφικών υψηλής ανάλυσης, αλλά είναι απαραίτητο για την σωστή εξομοίωση ορισμένου αριθμού παιχνιδιών.\n" "\n" "Αν δεν είστε σίγουροι, επιλέξτε εικονική XFB εξομοίωση." @@ -2634,12 +2634,12 @@ msgstr "Host" #: Source/Core/DolphinWX/Src/HotkeyDlg.h:44 msgid "Hotkey Configuration" -msgstr "Ρυθμίσεις Πλήκτρων Συντομεύσεως" +msgstr "Ρυθμίσεις Πλήκτρων Συντόμευσης" #: Source/Core/DolphinWX/Src/ConfigMain.cpp:570 #: Source/Core/DolphinWX/Src/HotkeyDlg.cpp:276 msgid "Hotkeys" -msgstr "Πλήκτρα Συντομεύσεως" +msgstr "Πλήκτρα Συντόμευσης" #: Source/Core/DolphinWX/Src/ConfigMain.cpp:300 msgid "Hungarian" @@ -2708,7 +2708,7 @@ msgstr "Αν τα FPS διακυμαίνονται, αυτή η επιλογή #: Source/Core/DolphinWX/Src/ConfigMain.cpp:481 msgid "If you set Framelimit higher than game full speed (NTSC:60, PAL:50), you also have to disable Audio Throttle in DSP to make it effective." msgstr "" -"Αν θέσετε τον περιορισμό καρέ υψηλότερα από ότι την πλήρη ταχύτητα του παιχνιδιού (NTSC:60, PAL:50),\n" +"Αν θέσετε τιμή υψηλότερη από την πλήρη ταχύτητα του παιχνιδιού (NTSC:60, PAL:50),\n" "θα πρέπει επίσης να απενεργοποιήσετε το Throttle Ήχου στο DSP για να έχει αποτέλεσμα. " #: Source/Core/DolphinWX/Src/VideoConfigDiag.cpp:427 @@ -2773,7 +2773,7 @@ msgid "" "\n" "If unsure, leave this unchecked." msgstr "" -"Βελτιώνει τις επιδόσεις αλλά προκαλεί προβλήματα σε παιχνίδια που βασίζονται στη σωστή εξομοίωση ομίχλης.\n" +"Βελτιώνει τις επιδόσεις αλλά προκαλεί προβλήματα σε παιχνίδια που βασίζονται στη σωστή εξομοίωση της ομίχλης.\n" "\n" "Αν δεν είστε σίγουροι, αφήστε το αποεπιλεγμένο." @@ -3022,7 +3022,7 @@ msgstr "Μικρότερο από" #: Source/Core/DolphinWX/Src/ConfigMain.cpp:539 msgid "Limit by FPS" -msgstr "Περιορισμός με βάση τα FPS" +msgstr "Περιορισμός με βάση τα Καρέ" #: Source/Core/DolphinWX/Src/InputConfigDiag.cpp:928 msgid "Load" @@ -4312,8 +4312,8 @@ msgid "" "Disabling this may avoid annoying and non-fatal messages, but it may also mean that Dolphin suddenly crashes without any explanation at all." msgstr "" "Εμφάνιση μηνύματος όταν προκύψει ένα πιθανά σοβαρό σφάλμα.\n" -"Απενεργοποιώντας αυτήν την επιλογή μπορεί να σας γλιτώσει από ενοχλητικά μη κρίσιμα σφάλματα, αλλά επίσης σημαίνει\n" -"ότι το Dolphin μπορεί να κρασάρει ξαφνικά χωρίς καμία εξήγηση. " +"Απενεργοποιώντας αυτήν την επιλογή μπορεί να γλιτώσετε από ενοχλητικά μη κρίσιμα σφάλματα, αλλά \n" +"το Dolphin μπορεί να κρασάρει ξαφνικά χωρίς καμία εξήγηση. " #: Source/Core/DolphinWX/Src/MemcardManager.cpp:812 msgid "Show first block" @@ -4393,7 +4393,7 @@ msgid "" "\n" "If unsure, leave this unchecked." msgstr "" -"Παράλειψη του destination alpha pass που χρησιμοποιείται σε πολλά παιχνίδια για ποικίλα γραφικά εφέ.\n" +"Παράλειψη του destination alpha pass που χρησιμοποιείται από πολλά παιχνίδια σε διάφορα γραφικά εφέ.\n" "\n" "Αν δεν είστε σίγουροι, αφήστε το αποεπιλεγμένο." @@ -4427,7 +4427,7 @@ msgid "" msgstr "" "Η απεικόνιση λογισμικού είναι αρκετές βαθμίδες πιο αργή απ' ότι τα υπόλοιπα backends.\n" "Είναι μόνο χρήσιμη για debugging σκοπούς.\n" -"Θέλετε όντως να χρησιμοπποιήσετε την απεικόνιση λογισμικού; Αν δεν είστε σίγουροι, επιλέξτε 'No'." +"Θέλετε όντως να χρησιμοποιήσετε την απεικόνιση λογισμικού; Αν δεν είστε σίγουροι, επιλέξτε 'Όχι'." #: Source/Core/DolphinWX/Src/ConfigMain.cpp:618 msgid "Sound Settings" @@ -4727,8 +4727,8 @@ msgid "" "Keyboard Shortcut : Hold down to instantly disable Throttle." msgstr "" "Χρησιμοποιείται για τον έλεγχο της ταχύτητας του παιχνιδιού με throttle ήχου.\n" -"Απενεργοποίησή της μπορεί να προκαλέσει μη φυσιολογική ταχύτητα παιχνιδιού, όπως πολύ γρήγορη.\n" -"Αλλά μερικές φορές η ενεργοποίησή της μπορεί να προκαλέσει μόνιμο θόρυβο.\n" +"Απενεργοποιώντας το μπορεί να προκλήθει αφύσικη ταχύτητα σε παιχνίδια, π.χ. πολύ γρήγορη.\n" +"Όμως ορισμένες φορές η ενεργοποίησή της μπορεί να προκαλέσει μόνιμο θόρυβο.\n" "\n" "Συντόμευση πληκτρολογίου : Κρατήστε το πατημένο για να απενεργοποιηθεί η λειτουργία Throttle." @@ -4747,7 +4747,7 @@ msgstr "" #: Source/Core/DolphinWX/Src/ISOProperties.cpp:283 msgid "This will let you Manually Edit the INI config file" -msgstr "Αυτό θα σας επιτρέψει να επεξεργαστείτε χειροκίνητα το αρχείο ρυθμίσεων INI" +msgstr "Αυτό σας επιτρέπει την χειροκίνητη επεξεργασία του αρχείου ρυθμίσεων INI" #: Source/Core/InputCommon/Src/ControllerEmu.cpp:249 #: Source/Core/InputCommon/Src/ControllerEmu.cpp:254 @@ -5044,7 +5044,7 @@ msgid "" msgstr "" "Προειδοποίηση: Αυτό θα αντικαταστήσει όλα τα υπάρχοντα σημεία αποθήκευσης που υπάρχουν στον φάκελο:\n" "%s\n" -"κι έχουν το ίδιο όνομα με αρχεία στη memcard\n" +"και έχουν το ίδιο όνομα με αρχεία στη memcard\n" "Συνέχεια;" #: Source/Core/AudioCommon/Src/WaveFile.cpp:106 @@ -5257,7 +5257,7 @@ msgid "" "If unsure, leave this unchecked." msgstr "" "[ΧΑΛΑΣΜΕΝΟ]\n" -"Τονίζει τις περιοχές από όπου το EFB αντιγράφηκε.\n" +"Τονίζει τις περιοχές από όπου έγινε αντιγραφή του EFB.\n" "\n" "Αν δεν είστε σίγουροι, αφήστε το αποεπιλεγμένο." From 1f8a8268c66b3349c7b0d7ba0e5e2e8c9bd2dd2e Mon Sep 17 00:00:00 2001 From: "kostamarino@hotmail.com" Date: Fri, 23 Sep 2011 02:27:30 +0300 Subject: [PATCH 30/36] Another gameini database update. This makes playable by default games such as The Urbz (GC), Chicken Blaster, Wild West Shootout, Phineas and Ferb Across the 2nd Dimension (PAL), along with proper settings for METAL SLUG Anthology. --- Data/User/GameConfig/GUBE69.ini | 19 +++++++++++++++++++ Data/User/GameConfig/GUBP69.ini | 19 +++++++++++++++++++ Data/User/GameConfig/R8LE20.ini | 18 ++++++++++++++++++ Data/User/GameConfig/R8LP7J.ini | 18 ++++++++++++++++++ Data/User/GameConfig/RMLEH4.ini | 16 ++++++++++++++-- Data/User/GameConfig/RMLJH4.ini | 19 +++++++++++++++++++ Data/User/GameConfig/RMLK52.ini | 19 +++++++++++++++++++ Data/User/GameConfig/RMLP7U.ini | 19 +++++++++++++++++++ Data/User/GameConfig/RMLPH4.ini | 19 +++++++++++++++++++ Data/User/GameConfig/SMFP4Q.ini | 22 ++++++++++++++++++++++ Data/User/GameConfig/SSRE20.ini | 18 ++++++++++++++++++ Data/User/GameConfig/SSRPXT.ini | 18 ++++++++++++++++++ 12 files changed, 222 insertions(+), 2 deletions(-) create mode 100644 Data/User/GameConfig/GUBE69.ini create mode 100644 Data/User/GameConfig/GUBP69.ini create mode 100644 Data/User/GameConfig/R8LE20.ini create mode 100644 Data/User/GameConfig/R8LP7J.ini create mode 100644 Data/User/GameConfig/RMLJH4.ini create mode 100644 Data/User/GameConfig/RMLK52.ini create mode 100644 Data/User/GameConfig/RMLP7U.ini create mode 100644 Data/User/GameConfig/RMLPH4.ini create mode 100644 Data/User/GameConfig/SMFP4Q.ini create mode 100644 Data/User/GameConfig/SSRE20.ini create mode 100644 Data/User/GameConfig/SSRPXT.ini diff --git a/Data/User/GameConfig/GUBE69.ini b/Data/User/GameConfig/GUBE69.ini new file mode 100644 index 0000000000..a7fb26674a --- /dev/null +++ b/Data/User/GameConfig/GUBE69.ini @@ -0,0 +1,19 @@ +# GUBE69 - The Urbz GameCube +[Core] Values set here will override the main dolphin settings. +TLBHack = 1 +[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set. +EmulationStateId = 4 +EmulationIssues = LLE audio is needed to fix some sound issues. +[OnFrame] Add memory patches to be applied every frame here. +[ActionReplay] Add action replay cheats here. +[Video] +ProjectionHack = 0 +PH_SZNear = 0 +PH_SZFar = 0 +PH_ExtraParam = 0 +PH_ZNear = +PH_ZFar = +[Gecko] +[Video_Settings] +SafeTextureCache = True +SafeTextureCacheColorSamples = 512 diff --git a/Data/User/GameConfig/GUBP69.ini b/Data/User/GameConfig/GUBP69.ini new file mode 100644 index 0000000000..1ac1ed9c1d --- /dev/null +++ b/Data/User/GameConfig/GUBP69.ini @@ -0,0 +1,19 @@ +# GUBP69 - The Urbz GameCube +[Core] Values set here will override the main dolphin settings. +TLBHack = 1 +[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set. +EmulationStateId = 4 +EmulationIssues = LLE audio is needed to fix some sound issues. +[OnFrame] Add memory patches to be applied every frame here. +[ActionReplay] Add action replay cheats here. +[Video] +ProjectionHack = 0 +PH_SZNear = 0 +PH_SZFar = 0 +PH_ExtraParam = 0 +PH_ZNear = +PH_ZFar = +[Gecko] +[Video_Settings] +SafeTextureCache = True +SafeTextureCacheColorSamples = 512 diff --git a/Data/User/GameConfig/R8LE20.ini b/Data/User/GameConfig/R8LE20.ini new file mode 100644 index 0000000000..a38514bc43 --- /dev/null +++ b/Data/User/GameConfig/R8LE20.ini @@ -0,0 +1,18 @@ +# R8LE20 - Chicken Blaster +[Core] Values set here will override the main dolphin settings. +[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set. +EmulationStateId = 4 +EmulationIssues = +[OnFrame] Add memory patches to be applied every frame here. +[ActionReplay] Add action replay cheats here. +[Video] +ProjectionHack = 0 +PH_SZNear = 0 +PH_SZFar = 0 +PH_ExtraParam = 0 +PH_ZNear = +PH_ZFar = +[Gecko] +[Video_Settings] +UseXFB = True +UseRealXFB = True diff --git a/Data/User/GameConfig/R8LP7J.ini b/Data/User/GameConfig/R8LP7J.ini new file mode 100644 index 0000000000..532178c53b --- /dev/null +++ b/Data/User/GameConfig/R8LP7J.ini @@ -0,0 +1,18 @@ +# R8LP7J - Chicken Blaster +[Core] Values set here will override the main dolphin settings. +[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set. +EmulationStateId = 4 +EmulationIssues = +[OnFrame] Add memory patches to be applied every frame here. +[ActionReplay] Add action replay cheats here. +[Video] +ProjectionHack = 0 +PH_SZNear = 0 +PH_SZFar = 0 +PH_ExtraParam = 0 +PH_ZNear = +PH_ZFar = +[Gecko] +[Video_Settings] +UseXFB = True +UseRealXFB = True diff --git a/Data/User/GameConfig/RMLEH4.ini b/Data/User/GameConfig/RMLEH4.ini index e1444f1498..6bf280dc75 100644 --- a/Data/User/GameConfig/RMLEH4.ini +++ b/Data/User/GameConfig/RMLEH4.ini @@ -1,7 +1,19 @@ # RMLEH4 - METAL SLUG Anthology [Core] Values set here will override the main dolphin settings. +TLBHack = 1 [EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set. -EmulationStateId = 5 -EmulationIssues = +EmulationStateId = 4 +EmulationIssues = Use LLE audio to solve some sound issues. [OnFrame] Add memory patches to be applied every frame here. [ActionReplay] Add action replay cheats here. +[Video] +ProjectionHack = 0 +PH_SZNear = 0 +PH_SZFar = 0 +PH_ExtraParam = 0 +PH_ZNear = +PH_ZFar = +[Gecko] +[Video_Settings] +SafeTextureCache = True +SafeTextureCacheColorSamples = 512 diff --git a/Data/User/GameConfig/RMLJH4.ini b/Data/User/GameConfig/RMLJH4.ini new file mode 100644 index 0000000000..cc6422800d --- /dev/null +++ b/Data/User/GameConfig/RMLJH4.ini @@ -0,0 +1,19 @@ +# RMLJH4 - Metal Slug Complete +[Core] Values set here will override the main dolphin settings. +TLBHack = 1 +[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set. +EmulationStateId = 4 +EmulationIssues = Use LLE audio to solve some sound issues. +[OnFrame] Add memory patches to be applied every frame here. +[ActionReplay] Add action replay cheats here. +[Video] +ProjectionHack = 0 +PH_SZNear = 0 +PH_SZFar = 0 +PH_ExtraParam = 0 +PH_ZNear = +PH_ZFar = +[Gecko] +[Video_Settings] +SafeTextureCache = True +SafeTextureCacheColorSamples = 512 diff --git a/Data/User/GameConfig/RMLK52.ini b/Data/User/GameConfig/RMLK52.ini new file mode 100644 index 0000000000..12a6d1c800 --- /dev/null +++ b/Data/User/GameConfig/RMLK52.ini @@ -0,0 +1,19 @@ +# RMLK52 - Metal Slug Complete +[Core] Values set here will override the main dolphin settings. +TLBHack = 1 +[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set. +EmulationStateId = 4 +EmulationIssues = Use LLE audio to solve some sound issues. +[OnFrame] Add memory patches to be applied every frame here. +[ActionReplay] Add action replay cheats here. +[Video] +ProjectionHack = 0 +PH_SZNear = 0 +PH_SZFar = 0 +PH_ExtraParam = 0 +PH_ZNear = +PH_ZFar = +[Gecko] +[Video_Settings] +SafeTextureCache = True +SafeTextureCacheColorSamples = 512 diff --git a/Data/User/GameConfig/RMLP7U.ini b/Data/User/GameConfig/RMLP7U.ini new file mode 100644 index 0000000000..0666be4c4a --- /dev/null +++ b/Data/User/GameConfig/RMLP7U.ini @@ -0,0 +1,19 @@ +# RMLP7U - METAL SLUG Anthology +[Core] Values set here will override the main dolphin settings. +TLBHack = 1 +[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set. +EmulationStateId = 4 +EmulationIssues = Use LLE audio to solve some sound issues. +[OnFrame] Add memory patches to be applied every frame here. +[ActionReplay] Add action replay cheats here. +[Video] +ProjectionHack = 0 +PH_SZNear = 0 +PH_SZFar = 0 +PH_ExtraParam = 0 +PH_ZNear = +PH_ZFar = +[Gecko] +[Video_Settings] +SafeTextureCache = True +SafeTextureCacheColorSamples = 512 diff --git a/Data/User/GameConfig/RMLPH4.ini b/Data/User/GameConfig/RMLPH4.ini new file mode 100644 index 0000000000..9c062079f2 --- /dev/null +++ b/Data/User/GameConfig/RMLPH4.ini @@ -0,0 +1,19 @@ +# RMLPH4 - METAL SLUG Anthology +[Core] Values set here will override the main dolphin settings. +TLBHack = 1 +[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set. +EmulationStateId = 4 +EmulationIssues = Use LLE audio to solve some sound issues. +[OnFrame] Add memory patches to be applied every frame here. +[ActionReplay] Add action replay cheats here. +[Video] +ProjectionHack = 0 +PH_SZNear = 0 +PH_SZFar = 0 +PH_ExtraParam = 0 +PH_ZNear = +PH_ZFar = +[Gecko] +[Video_Settings] +SafeTextureCache = True +SafeTextureCacheColorSamples = 512 diff --git a/Data/User/GameConfig/SMFP4Q.ini b/Data/User/GameConfig/SMFP4Q.ini new file mode 100644 index 0000000000..ee1358c1c8 --- /dev/null +++ b/Data/User/GameConfig/SMFP4Q.ini @@ -0,0 +1,22 @@ +# SMFP4Q - Phineas and Ferb Across the 2nd Dimension +[Core] Values set here will override the main dolphin settings. +[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set. +EmulationStateId = 4 +EmulationIssues = +[OnFrame] Add memory patches to be applied every frame here. +[ActionReplay] Add action replay cheats here. +[Video] +ProjectionHack = 0 +PH_SZNear = 0 +PH_SZFar = 0 +PH_ExtraParam = 0 +PH_ZNear = +PH_ZFar = +[Gecko] +[Video_Settings] +SafeTextureCache = True +SafeTextureCacheColorSamples = 0 +UseXFB = True +UseRealXFB = False +[Video_Hacks] +EFBEmulateFormatChanges = False diff --git a/Data/User/GameConfig/SSRE20.ini b/Data/User/GameConfig/SSRE20.ini new file mode 100644 index 0000000000..20edfda0c0 --- /dev/null +++ b/Data/User/GameConfig/SSRE20.ini @@ -0,0 +1,18 @@ +# SSRE20 - Wild West Shootout +[Core] Values set here will override the main dolphin settings. +[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set. +EmulationStateId = 4 +EmulationIssues = +[OnFrame] Add memory patches to be applied every frame here. +[ActionReplay] Add action replay cheats here. +[Video] +ProjectionHack = 0 +PH_SZNear = 0 +PH_SZFar = 0 +PH_ExtraParam = 0 +PH_ZNear = +PH_ZFar = +[Gecko] +[Video_Settings] +UseXFB = True +UseRealXFB = True diff --git a/Data/User/GameConfig/SSRPXT.ini b/Data/User/GameConfig/SSRPXT.ini new file mode 100644 index 0000000000..880617b35c --- /dev/null +++ b/Data/User/GameConfig/SSRPXT.ini @@ -0,0 +1,18 @@ +# SSRPXT - Wild West Shootout +[Core] Values set here will override the main dolphin settings. +[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set. +EmulationStateId = 4 +EmulationIssues = +[OnFrame] Add memory patches to be applied every frame here. +[ActionReplay] Add action replay cheats here. +[Video] +ProjectionHack = 0 +PH_SZNear = 0 +PH_SZFar = 0 +PH_ExtraParam = 0 +PH_ZNear = +PH_ZFar = +[Gecko] +[Video_Settings] +UseXFB = True +UseRealXFB = True From ca7e8a9e88aeb2271ed04af4ff3994286c00a90c Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Thu, 29 Sep 2011 21:21:09 +0200 Subject: [PATCH 31/36] Fix pixel lighting. --- .../Core/VideoCommon/Src/LightingShaderGen.cpp | 15 +++++++++++++++ .../Core/VideoCommon/Src/LightingShaderGen.h | 3 +++ Source/Core/VideoCommon/Src/PixelShaderGen.cpp | 18 +++++++++++------- Source/Core/VideoCommon/Src/PixelShaderGen.h | 4 ++-- .../Core/VideoCommon/Src/VertexShaderGen.cpp | 14 +++++--------- 5 files changed, 36 insertions(+), 18 deletions(-) diff --git a/Source/Core/VideoCommon/Src/LightingShaderGen.cpp b/Source/Core/VideoCommon/Src/LightingShaderGen.cpp index 6824fbd2fc..a506acadfc 100644 --- a/Source/Core/VideoCommon/Src/LightingShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/LightingShaderGen.cpp @@ -21,6 +21,21 @@ #define WRITE p+=sprintf +int GetLightingShaderId(u32* out) +{ + for (int i = 0; i < xfregs.numChan.numColorChans; ++i) + { + out[i] = xfregs.color[i].enablelighting ? + (u32)xfregs.color[i].hex : + (u32)xfregs.color[i].matsource; + out[i] |= (xfregs.alpha[i].enablelighting ? + (u32)xfregs.alpha[i].hex : + (u32)xfregs.alpha[i].matsource) << 15; + } + _assert_(xfregs.numChan.numColorChans <= 2); + return xfregs.numChan.numColorChans; +} + // coloralpha - 1 if color, 2 if alpha char *GenerateLightShader(char *p, int index, const LitChannel& chan, const char* lightsName, int coloralpha) { diff --git a/Source/Core/VideoCommon/Src/LightingShaderGen.h b/Source/Core/VideoCommon/Src/LightingShaderGen.h index 21da8ca01a..e72623a4d2 100644 --- a/Source/Core/VideoCommon/Src/LightingShaderGen.h +++ b/Source/Core/VideoCommon/Src/LightingShaderGen.h @@ -18,6 +18,9 @@ #ifndef _LIGHTINGSHADERGEN_H_ #define _LIGHTINGSHADERGEN_H_ +#include "CommonTypes.h" + +int GetLightingShaderId(u32* out); char *GenerateLightingShader(char *p, int components, const char* materialsName, const char* lightsName, const char* inColorName, const char* dest); #endif // _LIGHTINGSHADERGEN_H_ diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp index 7937c695ce..52a4477390 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp @@ -125,16 +125,11 @@ void GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode) if (alphaPreTest == 1 || (alphaPreTest && !DepthTextureEnable && dstAlphaMode == DSTALPHA_ALPHA_PASS)) { // Courtesy of PreAlphaTest, we're done already ;) - // TODO: There's a comment including bpmem.genmode.numindstages.. shouldnt really bother about that though. + // NOTE: The comment header of generated shaders depends on the value of bpmem.genmode.numindstages.. shouldnt really bother about that though. uid->num_values = 1; return; } - if (enablePL) - { - // TODO: Include register states for lighting shader - } - for (unsigned int i = 0; i < bpmem.genMode.numtexgens; ++i) { if (18+i < 32) @@ -194,7 +189,12 @@ void GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode) ptr[0] |= bpmem.fogRange.Base.Enabled << 17; // 1 } } - uid->num_values = (ptr+1) - uid->values; + + ++ptr; + if (enablePL) + ptr += GetLightingShaderId(ptr); + + uid->num_values = ptr - uid->values; } void GetSafePixelShaderId(PIXELSHADERUIDSAFE *uid, DSTALPHA_MODE dstAlphaMode) @@ -212,6 +212,10 @@ void GetSafePixelShaderId(PIXELSHADERUIDSAFE *uid, DSTALPHA_MODE dstAlphaMode) if (g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) { // TODO: Include register states for lighting shader + *ptr++ = xfregs.color[0].hex; + *ptr++ = xfregs.alpha[0].hex; + *ptr++ = xfregs.color[1].hex; + *ptr++ = xfregs.alpha[1].hex; } for (unsigned int i = 0; i < 8; ++i) diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.h b/Source/Core/VideoCommon/Src/PixelShaderGen.h index 8031fdfbb2..b24b656784 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderGen.h +++ b/Source/Core/VideoCommon/Src/PixelShaderGen.h @@ -44,8 +44,8 @@ #define C_PLIGHTS (C_FOG + 3) #define C_PMATERIALS (C_PLIGHTS + 40) #define C_PENVCONST_END (C_PMATERIALS + 4) -#define PIXELSHADERUID_MAX_VALUES 67 -#define PIXELSHADERUID_MAX_VALUES_SAFE 115 +#define PIXELSHADERUID_MAX_VALUES 69 +#define PIXELSHADERUID_MAX_VALUES_SAFE 117 // DO NOT make anything in this class virtual. template diff --git a/Source/Core/VideoCommon/Src/VertexShaderGen.cpp b/Source/Core/VideoCommon/Src/VertexShaderGen.cpp index 5c6c12887a..a492d5a201 100644 --- a/Source/Core/VideoCommon/Src/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/VertexShaderGen.cpp @@ -37,14 +37,9 @@ void GetVertexShaderId(VERTEXSHADERUID *uid, u32 components) (xfregs.numChan.numColorChans << 27) | (xfregs.dualTexTrans.enabled << 29); - for (int i = 0; i < xfregs.numChan.numColorChans; ++i) { - uid->values[1+i] = xfregs.color[i].enablelighting ? - (u32)xfregs.color[i].hex : - (u32)xfregs.color[i].matsource; - uid->values[1+i] |= (xfregs.alpha[i].enablelighting ? - (u32)xfregs.alpha[i].hex : - (u32)xfregs.alpha[i].matsource) << 15; - } + // TODO: If pixel lighting is enabled, do we even have to bother about storing lighting related registers here? + GetLightingShaderId(&uid->values[1]); + uid->values[2] |= (g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) << 31; u32 *pcurvalue = &uid->values[3]; for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i) { @@ -306,7 +301,8 @@ const char *GenerateVertexShaderCode(u32 components, API_TYPE api_type) else WRITE(p, "o.colors_0 = float4(1.0f, 1.0f, 1.0f, 1.0f);\n"); } - + + // TODO: This probably isn't necessary if pixel lighting is enabled. p = GenerateLightingShader(p, components, I_MATERIALS, I_LIGHTS, "color", "o.colors_"); if(xfregs.numChan.numColorChans < 2) From ddfe219293e3af9e04f7020f0557736e1762370b Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Thu, 29 Sep 2011 21:52:13 +0200 Subject: [PATCH 32/36] Fixup line endings. --- .../Core/VideoCommon/Src/PixelShaderGen.cpp | 2482 ++++++++--------- .../Core/VideoCommon/Src/VertexShaderGen.cpp | 1006 +++---- 2 files changed, 1744 insertions(+), 1744 deletions(-) diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp index 52a4477390..f52c6b4190 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp @@ -1,1242 +1,1242 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include -#include -#include -#include - -#include "LightingShaderGen.h" -#include "PixelShaderGen.h" -#include "XFMemory.h" // for texture projection mode -#include "BPMemory.h" -#include "VideoConfig.h" -#include "NativeVertexFormat.h" - -PIXELSHADERUID last_pixel_shader_uid; - -static int AlphaPreTest(); - -static void StageHash(int stage, u32* out) -{ - out[0] |= bpmem.combiners[stage].colorC.hex & 0xFFFFFF; // 24 - u32 alphaC = bpmem.combiners[stage].alphaC.hex & 0xFFFFF0; // 24, strip out tswap and rswap for now - out[0] |= (alphaC&0xF0) << 24; // 8 - out[1] |= alphaC >> 8; // 16 - - // reserve 3 bits for bpmem.tevorders[stage/2].getTexMap - out[1] |= bpmem.tevorders[stage/2].getTexCoord(stage&1) << 19; // 3 - out[1] |= bpmem.tevorders[stage/2].getEnable(stage&1) << 22; // 1 - // reserve 3 bits for bpmem.tevorders[stage/2].getColorChan - - bool bHasIndStage = bpmem.tevind[stage].IsActive() && bpmem.tevind[stage].bt < bpmem.genMode.numindstages; - out[2] |= bHasIndStage << 2; // 1 - - bool needstexcoord = false; - - if (bHasIndStage) - { - out[2] |= (bpmem.tevind[stage].hex & 0x17FFFF) << 3; // 21, TODO: needs an explanation - needstexcoord = true; - } - - - TevStageCombiner::ColorCombiner& cc = bpmem.combiners[stage].colorC; - TevStageCombiner::AlphaCombiner& ac = bpmem.combiners[stage].alphaC; - - if(cc.a == TEVCOLORARG_RASA || cc.a == TEVCOLORARG_RASC - || cc.b == TEVCOLORARG_RASA || cc.b == TEVCOLORARG_RASC - || cc.c == TEVCOLORARG_RASA || cc.c == TEVCOLORARG_RASC - || cc.d == TEVCOLORARG_RASA || cc.d == TEVCOLORARG_RASC - || ac.a == TEVALPHAARG_RASA || ac.b == TEVALPHAARG_RASA - || ac.c == TEVALPHAARG_RASA || ac.d == TEVALPHAARG_RASA) - { - out[0] |= bpmem.combiners[stage].alphaC.rswap; - out[2] |= bpmem.tevksel[bpmem.combiners[stage].alphaC.rswap*2].swap1 << 24; // 2 - out[2] |= bpmem.tevksel[bpmem.combiners[stage].alphaC.rswap*2].swap2 << 26; // 2 - out[2] |= bpmem.tevksel[bpmem.combiners[stage].alphaC.rswap*2+1].swap1 << 28; // 2 - out[2] |= bpmem.tevksel[bpmem.combiners[stage].alphaC.rswap*2+1].swap2 << 30; // 2 - out[1] |= (bpmem.tevorders[stage/2].getColorChan(stage&1)&1) << 23; - out[2] |= (bpmem.tevorders[stage/2].getColorChan(stage&1)&0x6) >> 1; - } - - out[3] |= bpmem.tevorders[stage/2].getEnable(stage&1); - if (bpmem.tevorders[stage/2].getEnable(stage&1)) - { - if (bHasIndStage) needstexcoord = true; - - out[0] |= bpmem.combiners[stage].alphaC.tswap; - out[3] |= bpmem.tevksel[bpmem.combiners[stage].alphaC.tswap*2].swap1 << 1; // 2 - out[3] |= bpmem.tevksel[bpmem.combiners[stage].alphaC.tswap*2].swap2 << 3; // 2 - out[3] |= bpmem.tevksel[bpmem.combiners[stage].alphaC.tswap*2+1].swap1 << 5; // 2 - out[3] |= bpmem.tevksel[bpmem.combiners[stage].alphaC.tswap*2+1].swap2 << 7; // 2 - out[1] |= bpmem.tevorders[stage/2].getTexMap(stage&1) << 16; - } - - if (cc.a == TEVCOLORARG_KONST || cc.b == TEVCOLORARG_KONST || cc.c == TEVCOLORARG_KONST || cc.d == TEVCOLORARG_KONST - || ac.a == TEVALPHAARG_KONST || ac.b == TEVALPHAARG_KONST || ac.c == TEVALPHAARG_KONST || ac.d == TEVALPHAARG_KONST) - { - out[3] |= bpmem.tevksel[stage/2].getKC(stage&1) << 9; // 5 - out[3] |= bpmem.tevksel[stage/2].getKA(stage&1) << 14; // 5 - } - - if (needstexcoord) - { - out[1] |= bpmem.tevorders[stage/2].getTexCoord(stage&1) << 16; - } -} - -// Mash together all the inputs that contribute to the code of a generated pixel shader into -// a unique identifier, basically containing all the bits. Yup, it's a lot .... -// It would likely be a lot more efficient to build this incrementally as the attributes -// are set... -void GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode) -{ - uid->values[0] |= bpmem.genMode.numtevstages; // 4 - uid->values[0] |= bpmem.genMode.numtexgens << 4; // 4 - uid->values[0] |= dstAlphaMode << 8; // 2 - - bool DepthTextureEnable = (bpmem.ztex2.op != ZTEXTURE_DISABLE && !bpmem.zcontrol.zcomploc && bpmem.zmode.testenable && bpmem.zmode.updateenable) || g_ActiveConfig.bEnablePerPixelDepth; - - uid->values[0] |= DepthTextureEnable << 10; // 1 - - bool enablePL = g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting; - uid->values[0] |= enablePL << 11; // 1 - - if (!enablePL) uid->values[0] |= xfregs.numTexGen.numTexGens << 12; // 4 - u32 alphaPreTest = AlphaPreTest()+1; - - uid->values[0] |= alphaPreTest << 16; // 2 - - if (alphaPreTest == 1 || (alphaPreTest && !DepthTextureEnable && dstAlphaMode == DSTALPHA_ALPHA_PASS)) - { - // Courtesy of PreAlphaTest, we're done already ;) - // NOTE: The comment header of generated shaders depends on the value of bpmem.genmode.numindstages.. shouldnt really bother about that though. - uid->num_values = 1; - return; - } - - for (unsigned int i = 0; i < bpmem.genMode.numtexgens; ++i) - { - if (18+i < 32) - uid->values[0] |= xfregs.texMtxInfo[i].projection << (18+i); // 1 - else - uid->values[1] |= xfregs.texMtxInfo[i].projection << (i - 14); // 1 - } - - uid->values[1] = bpmem.genMode.numindstages << 2; // 3 - u32 indirectStagesUsed = 0; - for (unsigned int i = 0; i < bpmem.genMode.numindstages; ++i) - if (bpmem.tevind[i].IsActive() && bpmem.tevind[i].bt < bpmem.genMode.numindstages) - indirectStagesUsed |= (1 << bpmem.tevind[i].bt); - - assert(indirectStagesUsed == (indirectStagesUsed & 0xF)); - - uid->values[1] |= indirectStagesUsed << 5; // 4; - - for (unsigned int i = 0; i < bpmem.genMode.numindstages; ++i) - { - if (indirectStagesUsed & (1 << i)) - { - uid->values[1] |= (bpmem.tevindref.getTexCoord(i) < bpmem.genMode.numtexgens) << (9 + 3*i); // 1 - if (bpmem.tevindref.getTexCoord(i) < bpmem.genMode.numtexgens) - uid->values[1] |= bpmem.tevindref.getTexCoord(i) << (10 + 3*i); // 2 - } - } - - u32* ptr = &uid->values[2]; - for (int i = 0; i < bpmem.genMode.numtevstages+1; ++i) - { - StageHash(i, ptr); - ptr += 4; // max: ptr = &uid->values[66] - } - - ptr[0] |= bpmem.alphaFunc.comp0; // 3 - ptr[0] |= bpmem.alphaFunc.comp1 << 3; // 3 - ptr[0] |= bpmem.alphaFunc.logic << 6; // 2 - - if (alphaPreTest == 0 || alphaPreTest == 2) - { - ptr[0] |= bpmem.fog.c_proj_fsel.fsel << 8; // 3 - if (DepthTextureEnable) - { - ptr[0] |= bpmem.ztex2.op << 11; // 2 - ptr[0] |= bpmem.zcontrol.zcomploc << 13; // 1 - ptr[0] |= bpmem.zmode.testenable << 14; // 1 - ptr[0] |= bpmem.zmode.updateenable << 15; // 1 - } - } - - if (dstAlphaMode != DSTALPHA_ALPHA_PASS) - { - if (bpmem.fog.c_proj_fsel.fsel != 0) - { - ptr[0] |= bpmem.fog.c_proj_fsel.proj << 16; // 1 - ptr[0] |= bpmem.fogRange.Base.Enabled << 17; // 1 - } - } - - ++ptr; - if (enablePL) - ptr += GetLightingShaderId(ptr); - - uid->num_values = ptr - uid->values; -} - -void GetSafePixelShaderId(PIXELSHADERUIDSAFE *uid, DSTALPHA_MODE dstAlphaMode) -{ - u32* ptr = uid->values; - *ptr++ = dstAlphaMode; // 0 - *ptr++ = bpmem.genMode.hex; // 1 - *ptr++ = bpmem.ztex2.hex; // 2 - *ptr++ = bpmem.zcontrol.hex; // 3 - *ptr++ = bpmem.zmode.hex; // 4 - *ptr++ = g_ActiveConfig.bEnablePerPixelDepth; // 5 - *ptr++ = g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting; // 6 - *ptr++ = xfregs.numTexGen.hex; // 7 - - if (g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) - { - // TODO: Include register states for lighting shader - *ptr++ = xfregs.color[0].hex; - *ptr++ = xfregs.alpha[0].hex; - *ptr++ = xfregs.color[1].hex; - *ptr++ = xfregs.alpha[1].hex; - } - - for (unsigned int i = 0; i < 8; ++i) - *ptr++ = xfregs.texMtxInfo[i].hex; // 8-15 - - for (unsigned int i = 0; i < 16; ++i) - *ptr++ = bpmem.tevind[i].hex; // 16-31 - - *ptr++ = bpmem.tevindref.hex; // 32 - - for (int i = 0; i < bpmem.genMode.numtevstages+1; ++i) // up to 16 times - { - *ptr++ = bpmem.combiners[i].colorC.hex; // 33+5*i - *ptr++ = bpmem.combiners[i].alphaC.hex; // 34+5*i - *ptr++ = bpmem.tevind[i].hex; // 35+5*i - *ptr++ = bpmem.tevksel[i/2].hex; // 36+5*i - *ptr++ = bpmem.tevorders[i/2].hex; // 37+5*i - } - - ptr = &uid->values[113]; - - *ptr++ = bpmem.alphaFunc.hex; // 113 - - *ptr++ = bpmem.fog.c_proj_fsel.hex; // 114 - *ptr++ = bpmem.fogRange.Base.hex; // 115 - - _assert_((ptr - uid->values) == uid->GetNumValues()); -} - -void ValidatePixelShaderIDs(API_TYPE api, PIXELSHADERUIDSAFE old_id, const std::string& old_code, DSTALPHA_MODE dstAlphaMode, u32 components) -{ - if (!g_ActiveConfig.bEnableShaderDebugging) - return; - - PIXELSHADERUIDSAFE new_id; - GetSafePixelShaderId(&new_id, dstAlphaMode); - - if (!(old_id == new_id)) - { - std::string new_code(GeneratePixelShaderCode(dstAlphaMode, api, components)); - if (old_code != new_code) - { - _assert_(old_id.GetNumValues() == new_id.GetNumValues()); - - char msg[8192]; - char* ptr = msg; - ptr += sprintf(ptr, "Pixel shader IDs matched but unique IDs did not!\nUnique IDs (old <-> new):\n"); - const int N = new_id.GetNumValues(); - for (int i = 0; i < N/2; ++i) - ptr += sprintf(ptr, "%02d, %08X %08X | %08X %08X\n", 2*i, old_id.values[2*i], old_id.values[2*i+1], - new_id.values[2*i], new_id.values[2*i+1]); - if (N % 2) - ptr += sprintf(ptr, "%02d, %08X | %08X\n", N-1, old_id.values[N-1], new_id.values[N-1]); - - static int num_failures = 0; - char szTemp[MAX_PATH]; - sprintf(szTemp, "%spsuid_mismatch_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++); - std::ofstream file(szTemp); - file << msg; - file << "\n\nOld shader code:\n" << old_code; - file << "\n\nNew shader code:\n" << new_code; - file.close(); - - PanicAlert("Unique pixel shader ID mismatch!\n\nReport this to the devs, along with the contents of %s.", szTemp); - } - } -} - -// old tev->pixelshader notes -// -// color for this stage (alpha, color) is given by bpmem.tevorders[0].colorchan0 -// konstant for this stage (alpha, color) is given by bpmem.tevksel -// inputs are given by bpmem.combiners[0].colorC.a/b/c/d << could be current chan color -// according to GXTevColorArg table above -// output is given by .outreg -// tevtemp is set according to swapmodetables and - -static void WriteStage(char *&p, int n, API_TYPE ApiType); -static void SampleTexture(char *&p, const char *destination, const char *texcoords, const char *texswap, int texmap, API_TYPE ApiType); -// static void WriteAlphaCompare(char *&p, int num, int comp); -static bool WriteAlphaTest(char *&p, API_TYPE ApiType,DSTALPHA_MODE dstAlphaMode); -static void WriteFog(char *&p); - -static const char *tevKSelTableC[] = // KCSEL -{ - "1.0f,1.0f,1.0f", // 1 = 0x00 - "0.875f,0.875f,0.875f", // 7_8 = 0x01 - "0.75f,0.75f,0.75f", // 3_4 = 0x02 - "0.625f,0.625f,0.625f", // 5_8 = 0x03 - "0.5f,0.5f,0.5f", // 1_2 = 0x04 - "0.375f,0.375f,0.375f", // 3_8 = 0x05 - "0.25f,0.25f,0.25f", // 1_4 = 0x06 - "0.125f,0.125f,0.125f", // 1_8 = 0x07 - "ERROR", // 0x08 - "ERROR", // 0x09 - "ERROR", // 0x0a - "ERROR", // 0x0b - I_KCOLORS"[0].rgb", // K0 = 0x0C - I_KCOLORS"[1].rgb", // K1 = 0x0D - I_KCOLORS"[2].rgb", // K2 = 0x0E - I_KCOLORS"[3].rgb", // K3 = 0x0F - I_KCOLORS"[0].rrr", // K0_R = 0x10 - I_KCOLORS"[1].rrr", // K1_R = 0x11 - I_KCOLORS"[2].rrr", // K2_R = 0x12 - I_KCOLORS"[3].rrr", // K3_R = 0x13 - I_KCOLORS"[0].ggg", // K0_G = 0x14 - I_KCOLORS"[1].ggg", // K1_G = 0x15 - I_KCOLORS"[2].ggg", // K2_G = 0x16 - I_KCOLORS"[3].ggg", // K3_G = 0x17 - I_KCOLORS"[0].bbb", // K0_B = 0x18 - I_KCOLORS"[1].bbb", // K1_B = 0x19 - I_KCOLORS"[2].bbb", // K2_B = 0x1A - I_KCOLORS"[3].bbb", // K3_B = 0x1B - I_KCOLORS"[0].aaa", // K0_A = 0x1C - I_KCOLORS"[1].aaa", // K1_A = 0x1D - I_KCOLORS"[2].aaa", // K2_A = 0x1E - I_KCOLORS"[3].aaa", // K3_A = 0x1F -}; - -static const char *tevKSelTableA[] = // KASEL -{ - "1.0f", // 1 = 0x00 - "0.875f",// 7_8 = 0x01 - "0.75f", // 3_4 = 0x02 - "0.625f",// 5_8 = 0x03 - "0.5f", // 1_2 = 0x04 - "0.375f",// 3_8 = 0x05 - "0.25f", // 1_4 = 0x06 - "0.125f",// 1_8 = 0x07 - "ERROR", // 0x08 - "ERROR", // 0x09 - "ERROR", // 0x0a - "ERROR", // 0x0b - "ERROR", // 0x0c - "ERROR", // 0x0d - "ERROR", // 0x0e - "ERROR", // 0x0f - I_KCOLORS"[0].r", // K0_R = 0x10 - I_KCOLORS"[1].r", // K1_R = 0x11 - I_KCOLORS"[2].r", // K2_R = 0x12 - I_KCOLORS"[3].r", // K3_R = 0x13 - I_KCOLORS"[0].g", // K0_G = 0x14 - I_KCOLORS"[1].g", // K1_G = 0x15 - I_KCOLORS"[2].g", // K2_G = 0x16 - I_KCOLORS"[3].g", // K3_G = 0x17 - I_KCOLORS"[0].b", // K0_B = 0x18 - I_KCOLORS"[1].b", // K1_B = 0x19 - I_KCOLORS"[2].b", // K2_B = 0x1A - I_KCOLORS"[3].b", // K3_B = 0x1B - I_KCOLORS"[0].a", // K0_A = 0x1C - I_KCOLORS"[1].a", // K1_A = 0x1D - I_KCOLORS"[2].a", // K2_A = 0x1E - I_KCOLORS"[3].a", // K3_A = 0x1F -}; - -static const char *tevScaleTable[] = // CS -{ - "1.0f", // SCALE_1 - "2.0f", // SCALE_2 - "4.0f", // SCALE_4 - "0.5f", // DIVIDE_2 -}; - -static const char *tevBiasTable[] = // TB -{ - "", // ZERO, - "+0.5f", // ADDHALF, - "-0.5f", // SUBHALF, - "", -}; - -static const char *tevOpTable[] = { // TEV - "+", // TEVOP_ADD = 0, - "-", // TEVOP_SUB = 1, -}; - -static const char *tevCInputTable[] = // CC -{ - "(prev.rgb)", // CPREV, - "(prev.aaa)", // APREV, - "(c0.rgb)", // C0, - "(c0.aaa)", // A0, - "(c1.rgb)", // C1, - "(c1.aaa)", // A1, - "(c2.rgb)", // C2, - "(c2.aaa)", // A2, - "(textemp.rgb)", // TEXC, - "(textemp.aaa)", // TEXA, - "(rastemp.rgb)", // RASC, - "(rastemp.aaa)", // RASA, - "float3(1.0f, 1.0f, 1.0f)", // ONE - "float3(0.5f, 0.5f, 0.5f)", // HALF - "(konsttemp.rgb)", //"konsttemp.rgb", // KONST - "float3(0.0f, 0.0f, 0.0f)", // ZERO - ///aded extra values to map clamped values - "(cprev.rgb)", // CPREV, - "(cprev.aaa)", // APREV, - "(cc0.rgb)", // C0, - "(cc0.aaa)", // A0, - "(cc1.rgb)", // C1, - "(cc1.aaa)", // A1, - "(cc2.rgb)", // C2, - "(cc2.aaa)", // A2, - "(textemp.rgb)", // TEXC, - "(textemp.aaa)", // TEXA, - "(crastemp.rgb)", // RASC, - "(crastemp.aaa)", // RASA, - "float3(1.0f, 1.0f, 1.0f)", // ONE - "float3(0.5f, 0.5f, 0.5f)", // HALF - "(ckonsttemp.rgb)", //"konsttemp.rgb", // KONST - "float3(0.0f, 0.0f, 0.0f)", // ZERO - "PADERROR", "PADERROR", "PADERROR", "PADERROR" -}; - -static const char *tevAInputTable[] = // CA -{ - "prev", // APREV, - "c0", // A0, - "c1", // A1, - "c2", // A2, - "textemp", // TEXA, - "rastemp", // RASA, - "konsttemp", // KONST, (hw1 had quarter) - "float4(0.0f, 0.0f, 0.0f, 0.0f)", // ZERO - ///aded extra values to map clamped values - "cprev", // APREV, - "cc0", // A0, - "cc1", // A1, - "cc2", // A2, - "textemp", // TEXA, - "crastemp", // RASA, - "ckonsttemp", // KONST, (hw1 had quarter) - "float4(0.0f, 0.0f, 0.0f, 0.0f)", // ZERO - "PADERROR", "PADERROR", "PADERROR", "PADERROR", - "PADERROR", "PADERROR", "PADERROR", "PADERROR", -}; - -static const char *tevRasTable[] = -{ - "colors_0", - "colors_1", - "ERROR", //2 - "ERROR", //3 - "ERROR", //4 - "alphabump", // use bump alpha - "(alphabump*(255.0f/248.0f))", //normalized - "float4(0.0f, 0.0f, 0.0f, 0.0f)", // zero -}; - -//static const char *tevTexFunc[] = { "tex2D", "texRECT" }; - -static const char *tevCOutputTable[] = { "prev.rgb", "c0.rgb", "c1.rgb", "c2.rgb" }; -static const char *tevAOutputTable[] = { "prev.a", "c0.a", "c1.a", "c2.a" }; -static const char *tevIndAlphaSel[] = {"", "x", "y", "z"}; -//static const char *tevIndAlphaScale[] = {"", "*32", "*16", "*8"}; -static const char *tevIndAlphaScale[] = {"*(248.0f/255.0f)", "*(224.0f/255.0f)", "*(240.0f/255.0f)", "*(248.0f/255.0f)"}; -static const char *tevIndBiasField[] = {"", "x", "y", "xy", "z", "xz", "yz", "xyz"}; // indexed by bias -static const char *tevIndBiasAdd[] = {"-128.0f", "1.0f", "1.0f", "1.0f" }; // indexed by fmt -static const char *tevIndWrapStart[] = {"0.0f", "256.0f", "128.0f", "64.0f", "32.0f", "16.0f", "0.001f" }; -static const char *tevIndFmtScale[] = {"255.0f", "31.0f", "15.0f", "7.0f" }; - -#define WRITE p+=sprintf - -static char swapModeTable[4][5]; - -static char text[16384]; -static bool DepthTextureEnable; - -static void BuildSwapModeTable() -{ - static const char *swapColors = "rgba"; - for (int i = 0; i < 4; i++) - { - swapModeTable[i][0] = swapColors[bpmem.tevksel[i*2].swap1]; - swapModeTable[i][1] = swapColors[bpmem.tevksel[i*2].swap2]; - swapModeTable[i][2] = swapColors[bpmem.tevksel[i*2+1].swap1]; - swapModeTable[i][3] = swapColors[bpmem.tevksel[i*2+1].swap2]; - swapModeTable[i][4] = 0; - } -} - -const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType, u32 components) -{ - setlocale(LC_NUMERIC, "C"); // Reset locale for compilation - text[sizeof(text) - 1] = 0x7C; // canary - - BuildSwapModeTable(); // Needed for WriteStage - int numStages = bpmem.genMode.numtevstages + 1; - int numTexgen = bpmem.genMode.numtexgens; - - char *p = text; - WRITE(p, "//Pixel Shader for TEV stages\n"); - WRITE(p, "//%i TEV stages, %i texgens, XXX IND stages\n", - numStages, numTexgen/*, bpmem.genMode.numindstages*/); - - int nIndirectStagesUsed = 0; - if (bpmem.genMode.numindstages > 0) - { - for (int i = 0; i < numStages; ++i) - { - if (bpmem.tevind[i].IsActive() && bpmem.tevind[i].bt < bpmem.genMode.numindstages) - nIndirectStagesUsed |= 1 << bpmem.tevind[i].bt; - } - } - DepthTextureEnable = (bpmem.ztex2.op != ZTEXTURE_DISABLE && !bpmem.zcontrol.zcomploc && bpmem.zmode.testenable && bpmem.zmode.updateenable) || g_ActiveConfig.bEnablePerPixelDepth ; - // Declare samplers - - if(ApiType != API_D3D11) - { - WRITE(p, "uniform sampler2D "); - } - else - { - WRITE(p, "sampler "); - } - - bool bfirst = true; - for (int i = 0; i < 8; ++i) - { - WRITE(p, "%s samp%d : register(s%d)", bfirst?"":",", i, i); - bfirst = false; - } - WRITE(p, ";\n"); - if(ApiType == API_D3D11) - { - WRITE(p, "Texture2D "); - bfirst = true; - for (int i = 0; i < 8; ++i) - { - WRITE(p, "%s Tex%d : register(t%d)", bfirst?"":",", i, i); - bfirst = false; - } - WRITE(p, ";\n"); - } - - WRITE(p, "\n"); - - WRITE(p, "uniform float4 "I_COLORS"[4] : register(c%d);\n", C_COLORS); - WRITE(p, "uniform float4 "I_KCOLORS"[4] : register(c%d);\n", C_KCOLORS); - WRITE(p, "uniform float4 "I_ALPHA"[1] : register(c%d);\n", C_ALPHA); - WRITE(p, "uniform float4 "I_TEXDIMS"[8] : register(c%d);\n", C_TEXDIMS); - WRITE(p, "uniform float4 "I_ZBIAS"[2] : register(c%d);\n", C_ZBIAS); - WRITE(p, "uniform float4 "I_INDTEXSCALE"[2] : register(c%d);\n", C_INDTEXSCALE); - WRITE(p, "uniform float4 "I_INDTEXMTX"[6] : register(c%d);\n", C_INDTEXMTX); - WRITE(p, "uniform float4 "I_FOG"[3] : register(c%d);\n", C_FOG); - - if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) - { - WRITE(p,"typedef struct { float4 col; float4 cosatt; float4 distatt; float4 pos; float4 dir; } Light;\n"); - WRITE(p,"typedef struct { Light lights[8]; } s_"I_PLIGHTS";\n"); - WRITE(p, "uniform s_"I_PLIGHTS" "I_PLIGHTS" : register(c%d);\n", C_PLIGHTS); - WRITE(p, "typedef struct { float4 C0, C1, C2, C3; } s_"I_PMATERIALS";\n"); - WRITE(p, "uniform s_"I_PMATERIALS" "I_PMATERIALS" : register(c%d);\n", C_PMATERIALS); - } - - WRITE(p, "void main(\n"); - if(ApiType != API_D3D11) - { - WRITE(p, " out float4 ocol0 : COLOR0,%s%s\n in float4 rawpos : %s,\n", - dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND ? "\n out float4 ocol1 : COLOR1," : "", - DepthTextureEnable ? "\n out float depth : DEPTH," : "", - ApiType & API_OPENGL ? "WPOS" : ApiType & API_D3D9_SM20 ? "POSITION" : "VPOS"); - } - else - { - WRITE(p, " out float4 ocol0 : SV_Target0,%s%s\n in float4 rawpos : SV_Position,\n", - dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND ? "\n out float4 ocol1 : SV_Target1," : "", - DepthTextureEnable ? "\n out float depth : SV_Depth," : ""); - } - - WRITE(p, " in float4 colors_0 : COLOR0,\n"); - WRITE(p, " in float4 colors_1 : COLOR1"); - - // compute window position if needed because binding semantic WPOS is not widely supported - if (numTexgen < 7) - { - for (int i = 0; i < numTexgen; ++i) - WRITE(p, ",\n in float3 uv%d : TEXCOORD%d", i, i); - WRITE(p, ",\n in float4 clipPos : TEXCOORD%d", numTexgen); - if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) - WRITE(p, ",\n in float4 Normal : TEXCOORD%d", numTexgen + 1); - } - else - { - // wpos is in w of first 4 texcoords - if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) - { - for (int i = 0; i < 8; ++i) - WRITE(p, ",\n in float4 uv%d : TEXCOORD%d", i, i); - } - else - { - for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i) - WRITE(p, ",\n in float%d uv%d : TEXCOORD%d", i < 4 ? 4 : 3 , i, i); - } - } - WRITE(p, " ) {\n"); - - char* pmainstart = p; - int Pretest = AlphaPreTest(); - if (dstAlphaMode == DSTALPHA_ALPHA_PASS && !DepthTextureEnable && Pretest >= 0) - { - if (!Pretest) - { - // alpha test will always fail, so restart the shader and just make it an empty function - WRITE(p, "ocol0 = 0;\n"); - WRITE(p, "discard;\n"); - if(ApiType != API_D3D11) - WRITE(p, "return;\n"); - } - else - { - WRITE(p, " ocol0 = "I_ALPHA"[0].aaaa;\n"); - } - WRITE(p, "}\n"); - return text; - } - - WRITE(p, " float4 c0 = "I_COLORS"[1], c1 = "I_COLORS"[2], c2 = "I_COLORS"[3], prev = float4(0.0f, 0.0f, 0.0f, 0.0f), textemp = float4(0.0f, 0.0f, 0.0f, 0.0f), rastemp = float4(0.0f, 0.0f, 0.0f, 0.0f), konsttemp = float4(0.0f, 0.0f, 0.0f, 0.0f);\n" - " float3 comp16 = float3(1.0f, 255.0f, 0.0f), comp24 = float3(1.0f, 255.0f, 255.0f*255.0f);\n" - " float4 alphabump=float4(0.0f,0.0f,0.0f,0.0f);\n" - " float3 tevcoord=float3(0.0f, 0.0f, 0.0f);\n" - " float2 wrappedcoord=float2(0.0f,0.0f), tempcoord=float2(0.0f,0.0f);\n" - " float4 cc0=float4(0.0f,0.0f,0.0f,0.0f), cc1=float4(0.0f,0.0f,0.0f,0.0f);\n" - " float4 cc2=float4(0.0f,0.0f,0.0f,0.0f), cprev=float4(0.0f,0.0f,0.0f,0.0f);\n" - " float4 crastemp=float4(0.0f,0.0f,0.0f,0.0f),ckonsttemp=float4(0.0f,0.0f,0.0f,0.0f);\n\n"); - - if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) - { - if (xfregs.numTexGen.numTexGens < 7) - { - WRITE(p,"float3 _norm0 = normalize(Normal.xyz);\n\n"); - WRITE(p,"float3 pos = float3(clipPos.x,clipPos.y,Normal.w);\n"); - } - else - { - WRITE(p," float3 _norm0 = normalize(float3(uv4.w,uv5.w,uv6.w));\n\n"); - WRITE(p,"float3 pos = float3(uv0.w,uv1.w,uv7.w);\n"); - } - - - WRITE(p, "float4 mat, lacc;\n" - "float3 ldir, h;\n" - "float dist, dist2, attn;\n"); - - p = GenerateLightingShader(p, components, I_PMATERIALS, I_PLIGHTS, "colors_", "colors_"); - } - - if (numTexgen < 7) - WRITE(p, "clipPos = float4(rawpos.x, rawpos.y, clipPos.z, clipPos.w);\n"); - else - WRITE(p, "float4 clipPos = float4(rawpos.x, rawpos.y, uv2.w, uv3.w);\n"); - - // HACK to handle cases where the tex gen is not enabled - if (numTexgen == 0) - { - WRITE(p, "float3 uv0 = float3(0.0f, 0.0f, 0.0f);\n"); - } - else - { - for (int i = 0; i < numTexgen; ++i) - { - // optional perspective divides - if (xfregs.texMtxInfo[i].projection == XF_TEXPROJ_STQ) - { - WRITE(p, "if (uv%d.z)", i); - WRITE(p, " uv%d.xy = uv%d.xy / uv%d.z;\n", i, i, i); - } - - WRITE(p, "uv%d.xy = uv%d.xy * "I_TEXDIMS"[%d].zw;\n", i, i, i); - } - } - - // indirect texture map lookup - for(u32 i = 0; i < bpmem.genMode.numindstages; ++i) - { - if (nIndirectStagesUsed & (1<= %s.r + (0.25f/255.0f)) ? %s : float3(0.0f, 0.0f, 0.0f))",//#define TEVCMP_R8_GT 8 - " %s + ((abs(%s.r - %s.r) < (0.5f/255.0f)) ? %s : float3(0.0f, 0.0f, 0.0f))",//#define TEVCMP_R8_EQ 9 - " %s + (( dot(%s.rgb, comp16) >= (dot(%s.rgb, comp16) + (0.25f/255.0f))) ? %s : float3(0.0f, 0.0f, 0.0f))",//#define TEVCMP_GR16_GT 10 - " %s + (abs(dot(%s.rgb, comp16) - dot(%s.rgb, comp16)) < (0.5f/255.0f) ? %s : float3(0.0f, 0.0f, 0.0f))",//#define TEVCMP_GR16_EQ 11 - " %s + (( dot(%s.rgb, comp24) >= (dot(%s.rgb, comp24) + (0.25f/255.0f))) ? %s : float3(0.0f, 0.0f, 0.0f))",//#define TEVCMP_BGR24_GT 12 - " %s + (abs(dot(%s.rgb, comp24) - dot(%s.rgb, comp24)) < (0.5f/255.0f) ? %s : float3(0.0f, 0.0f, 0.0f))",//#define TEVCMP_BGR24_EQ 13 - " %s + (max(sign(%s.rgb - %s.rgb - (0.25f/255.0f)), float3(0.0f, 0.0f, 0.0f)) * %s)",//#define TEVCMP_RGB8_GT 14 - " %s + ((float3(1.0f, 1.0f, 1.0f) - max(sign(abs(%s.rgb - %s.rgb) - (0.5f/255.0f)), float3(0.0f, 0.0f, 0.0f))) * %s)"//#define TEVCMP_RGB8_EQ 15 -}; - -//table with the alpha compare operations -static const char *TEVCMPAlphaOPTable[16] = -{ - "0.0f",//0 - "0.0f",//1 - "0.0f",//2 - "0.0f",//3 - "0.0f",//4 - "0.0f",//5 - "0.0f",//6 - "0.0f",//7 - " %s.a + ((%s.r >= (%s.r + (0.25f/255.0f))) ? %s.a : 0.0f)",//#define TEVCMP_R8_GT 8 - " %s.a + (abs(%s.r - %s.r) < (0.5f/255.0f) ? %s.a : 0.0f)",//#define TEVCMP_R8_EQ 9 - " %s.a + ((dot(%s.rgb, comp16) >= (dot(%s.rgb, comp16) + (0.25f/255.0f))) ? %s.a : 0.0f)",//#define TEVCMP_GR16_GT 10 - " %s.a + (abs(dot(%s.rgb, comp16) - dot(%s.rgb, comp16)) < (0.5f/255.0f) ? %s.a : 0.0f)",//#define TEVCMP_GR16_EQ 11 - " %s.a + ((dot(%s.rgb, comp24) >= (dot(%s.rgb, comp24) + (0.25f/255.0f))) ? %s.a : 0.0f)",//#define TEVCMP_BGR24_GT 12 - " %s.a + (abs(dot(%s.rgb, comp24) - dot(%s.rgb, comp24)) < (0.5f/255.0f) ? %s.a : 0.0f)",//#define TEVCMP_BGR24_EQ 13 - " %s.a + ((%s.a >= (%s.a + (0.25f/255.0f))) ? %s.a : 0.0f)",//#define TEVCMP_A8_GT 14 - " %s.a + (abs(%s.a - %s.a) < (0.5f/255.0f) ? %s.a : 0.0f)"//#define TEVCMP_A8_EQ 15 - -}; - - -static void WriteStage(char *&p, int n, API_TYPE ApiType) -{ - int texcoord = bpmem.tevorders[n/2].getTexCoord(n&1); - bool bHasTexCoord = (u32)texcoord < bpmem.genMode.numtexgens; - bool bHasIndStage = bpmem.tevind[n].IsActive() && bpmem.tevind[n].bt < bpmem.genMode.numindstages; - - // HACK to handle cases where the tex gen is not enabled - if (!bHasTexCoord) - texcoord = 0; - - WRITE(p, "// TEV stage %d\n", n); - - if (bHasIndStage) - { - WRITE(p, "// indirect op\n"); - // perform the indirect op on the incoming regular coordinates using indtex%d as the offset coords - if (bpmem.tevind[n].bs != ITBA_OFF) - { - WRITE(p, "alphabump = indtex%d.%s %s;\n", - bpmem.tevind[n].bt, - tevIndAlphaSel[bpmem.tevind[n].bs], - tevIndAlphaScale[bpmem.tevind[n].fmt]); - } - // format - WRITE(p, "float3 indtevcrd%d = indtex%d * %s;\n", n, bpmem.tevind[n].bt, tevIndFmtScale[bpmem.tevind[n].fmt]); - - // bias - if (bpmem.tevind[n].bias != ITB_NONE ) - WRITE(p, "indtevcrd%d.%s += %s;\n", n, tevIndBiasField[bpmem.tevind[n].bias], tevIndBiasAdd[bpmem.tevind[n].fmt]); - - // multiply by offset matrix and scale - if (bpmem.tevind[n].mid != 0) - { - if (bpmem.tevind[n].mid <= 3) - { - int mtxidx = 2*(bpmem.tevind[n].mid-1); - WRITE(p, "float2 indtevtrans%d = float2(dot("I_INDTEXMTX"[%d].xyz, indtevcrd%d), dot("I_INDTEXMTX"[%d].xyz, indtevcrd%d));\n", - n, mtxidx, n, mtxidx+1, n); - } - else if (bpmem.tevind[n].mid <= 7 && bHasTexCoord) - { // s matrix - // TODO: Might become negative? - int mtxidx = 2*(bpmem.tevind[n].mid-5); - WRITE(p, "float2 indtevtrans%d = "I_INDTEXMTX"[%d].ww * uv%d.xy * indtevcrd%d.xx;\n", n, mtxidx, texcoord, n); - } - else if (bpmem.tevind[n].mid <= 11 && bHasTexCoord) - { // t matrix - // TODO: Might become negative? - int mtxidx = 2*(bpmem.tevind[n].mid-9); - WRITE(p, "float2 indtevtrans%d = "I_INDTEXMTX"[%d].ww * uv%d.xy * indtevcrd%d.yy;\n", n, mtxidx, texcoord, n); - } - else - WRITE(p, "float2 indtevtrans%d = 0;\n", n); - } - else - WRITE(p, "float2 indtevtrans%d = 0;\n", n); - - // --------- - // Wrapping - // --------- - - // wrap S - if (bpmem.tevind[n].sw == ITW_OFF) - WRITE(p, "wrappedcoord.x = uv%d.x;\n", texcoord); - else if (bpmem.tevind[n].sw == ITW_0) - WRITE(p, "wrappedcoord.x = 0.0f;\n"); - else - WRITE(p, "wrappedcoord.x = fmod( uv%d.x, %s );\n", texcoord, tevIndWrapStart[bpmem.tevind[n].sw]); - - // wrap T - if (bpmem.tevind[n].tw == ITW_OFF) - WRITE(p, "wrappedcoord.y = uv%d.y;\n", texcoord); - else if (bpmem.tevind[n].tw == ITW_0) - WRITE(p, "wrappedcoord.y = 0.0f;\n"); - else - WRITE(p, "wrappedcoord.y = fmod( uv%d.y, %s );\n", texcoord, tevIndWrapStart[bpmem.tevind[n].tw]); - - if (bpmem.tevind[n].fb_addprev) // add previous tevcoord - WRITE(p, "tevcoord.xy += wrappedcoord + indtevtrans%d;\n", n); - else - WRITE(p, "tevcoord.xy = wrappedcoord + indtevtrans%d;\n", n); - } - - TevStageCombiner::ColorCombiner &cc = bpmem.combiners[n].colorC; - TevStageCombiner::AlphaCombiner &ac = bpmem.combiners[n].alphaC; - - // blah1 - if(cc.a == TEVCOLORARG_RASA || cc.a == TEVCOLORARG_RASC - || cc.b == TEVCOLORARG_RASA || cc.b == TEVCOLORARG_RASC - || cc.c == TEVCOLORARG_RASA || cc.c == TEVCOLORARG_RASC - || cc.d == TEVCOLORARG_RASA || cc.d == TEVCOLORARG_RASC - || ac.a == TEVALPHAARG_RASA || ac.b == TEVALPHAARG_RASA - || ac.c == TEVALPHAARG_RASA || ac.d == TEVALPHAARG_RASA) - { - char *rasswap = swapModeTable[bpmem.combiners[n].alphaC.rswap]; - WRITE(p, "rastemp = %s.%s;\n", tevRasTable[bpmem.tevorders[n / 2].getColorChan(n & 1)], rasswap); - WRITE(p, "crastemp = frac(rastemp * (255.0f/256.0f)) * (256.0f/255.0f);\n"); - } - - - if (bpmem.tevorders[n/2].getEnable(n&1)) - { - if(!bHasIndStage) - { - // calc tevcord - if(bHasTexCoord) - WRITE(p, "tevcoord.xy = uv%d.xy;\n", texcoord); - else - WRITE(p, "tevcoord.xy = float2(0.0f, 0.0f);\n"); - } - - char *texswap = swapModeTable[bpmem.combiners[n].alphaC.tswap]; - int texmap = bpmem.tevorders[n/2].getTexMap(n&1); - SampleTexture(p, "textemp", "tevcoord", texswap, texmap, ApiType); - } - else - WRITE(p, "textemp = float4(1.0f, 1.0f, 1.0f, 1.0f);\n"); - - - // blah2 - if (cc.a == TEVCOLORARG_KONST || cc.b == TEVCOLORARG_KONST || cc.c == TEVCOLORARG_KONST || cc.d == TEVCOLORARG_KONST - || ac.a == TEVALPHAARG_KONST || ac.b == TEVALPHAARG_KONST || ac.c == TEVALPHAARG_KONST || ac.d == TEVALPHAARG_KONST) - { - int kc = bpmem.tevksel[n / 2].getKC(n & 1); - int ka = bpmem.tevksel[n / 2].getKA(n & 1); - WRITE(p, "konsttemp = float4(%s, %s);\n", tevKSelTableC[kc], tevKSelTableA[ka]); - if(kc > 7 || ka > 7) - { - WRITE(p, "ckonsttemp = frac(konsttemp * (255.0f/256.0f)) * (256.0f/255.0f);\n"); - } - else - { - WRITE(p, "ckonsttemp = konsttemp;\n"); - } - } - - if(cc.a == TEVCOLORARG_CPREV || cc.a == TEVCOLORARG_APREV - || cc.b == TEVCOLORARG_CPREV || cc.b == TEVCOLORARG_APREV - || cc.c == TEVCOLORARG_CPREV || cc.c == TEVCOLORARG_APREV - || ac.a == TEVALPHAARG_APREV || ac.b == TEVALPHAARG_APREV || ac.c == TEVALPHAARG_APREV) - WRITE(p, "cprev = frac(prev * (255.0f/256.0f)) * (256.0f/255.0f);\n"); - - - if(cc.a == TEVCOLORARG_C0 || cc.a == TEVCOLORARG_A0 - || cc.b == TEVCOLORARG_C0 || cc.b == TEVCOLORARG_A0 - || cc.c == TEVCOLORARG_C0 || cc.c == TEVCOLORARG_A0 - || ac.a == TEVALPHAARG_A0 || ac.b == TEVALPHAARG_A0 || ac.c == TEVALPHAARG_A0) - WRITE(p, "cc0 = frac(c0 * (255.0f/256.0f)) * (256.0f/255.0f);\n"); - - - if(cc.a == TEVCOLORARG_C1 || cc.a == TEVCOLORARG_A1 - || cc.b == TEVCOLORARG_C1 || cc.b == TEVCOLORARG_A1 - || cc.c == TEVCOLORARG_C1 || cc.c == TEVCOLORARG_A1 - || ac.a == TEVALPHAARG_A1 || ac.b == TEVALPHAARG_A1 || ac.c == TEVALPHAARG_A1) - WRITE(p, "cc1 = frac(c1 * (255.0f/256.0f)) * (256.0f/255.0f);\n"); - - - if(cc.a == TEVCOLORARG_C2 || cc.a == TEVCOLORARG_A2 - || cc.b == TEVCOLORARG_C2 || cc.b == TEVCOLORARG_A2 - || cc.c == TEVCOLORARG_C2 || cc.c == TEVCOLORARG_A2 - || ac.a == TEVALPHAARG_A2 || ac.b == TEVALPHAARG_A2 || ac.c == TEVALPHAARG_A2) - WRITE(p, "cc2 = frac(c2 * (255.0f/256.0f)) * (256.0f/255.0f);\n"); - - - WRITE(p, "// color combine\n"); - if (cc.clamp) - WRITE(p, "%s = saturate(", tevCOutputTable[cc.dest]); - else - WRITE(p, "%s = ", tevCOutputTable[cc.dest]); - - // combine the color channel - if (cc.bias != TevBias_COMPARE) // if not compare - { - //normal color combiner goes here - if (cc.shift > TEVSCALE_1) - WRITE(p, "%s*(", tevScaleTable[cc.shift]); - - if(!(cc.d == TEVCOLORARG_ZERO && cc.op == TEVOP_ADD)) - WRITE(p, "%s%s", tevCInputTable[cc.d], tevOpTable[cc.op]); - - if (cc.a == cc.b) - WRITE(p, "%s", tevCInputTable[cc.a + 16]); - else if (cc.c == TEVCOLORARG_ZERO) - WRITE(p, "%s", tevCInputTable[cc.a + 16]); - else if (cc.c == TEVCOLORARG_ONE) - WRITE(p, "%s", tevCInputTable[cc.b + 16]); - else if (cc.a == TEVCOLORARG_ZERO) - WRITE(p, "%s*%s", tevCInputTable[cc.b + 16], tevCInputTable[cc.c + 16]); - else if (cc.b == TEVCOLORARG_ZERO) - WRITE(p, "%s*(float3(1.0f, 1.0f, 1.0f)-%s)", tevCInputTable[cc.a + 16], tevCInputTable[cc.c + 16]); - else - WRITE(p, "lerp(%s, %s, %s)", tevCInputTable[cc.a + 16], tevCInputTable[cc.b + 16], tevCInputTable[cc.c + 16]); - - WRITE(p, "%s", tevBiasTable[cc.bias]); - - if (cc.shift > TEVSCALE_1) - WRITE(p, ")"); - } - else - { - int cmp = (cc.shift<<1)|cc.op|8; // comparemode stored here - WRITE(p, TEVCMPColorOPTable[cmp],//lookup the function from the op table - tevCInputTable[cc.d], - tevCInputTable[cc.a + 16], - tevCInputTable[cc.b + 16], - tevCInputTable[cc.c + 16]); - } - if (cc.clamp) - WRITE(p, ")"); - WRITE(p,";\n"); - - WRITE(p, "// alpha combine\n"); - // combine the alpha channel - if (ac.clamp) - WRITE(p, "%s = saturate(", tevAOutputTable[ac.dest]); - else - WRITE(p, "%s = ", tevAOutputTable[ac.dest]); - - if (ac.bias != TevBias_COMPARE) // if not compare - { - //normal alpha combiner goes here - if (ac.shift > TEVSCALE_1) - WRITE(p, "%s*(", tevScaleTable[ac.shift]); - - if(!(ac.d == TEVALPHAARG_ZERO && ac.op == TEVOP_ADD)) - WRITE(p, "%s.a%s", tevAInputTable[ac.d], tevOpTable[ac.op]); - - if (ac.a == ac.b) - WRITE(p, "%s.a", tevAInputTable[ac.a + 8]); - else if (ac.c == TEVALPHAARG_ZERO) - WRITE(p, "%s.a", tevAInputTable[ac.a + 8]); - else if (ac.a == TEVALPHAARG_ZERO) - WRITE(p, "%s.a*%s.a", tevAInputTable[ac.b + 8], tevAInputTable[ac.c + 8]); - else if (ac.b == TEVALPHAARG_ZERO) - WRITE(p, "%s.a*(1.0f-%s.a)", tevAInputTable[ac.a + 8], tevAInputTable[ac.c + 8]); - else - WRITE(p, "lerp(%s.a, %s.a, %s.a)", tevAInputTable[ac.a + 8], tevAInputTable[ac.b + 8], tevAInputTable[ac.c + 8]); - - WRITE(p, "%s",tevBiasTable[ac.bias]); - - if (ac.shift>0) - WRITE(p, ")"); - - } - else - { - //compare alpha combiner goes here - int cmp = (ac.shift<<1)|ac.op|8; // comparemode stored here - WRITE(p, TEVCMPAlphaOPTable[cmp], - tevAInputTable[ac.d], - tevAInputTable[ac.a + 8], - tevAInputTable[ac.b + 8], - tevAInputTable[ac.c + 8]); - } - if (ac.clamp) - WRITE(p, ")"); - WRITE(p, ";\n\n"); - WRITE(p, "// TEV done\n"); -} - -void SampleTexture(char *&p, const char *destination, const char *texcoords, const char *texswap, int texmap, API_TYPE ApiType) -{ - if (ApiType == API_D3D11) - WRITE(p, "%s=Tex%d.Sample(samp%d,%s.xy * "I_TEXDIMS"[%d].xy).%s;\n", destination, texmap,texmap, texcoords, texmap, texswap); - else - WRITE(p, "%s=tex2D(samp%d,%s.xy * "I_TEXDIMS"[%d].xy).%s;\n", destination, texmap, texcoords, texmap, texswap); -} - -static const char *tevAlphaFuncsTable[] = -{ - "(false)", //ALPHACMP_NEVER 0 - "(prev.a <= %s - (0.25f/255.0f))", //ALPHACMP_LESS 1 - "(abs( prev.a - %s ) < (0.5f/255.0f))", //ALPHACMP_EQUAL 2 - "(prev.a < %s + (0.25f/255.0f))", //ALPHACMP_LEQUAL 3 - "(prev.a >= %s + (0.25f/255.0f))", //ALPHACMP_GREATER 4 - "(abs( prev.a - %s ) >= (0.5f/255.0f))", //ALPHACMP_NEQUAL 5 - "(prev.a > %s - (0.25f/255.0f))", //ALPHACMP_GEQUAL 6 - "(true)" //ALPHACMP_ALWAYS 7 -}; - -static const char *tevAlphaFunclogicTable[] = -{ - " && ", // and - " || ", // or - " != ", // xor - " == " // xnor -}; -static int AlphaPreTest() -{ - u32 op = bpmem.alphaFunc.logic; - u32 comp[2] = {bpmem.alphaFunc.comp0, bpmem.alphaFunc.comp1}; - - // First kill all the simple cases - switch(op) - { - case 0: // AND - if (comp[0] == ALPHACMP_ALWAYS && comp[1] == ALPHACMP_ALWAYS) return true; - if (comp[0] == ALPHACMP_NEVER || comp[1] == ALPHACMP_NEVER) return false; - break; - case 1: // OR - if (comp[0] == ALPHACMP_ALWAYS || comp[1] == ALPHACMP_ALWAYS) return true; - if (comp[0] == ALPHACMP_NEVER && comp[1] == ALPHACMP_NEVER)return false; - break; - case 2: // XOR - if ((comp[0] == ALPHACMP_ALWAYS && comp[1] == ALPHACMP_NEVER) || (comp[0] == ALPHACMP_NEVER && comp[1] == ALPHACMP_ALWAYS)) - return true; - if ((comp[0] == ALPHACMP_ALWAYS && comp[1] == ALPHACMP_ALWAYS) || (comp[0] == ALPHACMP_NEVER && comp[1] == ALPHACMP_NEVER)) - return false; - break; - case 3: // XNOR - if ((comp[0] == ALPHACMP_ALWAYS && comp[1] == ALPHACMP_NEVER) || (comp[0] == ALPHACMP_NEVER && comp[1] == ALPHACMP_ALWAYS)) - return false; - if ((comp[0] == ALPHACMP_ALWAYS && comp[1] == ALPHACMP_ALWAYS) || (comp[0] == ALPHACMP_NEVER && comp[1] == ALPHACMP_NEVER)) - return true; - break; - default: PanicAlert("bad logic for alpha test? %08x", op); - } - return -1; -} - - -static bool WriteAlphaTest(char *&p, API_TYPE ApiType,DSTALPHA_MODE dstAlphaMode) -{ - static const char *alphaRef[2] = - { - I_ALPHA"[0].r", - I_ALPHA"[0].g" - }; - - int Pretest = AlphaPreTest(); - if(Pretest >= 0) - { - return Pretest != 0; - } - - // using discard then return works the same in cg and dx9 but not in dx11 - WRITE(p, "if(!( "); - - int compindex = bpmem.alphaFunc.comp0 % 8; - WRITE(p, tevAlphaFuncsTable[compindex],alphaRef[0]);//lookup the first component from the alpha function table - - WRITE(p, "%s", tevAlphaFunclogicTable[bpmem.alphaFunc.logic % 4]);//lookup the logic op - - compindex = bpmem.alphaFunc.comp1 % 8; - WRITE(p, tevAlphaFuncsTable[compindex],alphaRef[1]);//lookup the second component from the alpha function table - WRITE(p, ")){ocol0 = 0;%s%s discard;%s}\n", - dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND ? "ocol1 = 0;" : "", - DepthTextureEnable ? "depth = 1.f;" : "", - (ApiType != API_D3D11) ? "return;" : ""); - return true; -} - -static const char *tevFogFuncsTable[] = -{ - "", //No Fog - "", //? - "", //Linear - "", //? - " fog = 1.0f - pow(2.0f, -8.0f * fog);\n", //exp - " fog = 1.0f - pow(2.0f, -8.0f * fog * fog);\n", //exp2 - " fog = pow(2.0f, -8.0f * (1.0f - fog));\n", //backward exp - " fog = 1.0f - fog;\n fog = pow(2.0f, -8.0f * fog * fog);\n" //backward exp2 -}; - -static void WriteFog(char *&p) -{ - if(bpmem.fog.c_proj_fsel.fsel == 0)return;//no Fog - - if (bpmem.fog.c_proj_fsel.proj == 0) - { - // perspective - // ze = A/(B - (Zs >> B_SHF) - WRITE (p, " float ze = "I_FOG"[1].x / ("I_FOG"[1].y - (zCoord / "I_FOG"[1].w));\n"); - } - else - { - // orthographic - // ze = a*Zs (here, no B_SHF) - WRITE (p, " float ze = "I_FOG"[1].x * zCoord;\n"); - } - - // x_adjust = sqrt((x-center)^2 + k^2)/k - // ze *= x_adjust - //this is complitly teorical as the real hard seems to use a table intead of calculate the values. - if(bpmem.fogRange.Base.Enabled) - { - WRITE (p, " float x_adjust = (2.0f * (clipPos.x / "I_FOG"[2].y)) - 1.0f - "I_FOG"[2].x;\n"); - WRITE (p, " x_adjust = sqrt(x_adjust * x_adjust + "I_FOG"[2].z * "I_FOG"[2].z) / "I_FOG"[2].z;\n"); - WRITE (p, " ze *= x_adjust;\n"); - } - - WRITE (p, " float fog = saturate(ze - "I_FOG"[1].z);\n"); - - if(bpmem.fog.c_proj_fsel.fsel > 3) - { - WRITE(p, "%s", tevFogFuncsTable[bpmem.fog.c_proj_fsel.fsel]); - } - else - { - if(bpmem.fog.c_proj_fsel.fsel != 2) - WARN_LOG(VIDEO, "Unknown Fog Type! %08x", bpmem.fog.c_proj_fsel.fsel); - } - - WRITE(p, " prev.rgb = lerp(prev.rgb,"I_FOG"[0].rgb,fog);\n"); - - +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include +#include +#include +#include + +#include "LightingShaderGen.h" +#include "PixelShaderGen.h" +#include "XFMemory.h" // for texture projection mode +#include "BPMemory.h" +#include "VideoConfig.h" +#include "NativeVertexFormat.h" + +PIXELSHADERUID last_pixel_shader_uid; + +static int AlphaPreTest(); + +static void StageHash(int stage, u32* out) +{ + out[0] |= bpmem.combiners[stage].colorC.hex & 0xFFFFFF; // 24 + u32 alphaC = bpmem.combiners[stage].alphaC.hex & 0xFFFFF0; // 24, strip out tswap and rswap for now + out[0] |= (alphaC&0xF0) << 24; // 8 + out[1] |= alphaC >> 8; // 16 + + // reserve 3 bits for bpmem.tevorders[stage/2].getTexMap + out[1] |= bpmem.tevorders[stage/2].getTexCoord(stage&1) << 19; // 3 + out[1] |= bpmem.tevorders[stage/2].getEnable(stage&1) << 22; // 1 + // reserve 3 bits for bpmem.tevorders[stage/2].getColorChan + + bool bHasIndStage = bpmem.tevind[stage].IsActive() && bpmem.tevind[stage].bt < bpmem.genMode.numindstages; + out[2] |= bHasIndStage << 2; // 1 + + bool needstexcoord = false; + + if (bHasIndStage) + { + out[2] |= (bpmem.tevind[stage].hex & 0x17FFFF) << 3; // 21, TODO: needs an explanation + needstexcoord = true; + } + + + TevStageCombiner::ColorCombiner& cc = bpmem.combiners[stage].colorC; + TevStageCombiner::AlphaCombiner& ac = bpmem.combiners[stage].alphaC; + + if(cc.a == TEVCOLORARG_RASA || cc.a == TEVCOLORARG_RASC + || cc.b == TEVCOLORARG_RASA || cc.b == TEVCOLORARG_RASC + || cc.c == TEVCOLORARG_RASA || cc.c == TEVCOLORARG_RASC + || cc.d == TEVCOLORARG_RASA || cc.d == TEVCOLORARG_RASC + || ac.a == TEVALPHAARG_RASA || ac.b == TEVALPHAARG_RASA + || ac.c == TEVALPHAARG_RASA || ac.d == TEVALPHAARG_RASA) + { + out[0] |= bpmem.combiners[stage].alphaC.rswap; + out[2] |= bpmem.tevksel[bpmem.combiners[stage].alphaC.rswap*2].swap1 << 24; // 2 + out[2] |= bpmem.tevksel[bpmem.combiners[stage].alphaC.rswap*2].swap2 << 26; // 2 + out[2] |= bpmem.tevksel[bpmem.combiners[stage].alphaC.rswap*2+1].swap1 << 28; // 2 + out[2] |= bpmem.tevksel[bpmem.combiners[stage].alphaC.rswap*2+1].swap2 << 30; // 2 + out[1] |= (bpmem.tevorders[stage/2].getColorChan(stage&1)&1) << 23; + out[2] |= (bpmem.tevorders[stage/2].getColorChan(stage&1)&0x6) >> 1; + } + + out[3] |= bpmem.tevorders[stage/2].getEnable(stage&1); + if (bpmem.tevorders[stage/2].getEnable(stage&1)) + { + if (bHasIndStage) needstexcoord = true; + + out[0] |= bpmem.combiners[stage].alphaC.tswap; + out[3] |= bpmem.tevksel[bpmem.combiners[stage].alphaC.tswap*2].swap1 << 1; // 2 + out[3] |= bpmem.tevksel[bpmem.combiners[stage].alphaC.tswap*2].swap2 << 3; // 2 + out[3] |= bpmem.tevksel[bpmem.combiners[stage].alphaC.tswap*2+1].swap1 << 5; // 2 + out[3] |= bpmem.tevksel[bpmem.combiners[stage].alphaC.tswap*2+1].swap2 << 7; // 2 + out[1] |= bpmem.tevorders[stage/2].getTexMap(stage&1) << 16; + } + + if (cc.a == TEVCOLORARG_KONST || cc.b == TEVCOLORARG_KONST || cc.c == TEVCOLORARG_KONST || cc.d == TEVCOLORARG_KONST + || ac.a == TEVALPHAARG_KONST || ac.b == TEVALPHAARG_KONST || ac.c == TEVALPHAARG_KONST || ac.d == TEVALPHAARG_KONST) + { + out[3] |= bpmem.tevksel[stage/2].getKC(stage&1) << 9; // 5 + out[3] |= bpmem.tevksel[stage/2].getKA(stage&1) << 14; // 5 + } + + if (needstexcoord) + { + out[1] |= bpmem.tevorders[stage/2].getTexCoord(stage&1) << 16; + } +} + +// Mash together all the inputs that contribute to the code of a generated pixel shader into +// a unique identifier, basically containing all the bits. Yup, it's a lot .... +// It would likely be a lot more efficient to build this incrementally as the attributes +// are set... +void GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode) +{ + uid->values[0] |= bpmem.genMode.numtevstages; // 4 + uid->values[0] |= bpmem.genMode.numtexgens << 4; // 4 + uid->values[0] |= dstAlphaMode << 8; // 2 + + bool DepthTextureEnable = (bpmem.ztex2.op != ZTEXTURE_DISABLE && !bpmem.zcontrol.zcomploc && bpmem.zmode.testenable && bpmem.zmode.updateenable) || g_ActiveConfig.bEnablePerPixelDepth; + + uid->values[0] |= DepthTextureEnable << 10; // 1 + + bool enablePL = g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting; + uid->values[0] |= enablePL << 11; // 1 + + if (!enablePL) uid->values[0] |= xfregs.numTexGen.numTexGens << 12; // 4 + u32 alphaPreTest = AlphaPreTest()+1; + + uid->values[0] |= alphaPreTest << 16; // 2 + + if (alphaPreTest == 1 || (alphaPreTest && !DepthTextureEnable && dstAlphaMode == DSTALPHA_ALPHA_PASS)) + { + // Courtesy of PreAlphaTest, we're done already ;) + // NOTE: The comment header of generated shaders depends on the value of bpmem.genmode.numindstages.. shouldnt really bother about that though. + uid->num_values = 1; + return; + } + + for (unsigned int i = 0; i < bpmem.genMode.numtexgens; ++i) + { + if (18+i < 32) + uid->values[0] |= xfregs.texMtxInfo[i].projection << (18+i); // 1 + else + uid->values[1] |= xfregs.texMtxInfo[i].projection << (i - 14); // 1 + } + + uid->values[1] = bpmem.genMode.numindstages << 2; // 3 + u32 indirectStagesUsed = 0; + for (unsigned int i = 0; i < bpmem.genMode.numindstages; ++i) + if (bpmem.tevind[i].IsActive() && bpmem.tevind[i].bt < bpmem.genMode.numindstages) + indirectStagesUsed |= (1 << bpmem.tevind[i].bt); + + assert(indirectStagesUsed == (indirectStagesUsed & 0xF)); + + uid->values[1] |= indirectStagesUsed << 5; // 4; + + for (unsigned int i = 0; i < bpmem.genMode.numindstages; ++i) + { + if (indirectStagesUsed & (1 << i)) + { + uid->values[1] |= (bpmem.tevindref.getTexCoord(i) < bpmem.genMode.numtexgens) << (9 + 3*i); // 1 + if (bpmem.tevindref.getTexCoord(i) < bpmem.genMode.numtexgens) + uid->values[1] |= bpmem.tevindref.getTexCoord(i) << (10 + 3*i); // 2 + } + } + + u32* ptr = &uid->values[2]; + for (int i = 0; i < bpmem.genMode.numtevstages+1; ++i) + { + StageHash(i, ptr); + ptr += 4; // max: ptr = &uid->values[66] + } + + ptr[0] |= bpmem.alphaFunc.comp0; // 3 + ptr[0] |= bpmem.alphaFunc.comp1 << 3; // 3 + ptr[0] |= bpmem.alphaFunc.logic << 6; // 2 + + if (alphaPreTest == 0 || alphaPreTest == 2) + { + ptr[0] |= bpmem.fog.c_proj_fsel.fsel << 8; // 3 + if (DepthTextureEnable) + { + ptr[0] |= bpmem.ztex2.op << 11; // 2 + ptr[0] |= bpmem.zcontrol.zcomploc << 13; // 1 + ptr[0] |= bpmem.zmode.testenable << 14; // 1 + ptr[0] |= bpmem.zmode.updateenable << 15; // 1 + } + } + + if (dstAlphaMode != DSTALPHA_ALPHA_PASS) + { + if (bpmem.fog.c_proj_fsel.fsel != 0) + { + ptr[0] |= bpmem.fog.c_proj_fsel.proj << 16; // 1 + ptr[0] |= bpmem.fogRange.Base.Enabled << 17; // 1 + } + } + + ++ptr; + if (enablePL) + ptr += GetLightingShaderId(ptr); + + uid->num_values = ptr - uid->values; +} + +void GetSafePixelShaderId(PIXELSHADERUIDSAFE *uid, DSTALPHA_MODE dstAlphaMode) +{ + u32* ptr = uid->values; + *ptr++ = dstAlphaMode; // 0 + *ptr++ = bpmem.genMode.hex; // 1 + *ptr++ = bpmem.ztex2.hex; // 2 + *ptr++ = bpmem.zcontrol.hex; // 3 + *ptr++ = bpmem.zmode.hex; // 4 + *ptr++ = g_ActiveConfig.bEnablePerPixelDepth; // 5 + *ptr++ = g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting; // 6 + *ptr++ = xfregs.numTexGen.hex; // 7 + + if (g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) + { + // TODO: Include register states for lighting shader + *ptr++ = xfregs.color[0].hex; + *ptr++ = xfregs.alpha[0].hex; + *ptr++ = xfregs.color[1].hex; + *ptr++ = xfregs.alpha[1].hex; + } + + for (unsigned int i = 0; i < 8; ++i) + *ptr++ = xfregs.texMtxInfo[i].hex; // 8-15 + + for (unsigned int i = 0; i < 16; ++i) + *ptr++ = bpmem.tevind[i].hex; // 16-31 + + *ptr++ = bpmem.tevindref.hex; // 32 + + for (int i = 0; i < bpmem.genMode.numtevstages+1; ++i) // up to 16 times + { + *ptr++ = bpmem.combiners[i].colorC.hex; // 33+5*i + *ptr++ = bpmem.combiners[i].alphaC.hex; // 34+5*i + *ptr++ = bpmem.tevind[i].hex; // 35+5*i + *ptr++ = bpmem.tevksel[i/2].hex; // 36+5*i + *ptr++ = bpmem.tevorders[i/2].hex; // 37+5*i + } + + ptr = &uid->values[113]; + + *ptr++ = bpmem.alphaFunc.hex; // 113 + + *ptr++ = bpmem.fog.c_proj_fsel.hex; // 114 + *ptr++ = bpmem.fogRange.Base.hex; // 115 + + _assert_((ptr - uid->values) == uid->GetNumValues()); +} + +void ValidatePixelShaderIDs(API_TYPE api, PIXELSHADERUIDSAFE old_id, const std::string& old_code, DSTALPHA_MODE dstAlphaMode, u32 components) +{ + if (!g_ActiveConfig.bEnableShaderDebugging) + return; + + PIXELSHADERUIDSAFE new_id; + GetSafePixelShaderId(&new_id, dstAlphaMode); + + if (!(old_id == new_id)) + { + std::string new_code(GeneratePixelShaderCode(dstAlphaMode, api, components)); + if (old_code != new_code) + { + _assert_(old_id.GetNumValues() == new_id.GetNumValues()); + + char msg[8192]; + char* ptr = msg; + ptr += sprintf(ptr, "Pixel shader IDs matched but unique IDs did not!\nUnique IDs (old <-> new):\n"); + const int N = new_id.GetNumValues(); + for (int i = 0; i < N/2; ++i) + ptr += sprintf(ptr, "%02d, %08X %08X | %08X %08X\n", 2*i, old_id.values[2*i], old_id.values[2*i+1], + new_id.values[2*i], new_id.values[2*i+1]); + if (N % 2) + ptr += sprintf(ptr, "%02d, %08X | %08X\n", N-1, old_id.values[N-1], new_id.values[N-1]); + + static int num_failures = 0; + char szTemp[MAX_PATH]; + sprintf(szTemp, "%spsuid_mismatch_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++); + std::ofstream file(szTemp); + file << msg; + file << "\n\nOld shader code:\n" << old_code; + file << "\n\nNew shader code:\n" << new_code; + file.close(); + + PanicAlert("Unique pixel shader ID mismatch!\n\nReport this to the devs, along with the contents of %s.", szTemp); + } + } +} + +// old tev->pixelshader notes +// +// color for this stage (alpha, color) is given by bpmem.tevorders[0].colorchan0 +// konstant for this stage (alpha, color) is given by bpmem.tevksel +// inputs are given by bpmem.combiners[0].colorC.a/b/c/d << could be current chan color +// according to GXTevColorArg table above +// output is given by .outreg +// tevtemp is set according to swapmodetables and + +static void WriteStage(char *&p, int n, API_TYPE ApiType); +static void SampleTexture(char *&p, const char *destination, const char *texcoords, const char *texswap, int texmap, API_TYPE ApiType); +// static void WriteAlphaCompare(char *&p, int num, int comp); +static bool WriteAlphaTest(char *&p, API_TYPE ApiType,DSTALPHA_MODE dstAlphaMode); +static void WriteFog(char *&p); + +static const char *tevKSelTableC[] = // KCSEL +{ + "1.0f,1.0f,1.0f", // 1 = 0x00 + "0.875f,0.875f,0.875f", // 7_8 = 0x01 + "0.75f,0.75f,0.75f", // 3_4 = 0x02 + "0.625f,0.625f,0.625f", // 5_8 = 0x03 + "0.5f,0.5f,0.5f", // 1_2 = 0x04 + "0.375f,0.375f,0.375f", // 3_8 = 0x05 + "0.25f,0.25f,0.25f", // 1_4 = 0x06 + "0.125f,0.125f,0.125f", // 1_8 = 0x07 + "ERROR", // 0x08 + "ERROR", // 0x09 + "ERROR", // 0x0a + "ERROR", // 0x0b + I_KCOLORS"[0].rgb", // K0 = 0x0C + I_KCOLORS"[1].rgb", // K1 = 0x0D + I_KCOLORS"[2].rgb", // K2 = 0x0E + I_KCOLORS"[3].rgb", // K3 = 0x0F + I_KCOLORS"[0].rrr", // K0_R = 0x10 + I_KCOLORS"[1].rrr", // K1_R = 0x11 + I_KCOLORS"[2].rrr", // K2_R = 0x12 + I_KCOLORS"[3].rrr", // K3_R = 0x13 + I_KCOLORS"[0].ggg", // K0_G = 0x14 + I_KCOLORS"[1].ggg", // K1_G = 0x15 + I_KCOLORS"[2].ggg", // K2_G = 0x16 + I_KCOLORS"[3].ggg", // K3_G = 0x17 + I_KCOLORS"[0].bbb", // K0_B = 0x18 + I_KCOLORS"[1].bbb", // K1_B = 0x19 + I_KCOLORS"[2].bbb", // K2_B = 0x1A + I_KCOLORS"[3].bbb", // K3_B = 0x1B + I_KCOLORS"[0].aaa", // K0_A = 0x1C + I_KCOLORS"[1].aaa", // K1_A = 0x1D + I_KCOLORS"[2].aaa", // K2_A = 0x1E + I_KCOLORS"[3].aaa", // K3_A = 0x1F +}; + +static const char *tevKSelTableA[] = // KASEL +{ + "1.0f", // 1 = 0x00 + "0.875f",// 7_8 = 0x01 + "0.75f", // 3_4 = 0x02 + "0.625f",// 5_8 = 0x03 + "0.5f", // 1_2 = 0x04 + "0.375f",// 3_8 = 0x05 + "0.25f", // 1_4 = 0x06 + "0.125f",// 1_8 = 0x07 + "ERROR", // 0x08 + "ERROR", // 0x09 + "ERROR", // 0x0a + "ERROR", // 0x0b + "ERROR", // 0x0c + "ERROR", // 0x0d + "ERROR", // 0x0e + "ERROR", // 0x0f + I_KCOLORS"[0].r", // K0_R = 0x10 + I_KCOLORS"[1].r", // K1_R = 0x11 + I_KCOLORS"[2].r", // K2_R = 0x12 + I_KCOLORS"[3].r", // K3_R = 0x13 + I_KCOLORS"[0].g", // K0_G = 0x14 + I_KCOLORS"[1].g", // K1_G = 0x15 + I_KCOLORS"[2].g", // K2_G = 0x16 + I_KCOLORS"[3].g", // K3_G = 0x17 + I_KCOLORS"[0].b", // K0_B = 0x18 + I_KCOLORS"[1].b", // K1_B = 0x19 + I_KCOLORS"[2].b", // K2_B = 0x1A + I_KCOLORS"[3].b", // K3_B = 0x1B + I_KCOLORS"[0].a", // K0_A = 0x1C + I_KCOLORS"[1].a", // K1_A = 0x1D + I_KCOLORS"[2].a", // K2_A = 0x1E + I_KCOLORS"[3].a", // K3_A = 0x1F +}; + +static const char *tevScaleTable[] = // CS +{ + "1.0f", // SCALE_1 + "2.0f", // SCALE_2 + "4.0f", // SCALE_4 + "0.5f", // DIVIDE_2 +}; + +static const char *tevBiasTable[] = // TB +{ + "", // ZERO, + "+0.5f", // ADDHALF, + "-0.5f", // SUBHALF, + "", +}; + +static const char *tevOpTable[] = { // TEV + "+", // TEVOP_ADD = 0, + "-", // TEVOP_SUB = 1, +}; + +static const char *tevCInputTable[] = // CC +{ + "(prev.rgb)", // CPREV, + "(prev.aaa)", // APREV, + "(c0.rgb)", // C0, + "(c0.aaa)", // A0, + "(c1.rgb)", // C1, + "(c1.aaa)", // A1, + "(c2.rgb)", // C2, + "(c2.aaa)", // A2, + "(textemp.rgb)", // TEXC, + "(textemp.aaa)", // TEXA, + "(rastemp.rgb)", // RASC, + "(rastemp.aaa)", // RASA, + "float3(1.0f, 1.0f, 1.0f)", // ONE + "float3(0.5f, 0.5f, 0.5f)", // HALF + "(konsttemp.rgb)", //"konsttemp.rgb", // KONST + "float3(0.0f, 0.0f, 0.0f)", // ZERO + ///aded extra values to map clamped values + "(cprev.rgb)", // CPREV, + "(cprev.aaa)", // APREV, + "(cc0.rgb)", // C0, + "(cc0.aaa)", // A0, + "(cc1.rgb)", // C1, + "(cc1.aaa)", // A1, + "(cc2.rgb)", // C2, + "(cc2.aaa)", // A2, + "(textemp.rgb)", // TEXC, + "(textemp.aaa)", // TEXA, + "(crastemp.rgb)", // RASC, + "(crastemp.aaa)", // RASA, + "float3(1.0f, 1.0f, 1.0f)", // ONE + "float3(0.5f, 0.5f, 0.5f)", // HALF + "(ckonsttemp.rgb)", //"konsttemp.rgb", // KONST + "float3(0.0f, 0.0f, 0.0f)", // ZERO + "PADERROR", "PADERROR", "PADERROR", "PADERROR" +}; + +static const char *tevAInputTable[] = // CA +{ + "prev", // APREV, + "c0", // A0, + "c1", // A1, + "c2", // A2, + "textemp", // TEXA, + "rastemp", // RASA, + "konsttemp", // KONST, (hw1 had quarter) + "float4(0.0f, 0.0f, 0.0f, 0.0f)", // ZERO + ///aded extra values to map clamped values + "cprev", // APREV, + "cc0", // A0, + "cc1", // A1, + "cc2", // A2, + "textemp", // TEXA, + "crastemp", // RASA, + "ckonsttemp", // KONST, (hw1 had quarter) + "float4(0.0f, 0.0f, 0.0f, 0.0f)", // ZERO + "PADERROR", "PADERROR", "PADERROR", "PADERROR", + "PADERROR", "PADERROR", "PADERROR", "PADERROR", +}; + +static const char *tevRasTable[] = +{ + "colors_0", + "colors_1", + "ERROR", //2 + "ERROR", //3 + "ERROR", //4 + "alphabump", // use bump alpha + "(alphabump*(255.0f/248.0f))", //normalized + "float4(0.0f, 0.0f, 0.0f, 0.0f)", // zero +}; + +//static const char *tevTexFunc[] = { "tex2D", "texRECT" }; + +static const char *tevCOutputTable[] = { "prev.rgb", "c0.rgb", "c1.rgb", "c2.rgb" }; +static const char *tevAOutputTable[] = { "prev.a", "c0.a", "c1.a", "c2.a" }; +static const char *tevIndAlphaSel[] = {"", "x", "y", "z"}; +//static const char *tevIndAlphaScale[] = {"", "*32", "*16", "*8"}; +static const char *tevIndAlphaScale[] = {"*(248.0f/255.0f)", "*(224.0f/255.0f)", "*(240.0f/255.0f)", "*(248.0f/255.0f)"}; +static const char *tevIndBiasField[] = {"", "x", "y", "xy", "z", "xz", "yz", "xyz"}; // indexed by bias +static const char *tevIndBiasAdd[] = {"-128.0f", "1.0f", "1.0f", "1.0f" }; // indexed by fmt +static const char *tevIndWrapStart[] = {"0.0f", "256.0f", "128.0f", "64.0f", "32.0f", "16.0f", "0.001f" }; +static const char *tevIndFmtScale[] = {"255.0f", "31.0f", "15.0f", "7.0f" }; + +#define WRITE p+=sprintf + +static char swapModeTable[4][5]; + +static char text[16384]; +static bool DepthTextureEnable; + +static void BuildSwapModeTable() +{ + static const char *swapColors = "rgba"; + for (int i = 0; i < 4; i++) + { + swapModeTable[i][0] = swapColors[bpmem.tevksel[i*2].swap1]; + swapModeTable[i][1] = swapColors[bpmem.tevksel[i*2].swap2]; + swapModeTable[i][2] = swapColors[bpmem.tevksel[i*2+1].swap1]; + swapModeTable[i][3] = swapColors[bpmem.tevksel[i*2+1].swap2]; + swapModeTable[i][4] = 0; + } +} + +const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType, u32 components) +{ + setlocale(LC_NUMERIC, "C"); // Reset locale for compilation + text[sizeof(text) - 1] = 0x7C; // canary + + BuildSwapModeTable(); // Needed for WriteStage + int numStages = bpmem.genMode.numtevstages + 1; + int numTexgen = bpmem.genMode.numtexgens; + + char *p = text; + WRITE(p, "//Pixel Shader for TEV stages\n"); + WRITE(p, "//%i TEV stages, %i texgens, XXX IND stages\n", + numStages, numTexgen/*, bpmem.genMode.numindstages*/); + + int nIndirectStagesUsed = 0; + if (bpmem.genMode.numindstages > 0) + { + for (int i = 0; i < numStages; ++i) + { + if (bpmem.tevind[i].IsActive() && bpmem.tevind[i].bt < bpmem.genMode.numindstages) + nIndirectStagesUsed |= 1 << bpmem.tevind[i].bt; + } + } + DepthTextureEnable = (bpmem.ztex2.op != ZTEXTURE_DISABLE && !bpmem.zcontrol.zcomploc && bpmem.zmode.testenable && bpmem.zmode.updateenable) || g_ActiveConfig.bEnablePerPixelDepth ; + // Declare samplers + + if(ApiType != API_D3D11) + { + WRITE(p, "uniform sampler2D "); + } + else + { + WRITE(p, "sampler "); + } + + bool bfirst = true; + for (int i = 0; i < 8; ++i) + { + WRITE(p, "%s samp%d : register(s%d)", bfirst?"":",", i, i); + bfirst = false; + } + WRITE(p, ";\n"); + if(ApiType == API_D3D11) + { + WRITE(p, "Texture2D "); + bfirst = true; + for (int i = 0; i < 8; ++i) + { + WRITE(p, "%s Tex%d : register(t%d)", bfirst?"":",", i, i); + bfirst = false; + } + WRITE(p, ";\n"); + } + + WRITE(p, "\n"); + + WRITE(p, "uniform float4 "I_COLORS"[4] : register(c%d);\n", C_COLORS); + WRITE(p, "uniform float4 "I_KCOLORS"[4] : register(c%d);\n", C_KCOLORS); + WRITE(p, "uniform float4 "I_ALPHA"[1] : register(c%d);\n", C_ALPHA); + WRITE(p, "uniform float4 "I_TEXDIMS"[8] : register(c%d);\n", C_TEXDIMS); + WRITE(p, "uniform float4 "I_ZBIAS"[2] : register(c%d);\n", C_ZBIAS); + WRITE(p, "uniform float4 "I_INDTEXSCALE"[2] : register(c%d);\n", C_INDTEXSCALE); + WRITE(p, "uniform float4 "I_INDTEXMTX"[6] : register(c%d);\n", C_INDTEXMTX); + WRITE(p, "uniform float4 "I_FOG"[3] : register(c%d);\n", C_FOG); + + if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) + { + WRITE(p,"typedef struct { float4 col; float4 cosatt; float4 distatt; float4 pos; float4 dir; } Light;\n"); + WRITE(p,"typedef struct { Light lights[8]; } s_"I_PLIGHTS";\n"); + WRITE(p, "uniform s_"I_PLIGHTS" "I_PLIGHTS" : register(c%d);\n", C_PLIGHTS); + WRITE(p, "typedef struct { float4 C0, C1, C2, C3; } s_"I_PMATERIALS";\n"); + WRITE(p, "uniform s_"I_PMATERIALS" "I_PMATERIALS" : register(c%d);\n", C_PMATERIALS); + } + + WRITE(p, "void main(\n"); + if(ApiType != API_D3D11) + { + WRITE(p, " out float4 ocol0 : COLOR0,%s%s\n in float4 rawpos : %s,\n", + dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND ? "\n out float4 ocol1 : COLOR1," : "", + DepthTextureEnable ? "\n out float depth : DEPTH," : "", + ApiType & API_OPENGL ? "WPOS" : ApiType & API_D3D9_SM20 ? "POSITION" : "VPOS"); + } + else + { + WRITE(p, " out float4 ocol0 : SV_Target0,%s%s\n in float4 rawpos : SV_Position,\n", + dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND ? "\n out float4 ocol1 : SV_Target1," : "", + DepthTextureEnable ? "\n out float depth : SV_Depth," : ""); + } + + WRITE(p, " in float4 colors_0 : COLOR0,\n"); + WRITE(p, " in float4 colors_1 : COLOR1"); + + // compute window position if needed because binding semantic WPOS is not widely supported + if (numTexgen < 7) + { + for (int i = 0; i < numTexgen; ++i) + WRITE(p, ",\n in float3 uv%d : TEXCOORD%d", i, i); + WRITE(p, ",\n in float4 clipPos : TEXCOORD%d", numTexgen); + if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) + WRITE(p, ",\n in float4 Normal : TEXCOORD%d", numTexgen + 1); + } + else + { + // wpos is in w of first 4 texcoords + if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) + { + for (int i = 0; i < 8; ++i) + WRITE(p, ",\n in float4 uv%d : TEXCOORD%d", i, i); + } + else + { + for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i) + WRITE(p, ",\n in float%d uv%d : TEXCOORD%d", i < 4 ? 4 : 3 , i, i); + } + } + WRITE(p, " ) {\n"); + + char* pmainstart = p; + int Pretest = AlphaPreTest(); + if (dstAlphaMode == DSTALPHA_ALPHA_PASS && !DepthTextureEnable && Pretest >= 0) + { + if (!Pretest) + { + // alpha test will always fail, so restart the shader and just make it an empty function + WRITE(p, "ocol0 = 0;\n"); + WRITE(p, "discard;\n"); + if(ApiType != API_D3D11) + WRITE(p, "return;\n"); + } + else + { + WRITE(p, " ocol0 = "I_ALPHA"[0].aaaa;\n"); + } + WRITE(p, "}\n"); + return text; + } + + WRITE(p, " float4 c0 = "I_COLORS"[1], c1 = "I_COLORS"[2], c2 = "I_COLORS"[3], prev = float4(0.0f, 0.0f, 0.0f, 0.0f), textemp = float4(0.0f, 0.0f, 0.0f, 0.0f), rastemp = float4(0.0f, 0.0f, 0.0f, 0.0f), konsttemp = float4(0.0f, 0.0f, 0.0f, 0.0f);\n" + " float3 comp16 = float3(1.0f, 255.0f, 0.0f), comp24 = float3(1.0f, 255.0f, 255.0f*255.0f);\n" + " float4 alphabump=float4(0.0f,0.0f,0.0f,0.0f);\n" + " float3 tevcoord=float3(0.0f, 0.0f, 0.0f);\n" + " float2 wrappedcoord=float2(0.0f,0.0f), tempcoord=float2(0.0f,0.0f);\n" + " float4 cc0=float4(0.0f,0.0f,0.0f,0.0f), cc1=float4(0.0f,0.0f,0.0f,0.0f);\n" + " float4 cc2=float4(0.0f,0.0f,0.0f,0.0f), cprev=float4(0.0f,0.0f,0.0f,0.0f);\n" + " float4 crastemp=float4(0.0f,0.0f,0.0f,0.0f),ckonsttemp=float4(0.0f,0.0f,0.0f,0.0f);\n\n"); + + if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) + { + if (xfregs.numTexGen.numTexGens < 7) + { + WRITE(p,"float3 _norm0 = normalize(Normal.xyz);\n\n"); + WRITE(p,"float3 pos = float3(clipPos.x,clipPos.y,Normal.w);\n"); + } + else + { + WRITE(p," float3 _norm0 = normalize(float3(uv4.w,uv5.w,uv6.w));\n\n"); + WRITE(p,"float3 pos = float3(uv0.w,uv1.w,uv7.w);\n"); + } + + + WRITE(p, "float4 mat, lacc;\n" + "float3 ldir, h;\n" + "float dist, dist2, attn;\n"); + + p = GenerateLightingShader(p, components, I_PMATERIALS, I_PLIGHTS, "colors_", "colors_"); + } + + if (numTexgen < 7) + WRITE(p, "clipPos = float4(rawpos.x, rawpos.y, clipPos.z, clipPos.w);\n"); + else + WRITE(p, "float4 clipPos = float4(rawpos.x, rawpos.y, uv2.w, uv3.w);\n"); + + // HACK to handle cases where the tex gen is not enabled + if (numTexgen == 0) + { + WRITE(p, "float3 uv0 = float3(0.0f, 0.0f, 0.0f);\n"); + } + else + { + for (int i = 0; i < numTexgen; ++i) + { + // optional perspective divides + if (xfregs.texMtxInfo[i].projection == XF_TEXPROJ_STQ) + { + WRITE(p, "if (uv%d.z)", i); + WRITE(p, " uv%d.xy = uv%d.xy / uv%d.z;\n", i, i, i); + } + + WRITE(p, "uv%d.xy = uv%d.xy * "I_TEXDIMS"[%d].zw;\n", i, i, i); + } + } + + // indirect texture map lookup + for(u32 i = 0; i < bpmem.genMode.numindstages; ++i) + { + if (nIndirectStagesUsed & (1<= %s.r + (0.25f/255.0f)) ? %s : float3(0.0f, 0.0f, 0.0f))",//#define TEVCMP_R8_GT 8 + " %s + ((abs(%s.r - %s.r) < (0.5f/255.0f)) ? %s : float3(0.0f, 0.0f, 0.0f))",//#define TEVCMP_R8_EQ 9 + " %s + (( dot(%s.rgb, comp16) >= (dot(%s.rgb, comp16) + (0.25f/255.0f))) ? %s : float3(0.0f, 0.0f, 0.0f))",//#define TEVCMP_GR16_GT 10 + " %s + (abs(dot(%s.rgb, comp16) - dot(%s.rgb, comp16)) < (0.5f/255.0f) ? %s : float3(0.0f, 0.0f, 0.0f))",//#define TEVCMP_GR16_EQ 11 + " %s + (( dot(%s.rgb, comp24) >= (dot(%s.rgb, comp24) + (0.25f/255.0f))) ? %s : float3(0.0f, 0.0f, 0.0f))",//#define TEVCMP_BGR24_GT 12 + " %s + (abs(dot(%s.rgb, comp24) - dot(%s.rgb, comp24)) < (0.5f/255.0f) ? %s : float3(0.0f, 0.0f, 0.0f))",//#define TEVCMP_BGR24_EQ 13 + " %s + (max(sign(%s.rgb - %s.rgb - (0.25f/255.0f)), float3(0.0f, 0.0f, 0.0f)) * %s)",//#define TEVCMP_RGB8_GT 14 + " %s + ((float3(1.0f, 1.0f, 1.0f) - max(sign(abs(%s.rgb - %s.rgb) - (0.5f/255.0f)), float3(0.0f, 0.0f, 0.0f))) * %s)"//#define TEVCMP_RGB8_EQ 15 +}; + +//table with the alpha compare operations +static const char *TEVCMPAlphaOPTable[16] = +{ + "0.0f",//0 + "0.0f",//1 + "0.0f",//2 + "0.0f",//3 + "0.0f",//4 + "0.0f",//5 + "0.0f",//6 + "0.0f",//7 + " %s.a + ((%s.r >= (%s.r + (0.25f/255.0f))) ? %s.a : 0.0f)",//#define TEVCMP_R8_GT 8 + " %s.a + (abs(%s.r - %s.r) < (0.5f/255.0f) ? %s.a : 0.0f)",//#define TEVCMP_R8_EQ 9 + " %s.a + ((dot(%s.rgb, comp16) >= (dot(%s.rgb, comp16) + (0.25f/255.0f))) ? %s.a : 0.0f)",//#define TEVCMP_GR16_GT 10 + " %s.a + (abs(dot(%s.rgb, comp16) - dot(%s.rgb, comp16)) < (0.5f/255.0f) ? %s.a : 0.0f)",//#define TEVCMP_GR16_EQ 11 + " %s.a + ((dot(%s.rgb, comp24) >= (dot(%s.rgb, comp24) + (0.25f/255.0f))) ? %s.a : 0.0f)",//#define TEVCMP_BGR24_GT 12 + " %s.a + (abs(dot(%s.rgb, comp24) - dot(%s.rgb, comp24)) < (0.5f/255.0f) ? %s.a : 0.0f)",//#define TEVCMP_BGR24_EQ 13 + " %s.a + ((%s.a >= (%s.a + (0.25f/255.0f))) ? %s.a : 0.0f)",//#define TEVCMP_A8_GT 14 + " %s.a + (abs(%s.a - %s.a) < (0.5f/255.0f) ? %s.a : 0.0f)"//#define TEVCMP_A8_EQ 15 + +}; + + +static void WriteStage(char *&p, int n, API_TYPE ApiType) +{ + int texcoord = bpmem.tevorders[n/2].getTexCoord(n&1); + bool bHasTexCoord = (u32)texcoord < bpmem.genMode.numtexgens; + bool bHasIndStage = bpmem.tevind[n].IsActive() && bpmem.tevind[n].bt < bpmem.genMode.numindstages; + + // HACK to handle cases where the tex gen is not enabled + if (!bHasTexCoord) + texcoord = 0; + + WRITE(p, "// TEV stage %d\n", n); + + if (bHasIndStage) + { + WRITE(p, "// indirect op\n"); + // perform the indirect op on the incoming regular coordinates using indtex%d as the offset coords + if (bpmem.tevind[n].bs != ITBA_OFF) + { + WRITE(p, "alphabump = indtex%d.%s %s;\n", + bpmem.tevind[n].bt, + tevIndAlphaSel[bpmem.tevind[n].bs], + tevIndAlphaScale[bpmem.tevind[n].fmt]); + } + // format + WRITE(p, "float3 indtevcrd%d = indtex%d * %s;\n", n, bpmem.tevind[n].bt, tevIndFmtScale[bpmem.tevind[n].fmt]); + + // bias + if (bpmem.tevind[n].bias != ITB_NONE ) + WRITE(p, "indtevcrd%d.%s += %s;\n", n, tevIndBiasField[bpmem.tevind[n].bias], tevIndBiasAdd[bpmem.tevind[n].fmt]); + + // multiply by offset matrix and scale + if (bpmem.tevind[n].mid != 0) + { + if (bpmem.tevind[n].mid <= 3) + { + int mtxidx = 2*(bpmem.tevind[n].mid-1); + WRITE(p, "float2 indtevtrans%d = float2(dot("I_INDTEXMTX"[%d].xyz, indtevcrd%d), dot("I_INDTEXMTX"[%d].xyz, indtevcrd%d));\n", + n, mtxidx, n, mtxidx+1, n); + } + else if (bpmem.tevind[n].mid <= 7 && bHasTexCoord) + { // s matrix + // TODO: Might become negative? + int mtxidx = 2*(bpmem.tevind[n].mid-5); + WRITE(p, "float2 indtevtrans%d = "I_INDTEXMTX"[%d].ww * uv%d.xy * indtevcrd%d.xx;\n", n, mtxidx, texcoord, n); + } + else if (bpmem.tevind[n].mid <= 11 && bHasTexCoord) + { // t matrix + // TODO: Might become negative? + int mtxidx = 2*(bpmem.tevind[n].mid-9); + WRITE(p, "float2 indtevtrans%d = "I_INDTEXMTX"[%d].ww * uv%d.xy * indtevcrd%d.yy;\n", n, mtxidx, texcoord, n); + } + else + WRITE(p, "float2 indtevtrans%d = 0;\n", n); + } + else + WRITE(p, "float2 indtevtrans%d = 0;\n", n); + + // --------- + // Wrapping + // --------- + + // wrap S + if (bpmem.tevind[n].sw == ITW_OFF) + WRITE(p, "wrappedcoord.x = uv%d.x;\n", texcoord); + else if (bpmem.tevind[n].sw == ITW_0) + WRITE(p, "wrappedcoord.x = 0.0f;\n"); + else + WRITE(p, "wrappedcoord.x = fmod( uv%d.x, %s );\n", texcoord, tevIndWrapStart[bpmem.tevind[n].sw]); + + // wrap T + if (bpmem.tevind[n].tw == ITW_OFF) + WRITE(p, "wrappedcoord.y = uv%d.y;\n", texcoord); + else if (bpmem.tevind[n].tw == ITW_0) + WRITE(p, "wrappedcoord.y = 0.0f;\n"); + else + WRITE(p, "wrappedcoord.y = fmod( uv%d.y, %s );\n", texcoord, tevIndWrapStart[bpmem.tevind[n].tw]); + + if (bpmem.tevind[n].fb_addprev) // add previous tevcoord + WRITE(p, "tevcoord.xy += wrappedcoord + indtevtrans%d;\n", n); + else + WRITE(p, "tevcoord.xy = wrappedcoord + indtevtrans%d;\n", n); + } + + TevStageCombiner::ColorCombiner &cc = bpmem.combiners[n].colorC; + TevStageCombiner::AlphaCombiner &ac = bpmem.combiners[n].alphaC; + + // blah1 + if(cc.a == TEVCOLORARG_RASA || cc.a == TEVCOLORARG_RASC + || cc.b == TEVCOLORARG_RASA || cc.b == TEVCOLORARG_RASC + || cc.c == TEVCOLORARG_RASA || cc.c == TEVCOLORARG_RASC + || cc.d == TEVCOLORARG_RASA || cc.d == TEVCOLORARG_RASC + || ac.a == TEVALPHAARG_RASA || ac.b == TEVALPHAARG_RASA + || ac.c == TEVALPHAARG_RASA || ac.d == TEVALPHAARG_RASA) + { + char *rasswap = swapModeTable[bpmem.combiners[n].alphaC.rswap]; + WRITE(p, "rastemp = %s.%s;\n", tevRasTable[bpmem.tevorders[n / 2].getColorChan(n & 1)], rasswap); + WRITE(p, "crastemp = frac(rastemp * (255.0f/256.0f)) * (256.0f/255.0f);\n"); + } + + + if (bpmem.tevorders[n/2].getEnable(n&1)) + { + if(!bHasIndStage) + { + // calc tevcord + if(bHasTexCoord) + WRITE(p, "tevcoord.xy = uv%d.xy;\n", texcoord); + else + WRITE(p, "tevcoord.xy = float2(0.0f, 0.0f);\n"); + } + + char *texswap = swapModeTable[bpmem.combiners[n].alphaC.tswap]; + int texmap = bpmem.tevorders[n/2].getTexMap(n&1); + SampleTexture(p, "textemp", "tevcoord", texswap, texmap, ApiType); + } + else + WRITE(p, "textemp = float4(1.0f, 1.0f, 1.0f, 1.0f);\n"); + + + // blah2 + if (cc.a == TEVCOLORARG_KONST || cc.b == TEVCOLORARG_KONST || cc.c == TEVCOLORARG_KONST || cc.d == TEVCOLORARG_KONST + || ac.a == TEVALPHAARG_KONST || ac.b == TEVALPHAARG_KONST || ac.c == TEVALPHAARG_KONST || ac.d == TEVALPHAARG_KONST) + { + int kc = bpmem.tevksel[n / 2].getKC(n & 1); + int ka = bpmem.tevksel[n / 2].getKA(n & 1); + WRITE(p, "konsttemp = float4(%s, %s);\n", tevKSelTableC[kc], tevKSelTableA[ka]); + if(kc > 7 || ka > 7) + { + WRITE(p, "ckonsttemp = frac(konsttemp * (255.0f/256.0f)) * (256.0f/255.0f);\n"); + } + else + { + WRITE(p, "ckonsttemp = konsttemp;\n"); + } + } + + if(cc.a == TEVCOLORARG_CPREV || cc.a == TEVCOLORARG_APREV + || cc.b == TEVCOLORARG_CPREV || cc.b == TEVCOLORARG_APREV + || cc.c == TEVCOLORARG_CPREV || cc.c == TEVCOLORARG_APREV + || ac.a == TEVALPHAARG_APREV || ac.b == TEVALPHAARG_APREV || ac.c == TEVALPHAARG_APREV) + WRITE(p, "cprev = frac(prev * (255.0f/256.0f)) * (256.0f/255.0f);\n"); + + + if(cc.a == TEVCOLORARG_C0 || cc.a == TEVCOLORARG_A0 + || cc.b == TEVCOLORARG_C0 || cc.b == TEVCOLORARG_A0 + || cc.c == TEVCOLORARG_C0 || cc.c == TEVCOLORARG_A0 + || ac.a == TEVALPHAARG_A0 || ac.b == TEVALPHAARG_A0 || ac.c == TEVALPHAARG_A0) + WRITE(p, "cc0 = frac(c0 * (255.0f/256.0f)) * (256.0f/255.0f);\n"); + + + if(cc.a == TEVCOLORARG_C1 || cc.a == TEVCOLORARG_A1 + || cc.b == TEVCOLORARG_C1 || cc.b == TEVCOLORARG_A1 + || cc.c == TEVCOLORARG_C1 || cc.c == TEVCOLORARG_A1 + || ac.a == TEVALPHAARG_A1 || ac.b == TEVALPHAARG_A1 || ac.c == TEVALPHAARG_A1) + WRITE(p, "cc1 = frac(c1 * (255.0f/256.0f)) * (256.0f/255.0f);\n"); + + + if(cc.a == TEVCOLORARG_C2 || cc.a == TEVCOLORARG_A2 + || cc.b == TEVCOLORARG_C2 || cc.b == TEVCOLORARG_A2 + || cc.c == TEVCOLORARG_C2 || cc.c == TEVCOLORARG_A2 + || ac.a == TEVALPHAARG_A2 || ac.b == TEVALPHAARG_A2 || ac.c == TEVALPHAARG_A2) + WRITE(p, "cc2 = frac(c2 * (255.0f/256.0f)) * (256.0f/255.0f);\n"); + + + WRITE(p, "// color combine\n"); + if (cc.clamp) + WRITE(p, "%s = saturate(", tevCOutputTable[cc.dest]); + else + WRITE(p, "%s = ", tevCOutputTable[cc.dest]); + + // combine the color channel + if (cc.bias != TevBias_COMPARE) // if not compare + { + //normal color combiner goes here + if (cc.shift > TEVSCALE_1) + WRITE(p, "%s*(", tevScaleTable[cc.shift]); + + if(!(cc.d == TEVCOLORARG_ZERO && cc.op == TEVOP_ADD)) + WRITE(p, "%s%s", tevCInputTable[cc.d], tevOpTable[cc.op]); + + if (cc.a == cc.b) + WRITE(p, "%s", tevCInputTable[cc.a + 16]); + else if (cc.c == TEVCOLORARG_ZERO) + WRITE(p, "%s", tevCInputTable[cc.a + 16]); + else if (cc.c == TEVCOLORARG_ONE) + WRITE(p, "%s", tevCInputTable[cc.b + 16]); + else if (cc.a == TEVCOLORARG_ZERO) + WRITE(p, "%s*%s", tevCInputTable[cc.b + 16], tevCInputTable[cc.c + 16]); + else if (cc.b == TEVCOLORARG_ZERO) + WRITE(p, "%s*(float3(1.0f, 1.0f, 1.0f)-%s)", tevCInputTable[cc.a + 16], tevCInputTable[cc.c + 16]); + else + WRITE(p, "lerp(%s, %s, %s)", tevCInputTable[cc.a + 16], tevCInputTable[cc.b + 16], tevCInputTable[cc.c + 16]); + + WRITE(p, "%s", tevBiasTable[cc.bias]); + + if (cc.shift > TEVSCALE_1) + WRITE(p, ")"); + } + else + { + int cmp = (cc.shift<<1)|cc.op|8; // comparemode stored here + WRITE(p, TEVCMPColorOPTable[cmp],//lookup the function from the op table + tevCInputTable[cc.d], + tevCInputTable[cc.a + 16], + tevCInputTable[cc.b + 16], + tevCInputTable[cc.c + 16]); + } + if (cc.clamp) + WRITE(p, ")"); + WRITE(p,";\n"); + + WRITE(p, "// alpha combine\n"); + // combine the alpha channel + if (ac.clamp) + WRITE(p, "%s = saturate(", tevAOutputTable[ac.dest]); + else + WRITE(p, "%s = ", tevAOutputTable[ac.dest]); + + if (ac.bias != TevBias_COMPARE) // if not compare + { + //normal alpha combiner goes here + if (ac.shift > TEVSCALE_1) + WRITE(p, "%s*(", tevScaleTable[ac.shift]); + + if(!(ac.d == TEVALPHAARG_ZERO && ac.op == TEVOP_ADD)) + WRITE(p, "%s.a%s", tevAInputTable[ac.d], tevOpTable[ac.op]); + + if (ac.a == ac.b) + WRITE(p, "%s.a", tevAInputTable[ac.a + 8]); + else if (ac.c == TEVALPHAARG_ZERO) + WRITE(p, "%s.a", tevAInputTable[ac.a + 8]); + else if (ac.a == TEVALPHAARG_ZERO) + WRITE(p, "%s.a*%s.a", tevAInputTable[ac.b + 8], tevAInputTable[ac.c + 8]); + else if (ac.b == TEVALPHAARG_ZERO) + WRITE(p, "%s.a*(1.0f-%s.a)", tevAInputTable[ac.a + 8], tevAInputTable[ac.c + 8]); + else + WRITE(p, "lerp(%s.a, %s.a, %s.a)", tevAInputTable[ac.a + 8], tevAInputTable[ac.b + 8], tevAInputTable[ac.c + 8]); + + WRITE(p, "%s",tevBiasTable[ac.bias]); + + if (ac.shift>0) + WRITE(p, ")"); + + } + else + { + //compare alpha combiner goes here + int cmp = (ac.shift<<1)|ac.op|8; // comparemode stored here + WRITE(p, TEVCMPAlphaOPTable[cmp], + tevAInputTable[ac.d], + tevAInputTable[ac.a + 8], + tevAInputTable[ac.b + 8], + tevAInputTable[ac.c + 8]); + } + if (ac.clamp) + WRITE(p, ")"); + WRITE(p, ";\n\n"); + WRITE(p, "// TEV done\n"); +} + +void SampleTexture(char *&p, const char *destination, const char *texcoords, const char *texswap, int texmap, API_TYPE ApiType) +{ + if (ApiType == API_D3D11) + WRITE(p, "%s=Tex%d.Sample(samp%d,%s.xy * "I_TEXDIMS"[%d].xy).%s;\n", destination, texmap,texmap, texcoords, texmap, texswap); + else + WRITE(p, "%s=tex2D(samp%d,%s.xy * "I_TEXDIMS"[%d].xy).%s;\n", destination, texmap, texcoords, texmap, texswap); +} + +static const char *tevAlphaFuncsTable[] = +{ + "(false)", //ALPHACMP_NEVER 0 + "(prev.a <= %s - (0.25f/255.0f))", //ALPHACMP_LESS 1 + "(abs( prev.a - %s ) < (0.5f/255.0f))", //ALPHACMP_EQUAL 2 + "(prev.a < %s + (0.25f/255.0f))", //ALPHACMP_LEQUAL 3 + "(prev.a >= %s + (0.25f/255.0f))", //ALPHACMP_GREATER 4 + "(abs( prev.a - %s ) >= (0.5f/255.0f))", //ALPHACMP_NEQUAL 5 + "(prev.a > %s - (0.25f/255.0f))", //ALPHACMP_GEQUAL 6 + "(true)" //ALPHACMP_ALWAYS 7 +}; + +static const char *tevAlphaFunclogicTable[] = +{ + " && ", // and + " || ", // or + " != ", // xor + " == " // xnor +}; +static int AlphaPreTest() +{ + u32 op = bpmem.alphaFunc.logic; + u32 comp[2] = {bpmem.alphaFunc.comp0, bpmem.alphaFunc.comp1}; + + // First kill all the simple cases + switch(op) + { + case 0: // AND + if (comp[0] == ALPHACMP_ALWAYS && comp[1] == ALPHACMP_ALWAYS) return true; + if (comp[0] == ALPHACMP_NEVER || comp[1] == ALPHACMP_NEVER) return false; + break; + case 1: // OR + if (comp[0] == ALPHACMP_ALWAYS || comp[1] == ALPHACMP_ALWAYS) return true; + if (comp[0] == ALPHACMP_NEVER && comp[1] == ALPHACMP_NEVER)return false; + break; + case 2: // XOR + if ((comp[0] == ALPHACMP_ALWAYS && comp[1] == ALPHACMP_NEVER) || (comp[0] == ALPHACMP_NEVER && comp[1] == ALPHACMP_ALWAYS)) + return true; + if ((comp[0] == ALPHACMP_ALWAYS && comp[1] == ALPHACMP_ALWAYS) || (comp[0] == ALPHACMP_NEVER && comp[1] == ALPHACMP_NEVER)) + return false; + break; + case 3: // XNOR + if ((comp[0] == ALPHACMP_ALWAYS && comp[1] == ALPHACMP_NEVER) || (comp[0] == ALPHACMP_NEVER && comp[1] == ALPHACMP_ALWAYS)) + return false; + if ((comp[0] == ALPHACMP_ALWAYS && comp[1] == ALPHACMP_ALWAYS) || (comp[0] == ALPHACMP_NEVER && comp[1] == ALPHACMP_NEVER)) + return true; + break; + default: PanicAlert("bad logic for alpha test? %08x", op); + } + return -1; +} + + +static bool WriteAlphaTest(char *&p, API_TYPE ApiType,DSTALPHA_MODE dstAlphaMode) +{ + static const char *alphaRef[2] = + { + I_ALPHA"[0].r", + I_ALPHA"[0].g" + }; + + int Pretest = AlphaPreTest(); + if(Pretest >= 0) + { + return Pretest != 0; + } + + // using discard then return works the same in cg and dx9 but not in dx11 + WRITE(p, "if(!( "); + + int compindex = bpmem.alphaFunc.comp0 % 8; + WRITE(p, tevAlphaFuncsTable[compindex],alphaRef[0]);//lookup the first component from the alpha function table + + WRITE(p, "%s", tevAlphaFunclogicTable[bpmem.alphaFunc.logic % 4]);//lookup the logic op + + compindex = bpmem.alphaFunc.comp1 % 8; + WRITE(p, tevAlphaFuncsTable[compindex],alphaRef[1]);//lookup the second component from the alpha function table + WRITE(p, ")){ocol0 = 0;%s%s discard;%s}\n", + dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND ? "ocol1 = 0;" : "", + DepthTextureEnable ? "depth = 1.f;" : "", + (ApiType != API_D3D11) ? "return;" : ""); + return true; +} + +static const char *tevFogFuncsTable[] = +{ + "", //No Fog + "", //? + "", //Linear + "", //? + " fog = 1.0f - pow(2.0f, -8.0f * fog);\n", //exp + " fog = 1.0f - pow(2.0f, -8.0f * fog * fog);\n", //exp2 + " fog = pow(2.0f, -8.0f * (1.0f - fog));\n", //backward exp + " fog = 1.0f - fog;\n fog = pow(2.0f, -8.0f * fog * fog);\n" //backward exp2 +}; + +static void WriteFog(char *&p) +{ + if(bpmem.fog.c_proj_fsel.fsel == 0)return;//no Fog + + if (bpmem.fog.c_proj_fsel.proj == 0) + { + // perspective + // ze = A/(B - (Zs >> B_SHF) + WRITE (p, " float ze = "I_FOG"[1].x / ("I_FOG"[1].y - (zCoord / "I_FOG"[1].w));\n"); + } + else + { + // orthographic + // ze = a*Zs (here, no B_SHF) + WRITE (p, " float ze = "I_FOG"[1].x * zCoord;\n"); + } + + // x_adjust = sqrt((x-center)^2 + k^2)/k + // ze *= x_adjust + //this is complitly teorical as the real hard seems to use a table intead of calculate the values. + if(bpmem.fogRange.Base.Enabled) + { + WRITE (p, " float x_adjust = (2.0f * (clipPos.x / "I_FOG"[2].y)) - 1.0f - "I_FOG"[2].x;\n"); + WRITE (p, " x_adjust = sqrt(x_adjust * x_adjust + "I_FOG"[2].z * "I_FOG"[2].z) / "I_FOG"[2].z;\n"); + WRITE (p, " ze *= x_adjust;\n"); + } + + WRITE (p, " float fog = saturate(ze - "I_FOG"[1].z);\n"); + + if(bpmem.fog.c_proj_fsel.fsel > 3) + { + WRITE(p, "%s", tevFogFuncsTable[bpmem.fog.c_proj_fsel.fsel]); + } + else + { + if(bpmem.fog.c_proj_fsel.fsel != 2) + WARN_LOG(VIDEO, "Unknown Fog Type! %08x", bpmem.fog.c_proj_fsel.fsel); + } + + WRITE(p, " prev.rgb = lerp(prev.rgb,"I_FOG"[0].rgb,fog);\n"); + + } \ No newline at end of file diff --git a/Source/Core/VideoCommon/Src/VertexShaderGen.cpp b/Source/Core/VideoCommon/Src/VertexShaderGen.cpp index a492d5a201..8400fde9a5 100644 --- a/Source/Core/VideoCommon/Src/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/VertexShaderGen.cpp @@ -1,503 +1,503 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include -#include - -#include "NativeVertexFormat.h" - -#include "BPMemory.h" -#include "CPMemory.h" -#include "LightingShaderGen.h" -#include "VertexShaderGen.h" -#include "VideoConfig.h" - -VERTEXSHADERUID last_vertex_shader_uid; - -// Mash together all the inputs that contribute to the code of a generated vertex shader into -// a unique identifier, basically containing all the bits. Yup, it's a lot .... -void GetVertexShaderId(VERTEXSHADERUID *uid, u32 components) -{ - uid->values[0] = components | - (xfregs.numTexGen.numTexGens << 23) | - (xfregs.numChan.numColorChans << 27) | - (xfregs.dualTexTrans.enabled << 29); - - // TODO: If pixel lighting is enabled, do we even have to bother about storing lighting related registers here? - GetLightingShaderId(&uid->values[1]); - - uid->values[2] |= (g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) << 31; - u32 *pcurvalue = &uid->values[3]; - for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i) { - TexMtxInfo tinfo = xfregs.texMtxInfo[i]; - if (tinfo.texgentype != XF_TEXGEN_EMBOSS_MAP) - tinfo.hex &= 0x7ff; - if (tinfo.texgentype != XF_TEXGEN_REGULAR) - tinfo.projection = 0; - - u32 val = ((tinfo.hex >> 1) & 0x1ffff); - if (xfregs.dualTexTrans.enabled && tinfo.texgentype == XF_TEXGEN_REGULAR) { - // rewrite normalization and post index - val |= ((u32)xfregs.postMtxInfo[i].index << 17) | ((u32)xfregs.postMtxInfo[i].normalize << 23); - } - - switch (i & 3) { - case 0: pcurvalue[0] |= val; break; - case 1: pcurvalue[0] |= val << 24; pcurvalue[1] = val >> 8; ++pcurvalue; break; - case 2: pcurvalue[0] |= val << 16; pcurvalue[1] = val >> 16; ++pcurvalue; break; - case 3: pcurvalue[0] |= val << 8; ++pcurvalue; break; - } - } -} - -void GetSafeVertexShaderId(VERTEXSHADERUIDSAFE *uid, u32 components) -{ - // Just store all used registers here without caring whether we need all bits or less. - u32* ptr = uid->values; - *ptr++ = components; - *ptr++ = xfregs.numTexGen.hex; - *ptr++ = xfregs.numChan.hex; - *ptr++ = xfregs.dualTexTrans.hex; - - for (int i = 0; i < 2; ++i) { - *ptr++ = xfregs.color[i].hex; - *ptr++ = xfregs.alpha[i].hex; - } - *ptr++ = g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting; - for (unsigned int i = 0; i < 8; ++i) { - *ptr++ = xfregs.texMtxInfo[i].hex; - *ptr++ = xfregs.postMtxInfo[i].hex; - } - _assert_((ptr - uid->values) == uid->GetNumValues()); -} - - -void ValidateVertexShaderIDs(API_TYPE api, VERTEXSHADERUIDSAFE old_id, const std::string& old_code, u32 components) -{ - if (!g_ActiveConfig.bEnableShaderDebugging) - return; - - VERTEXSHADERUIDSAFE new_id; - GetSafeVertexShaderId(&new_id, components); - - if (!(old_id == new_id)) - { - std::string new_code(GenerateVertexShaderCode(components, api)); - if (old_code != new_code) - { - _assert_(old_id.GetNumValues() == new_id.GetNumValues()); - - char msg[8192]; - char* ptr = msg; - ptr += sprintf(ptr, "Vertex shader IDs matched but unique IDs did not!\nUnique IDs (old <-> new):\n"); - const int N = new_id.GetNumValues(); - for (int i = 0; i < N/2; ++i) - ptr += sprintf(ptr, "%02d, %08X %08X | %08X %08X\n", 2*i, old_id.values[2*i], old_id.values[2*i+1], - new_id.values[2*i], new_id.values[2*i+1]); - if (N % 2) - ptr += sprintf(ptr, "%02d, %08X | %08X\n", N-1, old_id.values[N-1], new_id.values[N-1]); - - static int num_failures = 0; - char szTemp[MAX_PATH]; - sprintf(szTemp, "%svsuid_mismatch_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++); - std::ofstream file(szTemp); - file << msg; - file << "\n\nOld shader code:\n" << old_code; - file << "\n\nNew shader code:\n" << new_code; - file.close(); - - PanicAlert("Unique pixel shader ID mismatch!\n\nReport this to the devs, along with the contents of %s.", szTemp); - } - } -} - - -static char text[16384]; - -#define WRITE p+=sprintf - -char* GenerateVSOutputStruct(char* p, u32 components, API_TYPE api_type) -{ - WRITE(p, "struct VS_OUTPUT {\n"); - WRITE(p, " float4 pos : POSITION;\n"); - WRITE(p, " float4 colors_0 : COLOR0;\n"); - WRITE(p, " float4 colors_1 : COLOR1;\n"); - - if (xfregs.numTexGen.numTexGens < 7) { - for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i) - WRITE(p, " float3 tex%d : TEXCOORD%d;\n", i, i); - WRITE(p, " float4 clipPos : TEXCOORD%d;\n", xfregs.numTexGen.numTexGens); - if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) - WRITE(p, " float4 Normal : TEXCOORD%d;\n", xfregs.numTexGen.numTexGens + 1); - } else { - // clip position is in w of first 4 texcoords - if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) - { - for (int i = 0; i < 8; ++i) - WRITE(p, " float4 tex%d : TEXCOORD%d;\n", i, i); - } - else - { - for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i) - WRITE(p, " float%d tex%d : TEXCOORD%d;\n", i < 4 ? 4 : 3 , i, i); - } - } - WRITE(p, "};\n"); - - return p; -} - -const char *GenerateVertexShaderCode(u32 components, API_TYPE api_type) -{ - setlocale(LC_NUMERIC, "C"); // Reset locale for compilation - text[sizeof(text) - 1] = 0x7C; // canary - - _assert_(bpmem.genMode.numtexgens == xfregs.numTexGen.numTexGens); - _assert_(bpmem.genMode.numcolchans == xfregs.numChan.numColorChans); - - bool is_d3d = (api_type & API_D3D9 || api_type == API_D3D11); - u32 lightMask = 0; - if (xfregs.numChan.numColorChans > 0) - lightMask |= xfregs.color[0].GetFullLightMask() | xfregs.alpha[0].GetFullLightMask(); - if (xfregs.numChan.numColorChans > 1) - lightMask |= xfregs.color[1].GetFullLightMask() | xfregs.alpha[1].GetFullLightMask(); - - char *p = text; - WRITE(p, "//Vertex Shader: comp:%x, \n", components); - WRITE(p, "typedef struct { float4 T0, T1, T2; float4 N0, N1, N2; } s_"I_POSNORMALMATRIX";\n" - "typedef struct { float4 t; } FLT4;\n" - "typedef struct { FLT4 T[24]; } s_"I_TEXMATRICES";\n" - "typedef struct { FLT4 T[64]; } s_"I_TRANSFORMMATRICES";\n" - "typedef struct { FLT4 T[32]; } s_"I_NORMALMATRICES";\n" - "typedef struct { FLT4 T[64]; } s_"I_POSTTRANSFORMMATRICES";\n" - "typedef struct { float4 col; float4 cosatt; float4 distatt; float4 pos; float4 dir; } Light;\n" - "typedef struct { Light lights[8]; } s_"I_LIGHTS";\n" - "typedef struct { float4 C0, C1, C2, C3; } s_"I_MATERIALS";\n" - "typedef struct { float4 T0, T1, T2, T3; } s_"I_PROJECTION";\n" - ); - - p = GenerateVSOutputStruct(p, components, api_type); - - // uniforms - - WRITE(p, "uniform s_"I_TRANSFORMMATRICES" "I_TRANSFORMMATRICES" : register(c%d);\n", C_TRANSFORMMATRICES); - WRITE(p, "uniform s_"I_TEXMATRICES" "I_TEXMATRICES" : register(c%d);\n", C_TEXMATRICES); // also using tex matrices - WRITE(p, "uniform s_"I_NORMALMATRICES" "I_NORMALMATRICES" : register(c%d);\n", C_NORMALMATRICES); - WRITE(p, "uniform s_"I_POSNORMALMATRIX" "I_POSNORMALMATRIX" : register(c%d);\n", C_POSNORMALMATRIX); - WRITE(p, "uniform s_"I_POSTTRANSFORMMATRICES" "I_POSTTRANSFORMMATRICES" : register(c%d);\n", C_POSTTRANSFORMMATRICES); - WRITE(p, "uniform s_"I_LIGHTS" "I_LIGHTS" : register(c%d);\n", C_LIGHTS); - WRITE(p, "uniform s_"I_MATERIALS" "I_MATERIALS" : register(c%d);\n", C_MATERIALS); - WRITE(p, "uniform s_"I_PROJECTION" "I_PROJECTION" : register(c%d);\n", C_PROJECTION); - WRITE(p, "uniform float4 "I_DEPTHPARAMS" : register(c%d);\n", C_DEPTHPARAMS); - - WRITE(p, "VS_OUTPUT main(\n"); - - // inputs - if (components & VB_HAS_NRM0) - WRITE(p, " float3 rawnorm0 : NORMAL0,\n"); - if (components & VB_HAS_NRM1) { - if (is_d3d) - WRITE(p, " float3 rawnorm1 : NORMAL1,\n"); - else - WRITE(p, " float3 rawnorm1 : ATTR%d,\n", SHADER_NORM1_ATTRIB); - } - if (components & VB_HAS_NRM2) { - if (is_d3d) - WRITE(p, " float3 rawnorm2 : NORMAL2,\n"); - else - WRITE(p, " float3 rawnorm2 : ATTR%d,\n", SHADER_NORM2_ATTRIB); - } - if (components & VB_HAS_COL0) - WRITE(p, " float4 color0 : COLOR0,\n"); - if (components & VB_HAS_COL1) - WRITE(p, " float4 color1 : COLOR1,\n"); - for (int i = 0; i < 8; ++i) { - u32 hastexmtx = (components & (VB_HAS_TEXMTXIDX0<= 32 ? (posmtx-32) : posmtx;\n"); - WRITE(p, "float3 N0 = "I_NORMALMATRICES".T[normidx].t.xyz, N1 = "I_NORMALMATRICES".T[normidx+1].t.xyz, N2 = "I_NORMALMATRICES".T[normidx+2].t.xyz;\n"); - } - - if (components & VB_HAS_NRM0) - WRITE(p, "float3 _norm0 = normalize(float3(dot(N0, rawnorm0), dot(N1, rawnorm0), dot(N2, rawnorm0)));\n"); - if (components & VB_HAS_NRM1) - WRITE(p, "float3 _norm1 = float3(dot(N0, rawnorm1), dot(N1, rawnorm1), dot(N2, rawnorm1));\n"); - if (components & VB_HAS_NRM2) - WRITE(p, "float3 _norm2 = float3(dot(N0, rawnorm2), dot(N1, rawnorm2), dot(N2, rawnorm2));\n"); - } - else - { - WRITE(p, "float4 pos = float4(dot("I_POSNORMALMATRIX".T0, rawpos), dot("I_POSNORMALMATRIX".T1, rawpos), dot("I_POSNORMALMATRIX".T2, rawpos), 1.0f);\n"); - if (components & VB_HAS_NRM0) - WRITE(p, "float3 _norm0 = normalize(float3(dot("I_POSNORMALMATRIX".N0.xyz, rawnorm0), dot("I_POSNORMALMATRIX".N1.xyz, rawnorm0), dot("I_POSNORMALMATRIX".N2.xyz, rawnorm0)));\n"); - if (components & VB_HAS_NRM1) - WRITE(p, "float3 _norm1 = float3(dot("I_POSNORMALMATRIX".N0.xyz, rawnorm1), dot("I_POSNORMALMATRIX".N1.xyz, rawnorm1), dot("I_POSNORMALMATRIX".N2.xyz, rawnorm1));\n"); - if (components & VB_HAS_NRM2) - WRITE(p, "float3 _norm2 = float3(dot("I_POSNORMALMATRIX".N0.xyz, rawnorm2), dot("I_POSNORMALMATRIX".N1.xyz, rawnorm2), dot("I_POSNORMALMATRIX".N2.xyz, rawnorm2));\n"); - } - - if (!(components & VB_HAS_NRM0)) - WRITE(p, "float3 _norm0 = float3(0.0f, 0.0f, 0.0f);\n"); - - - - WRITE(p, "o.pos = float4(dot("I_PROJECTION".T0, pos), dot("I_PROJECTION".T1, pos), dot("I_PROJECTION".T2, pos), dot("I_PROJECTION".T3, pos));\n"); - - WRITE(p, "float4 mat, lacc;\n" - "float3 ldir, h;\n" - "float dist, dist2, attn;\n"); - - if(xfregs.numChan.numColorChans == 0) - { - if (components & VB_HAS_COL0) - WRITE(p, "o.colors_0 = color0;\n"); - else - WRITE(p, "o.colors_0 = float4(1.0f, 1.0f, 1.0f, 1.0f);\n"); - } - - // TODO: This probably isn't necessary if pixel lighting is enabled. - p = GenerateLightingShader(p, components, I_MATERIALS, I_LIGHTS, "color", "o.colors_"); - - if(xfregs.numChan.numColorChans < 2) - { - if (components & VB_HAS_COL1) - WRITE(p, "o.colors_1 = color1;\n"); - else - WRITE(p, "o.colors_1 = o.colors_0;\n"); - } - // special case if only pos and tex coord 0 and tex coord input is AB11 - // donko - this has caused problems in some games. removed for now. - bool texGenSpecialCase = false; - /*bool texGenSpecialCase = - ((g_VtxDesc.Hex & 0x60600L) == g_VtxDesc.Hex) && // only pos and tex coord 0 - (g_VtxDesc.Tex0Coord != NOT_PRESENT) && - (xfregs.texcoords[0].texmtxinfo.inputform == XF_TEXINPUT_AB11); - */ - - // transform texcoords - WRITE(p, "float4 coord = float4(0.0f, 0.0f, 1.0f, 1.0f);\n"); - for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i) { - TexMtxInfo& texinfo = xfregs.texMtxInfo[i]; - - WRITE(p, "{\n"); - WRITE(p, "coord = float4(0.0f, 0.0f, 1.0f, 1.0f);\n"); - switch (texinfo.sourcerow) { - case XF_SRCGEOM_INROW: - _assert_( texinfo.inputform == XF_TEXINPUT_ABC1 ); - WRITE(p, "coord = rawpos;\n"); // pos.w is 1 - break; - case XF_SRCNORMAL_INROW: - if (components & VB_HAS_NRM0) { - _assert_( texinfo.inputform == XF_TEXINPUT_ABC1 ); - WRITE(p, "coord = float4(rawnorm0.xyz, 1.0f);\n"); - } - break; - case XF_SRCCOLORS_INROW: - _assert_( texinfo.texgentype == XF_TEXGEN_COLOR_STRGBC0 || texinfo.texgentype == XF_TEXGEN_COLOR_STRGBC1 ); - break; - case XF_SRCBINORMAL_T_INROW: - if (components & VB_HAS_NRM1) { - _assert_( texinfo.inputform == XF_TEXINPUT_ABC1 ); - WRITE(p, "coord = float4(rawnorm1.xyz, 1.0f);\n"); - } - break; - case XF_SRCBINORMAL_B_INROW: - if (components & VB_HAS_NRM2) { - _assert_( texinfo.inputform == XF_TEXINPUT_ABC1 ); - WRITE(p, "coord = float4(rawnorm2.xyz, 1.0f);\n"); - } - break; - default: - _assert_(texinfo.sourcerow <= XF_SRCTEX7_INROW); - if (components & (VB_HAS_UV0<<(texinfo.sourcerow - XF_SRCTEX0_INROW)) ) - WRITE(p, "coord = float4(tex%d.x, tex%d.y, 1.0f, 1.0f);\n", texinfo.sourcerow - XF_SRCTEX0_INROW, texinfo.sourcerow - XF_SRCTEX0_INROW); - break; - } - - // first transformation - switch (texinfo.texgentype) { - case XF_TEXGEN_EMBOSS_MAP: // calculate tex coords into bump map - - if (components & (VB_HAS_NRM1|VB_HAS_NRM2)) { - // transform the light dir into tangent space - WRITE(p, "ldir = normalize("I_LIGHTS".lights[%d].pos.xyz - pos.xyz);\n", texinfo.embosslightshift); - WRITE(p, "o.tex%d.xyz = o.tex%d.xyz + float3(dot(ldir, _norm1), dot(ldir, _norm2), 0.0f);\n", i, texinfo.embosssourceshift); - } - else - { - _assert_(0); // should have normals - WRITE(p, "o.tex%d.xyz = o.tex%d.xyz;\n", i, texinfo.embosssourceshift); - } - - break; - case XF_TEXGEN_COLOR_STRGBC0: - _assert_(texinfo.sourcerow == XF_SRCCOLORS_INROW); - WRITE(p, "o.tex%d.xyz = float3(o.colors_0.x, o.colors_0.y, 1);\n", i); - break; - case XF_TEXGEN_COLOR_STRGBC1: - _assert_(texinfo.sourcerow == XF_SRCCOLORS_INROW); - WRITE(p, "o.tex%d.xyz = float3(o.colors_1.x, o.colors_1.y, 1);\n", i); - break; - case XF_TEXGEN_REGULAR: - default: - if (components & (VB_HAS_TEXMTXIDX0< +#include + +#include "NativeVertexFormat.h" + +#include "BPMemory.h" +#include "CPMemory.h" +#include "LightingShaderGen.h" +#include "VertexShaderGen.h" +#include "VideoConfig.h" + +VERTEXSHADERUID last_vertex_shader_uid; + +// Mash together all the inputs that contribute to the code of a generated vertex shader into +// a unique identifier, basically containing all the bits. Yup, it's a lot .... +void GetVertexShaderId(VERTEXSHADERUID *uid, u32 components) +{ + uid->values[0] = components | + (xfregs.numTexGen.numTexGens << 23) | + (xfregs.numChan.numColorChans << 27) | + (xfregs.dualTexTrans.enabled << 29); + + // TODO: If pixel lighting is enabled, do we even have to bother about storing lighting related registers here? + GetLightingShaderId(&uid->values[1]); + + uid->values[2] |= (g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) << 31; + u32 *pcurvalue = &uid->values[3]; + for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i) { + TexMtxInfo tinfo = xfregs.texMtxInfo[i]; + if (tinfo.texgentype != XF_TEXGEN_EMBOSS_MAP) + tinfo.hex &= 0x7ff; + if (tinfo.texgentype != XF_TEXGEN_REGULAR) + tinfo.projection = 0; + + u32 val = ((tinfo.hex >> 1) & 0x1ffff); + if (xfregs.dualTexTrans.enabled && tinfo.texgentype == XF_TEXGEN_REGULAR) { + // rewrite normalization and post index + val |= ((u32)xfregs.postMtxInfo[i].index << 17) | ((u32)xfregs.postMtxInfo[i].normalize << 23); + } + + switch (i & 3) { + case 0: pcurvalue[0] |= val; break; + case 1: pcurvalue[0] |= val << 24; pcurvalue[1] = val >> 8; ++pcurvalue; break; + case 2: pcurvalue[0] |= val << 16; pcurvalue[1] = val >> 16; ++pcurvalue; break; + case 3: pcurvalue[0] |= val << 8; ++pcurvalue; break; + } + } +} + +void GetSafeVertexShaderId(VERTEXSHADERUIDSAFE *uid, u32 components) +{ + // Just store all used registers here without caring whether we need all bits or less. + u32* ptr = uid->values; + *ptr++ = components; + *ptr++ = xfregs.numTexGen.hex; + *ptr++ = xfregs.numChan.hex; + *ptr++ = xfregs.dualTexTrans.hex; + + for (int i = 0; i < 2; ++i) { + *ptr++ = xfregs.color[i].hex; + *ptr++ = xfregs.alpha[i].hex; + } + *ptr++ = g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting; + for (unsigned int i = 0; i < 8; ++i) { + *ptr++ = xfregs.texMtxInfo[i].hex; + *ptr++ = xfregs.postMtxInfo[i].hex; + } + _assert_((ptr - uid->values) == uid->GetNumValues()); +} + + +void ValidateVertexShaderIDs(API_TYPE api, VERTEXSHADERUIDSAFE old_id, const std::string& old_code, u32 components) +{ + if (!g_ActiveConfig.bEnableShaderDebugging) + return; + + VERTEXSHADERUIDSAFE new_id; + GetSafeVertexShaderId(&new_id, components); + + if (!(old_id == new_id)) + { + std::string new_code(GenerateVertexShaderCode(components, api)); + if (old_code != new_code) + { + _assert_(old_id.GetNumValues() == new_id.GetNumValues()); + + char msg[8192]; + char* ptr = msg; + ptr += sprintf(ptr, "Vertex shader IDs matched but unique IDs did not!\nUnique IDs (old <-> new):\n"); + const int N = new_id.GetNumValues(); + for (int i = 0; i < N/2; ++i) + ptr += sprintf(ptr, "%02d, %08X %08X | %08X %08X\n", 2*i, old_id.values[2*i], old_id.values[2*i+1], + new_id.values[2*i], new_id.values[2*i+1]); + if (N % 2) + ptr += sprintf(ptr, "%02d, %08X | %08X\n", N-1, old_id.values[N-1], new_id.values[N-1]); + + static int num_failures = 0; + char szTemp[MAX_PATH]; + sprintf(szTemp, "%svsuid_mismatch_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++); + std::ofstream file(szTemp); + file << msg; + file << "\n\nOld shader code:\n" << old_code; + file << "\n\nNew shader code:\n" << new_code; + file.close(); + + PanicAlert("Unique pixel shader ID mismatch!\n\nReport this to the devs, along with the contents of %s.", szTemp); + } + } +} + + +static char text[16384]; + +#define WRITE p+=sprintf + +char* GenerateVSOutputStruct(char* p, u32 components, API_TYPE api_type) +{ + WRITE(p, "struct VS_OUTPUT {\n"); + WRITE(p, " float4 pos : POSITION;\n"); + WRITE(p, " float4 colors_0 : COLOR0;\n"); + WRITE(p, " float4 colors_1 : COLOR1;\n"); + + if (xfregs.numTexGen.numTexGens < 7) { + for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i) + WRITE(p, " float3 tex%d : TEXCOORD%d;\n", i, i); + WRITE(p, " float4 clipPos : TEXCOORD%d;\n", xfregs.numTexGen.numTexGens); + if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) + WRITE(p, " float4 Normal : TEXCOORD%d;\n", xfregs.numTexGen.numTexGens + 1); + } else { + // clip position is in w of first 4 texcoords + if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) + { + for (int i = 0; i < 8; ++i) + WRITE(p, " float4 tex%d : TEXCOORD%d;\n", i, i); + } + else + { + for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i) + WRITE(p, " float%d tex%d : TEXCOORD%d;\n", i < 4 ? 4 : 3 , i, i); + } + } + WRITE(p, "};\n"); + + return p; +} + +const char *GenerateVertexShaderCode(u32 components, API_TYPE api_type) +{ + setlocale(LC_NUMERIC, "C"); // Reset locale for compilation + text[sizeof(text) - 1] = 0x7C; // canary + + _assert_(bpmem.genMode.numtexgens == xfregs.numTexGen.numTexGens); + _assert_(bpmem.genMode.numcolchans == xfregs.numChan.numColorChans); + + bool is_d3d = (api_type & API_D3D9 || api_type == API_D3D11); + u32 lightMask = 0; + if (xfregs.numChan.numColorChans > 0) + lightMask |= xfregs.color[0].GetFullLightMask() | xfregs.alpha[0].GetFullLightMask(); + if (xfregs.numChan.numColorChans > 1) + lightMask |= xfregs.color[1].GetFullLightMask() | xfregs.alpha[1].GetFullLightMask(); + + char *p = text; + WRITE(p, "//Vertex Shader: comp:%x, \n", components); + WRITE(p, "typedef struct { float4 T0, T1, T2; float4 N0, N1, N2; } s_"I_POSNORMALMATRIX";\n" + "typedef struct { float4 t; } FLT4;\n" + "typedef struct { FLT4 T[24]; } s_"I_TEXMATRICES";\n" + "typedef struct { FLT4 T[64]; } s_"I_TRANSFORMMATRICES";\n" + "typedef struct { FLT4 T[32]; } s_"I_NORMALMATRICES";\n" + "typedef struct { FLT4 T[64]; } s_"I_POSTTRANSFORMMATRICES";\n" + "typedef struct { float4 col; float4 cosatt; float4 distatt; float4 pos; float4 dir; } Light;\n" + "typedef struct { Light lights[8]; } s_"I_LIGHTS";\n" + "typedef struct { float4 C0, C1, C2, C3; } s_"I_MATERIALS";\n" + "typedef struct { float4 T0, T1, T2, T3; } s_"I_PROJECTION";\n" + ); + + p = GenerateVSOutputStruct(p, components, api_type); + + // uniforms + + WRITE(p, "uniform s_"I_TRANSFORMMATRICES" "I_TRANSFORMMATRICES" : register(c%d);\n", C_TRANSFORMMATRICES); + WRITE(p, "uniform s_"I_TEXMATRICES" "I_TEXMATRICES" : register(c%d);\n", C_TEXMATRICES); // also using tex matrices + WRITE(p, "uniform s_"I_NORMALMATRICES" "I_NORMALMATRICES" : register(c%d);\n", C_NORMALMATRICES); + WRITE(p, "uniform s_"I_POSNORMALMATRIX" "I_POSNORMALMATRIX" : register(c%d);\n", C_POSNORMALMATRIX); + WRITE(p, "uniform s_"I_POSTTRANSFORMMATRICES" "I_POSTTRANSFORMMATRICES" : register(c%d);\n", C_POSTTRANSFORMMATRICES); + WRITE(p, "uniform s_"I_LIGHTS" "I_LIGHTS" : register(c%d);\n", C_LIGHTS); + WRITE(p, "uniform s_"I_MATERIALS" "I_MATERIALS" : register(c%d);\n", C_MATERIALS); + WRITE(p, "uniform s_"I_PROJECTION" "I_PROJECTION" : register(c%d);\n", C_PROJECTION); + WRITE(p, "uniform float4 "I_DEPTHPARAMS" : register(c%d);\n", C_DEPTHPARAMS); + + WRITE(p, "VS_OUTPUT main(\n"); + + // inputs + if (components & VB_HAS_NRM0) + WRITE(p, " float3 rawnorm0 : NORMAL0,\n"); + if (components & VB_HAS_NRM1) { + if (is_d3d) + WRITE(p, " float3 rawnorm1 : NORMAL1,\n"); + else + WRITE(p, " float3 rawnorm1 : ATTR%d,\n", SHADER_NORM1_ATTRIB); + } + if (components & VB_HAS_NRM2) { + if (is_d3d) + WRITE(p, " float3 rawnorm2 : NORMAL2,\n"); + else + WRITE(p, " float3 rawnorm2 : ATTR%d,\n", SHADER_NORM2_ATTRIB); + } + if (components & VB_HAS_COL0) + WRITE(p, " float4 color0 : COLOR0,\n"); + if (components & VB_HAS_COL1) + WRITE(p, " float4 color1 : COLOR1,\n"); + for (int i = 0; i < 8; ++i) { + u32 hastexmtx = (components & (VB_HAS_TEXMTXIDX0<= 32 ? (posmtx-32) : posmtx;\n"); + WRITE(p, "float3 N0 = "I_NORMALMATRICES".T[normidx].t.xyz, N1 = "I_NORMALMATRICES".T[normidx+1].t.xyz, N2 = "I_NORMALMATRICES".T[normidx+2].t.xyz;\n"); + } + + if (components & VB_HAS_NRM0) + WRITE(p, "float3 _norm0 = normalize(float3(dot(N0, rawnorm0), dot(N1, rawnorm0), dot(N2, rawnorm0)));\n"); + if (components & VB_HAS_NRM1) + WRITE(p, "float3 _norm1 = float3(dot(N0, rawnorm1), dot(N1, rawnorm1), dot(N2, rawnorm1));\n"); + if (components & VB_HAS_NRM2) + WRITE(p, "float3 _norm2 = float3(dot(N0, rawnorm2), dot(N1, rawnorm2), dot(N2, rawnorm2));\n"); + } + else + { + WRITE(p, "float4 pos = float4(dot("I_POSNORMALMATRIX".T0, rawpos), dot("I_POSNORMALMATRIX".T1, rawpos), dot("I_POSNORMALMATRIX".T2, rawpos), 1.0f);\n"); + if (components & VB_HAS_NRM0) + WRITE(p, "float3 _norm0 = normalize(float3(dot("I_POSNORMALMATRIX".N0.xyz, rawnorm0), dot("I_POSNORMALMATRIX".N1.xyz, rawnorm0), dot("I_POSNORMALMATRIX".N2.xyz, rawnorm0)));\n"); + if (components & VB_HAS_NRM1) + WRITE(p, "float3 _norm1 = float3(dot("I_POSNORMALMATRIX".N0.xyz, rawnorm1), dot("I_POSNORMALMATRIX".N1.xyz, rawnorm1), dot("I_POSNORMALMATRIX".N2.xyz, rawnorm1));\n"); + if (components & VB_HAS_NRM2) + WRITE(p, "float3 _norm2 = float3(dot("I_POSNORMALMATRIX".N0.xyz, rawnorm2), dot("I_POSNORMALMATRIX".N1.xyz, rawnorm2), dot("I_POSNORMALMATRIX".N2.xyz, rawnorm2));\n"); + } + + if (!(components & VB_HAS_NRM0)) + WRITE(p, "float3 _norm0 = float3(0.0f, 0.0f, 0.0f);\n"); + + + + WRITE(p, "o.pos = float4(dot("I_PROJECTION".T0, pos), dot("I_PROJECTION".T1, pos), dot("I_PROJECTION".T2, pos), dot("I_PROJECTION".T3, pos));\n"); + + WRITE(p, "float4 mat, lacc;\n" + "float3 ldir, h;\n" + "float dist, dist2, attn;\n"); + + if(xfregs.numChan.numColorChans == 0) + { + if (components & VB_HAS_COL0) + WRITE(p, "o.colors_0 = color0;\n"); + else + WRITE(p, "o.colors_0 = float4(1.0f, 1.0f, 1.0f, 1.0f);\n"); + } + + // TODO: This probably isn't necessary if pixel lighting is enabled. + p = GenerateLightingShader(p, components, I_MATERIALS, I_LIGHTS, "color", "o.colors_"); + + if(xfregs.numChan.numColorChans < 2) + { + if (components & VB_HAS_COL1) + WRITE(p, "o.colors_1 = color1;\n"); + else + WRITE(p, "o.colors_1 = o.colors_0;\n"); + } + // special case if only pos and tex coord 0 and tex coord input is AB11 + // donko - this has caused problems in some games. removed for now. + bool texGenSpecialCase = false; + /*bool texGenSpecialCase = + ((g_VtxDesc.Hex & 0x60600L) == g_VtxDesc.Hex) && // only pos and tex coord 0 + (g_VtxDesc.Tex0Coord != NOT_PRESENT) && + (xfregs.texcoords[0].texmtxinfo.inputform == XF_TEXINPUT_AB11); + */ + + // transform texcoords + WRITE(p, "float4 coord = float4(0.0f, 0.0f, 1.0f, 1.0f);\n"); + for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i) { + TexMtxInfo& texinfo = xfregs.texMtxInfo[i]; + + WRITE(p, "{\n"); + WRITE(p, "coord = float4(0.0f, 0.0f, 1.0f, 1.0f);\n"); + switch (texinfo.sourcerow) { + case XF_SRCGEOM_INROW: + _assert_( texinfo.inputform == XF_TEXINPUT_ABC1 ); + WRITE(p, "coord = rawpos;\n"); // pos.w is 1 + break; + case XF_SRCNORMAL_INROW: + if (components & VB_HAS_NRM0) { + _assert_( texinfo.inputform == XF_TEXINPUT_ABC1 ); + WRITE(p, "coord = float4(rawnorm0.xyz, 1.0f);\n"); + } + break; + case XF_SRCCOLORS_INROW: + _assert_( texinfo.texgentype == XF_TEXGEN_COLOR_STRGBC0 || texinfo.texgentype == XF_TEXGEN_COLOR_STRGBC1 ); + break; + case XF_SRCBINORMAL_T_INROW: + if (components & VB_HAS_NRM1) { + _assert_( texinfo.inputform == XF_TEXINPUT_ABC1 ); + WRITE(p, "coord = float4(rawnorm1.xyz, 1.0f);\n"); + } + break; + case XF_SRCBINORMAL_B_INROW: + if (components & VB_HAS_NRM2) { + _assert_( texinfo.inputform == XF_TEXINPUT_ABC1 ); + WRITE(p, "coord = float4(rawnorm2.xyz, 1.0f);\n"); + } + break; + default: + _assert_(texinfo.sourcerow <= XF_SRCTEX7_INROW); + if (components & (VB_HAS_UV0<<(texinfo.sourcerow - XF_SRCTEX0_INROW)) ) + WRITE(p, "coord = float4(tex%d.x, tex%d.y, 1.0f, 1.0f);\n", texinfo.sourcerow - XF_SRCTEX0_INROW, texinfo.sourcerow - XF_SRCTEX0_INROW); + break; + } + + // first transformation + switch (texinfo.texgentype) { + case XF_TEXGEN_EMBOSS_MAP: // calculate tex coords into bump map + + if (components & (VB_HAS_NRM1|VB_HAS_NRM2)) { + // transform the light dir into tangent space + WRITE(p, "ldir = normalize("I_LIGHTS".lights[%d].pos.xyz - pos.xyz);\n", texinfo.embosslightshift); + WRITE(p, "o.tex%d.xyz = o.tex%d.xyz + float3(dot(ldir, _norm1), dot(ldir, _norm2), 0.0f);\n", i, texinfo.embosssourceshift); + } + else + { + _assert_(0); // should have normals + WRITE(p, "o.tex%d.xyz = o.tex%d.xyz;\n", i, texinfo.embosssourceshift); + } + + break; + case XF_TEXGEN_COLOR_STRGBC0: + _assert_(texinfo.sourcerow == XF_SRCCOLORS_INROW); + WRITE(p, "o.tex%d.xyz = float3(o.colors_0.x, o.colors_0.y, 1);\n", i); + break; + case XF_TEXGEN_COLOR_STRGBC1: + _assert_(texinfo.sourcerow == XF_SRCCOLORS_INROW); + WRITE(p, "o.tex%d.xyz = float3(o.colors_1.x, o.colors_1.y, 1);\n", i); + break; + case XF_TEXGEN_REGULAR: + default: + if (components & (VB_HAS_TEXMTXIDX0< Date: Thu, 29 Sep 2011 23:32:05 +0200 Subject: [PATCH 33/36] Clean up various things. --- Source/Core/Common/Src/LinearDiskCache.h | 2 +- .../Core/VideoCommon/Src/PixelShaderGen.cpp | 19 ++++++---- Source/Core/VideoCommon/Src/PixelShaderGen.h | 17 +++------ .../Core/VideoCommon/Src/VertexShaderGen.cpp | 4 +- Source/Core/VideoCommon/Src/VertexShaderGen.h | 3 -- .../Plugin_VideoDX11/Src/PixelShaderCache.cpp | 2 +- .../Src/VertexShaderCache.cpp | 2 +- .../Plugin_VideoDX9/Src/PixelShaderCache.cpp | 2 +- .../Plugin_VideoDX9/Src/VertexShaderCache.cpp | 2 +- .../Plugin_VideoOGL/Src/PixelShaderCache.cpp | 37 +++++++++---------- .../Plugin_VideoOGL/Src/PixelShaderCache.h | 5 ++- .../Plugin_VideoOGL/Src/VertexShaderCache.cpp | 31 +++++++++------- .../Plugin_VideoOGL/Src/VertexShaderCache.h | 8 ++-- 13 files changed, 65 insertions(+), 69 deletions(-) diff --git a/Source/Core/Common/Src/LinearDiskCache.h b/Source/Core/Common/Src/LinearDiskCache.h index a2f758b416..450392e70a 100644 --- a/Source/Core/Common/Src/LinearDiskCache.h +++ b/Source/Core/Common/Src/LinearDiskCache.h @@ -24,7 +24,7 @@ // Increment this every time you change shader generation code. enum { - LINEAR_DISKCACHE_VER = 6965 + LINEAR_DISKCACHE_VER = 6966 }; // On disk format: diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp index f52c6b4190..1726855d54 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp @@ -27,8 +27,6 @@ #include "VideoConfig.h" #include "NativeVertexFormat.h" -PIXELSHADERUID last_pixel_shader_uid; - static int AlphaPreTest(); static void StageHash(int stage, u32* out) @@ -104,8 +102,9 @@ static void StageHash(int stage, u32* out) // a unique identifier, basically containing all the bits. Yup, it's a lot .... // It would likely be a lot more efficient to build this incrementally as the attributes // are set... -void GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode) +void GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode, u32 components) { + memset(uid->values, 0, sizeof(uid->values)); uid->values[0] |= bpmem.genMode.numtevstages; // 4 uid->values[0] |= bpmem.genMode.numtexgens << 4; // 4 uid->values[0] |= dstAlphaMode << 8; // 2 @@ -192,13 +191,17 @@ void GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode) ++ptr; if (enablePL) + { ptr += GetLightingShaderId(ptr); + *ptr++ = components; + } uid->num_values = ptr - uid->values; } -void GetSafePixelShaderId(PIXELSHADERUIDSAFE *uid, DSTALPHA_MODE dstAlphaMode) +void GetSafePixelShaderId(PIXELSHADERUIDSAFE *uid, DSTALPHA_MODE dstAlphaMode, u32 components) { + memset(uid->values, 0, sizeof(uid->values)); u32* ptr = uid->values; *ptr++ = dstAlphaMode; // 0 *ptr++ = bpmem.genMode.hex; // 1 @@ -211,11 +214,11 @@ void GetSafePixelShaderId(PIXELSHADERUIDSAFE *uid, DSTALPHA_MODE dstAlphaMode) if (g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) { - // TODO: Include register states for lighting shader *ptr++ = xfregs.color[0].hex; *ptr++ = xfregs.alpha[0].hex; *ptr++ = xfregs.color[1].hex; *ptr++ = xfregs.alpha[1].hex; + *ptr++ = components; } for (unsigned int i = 0; i < 8; ++i) @@ -251,7 +254,7 @@ void ValidatePixelShaderIDs(API_TYPE api, PIXELSHADERUIDSAFE old_id, const std:: return; PIXELSHADERUIDSAFE new_id; - GetSafePixelShaderId(&new_id, dstAlphaMode); + GetSafePixelShaderId(&new_id, dstAlphaMode, components); if (!(old_id == new_id)) { @@ -874,13 +877,13 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType) } else if (bpmem.tevind[n].mid <= 7 && bHasTexCoord) { // s matrix - // TODO: Might become negative? + _assert_(bpmem.tevind[n].mid >= 5); int mtxidx = 2*(bpmem.tevind[n].mid-5); WRITE(p, "float2 indtevtrans%d = "I_INDTEXMTX"[%d].ww * uv%d.xy * indtevcrd%d.xx;\n", n, mtxidx, texcoord, n); } else if (bpmem.tevind[n].mid <= 11 && bHasTexCoord) { // t matrix - // TODO: Might become negative? + _assert_(bpmem.tevind[n].mid >= 9); int mtxidx = 2*(bpmem.tevind[n].mid-9); WRITE(p, "float2 indtevtrans%d = "I_INDTEXMTX"[%d].ww * uv%d.xy * indtevcrd%d.yy;\n", n, mtxidx, texcoord, n); } diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.h b/Source/Core/VideoCommon/Src/PixelShaderGen.h index b24b656784..31242a916e 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderGen.h +++ b/Source/Core/VideoCommon/Src/PixelShaderGen.h @@ -44,8 +44,8 @@ #define C_PLIGHTS (C_FOG + 3) #define C_PMATERIALS (C_PLIGHTS + 40) #define C_PENVCONST_END (C_PMATERIALS + 4) -#define PIXELSHADERUID_MAX_VALUES 69 -#define PIXELSHADERUID_MAX_VALUES_SAFE 117 +#define PIXELSHADERUID_MAX_VALUES 70 +#define PIXELSHADERUID_MAX_VALUES_SAFE 120 // DO NOT make anything in this class virtual. template @@ -53,14 +53,10 @@ class _PIXELSHADERUID { public: u32 values[safe ? PIXELSHADERUID_MAX_VALUES_SAFE : PIXELSHADERUID_MAX_VALUES]; - u16 num_values; + int num_values; _PIXELSHADERUID() { - memset(values, 0, sizeof(values)); - - if (safe) num_values = sizeof(values) / sizeof(values[0]); - else num_values = 0; } _PIXELSHADERUID(const _PIXELSHADERUID& r) @@ -119,13 +115,10 @@ enum DSTALPHA_MODE const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType, u32 components); -// TODO: Wtf, those need components as well! -.- -void GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode); -void GetSafePixelShaderId(PIXELSHADERUIDSAFE *uid, DSTALPHA_MODE dstAlphaMode); +void GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode, u32 components); +void GetSafePixelShaderId(PIXELSHADERUIDSAFE *uid, DSTALPHA_MODE dstAlphaMode, u32 components); // Used to make sure that our optimized pixel shader IDs don't lose any possible shader code changes void ValidatePixelShaderIDs(API_TYPE api, PIXELSHADERUIDSAFE old_id, const std::string& old_code, DSTALPHA_MODE dstAlphaMode, u32 components); -extern PIXELSHADERUID last_pixel_shader_uid; - #endif // GCOGL_PIXELSHADER_H diff --git a/Source/Core/VideoCommon/Src/VertexShaderGen.cpp b/Source/Core/VideoCommon/Src/VertexShaderGen.cpp index 8400fde9a5..5076f9f044 100644 --- a/Source/Core/VideoCommon/Src/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/VertexShaderGen.cpp @@ -26,12 +26,11 @@ #include "VertexShaderGen.h" #include "VideoConfig.h" -VERTEXSHADERUID last_vertex_shader_uid; - // Mash together all the inputs that contribute to the code of a generated vertex shader into // a unique identifier, basically containing all the bits. Yup, it's a lot .... void GetVertexShaderId(VERTEXSHADERUID *uid, u32 components) { + memset(uid->values, 0, sizeof(uid->values)); uid->values[0] = components | (xfregs.numTexGen.numTexGens << 23) | (xfregs.numChan.numColorChans << 27) | @@ -67,6 +66,7 @@ void GetVertexShaderId(VERTEXSHADERUID *uid, u32 components) void GetSafeVertexShaderId(VERTEXSHADERUIDSAFE *uid, u32 components) { // Just store all used registers here without caring whether we need all bits or less. + memset(uid->values, 0, sizeof(uid->values)); u32* ptr = uid->values; *ptr++ = components; *ptr++ = xfregs.numTexGen.hex; diff --git a/Source/Core/VideoCommon/Src/VertexShaderGen.h b/Source/Core/VideoCommon/Src/VertexShaderGen.h index 0680be3c86..0c522286b1 100644 --- a/Source/Core/VideoCommon/Src/VertexShaderGen.h +++ b/Source/Core/VideoCommon/Src/VertexShaderGen.h @@ -57,7 +57,6 @@ public: _VERTEXSHADERUID() { - memset(values, 0, sizeof(values)); } _VERTEXSHADERUID(const _VERTEXSHADERUID& r) @@ -116,6 +115,4 @@ void GetSafeVertexShaderId(VERTEXSHADERUIDSAFE *uid, u32 components); // Used to make sure that our optimized vertex shader IDs don't lose any possible shader code changes void ValidateVertexShaderIDs(API_TYPE api, VERTEXSHADERUIDSAFE old_id, const std::string& old_code, u32 components); -extern VERTEXSHADERUID last_vertex_shader_uid; - #endif // GCOGL_VERTEXSHADER_H diff --git a/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.cpp b/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.cpp index 0a67584409..656f8ddff2 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.cpp @@ -413,7 +413,7 @@ void PixelShaderCache::Init() PixelShaderCacheInserter inserter; g_ps_disk_cache.OpenAndRead(cache_filename, inserter); - if (g_Config.bEnableShaderDebugging) // TODO: Hacks.. + if (g_Config.bEnableShaderDebugging) Clear(); } diff --git a/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.cpp b/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.cpp index c81993e5e1..a12acfedfd 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.cpp @@ -175,7 +175,7 @@ void VertexShaderCache::Init() VertexShaderCacheInserter inserter; g_vs_disk_cache.OpenAndRead(cache_filename, inserter); - if (g_Config.bEnableShaderDebugging) // TODO: Hacks.. + if (g_Config.bEnableShaderDebugging) Clear(); } diff --git a/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp b/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp index 7f2cdfceee..34d1c37594 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp @@ -284,7 +284,7 @@ void PixelShaderCache::Init() PixelShaderCacheInserter inserter; g_ps_disk_cache.OpenAndRead(cache_filename, inserter); - if (g_Config.bEnableShaderDebugging) // TODO: Hacks.. + if (g_Config.bEnableShaderDebugging) Clear(); } diff --git a/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.cpp b/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.cpp index 3ef18ffba8..5458157d80 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.cpp @@ -152,7 +152,7 @@ void VertexShaderCache::Init() VertexShaderCacheInserter inserter; g_vs_disk_cache.OpenAndRead(cache_filename, inserter); - if (g_Config.bEnableShaderDebugging) // TODO: Hacks.. + if (g_Config.bEnableShaderDebugging) Clear(); } diff --git a/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.cpp b/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.cpp index b76ce4ca9a..050b378d2f 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.cpp @@ -44,7 +44,8 @@ bool PixelShaderCache::s_displayCompileAlert; GLuint PixelShaderCache::CurrentShader; bool PixelShaderCache::ShaderEnabled; -static FRAGMENTSHADER* pShaderLast = NULL; +PixelShaderCache::PSCacheEntry* PixelShaderCache::last_entry = NULL; +PIXELSHADERUID PixelShaderCache::last_uid; GLuint PixelShaderCache::GetDepthMatrixProgram() { @@ -61,10 +62,9 @@ void PixelShaderCache::Init() glEnable(GL_FRAGMENT_PROGRAM_ARB); ShaderEnabled = true; CurrentShader = 0; + last_entry = NULL; GL_REPORT_ERRORD(); - memset(&last_pixel_shader_uid, 0xFF, sizeof(last_pixel_shader_uid)); - s_displayCompileAlert = true; glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB, (GLint *)&s_nMaxPixelInstructions); @@ -184,41 +184,40 @@ void PixelShaderCache::Shutdown() FRAGMENTSHADER* PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components) { PIXELSHADERUID uid; - GetPixelShaderId(&uid, dstAlphaMode); + GetPixelShaderId(&uid, dstAlphaMode, components); - // Check if the shader is already set - TODO: Use pShaderLast instead of PixelShaders[uid]? - if (uid == last_pixel_shader_uid && PixelShaders[uid].frameCount == frameCount) + // Check if the shader is already set + if (last_entry) { - GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); - ValidatePixelShaderIDs(API_OPENGL, PixelShaders[uid].safe_uid, PixelShaders[uid].shader.strprog, dstAlphaMode, components); - return pShaderLast; + if (uid == last_uid) + { + GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); + ValidatePixelShaderIDs(API_OPENGL, last_entry->safe_uid, last_entry->shader.strprog, dstAlphaMode, components); + return &last_entry->shader; + } } - memcpy(&last_pixel_shader_uid, &uid, sizeof(PIXELSHADERUID)); + last_uid = uid; PSCache::iterator iter = PixelShaders.find(uid); - if (iter != PixelShaders.end()) { - iter->second.frameCount = frameCount; PSCacheEntry &entry = iter->second; - if (&entry.shader != pShaderLast) - pShaderLast = &entry.shader; + last_entry = &entry; GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); ValidatePixelShaderIDs(API_OPENGL, entry.safe_uid, entry.shader.strprog, dstAlphaMode, components); - return pShaderLast; + return &last_entry->shader; } // Make an entry in the table PSCacheEntry& newentry = PixelShaders[uid]; - newentry.frameCount = frameCount; - pShaderLast = &newentry.shader; + last_entry = &newentry; const char *code = GeneratePixelShaderCode(dstAlphaMode, API_OPENGL, components); if (g_ActiveConfig.bEnableShaderDebugging && code) { - GetSafePixelShaderId(&newentry.safe_uid, dstAlphaMode); + GetSafePixelShaderId(&newentry.safe_uid, dstAlphaMode, components); newentry.shader.strprog = code; } @@ -240,7 +239,7 @@ FRAGMENTSHADER* PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 comp INCSTAT(stats.numPixelShadersCreated); SETSTAT(stats.numPixelShadersAlive, PixelShaders.size()); GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); - return pShaderLast; + return &last_entry->shader; } bool PixelShaderCache::CompilePixelShader(FRAGMENTSHADER& ps, const char* pstrprogram) diff --git a/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.h b/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.h index 2aac23a7e5..f528eeb35b 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.h @@ -47,8 +47,7 @@ class PixelShaderCache struct PSCacheEntry { FRAGMENTSHADER shader; - int frameCount; - PSCacheEntry() : frameCount(0) {} + PSCacheEntry() {} ~PSCacheEntry() {} void Destroy() { @@ -66,6 +65,8 @@ class PixelShaderCache static bool s_displayCompileAlert; static GLuint CurrentShader; + static PSCacheEntry* last_entry; + static PIXELSHADERUID last_uid; static bool ShaderEnabled; diff --git a/Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.cpp b/Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.cpp index d922ef63db..dbbb7ee29b 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.cpp @@ -41,7 +41,9 @@ VertexShaderCache::VSCache VertexShaderCache::vshaders; GLuint VertexShaderCache::CurrentShader; bool VertexShaderCache::ShaderEnabled; -static VERTEXSHADER *pShaderLast = NULL; +VertexShaderCache::VSCacheEntry* VertexShaderCache::last_entry = NULL; +VERTEXSHADERUID VertexShaderCache::last_uid; + static int s_nMaxVertexInstructions; @@ -50,7 +52,7 @@ void VertexShaderCache::Init() glEnable(GL_VERTEX_PROGRAM_ARB); ShaderEnabled = true; CurrentShader = 0; - memset(&last_vertex_shader_uid, 0xFF, sizeof(last_vertex_shader_uid)); + last_entry = NULL; glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, (GLint *)&s_nMaxVertexInstructions); if (strstr((const char*)glGetString(GL_VENDOR), "Humper") != NULL) s_nMaxVertexInstructions = 4096; @@ -74,31 +76,32 @@ VERTEXSHADER* VertexShaderCache::SetShader(u32 components) { VERTEXSHADERUID uid; GetVertexShaderId(&uid, components); - if (uid == last_vertex_shader_uid && vshaders[uid].frameCount == frameCount) + if (last_entry) { - GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); - ValidateVertexShaderIDs(API_OPENGL, vshaders[uid].safe_uid, vshaders[uid].shader.strprog, components); - return pShaderLast; + if (uid == last_uid) + { + GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); + ValidateVertexShaderIDs(API_OPENGL, vshaders[uid].safe_uid, vshaders[uid].shader.strprog, components); + return &last_entry->shader; + } } - memcpy(&last_vertex_shader_uid, &uid, sizeof(VERTEXSHADERUID)); + + last_uid = uid; VSCache::iterator iter = vshaders.find(uid); if (iter != vshaders.end()) { - iter->second.frameCount = frameCount; VSCacheEntry &entry = iter->second; - if (&entry.shader != pShaderLast) - pShaderLast = &entry.shader; + last_entry = &entry; GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); ValidateVertexShaderIDs(API_OPENGL, entry.safe_uid, entry.shader.strprog, components); - return pShaderLast; + return &last_entry->shader; } // Make an entry in the table VSCacheEntry& entry = vshaders[uid]; - entry.frameCount = frameCount; - pShaderLast = &entry.shader; + last_entry = &entry; const char *code = GenerateVertexShaderCode(components, API_OPENGL); GetSafeVertexShaderId(&entry.safe_uid, components); @@ -120,7 +123,7 @@ VERTEXSHADER* VertexShaderCache::SetShader(u32 components) INCSTAT(stats.numVertexShadersCreated); SETSTAT(stats.numVertexShadersAlive, vshaders.size()); GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); - return pShaderLast; + return &last_entry->shader; } bool VertexShaderCache::CompileVertexShader(VERTEXSHADER& vs, const char* pstrprogram) diff --git a/Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.h b/Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.h index 1711d42a63..6f4cbe25c2 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.h @@ -32,9 +32,7 @@ struct VERTEXSHADER VERTEXSHADER() : glprogid(0) {} GLuint glprogid; // opengl program id -//#if defined(_DEBUG) || defined(DEBUGFAST) std::string strprog; -//#endif }; class VertexShaderCache @@ -43,8 +41,7 @@ class VertexShaderCache { VERTEXSHADER shader; VERTEXSHADERUIDSAFE safe_uid; - int frameCount; - VSCacheEntry() : frameCount(0) {} + VSCacheEntry() {} void Destroy() { // printf("Destroying vs %i\n", shader.glprogid); glDeleteProgramsARB(1, &shader.glprogid); @@ -56,6 +53,9 @@ class VertexShaderCache static VSCache vshaders; + static VSCacheEntry* last_entry; + static VERTEXSHADERUID last_uid; + static GLuint CurrentShader; static bool ShaderEnabled; From 2b3b32872d2a01aba7195dc31a5270cf9613f5c1 Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Thu, 29 Sep 2011 22:54:52 +0200 Subject: [PATCH 34/36] Fix Windows build. --- .../Plugin_VideoDX11/Src/PixelShaderCache.cpp | 25 +++++++++++-------- .../Plugin_VideoDX11/Src/PixelShaderCache.h | 4 +-- .../Src/VertexShaderCache.cpp | 20 +++++++++------ .../Plugin_VideoDX11/Src/VertexShaderCache.h | 4 +-- .../Plugin_VideoDX9/Src/PixelShaderCache.cpp | 25 +++++++++++-------- .../Plugin_VideoDX9/Src/PixelShaderCache.h | 4 +-- .../Plugin_VideoDX9/Src/VertexShaderCache.cpp | 20 +++++++++------ .../Plugin_VideoDX9/Src/VertexShaderCache.h | 8 +++--- 8 files changed, 64 insertions(+), 46 deletions(-) diff --git a/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.cpp b/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.cpp index 656f8ddff2..7e4af031bd 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.cpp @@ -41,6 +41,7 @@ namespace DX11 PixelShaderCache::PSCache PixelShaderCache::PixelShaders; const PixelShaderCache::PSCacheEntry* PixelShaderCache::last_entry; +PIXELSHADERUID PixelShaderCache::last_uid; LinearDiskCache g_ps_disk_cache; @@ -415,6 +416,8 @@ void PixelShaderCache::Init() if (g_Config.bEnableShaderDebugging) Clear(); + + last_entry = NULL; } // ONLY to be used during shutdown. @@ -423,6 +426,8 @@ void PixelShaderCache::Clear() for (PSCache::iterator iter = PixelShaders.begin(); iter != PixelShaders.end(); iter++) iter->second.Destroy(); PixelShaders.clear(); + + last_entry = NULL; } // Used in Swap() when AA mode has changed @@ -457,25 +462,26 @@ void PixelShaderCache::Shutdown() bool PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components) { PIXELSHADERUID uid; - GetPixelShaderId(&uid, dstAlphaMode); + GetPixelShaderId(&uid, dstAlphaMode, components); // Check if the shader is already set - if (uid == last_pixel_shader_uid && PixelShaders[uid].frameCount == frameCount) + if (last_entry) { - PSCache::const_iterator iter = PixelShaders.find(uid); - GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE,true); - ValidatePixelShaderIDs(API_D3D11, PixelShaders[uid].safe_uid, PixelShaders[uid].code, dstAlphaMode, components); - return (iter != PixelShaders.end() && iter->second.shader); + if (uid == last_uid) + { + GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE,true); + ValidatePixelShaderIDs(API_D3D11, last_entry->safe_uid, last_entry->code, dstAlphaMode, components); + return (last_entry->shader != NULL); + } } - memcpy(&last_pixel_shader_uid, &uid, sizeof(PIXELSHADERUID)); + last_uid = uid; // Check if the shader is already in the cache PSCache::iterator iter; iter = PixelShaders.find(uid); if (iter != PixelShaders.end()) { - iter->second.frameCount = frameCount; const PSCacheEntry &entry = iter->second; last_entry = &entry; @@ -504,7 +510,7 @@ bool PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components) if (g_ActiveConfig.bEnableShaderDebugging && success) { PixelShaders[uid].code = code; - GetSafePixelShaderId(&PixelShaders[uid].safe_uid, dstAlphaMode); + GetSafePixelShaderId(&PixelShaders[uid].safe_uid, dstAlphaMode, components); } GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); @@ -523,7 +529,6 @@ bool PixelShaderCache::InsertByteCode(const PIXELSHADERUID &uid, const void* byt // Make an entry in the table PSCacheEntry newentry; newentry.shader = shader; - newentry.frameCount = frameCount; PixelShaders[uid] = newentry; last_entry = &PixelShaders[uid]; diff --git a/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.h b/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.h index f5a9cf34b8..874a47e4c1 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.h +++ b/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.h @@ -53,12 +53,11 @@ private: struct PSCacheEntry { ID3D11PixelShader* shader; - int frameCount; PIXELSHADERUIDSAFE safe_uid; std::string code; - PSCacheEntry() : shader(NULL), frameCount(0) {} + PSCacheEntry() : shader(NULL) {} void Destroy() { SAFE_RELEASE(shader); } }; @@ -66,6 +65,7 @@ private: static PSCache PixelShaders; static const PSCacheEntry* last_entry; + static PIXELSHADERUID last_uid; }; } // namespace DX11 diff --git a/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.cpp b/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.cpp index a12acfedfd..d9dae4cf91 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.cpp @@ -37,6 +37,7 @@ namespace DX11 { VertexShaderCache::VSCache VertexShaderCache::vshaders; const VertexShaderCache::VSCacheEntry *VertexShaderCache::last_entry; +VERTEXSHADERUID VertexShaderCache::last_uid; static ID3D11VertexShader* SimpleVertexShader = NULL; static ID3D11VertexShader* ClearVertexShader = NULL; @@ -177,6 +178,8 @@ void VertexShaderCache::Init() if (g_Config.bEnableShaderDebugging) Clear(); + + last_entry = NULL; } void VertexShaderCache::Clear() @@ -184,6 +187,8 @@ void VertexShaderCache::Clear() for (VSCache::iterator iter = vshaders.begin(); iter != vshaders.end(); ++iter) iter->second.Destroy(); vshaders.clear(); + + last_entry = NULL; } void VertexShaderCache::Shutdown() @@ -205,19 +210,21 @@ bool VertexShaderCache::SetShader(u32 components) { VERTEXSHADERUID uid; GetVertexShaderId(&uid, components); - if (uid == last_vertex_shader_uid && vshaders[uid].frameCount == frameCount) + if (last_entry) { - GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); - ValidateVertexShaderIDs(API_D3D11, vshaders[uid].safe_uid, vshaders[uid].code, components); - return (vshaders[uid].shader != NULL); + if (uid == last_uid) + { + GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); + ValidateVertexShaderIDs(API_D3D11, last_entry->safe_uid, last_entry->code, components); + return (last_entry->shader != NULL); + } } - memcpy(&last_vertex_shader_uid, &uid, sizeof(VERTEXSHADERUID)); + last_uid = uid; VSCache::iterator iter = vshaders.find(uid); if (iter != vshaders.end()) { - iter->second.frameCount = frameCount; const VSCacheEntry &entry = iter->second; last_entry = &entry; @@ -264,7 +271,6 @@ bool VertexShaderCache::InsertByteCode(const VERTEXSHADERUID &uid, D3DBlob* bcod // Make an entry in the table VSCacheEntry entry; entry.shader = shader; - entry.frameCount = frameCount; entry.SetByteCode(bcodeblob); vshaders[uid] = entry; diff --git a/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.h b/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.h index d614989b0a..6d9537606a 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.h +++ b/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.h @@ -51,12 +51,11 @@ private: { ID3D11VertexShader* shader; D3DBlob* bytecode; // needed to initialize the input layout - int frameCount; VERTEXSHADERUIDSAFE safe_uid; std::string code; - VSCacheEntry() : shader(NULL), bytecode(NULL), frameCount(0) {} + VSCacheEntry() : shader(NULL), bytecode(NULL) {} void SetByteCode(D3DBlob* blob) { SAFE_RELEASE(bytecode); @@ -73,6 +72,7 @@ private: static VSCache vshaders; static const VSCacheEntry* last_entry; + static VERTEXSHADERUID last_uid; }; } // namespace DX11 diff --git a/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp b/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp index 34d1c37594..14943e8f8f 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp @@ -43,6 +43,7 @@ namespace DX9 PixelShaderCache::PSCache PixelShaderCache::PixelShaders; const PixelShaderCache::PSCacheEntry *PixelShaderCache::last_entry; +PIXELSHADERUID PixelShaderCache::last_uid; static LinearDiskCache g_ps_disk_cache; static std::set unique_shaders; @@ -233,6 +234,8 @@ static LPDIRECT3DPIXELSHADER9 CreateCopyShader(int copyMatrixType, int depthConv void PixelShaderCache::Init() { + last_entry = NULL; + //program used for clear screen { char pprog[3072]; @@ -295,7 +298,7 @@ void PixelShaderCache::Clear() iter->second.Destroy(); PixelShaders.clear(); - memset(&last_pixel_shader_uid, 0xFF, sizeof(last_pixel_shader_uid)); + last_entry = NULL; } void PixelShaderCache::Shutdown() @@ -331,25 +334,26 @@ bool PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components) { const API_TYPE api = ((D3D::GetCaps().PixelShaderVersion >> 8) & 0xFF) < 3 ? API_D3D9_SM20 : API_D3D9_SM30; PIXELSHADERUID uid; - GetPixelShaderId(&uid, dstAlphaMode); + GetPixelShaderId(&uid, dstAlphaMode, components); // Check if the shader is already set - if (uid == last_pixel_shader_uid && PixelShaders[uid].frameCount == frameCount) + if (last_entry) { - PSCache::const_iterator iter = PixelShaders.find(uid); - GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); - ValidatePixelShaderIDs(api, PixelShaders[uid].safe_uid, PixelShaders[uid].code, dstAlphaMode, components); - return (iter != PixelShaders.end() && iter->second.shader); + if (uid == last_uid) + { + GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); + ValidatePixelShaderIDs(api, last_entry->safe_uid, last_entry->code, dstAlphaMode, components); + return last_entry->shader != NULL; + } } - memcpy(&last_pixel_shader_uid, &uid, sizeof(PIXELSHADERUID)); + last_uid = uid; // Check if the shader is already in the cache PSCache::iterator iter; iter = PixelShaders.find(uid); if (iter != PixelShaders.end()) { - iter->second.frameCount = frameCount; const PSCacheEntry &entry = iter->second; last_entry = &entry; @@ -398,7 +402,7 @@ bool PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components) if (g_ActiveConfig.bEnableShaderDebugging && success) { PixelShaders[uid].code = code; - GetSafePixelShaderId(&PixelShaders[uid].safe_uid, dstAlphaMode); + GetSafePixelShaderId(&PixelShaders[uid].safe_uid, dstAlphaMode, components); } GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); @@ -412,7 +416,6 @@ bool PixelShaderCache::InsertByteCode(const PIXELSHADERUID &uid, const u8 *bytec // Make an entry in the table PSCacheEntry newentry; newentry.shader = shader; - newentry.frameCount = frameCount; PixelShaders[uid] = newentry; last_entry = &PixelShaders[uid]; diff --git a/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.h b/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.h index d323311fe0..c771984d36 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.h +++ b/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.h @@ -40,12 +40,11 @@ private: { LPDIRECT3DPIXELSHADER9 shader; bool owns_shader; - int frameCount; PIXELSHADERUIDSAFE safe_uid; std::string code; - PSCacheEntry() : shader(NULL), owns_shader(true), frameCount(0) {} + PSCacheEntry() : shader(NULL), owns_shader(true) {} void Destroy() { if (shader && owns_shader) @@ -58,6 +57,7 @@ private: static PSCache PixelShaders; static const PSCacheEntry *last_entry; + static PIXELSHADERUID last_uid; static void Clear(); public: diff --git a/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.cpp b/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.cpp index 5458157d80..9448c07371 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.cpp @@ -38,6 +38,7 @@ namespace DX9 VertexShaderCache::VSCache VertexShaderCache::vshaders; const VertexShaderCache::VSCacheEntry *VertexShaderCache::last_entry; +VERTEXSHADERUID VertexShaderCache::last_uid; #define MAX_SSAA_SHADERS 3 @@ -154,6 +155,8 @@ void VertexShaderCache::Init() if (g_Config.bEnableShaderDebugging) Clear(); + + last_entry = NULL; } void VertexShaderCache::Clear() @@ -162,7 +165,7 @@ void VertexShaderCache::Clear() iter->second.Destroy(); vshaders.clear(); - memset(&last_vertex_shader_uid, 0xFF, sizeof(last_vertex_shader_uid)); + last_entry = NULL; } void VertexShaderCache::Shutdown() @@ -187,19 +190,21 @@ bool VertexShaderCache::SetShader(u32 components) { VERTEXSHADERUID uid; GetVertexShaderId(&uid, components); - if (uid == last_vertex_shader_uid && vshaders[uid].frameCount == frameCount) + if (last_entry) { - GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); - ValidateVertexShaderIDs(API_D3D9, vshaders[uid].safe_uid, vshaders[uid].code, components); - return (vshaders[uid].shader != NULL); + if (uid == last_uid) + { + GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); + ValidateVertexShaderIDs(API_D3D9, last_entry->safe_uid, last_entry->code, components); + return (last_entry->shader != NULL); + } } - memcpy(&last_vertex_shader_uid, &uid, sizeof(VERTEXSHADERUID)); + last_uid = uid; VSCache::iterator iter = vshaders.find(uid); if (iter != vshaders.end()) { - iter->second.frameCount = frameCount; const VSCacheEntry &entry = iter->second; last_entry = &entry; @@ -237,7 +242,6 @@ bool VertexShaderCache::InsertByteCode(const VERTEXSHADERUID &uid, const u8 *byt // Make an entry in the table VSCacheEntry entry; entry.shader = shader; - entry.frameCount = frameCount; vshaders[uid] = entry; last_entry = &vshaders[uid]; diff --git a/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.h b/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.h index 686f8b7c6d..c9c447e35b 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.h +++ b/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.h @@ -34,12 +34,11 @@ private: struct VSCacheEntry { LPDIRECT3DVERTEXSHADER9 shader; - int frameCount; -//#if defined(_DEBUG) || defined(DEBUGFAST) + std::string code; VERTEXSHADERUIDSAFE safe_uid; -//#endif - VSCacheEntry() : shader(NULL), frameCount(0) {} + + VSCacheEntry() : shader(NULL) {} void Destroy() { if (shader) @@ -52,6 +51,7 @@ private: static VSCache vshaders; static const VSCacheEntry *last_entry; + static VERTEXSHADERUID last_uid; static void Clear(); public: From 0e1383b788cdc4975ab595b9b9969b9db1878b94 Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Thu, 29 Sep 2011 22:55:28 +0200 Subject: [PATCH 35/36] Bump disk cache version. --- Source/Core/Common/Src/LinearDiskCache.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Core/Common/Src/LinearDiskCache.h b/Source/Core/Common/Src/LinearDiskCache.h index 450392e70a..f213d2959e 100644 --- a/Source/Core/Common/Src/LinearDiskCache.h +++ b/Source/Core/Common/Src/LinearDiskCache.h @@ -24,7 +24,7 @@ // Increment this every time you change shader generation code. enum { - LINEAR_DISKCACHE_VER = 6966 + LINEAR_DISKCACHE_VER = 6967 }; // On disk format: From 7eb06430ed35f73a073ca9851e199777a6695114 Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Thu, 29 Sep 2011 23:16:42 +0200 Subject: [PATCH 36/36] Only sync shader caches to disk on stop. --- Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.cpp | 1 - Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.cpp | 1 - Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp | 1 - Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.cpp | 1 - 4 files changed, 4 deletions(-) diff --git a/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.cpp b/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.cpp index 7e4af031bd..56f3719057 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoDX11/Src/PixelShaderCache.cpp @@ -502,7 +502,6 @@ bool PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components) // Insert the bytecode into the caches g_ps_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size()); - g_ps_disk_cache.Sync(); bool success = InsertByteCode(uid, pbytecode->Data(), pbytecode->Size()); pbytecode->Release(); diff --git a/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.cpp b/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.cpp index d9dae4cf91..d727ce1ebf 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoDX11/Src/VertexShaderCache.cpp @@ -244,7 +244,6 @@ bool VertexShaderCache::SetShader(u32 components) return false; } g_vs_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size()); - g_vs_disk_cache.Sync(); bool success = InsertByteCode(uid, pbytecode); pbytecode->Release(); diff --git a/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp b/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp index 14943e8f8f..f66d096ab6 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp @@ -393,7 +393,6 @@ bool PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components) // Insert the bytecode into the caches g_ps_disk_cache.Append(uid, bytecode, bytecodelen); - g_ps_disk_cache.Sync(); // And insert it into the shader cache. bool success = InsertByteCode(uid, bytecode, bytecodelen, true); diff --git a/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.cpp b/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.cpp index 9448c07371..e392cf3de0 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/VertexShaderCache.cpp @@ -223,7 +223,6 @@ bool VertexShaderCache::SetShader(u32 components) return false; } g_vs_disk_cache.Append(uid, bytecode, bytecodelen); - g_vs_disk_cache.Sync(); bool success = InsertByteCode(uid, bytecode, bytecodelen, true); if (g_ActiveConfig.bEnableShaderDebugging && success)