From b28348066e083d532d5ab62c93ce0f1dc5c217ed Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Fri, 9 Sep 2011 00:32:04 +0200 Subject: [PATCH] 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() {