diff options
| author | Matthew Parlane <parlane@gmail.com> | 2013-08-23 00:51:12 +1200 |
|---|---|---|
| committer | Matthew Parlane <parlane@gmail.com> | 2013-08-23 00:51:12 +1200 |
| commit | b6e054a2beef3236822e27d95dfe38a4ccee2eb1 (patch) | |
| tree | 6f744593b14def9c2fbc7be9e509df5507835cc4 /Source/Core/VideoCommon | |
| parent | f274b3b074fb8bb0477b0e9f4e88db0e08bf4f2c (diff) | |
| parent | 41c25d0c90a2461c3e34bf9659dcf1da5e1e8580 (diff) | |
Merge branch 'master' into wii-network
Conflicts:
Source/Core/Core/Core.vcxproj
Source/Core/Core/Core.vcxproj.filters
Source/Core/Core/Src/CoreParameter.cpp
Source/Core/DolphinWX/Dolphin.vcxproj
Source/Core/DolphinWX/Dolphin.vcxproj.filters
Diffstat (limited to 'Source/Core/VideoCommon')
23 files changed, 530 insertions, 224 deletions
diff --git a/Source/Core/VideoCommon/CMakeLists.txt b/Source/Core/VideoCommon/CMakeLists.txt index a4dad8293b..8503377779 100644 --- a/Source/Core/VideoCommon/CMakeLists.txt +++ b/Source/Core/VideoCommon/CMakeLists.txt @@ -33,6 +33,7 @@ set(SRCS Src/BPFunctions.cpp Src/VertexManagerBase.cpp Src/VertexShaderGen.cpp Src/VertexShaderManager.cpp + Src/VideoBackendBase.cpp Src/VideoConfig.cpp Src/VideoState.cpp Src/XFMemory.cpp diff --git a/Source/Core/VideoCommon/Src/BPMemory.cpp b/Source/Core/VideoCommon/Src/BPMemory.cpp index 77f2f6bab3..7272ed0993 100644 --- a/Source/Core/VideoCommon/Src/BPMemory.cpp +++ b/Source/Core/VideoCommon/Src/BPMemory.cpp @@ -299,38 +299,3 @@ void GetBPRegInfo(const u8* data, char* name, size_t name_size, char* desc, size #undef SetRegName } } - -AlphaTest::TEST_RESULT AlphaTest::TestResult() -{ - switch(logic) - { - case 0: // AND - if (comp0 == ALPHACMP_ALWAYS && comp1 == ALPHACMP_ALWAYS) - return PASS; - if (comp0 == ALPHACMP_NEVER || comp1 == ALPHACMP_NEVER) - return FAIL; - break; - - case 1: // OR - if (comp0 == ALPHACMP_ALWAYS || comp1 == ALPHACMP_ALWAYS) - return PASS; - if (comp0 == ALPHACMP_NEVER && comp1 == ALPHACMP_NEVER) - return FAIL; - break; - - case 2: // XOR - if ((comp0 == ALPHACMP_ALWAYS && comp1 == ALPHACMP_NEVER) || (comp0 == ALPHACMP_NEVER && comp1 == ALPHACMP_ALWAYS)) - return PASS; - if ((comp0 == ALPHACMP_ALWAYS && comp1 == ALPHACMP_ALWAYS) || (comp0 == ALPHACMP_NEVER && comp1 == ALPHACMP_NEVER)) - return FAIL; - break; - - case 3: // XNOR - if ((comp0 == ALPHACMP_ALWAYS && comp1 == ALPHACMP_NEVER) || (comp0 == ALPHACMP_NEVER && comp1 == ALPHACMP_ALWAYS)) - return FAIL; - if ((comp0 == ALPHACMP_ALWAYS && comp1 == ALPHACMP_ALWAYS) || (comp0 == ALPHACMP_NEVER && comp1 == ALPHACMP_NEVER)) - return PASS; - break; - } - return UNDETERMINED; -} diff --git a/Source/Core/VideoCommon/Src/BPMemory.h b/Source/Core/VideoCommon/Src/BPMemory.h index 90fffc6c6c..83dbefed50 100644 --- a/Source/Core/VideoCommon/Src/BPMemory.h +++ b/Source/Core/VideoCommon/Src/BPMemory.h @@ -805,6 +805,7 @@ union PE_CONTROL u32 unused : 17; u32 rid : 8; }; + u32 hex; }; @@ -884,7 +885,40 @@ union AlphaTest PASS = 2, }; - TEST_RESULT TestResult(); + inline TEST_RESULT TestResult() const + { + switch(logic) + { + case 0: // AND + if (comp0 == ALPHACMP_ALWAYS && comp1 == ALPHACMP_ALWAYS) + return PASS; + if (comp0 == ALPHACMP_NEVER || comp1 == ALPHACMP_NEVER) + return FAIL; + break; + + case 1: // OR + if (comp0 == ALPHACMP_ALWAYS || comp1 == ALPHACMP_ALWAYS) + return PASS; + if (comp0 == ALPHACMP_NEVER && comp1 == ALPHACMP_NEVER) + return FAIL; + break; + + case 2: // XOR + if ((comp0 == ALPHACMP_ALWAYS && comp1 == ALPHACMP_NEVER) || (comp0 == ALPHACMP_NEVER && comp1 == ALPHACMP_ALWAYS)) + return PASS; + if ((comp0 == ALPHACMP_ALWAYS && comp1 == ALPHACMP_ALWAYS) || (comp0 == ALPHACMP_NEVER && comp1 == ALPHACMP_NEVER)) + return FAIL; + break; + + case 3: // XNOR + if ((comp0 == ALPHACMP_ALWAYS && comp1 == ALPHACMP_NEVER) || (comp0 == ALPHACMP_NEVER && comp1 == ALPHACMP_ALWAYS)) + return FAIL; + if ((comp0 == ALPHACMP_ALWAYS && comp1 == ALPHACMP_ALWAYS) || (comp0 == ALPHACMP_NEVER && comp1 == ALPHACMP_NEVER)) + return PASS; + break; + } + return UNDETERMINED; + } }; union UPE_Copy @@ -1005,6 +1039,9 @@ struct BPMemory TevKSel tevksel[8];//0xf6,0xf7,f8,f9,fa,fb,fc,fd u32 bpMask; //0xFE u32 unknown18; //ff + + bool UseEarlyDepthTest() const { return zcontrol.early_ztest && zmode.testenable; } + bool UseLateDepthTest() const { return !zcontrol.early_ztest && zmode.testenable; } }; #pragma pack() diff --git a/Source/Core/VideoCommon/Src/BPStructs.cpp b/Source/Core/VideoCommon/Src/BPStructs.cpp index ce0346b523..00cecf0082 100644 --- a/Source/Core/VideoCommon/Src/BPStructs.cpp +++ b/Source/Core/VideoCommon/Src/BPStructs.cpp @@ -153,7 +153,10 @@ void BPWritten(const BPCmd& bp) bpmem.genMode.numtexgens, bpmem.genMode.numcolchans, bpmem.genMode.multisampling, bpmem.genMode.numtevstages+1, bpmem.genMode.cullmode, bpmem.genMode.numindstages, bpmem.genMode.zfreeze); - SetGenerationMode(); + + // Only call SetGenerationMode when cull mode changes. + if (bp.changes & 0xC000) + SetGenerationMode(); break; } case BPMEM_IND_MTXA: // Index Matrix Changed diff --git a/Source/Core/VideoCommon/Src/DriverDetails.cpp b/Source/Core/VideoCommon/Src/DriverDetails.cpp index 153a07226f..85b7d3a47f 100644 --- a/Source/Core/VideoCommon/Src/DriverDetails.cpp +++ b/Source/Core/VideoCommon/Src/DriverDetails.cpp @@ -20,6 +20,7 @@ namespace DriverDetails // Local members Vendor m_vendor = VENDOR_UNKNOWN; + Driver m_driver = DRIVER_UNKNOWN; u32 m_devfamily = 0; double m_version = 0.0; @@ -29,10 +30,6 @@ namespace DriverDetails {BUG_NODYNUBOACCESS, 300, 14.0, -1.0}, {BUG_BROKENCENTROID, 300, 14.0, -1.0}, {BUG_BROKENINFOLOG, 300, -1.0, -1.0}, - {BUG_BROKENBUFFERS, 300, 14.0, -1.0}, - }; - BugInfo m_armbugs[] = { - {BUG_MALIBROKENBUFFERS, 600, -1.0, -1.0}, }; std::map<std::pair<Vendor, Bug>, BugInfo> m_bugs; @@ -40,26 +37,52 @@ namespace DriverDetails // Private function void InitBugMap() { - switch(m_vendor) + switch(m_driver) { - case VENDOR_QUALCOMM: + case DRIVER_QUALCOMM: for (unsigned int a = 0; a < (sizeof(m_qualcommbugs) / sizeof(BugInfo)); ++a) m_bugs[std::make_pair(m_vendor, m_qualcommbugs[a].m_bug)] = m_qualcommbugs[a]; break; - case VENDOR_ARM: - for (unsigned int a = 0; a < (sizeof(m_armbugs) / sizeof(BugInfo)); ++a) - m_bugs[std::make_pair(m_vendor, m_armbugs[a].m_bug)] = m_armbugs[a]; default: break; } } - void Init(Vendor vendor, const u32 devfamily, const double version) + void Init(Vendor vendor, Driver driver, const u32 devfamily, const double version) { m_vendor = vendor; + m_driver = driver; m_devfamily = devfamily; m_version = version; - InitBugMap(); + InitBugMap(); + if (driver == DRIVER_UNKNOWN) + switch(vendor) + { + case VENDOR_NVIDIA: + case VENDOR_TEGRA: + m_driver = DRIVER_NVIDIA; + break; + case VENDOR_ATI: + m_driver = DRIVER_ATI; + break; + case VENDOR_INTEL: + m_driver = DRIVER_INTEL; + break; + case VENDOR_ARM: + m_driver = DRIVER_ARM; + break; + case VENDOR_QUALCOMM: + m_driver = DRIVER_QUALCOMM; + break; + case VENDOR_IMGTEC: + m_driver = DRIVER_IMGTEC; + break; + case VENDOR_VIVANTE: + m_driver = DRIVER_VIVANTE; + break; + default: + break; + } for (auto it = m_bugs.begin(); it != m_bugs.end(); ++it) if (it->second.m_devfamily == m_devfamily) diff --git a/Source/Core/VideoCommon/Src/DriverDetails.h b/Source/Core/VideoCommon/Src/DriverDetails.h index bf67abe9eb..cb8b104eea 100644 --- a/Source/Core/VideoCommon/Src/DriverDetails.h +++ b/Source/Core/VideoCommon/Src/DriverDetails.h @@ -21,6 +21,23 @@ namespace DriverDetails VENDOR_UNKNOWN }; + // Enum of known drivers + enum Driver + { + DRIVER_NVIDIA = 0, // Official Nvidia, including mobile GPU + DRIVER_NOUVEAU, // OSS nouveau + DRIVER_ATI, // Official ATI + DRIVER_RADEONHD, // OSS Radeon + DRIVER_INTEL, // Official Intel + DRIVER_ARM, // Official Mali driver + DRIVER_LIMA, // OSS Mali driver + DRIVER_QUALCOMM, // Official Adreno driver + DRIVER_FREEDRENO, // OSS Adreno driver + DRIVER_IMGTEC, // OSS PowerVR driver + DRIVER_VIVANTE, // Official vivante driver + DRIVER_UNKNOWN // Unknown driver, default to official hardware driver + }; + // Enum of known bugs // These can be vendor specific, but we put them all in here // For putting a new bug in here, make sure to put a detailed comment above the enum @@ -52,30 +69,10 @@ namespace DriverDetails // Adreno devices /always/ return 0 when querying GL_INFO_LOG_LENGTH // They also max out at 1024 bytes(1023 characters + null terminator) for the log BUG_BROKENINFOLOG, - // Bug: Uploading data with rendering causes issues - // Affected devices: Qualcomm/Adreno - // Started Version: 14 - // Ended Version: -1 - // When drawing our elements, the instruction buffer on Adreno devices - // becomes too long, causing the device to quickly run out of RAM - // I've watched the kernel module go up to ~700MB of RAM in a few seconds - // The "workaround" is calling swapbuffers every single time we flush - // This causes flickering, but it is the only known way to work around it - BUG_BROKENBUFFERS, - // Bug: Uploading data without swapping causes issues - // Affected devices: Mali-T6xx - // Started Version: -1 - // Ended Version: -1 - // This is similar to the Adreno rendering bug where uploading the data - // to the GPU causes the device to quickly run out of RAM. - // Unlike the Adreno workaround though, this can be fixed by calling - // either glFlush() or glFinish() after flushing. - // glFlush tends to take 0-1Ms on each call - BUG_MALIBROKENBUFFERS, }; // Initializes our internal vendor, device family, and driver version - void Init(Vendor vendor, const u32 devfamily, const double version); + void Init(Vendor vendor, Driver driver, const u32 devfamily, const double version); // Once Vendor and driver version is set, this will return if it has the applicable bug passed to it. bool HasBug(Bug bug); diff --git a/Source/Core/VideoCommon/Src/Fifo.cpp b/Source/Core/VideoCommon/Src/Fifo.cpp index 5114e3fc2b..a00e531fa4 100644 --- a/Source/Core/VideoCommon/Src/Fifo.cpp +++ b/Source/Core/VideoCommon/Src/Fifo.cpp @@ -151,9 +151,6 @@ void RunGpuLoop() // check if we are able to run this buffer while (GpuRunningState && !CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint()) { - if (!GpuRunningState) - break; - fifo.isGpuReadingData = true; CommandProcessor::isPossibleWaitingSetDrawDone = fifo.bFF_GPLinkEnable ? true : false; diff --git a/Source/Core/VideoCommon/Src/LightingShaderGen.h b/Source/Core/VideoCommon/Src/LightingShaderGen.h index 031dce44bd..fc107a2e2b 100644 --- a/Source/Core/VideoCommon/Src/LightingShaderGen.h +++ b/Source/Core/VideoCommon/Src/LightingShaderGen.h @@ -9,40 +9,22 @@ #include "NativeVertexFormat.h" #include "XFMemory.h" -static const char* LightCol(const char* lightsName, unsigned int index, const char* swizzle) -{ - static char result[32]; - snprintf(result, sizeof(result), "%s[5*%d].%s", lightsName, index, swizzle); - return result; -} -static const char* LightCosAtt(const char* lightsName, unsigned int index) -{ - static char result[32]; - snprintf(result, sizeof(result), "%s[5*%d+1]", lightsName, index); - return result; -} +#define LIGHT_COL "%s[5*%d].%s" +#define LIGHT_COL_PARAMS(lightsName, index, swizzle) (lightsName), (index), (swizzle) -static const char* LightDistAtt(const char* lightsName, unsigned int index) -{ - static char result[32]; - snprintf(result, sizeof(result), "%s[5*%d+2]", lightsName, index); - return result; -} +#define LIGHT_COSATT "%s[5*%d+1]" +#define LIGHT_COSATT_PARAMS(lightsName, index) (lightsName), (index) -static const char* LightPos(const char* lightsName, unsigned int index) -{ - static char result[32]; - snprintf(result, sizeof(result), "%s[5*%d+3]", lightsName, index); - return result; -} +#define LIGHT_DISTATT "%s[5*%d+2]" +#define LIGHT_DISTATT_PARAMS(lightsName, index) (lightsName), (index) + +#define LIGHT_POS "%s[5*%d+3]" +#define LIGHT_POS_PARAMS(lightsName, index) (lightsName), (index) + +#define LIGHT_DIR "%s[5*%d+4]" +#define LIGHT_DIR_PARAMS(lightsName, index) (lightsName), (index) -static const char* LightDir(const char* lightsName, unsigned int index) -{ - static char result[32]; - snprintf(result, sizeof(result), "%s[5*%d+4]", lightsName, index); - return result; -} template<class T> static void GenerateLightShader(T& object, LightingUidData& uid_data, int index, int litchan_index, const char* lightsName, int coloralpha) @@ -62,13 +44,13 @@ static void GenerateLightShader(T& object, LightingUidData& uid_data, int index, switch (chan.diffusefunc) { case LIGHTDIF_NONE: - object.Write("lacc.%s += %s;\n", swizzle, LightCol(lightsName, index, swizzle)); + object.Write("lacc.%s += " LIGHT_COL";\n", swizzle, LIGHT_COL_PARAMS(lightsName, index, swizzle)); break; case LIGHTDIF_SIGN: case LIGHTDIF_CLAMP: - object.Write("ldir = normalize(%s.xyz - pos.xyz);\n", LightPos(lightsName, index)); - object.Write("lacc.%s += %sdot(ldir, _norm0)) * %s;\n", - swizzle, chan.diffusefunc != LIGHTDIF_SIGN ? "max(0.0f," :"(", LightCol(lightsName, index, swizzle)); + object.Write("ldir = normalize(" LIGHT_POS".xyz - pos.xyz);\n", LIGHT_POS_PARAMS(lightsName, index)); + object.Write("lacc.%s += %sdot(ldir, _norm0)) * " LIGHT_COL";\n", + swizzle, chan.diffusefunc != LIGHTDIF_SIGN ? "max(0.0f," :"(", LIGHT_COL_PARAMS(lightsName, index, swizzle)); break; default: _assert_(0); } @@ -77,31 +59,34 @@ static void GenerateLightShader(T& object, LightingUidData& uid_data, int index, { if (chan.attnfunc == 3) { // spot - object.Write("ldir = %s.xyz - pos.xyz;\n", LightPos(lightsName, index)); + object.Write("ldir = " LIGHT_POS".xyz - pos.xyz;\n", LIGHT_POS_PARAMS(lightsName, index)); object.Write("dist2 = dot(ldir, ldir);\n" "dist = sqrt(dist2);\n" "ldir = ldir / dist;\n" - "attn = max(0.0f, dot(ldir, %s.xyz));\n", LightDir(lightsName, index)); - object.Write("attn = max(0.0f, dot(%s.xyz, float3(1.0f, attn, attn*attn))) / dot(%s.xyz, float3(1.0f,dist,dist2));\n", LightCosAtt(lightsName, index), LightDistAtt(lightsName, index)); + "attn = max(0.0f, dot(ldir, " LIGHT_DIR".xyz));\n", + LIGHT_DIR_PARAMS(lightsName, index)); + object.Write("attn = max(0.0f, dot(" LIGHT_COSATT".xyz, float3(1.0f, attn, attn*attn))) / dot(" LIGHT_DISTATT".xyz, float3(1.0f,dist,dist2));\n", + LIGHT_COSATT_PARAMS(lightsName, index), LIGHT_DISTATT_PARAMS(lightsName, index)); } else if (chan.attnfunc == 1) { // specular - object.Write("ldir = normalize(%s.xyz);\n", LightPos(lightsName, index)); - object.Write("attn = (dot(_norm0,ldir) >= 0.0f) ? max(0.0f, dot(_norm0, %s.xyz)) : 0.0f;\n", LightDir(lightsName, index)); - object.Write("attn = max(0.0f, dot(%s.xyz, float3(1,attn,attn*attn))) / dot(%s.xyz, float3(1,attn,attn*attn));\n", LightCosAtt(lightsName, index), LightDistAtt(lightsName, index)); + object.Write("ldir = normalize(" LIGHT_POS".xyz);\n", LIGHT_POS_PARAMS(lightsName, index)); + object.Write("attn = (dot(_norm0,ldir) >= 0.0f) ? max(0.0f, dot(_norm0, " LIGHT_DIR".xyz)) : 0.0f;\n", LIGHT_DIR_PARAMS(lightsName, index)); + object.Write("attn = max(0.0f, dot(" LIGHT_COSATT".xyz, float3(1,attn,attn*attn))) / dot(" LIGHT_DISTATT".xyz, float3(1,attn,attn*attn));\n", + LIGHT_COSATT_PARAMS(lightsName, index), LIGHT_DISTATT_PARAMS(lightsName, index)); } switch (chan.diffusefunc) { case LIGHTDIF_NONE: - object.Write("lacc.%s += attn * %s;\n", swizzle, LightCol(lightsName, index, swizzle)); + object.Write("lacc.%s += attn * " LIGHT_COL";\n", swizzle, LIGHT_COL_PARAMS(lightsName, index, swizzle)); break; case LIGHTDIF_SIGN: case LIGHTDIF_CLAMP: - object.Write("lacc.%s += attn * %sdot(ldir, _norm0)) * %s;\n", + object.Write("lacc.%s += attn * %sdot(ldir, _norm0)) * " LIGHT_COL";\n", swizzle, chan.diffusefunc != LIGHTDIF_SIGN ? "max(0.0f," :"(", - LightCol(lightsName, index, swizzle)); + LIGHT_COL_PARAMS(lightsName, index, swizzle)); break; default: _assert_(0); } @@ -150,7 +135,10 @@ static void GenerateLightingShader(T& object, LightingUidData& uid_data, int com else if (components & VB_HAS_COL0 ) object.Write("lacc = %s0;\n", inColorName); else - object.Write("lacc = float4(0.0f, 0.0f, 0.0f, 0.0f);\n"); + // TODO: this isn't verified. Here we want to read the ambient from the vertex, + // but the vertex itself has no color. So we don't know which value to read. + // Returing 1.0 is the same as disabled lightning, so this could be fine + object.Write("lacc = float4(1.0f, 1.0f, 1.0f, 1.0f);\n"); } else // from color { @@ -191,7 +179,8 @@ static void GenerateLightingShader(T& object, LightingUidData& uid_data, int com else if (components & VB_HAS_COL0 ) object.Write("lacc.w = %s0.w;\n", inColorName); else - object.Write("lacc.w = 0.0f;\n"); + // TODO: The same for alpha: We want to read from vertex, but the vertex has no color + object.Write("lacc.w = 1.0f;\n"); } else // from color { diff --git a/Source/Core/VideoCommon/Src/PerfQueryBase.cpp b/Source/Core/VideoCommon/Src/PerfQueryBase.cpp index c537d176f6..af8bfa72e5 100644 --- a/Source/Core/VideoCommon/Src/PerfQueryBase.cpp +++ b/Source/Core/VideoCommon/Src/PerfQueryBase.cpp @@ -1,3 +1,9 @@ #include "PerfQueryBase.h" +#include "VideoConfig.h" PerfQueryBase* g_perf_query = 0; + +bool PerfQueryBase::ShouldEmulate() const +{ + return g_ActiveConfig.bPerfQueriesEnable; +} diff --git a/Source/Core/VideoCommon/Src/PerfQueryBase.h b/Source/Core/VideoCommon/Src/PerfQueryBase.h index b979449edb..bf5474b4db 100644 --- a/Source/Core/VideoCommon/Src/PerfQueryBase.h +++ b/Source/Core/VideoCommon/Src/PerfQueryBase.h @@ -25,9 +25,12 @@ enum PerfQueryGroup class PerfQueryBase { public: - PerfQueryBase() {}; + PerfQueryBase() {} virtual ~PerfQueryBase() {} + // Checks if performance queries are enabled in the gameini configuration. + bool ShouldEmulate() const; + // Begin querying the specified value for the following host GPU commands virtual void EnableQuery(PerfQueryGroup type) {} diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp index 9e831541bd..b4ad513d37 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp @@ -216,7 +216,7 @@ static char swapModeTable[4][5]; static char text[16384]; -static void BuildSwapModeTable() +static inline void BuildSwapModeTable() { static const char *swapColors = "rgba"; for (int i = 0; i < 4; i++) @@ -229,13 +229,13 @@ static void BuildSwapModeTable() } } -template<class T> static void WriteStage(T& out, pixel_shader_uid_data& uid_data, int n, API_TYPE ApiType, RegisterState RegisterStates[4]); -template<class T> static void SampleTexture(T& out, const char *destination, const char *texcoords, const char *texswap, int texmap, API_TYPE ApiType); -template<class T> static void WriteAlphaTest(T& out, pixel_shader_uid_data& uid_data, API_TYPE ApiType,DSTALPHA_MODE dstAlphaMode, bool per_pixel_depth); -template<class T> static void WriteFog(T& out, pixel_shader_uid_data& uid_data); +template<class T> static inline void WriteStage(T& out, pixel_shader_uid_data& uid_data, int n, API_TYPE ApiType, RegisterState RegisterStates[4]); +template<class T> static inline void SampleTexture(T& out, const char *texcoords, const char *texswap, int texmap, API_TYPE ApiType); +template<class T> static inline void WriteAlphaTest(T& out, pixel_shader_uid_data& uid_data, API_TYPE ApiType,DSTALPHA_MODE dstAlphaMode, bool per_pixel_depth); +template<class T> static inline void WriteFog(T& out, pixel_shader_uid_data& uid_data); template<class T> -static void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType, u32 components) +static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType, u32 components) { // Non-uid template parameters will write to the dummy data (=> gets optimized out) pixel_shader_uid_data dummy_data; @@ -243,23 +243,25 @@ static void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_TYPE Api ? out.template GetUidData<pixel_shader_uid_data>() : dummy_data; out.SetBuffer(text); + const bool is_writing_shadercode = (out.GetBuffer() != NULL); #ifndef ANDROID locale_t locale; locale_t old_locale; - if (out.GetBuffer() != NULL) + if (is_writing_shadercode) { locale = newlocale(LC_NUMERIC_MASK, "C", NULL); // New locale for compilation old_locale = uselocale(locale); // Apply the locale for this thread } #endif - text[sizeof(text) - 1] = 0x7C; // canary + if (is_writing_shadercode) + text[sizeof(text) - 1] = 0x7C; // canary unsigned int numStages = bpmem.genMode.numtevstages + 1; unsigned int numTexgen = bpmem.genMode.numtexgens; - const bool forced_early_z = g_ActiveConfig.backend_info.bSupportsEarlyZ && bpmem.zcontrol.early_ztest && (g_ActiveConfig.bFastDepthCalc || bpmem.alpha_test.TestResult() == AlphaTest::UNDETERMINED); - const bool per_pixel_depth = (bpmem.ztex2.op != ZTEXTURE_DISABLE && !bpmem.zcontrol.early_ztest && bpmem.zmode.testenable) || (!g_ActiveConfig.bFastDepthCalc && !forced_early_z); + const bool forced_early_z = g_ActiveConfig.backend_info.bSupportsEarlyZ && bpmem.UseEarlyDepthTest() && (g_ActiveConfig.bFastDepthCalc || bpmem.alpha_test.TestResult() == AlphaTest::UNDETERMINED); + const bool per_pixel_depth = (bpmem.ztex2.op != ZTEXTURE_DISABLE && bpmem.UseLateDepthTest()) || (!g_ActiveConfig.bFastDepthCalc && bpmem.zmode.testenable && !forced_early_z); out.Write("//Pixel Shader for TEV stages\n"); out.Write("//%i TEV stages, %i texgens, %i IND stages\n", @@ -331,7 +333,7 @@ static void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_TYPE Api out.Write("VARYIN float4 colors_02;\n"); out.Write("VARYIN float4 colors_12;\n"); - + // compute window position if needed because binding semantic WPOS is not widely supported // Let's set up attributes if (xfregs.numTexGen.numTexGens < 7) @@ -365,18 +367,37 @@ static void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_TYPE Api } out.Write("float4 clipPos;\n"); } - + if (forced_early_z) { // HACK: This doesn't force the driver to write to depth buffer if alpha test fails. // It just allows it, but it seems that all drivers do. out.Write("layout(early_fragment_tests) in;\n"); } - + else if (bpmem.UseEarlyDepthTest() && (g_ActiveConfig.bFastDepthCalc || bpmem.alpha_test.TestResult() == AlphaTest::UNDETERMINED) && is_writing_shadercode) + { + static bool warn_once = true; + if (warn_once) + WARN_LOG(VIDEO, "Early z test enabled but not possible to emulate with current configuration. Make sure to use the D3D11 or OpenGL backend and enable fast depth calculations. If this message still shows up your hardware isn't able to emulate the feature properly (a GPU which supports D3D 11.0 / OGL 4.2 is required)."); + warn_once = false; + } + out.Write("void main()\n{\n"); } else { + if (forced_early_z) + { + out.Write("[earlydepthstencil]\n"); + } + else if (bpmem.UseEarlyDepthTest() && (g_ActiveConfig.bFastDepthCalc || bpmem.alpha_test.TestResult() == AlphaTest::UNDETERMINED) && is_writing_shadercode) + { + static bool warn_once = true; + if (warn_once) + WARN_LOG(VIDEO, "Early z test enabled but not possible to emulate with current configuration. Make sure to use the D3D11 or OpenGL backend and enable fast depth calculations. If this message still shows up your hardware isn't able to emulate the feature properly (a GPU which supports D3D 11.0 / OGL 4.2 is required)."); + warn_once = false; + } + out.Write("void main(\n"); if(ApiType != API_D3D11) { @@ -481,7 +502,6 @@ static void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_TYPE Api if (g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) { - uid_data.xfregs_numTexGen_numTexGens = xfregs.numTexGen.numTexGens; if (xfregs.numTexGen.numTexGens < 7) { out.Write("\tfloat3 _norm0 = normalize(Normal.xyz);\n\n"); @@ -558,9 +578,8 @@ static void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_TYPE Api else out.Write("\ttempcoord = float2(0.0f, 0.0f);\n"); - char buffer[32]; - sprintf(buffer, "float3 indtex%d", i); - SampleTexture<T>(out, buffer, "tempcoord", "abg", texmap, ApiType); + out.Write("float3 indtex%d = ", i); + SampleTexture<T>(out, "tempcoord", "abg", texmap, ApiType); } } @@ -608,7 +627,10 @@ static void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_TYPE Api AlphaTest::TEST_RESULT Pretest = bpmem.alpha_test.TestResult(); uid_data.Pretest = Pretest; - if (Pretest == AlphaTest::UNDETERMINED) + + // NOTE: Fragment may not be discarded if alpha test always fails and early depth test is enabled + // (in this case we need to write a depth value if depth test passes regardless of the alpha testing result) + if (Pretest == AlphaTest::UNDETERMINED || (Pretest == AlphaTest::FAIL && bpmem.UseLateDepthTest())) WriteAlphaTest<T>(out, uid_data, ApiType, dstAlphaMode, per_pixel_depth); @@ -631,11 +653,11 @@ static void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_TYPE Api uid_data.per_pixel_depth = per_pixel_depth; uid_data.forced_early_z = forced_early_z; uid_data.fast_depth_calc = g_ActiveConfig.bFastDepthCalc; - uid_data.early_ztest = bpmem.zcontrol.early_ztest; + uid_data.early_ztest = bpmem.UseEarlyDepthTest(); uid_data.fog_fsel = bpmem.fog.c_proj_fsel.fsel; // Note: z-textures are not written to depth buffer if early depth test is used - if (per_pixel_depth && bpmem.zcontrol.early_ztest) + if (per_pixel_depth && bpmem.UseEarlyDepthTest()) out.Write("depth = zCoord;\n"); // Note: depth texture output is only written to depth buffer if late depth test is used @@ -653,7 +675,7 @@ static void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_TYPE Api out.Write("zCoord = zCoord * (16777216.0f/16777215.0f);\n"); } - if (per_pixel_depth && !bpmem.zcontrol.early_ztest) + if (per_pixel_depth && bpmem.UseLateDepthTest()) out.Write("depth = zCoord;\n"); if (dstAlphaMode == DSTALPHA_ALPHA_PASS) @@ -688,16 +710,16 @@ static void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_TYPE Api out.Write("}\n"); - if (text[sizeof(text) - 1] != 0x7C) - PanicAlert("PixelShader generator - buffer too small, canary has been eaten!"); + if (is_writing_shadercode) + { + if (text[sizeof(text) - 1] != 0x7C) + PanicAlert("PixelShader generator - buffer too small, canary has been eaten!"); #ifndef ANDROID - if (out.GetBuffer() != NULL) - { uselocale(old_locale); // restore locale freelocale(locale); - } #endif + } } @@ -745,7 +767,7 @@ static const char *TEVCMPAlphaOPTable[16] = }; template<class T> -static void WriteStage(T& out, pixel_shader_uid_data& uid_data, int n, API_TYPE ApiType, RegisterState RegisterStates[4]) +static inline void WriteStage(T& out, pixel_shader_uid_data& uid_data, int n, API_TYPE ApiType, RegisterState RegisterStates[4]) { int texcoord = bpmem.tevorders[n/2].getTexCoord(n&1); bool bHasTexCoord = (u32)texcoord < bpmem.genMode.numtexgens; @@ -888,7 +910,9 @@ static void WriteStage(T& out, pixel_shader_uid_data& uid_data, int n, API_TYPE char *texswap = swapModeTable[bpmem.combiners[n].alphaC.tswap]; int texmap = bpmem.tevorders[n/2].getTexMap(n&1); uid_data.SetTevindrefTexmap(i, texmap); - SampleTexture<T>(out, "textemp", "tevcoord", texswap, texmap, ApiType); + + out.Write("textemp = "); + SampleTexture<T>(out, "tevcoord", texswap, texmap, ApiType); } else { @@ -1110,13 +1134,14 @@ static void WriteStage(T& out, pixel_shader_uid_data& uid_data, int n, API_TYPE } template<class T> -void SampleTexture(T& out, const char *destination, const char *texcoords, const char *texswap, int texmap, API_TYPE ApiType) +void SampleTexture(T& out, const char *texcoords, const char *texswap, int texmap, API_TYPE ApiType) { out.SetConstantsUsed(C_TEXDIMS+texmap,C_TEXDIMS+texmap); + if (ApiType == API_D3D11) - out.Write("%s=Tex%d.Sample(samp%d,%s.xy * " I_TEXDIMS"[%d].xy).%s;\n", destination, texmap,texmap, texcoords, texmap, texswap); + out.Write("Tex%d.Sample(samp%d,%s.xy * " I_TEXDIMS"[%d].xy).%s;\n", texmap,texmap, texcoords, texmap, texswap); else - out.Write("%s=%s(samp%d,%s.xy * " I_TEXDIMS"[%d].xy).%s;\n", destination, ApiType == API_OPENGL ? "texture" : "tex2D", texmap, texcoords, texmap, texswap); + out.Write("%s(samp%d,%s.xy * " I_TEXDIMS"[%d].xy).%s;\n", ApiType == API_OPENGL ? "texture" : "tex2D", texmap, texcoords, texmap, texswap); } static const char *tevAlphaFuncsTable[] = @@ -1140,7 +1165,7 @@ static const char *tevAlphaFunclogicTable[] = }; template<class T> -static void WriteAlphaTest(T& out, pixel_shader_uid_data& uid_data, API_TYPE ApiType, DSTALPHA_MODE dstAlphaMode, bool per_pixel_depth) +static inline void WriteAlphaTest(T& out, pixel_shader_uid_data& uid_data, API_TYPE ApiType, DSTALPHA_MODE dstAlphaMode, bool per_pixel_depth) { static const char *alphaRef[2] = { @@ -1183,11 +1208,11 @@ static void WriteAlphaTest(T& out, pixel_shader_uid_data& uid_data, API_TYPE Api // We implement "depth test before texturing" by disabling alpha test when early-z is in use. // It seems to be less buggy than not to update the depth buffer if alpha test fails, // but both ways wouldn't be accurate. - + // OpenGL 4.2 has a flag which allows the driver to still update the depth buffer // if alpha test fails. The driver doesn't have to, but I assume they all do because // it's the much faster code path for the GPU. - uid_data.alpha_test_use_zcomploc_hack = bpmem.zcontrol.early_ztest && bpmem.zmode.updateenable && !g_ActiveConfig.backend_info.bSupportsEarlyZ; + uid_data.alpha_test_use_zcomploc_hack = bpmem.UseEarlyDepthTest() && bpmem.zmode.updateenable && !g_ActiveConfig.backend_info.bSupportsEarlyZ; if (!uid_data.alpha_test_use_zcomploc_hack) { out.Write("\t\tdiscard;\n"); @@ -1211,7 +1236,7 @@ static const char *tevFogFuncsTable[] = }; template<class T> -static void WriteFog(T& out, pixel_shader_uid_data& uid_data) +static inline void WriteFog(T& out, pixel_shader_uid_data& uid_data) { uid_data.fog_fsel = bpmem.fog.c_proj_fsel.fsel; if(bpmem.fog.c_proj_fsel.fsel == 0) @@ -1253,7 +1278,7 @@ static void WriteFog(T& out, pixel_shader_uid_data& uid_data) } else { - if (bpmem.fog.c_proj_fsel.fsel != 2) + if (bpmem.fog.c_proj_fsel.fsel != 2 && out.GetBuffer() != NULL) WARN_LOG(VIDEO, "Unknown Fog Type! %08x", bpmem.fog.c_proj_fsel.fsel); } diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.h b/Source/Core/VideoCommon/Src/PixelShaderGen.h index c1ca009438..7763cbd574 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderGen.h +++ b/Source/Core/VideoCommon/Src/PixelShaderGen.h @@ -63,18 +63,30 @@ struct pixel_shader_uid_data u32 num_values; // TODO: Shouldn't be a u32 u32 NumValues() const { return num_values; } - u32 components; + u32 components : 23; u32 dstAlphaMode : 2; u32 Pretest : 2; + u32 nIndirectStagesUsed : 4; + u32 pad0 : 1; u32 genMode_numtexgens : 4; u32 genMode_numtevstages : 4; u32 genMode_numindstages : 3; - - u32 nIndirectStagesUsed : 8; + u32 alpha_test_comp0 : 3; + u32 alpha_test_comp1 : 3; + u32 alpha_test_logic : 2; + u32 alpha_test_use_zcomploc_hack : 1; + u32 fog_proj : 1; + u32 fog_fsel : 3; + u32 fog_RangeBaseEnabled : 1; + u32 ztex_op : 2; + u32 fast_depth_calc : 1; + u32 per_pixel_depth : 1; + u32 forced_early_z : 1; + u32 early_ztest : 1; + u32 pad1 : 1; u32 texMtxInfo_n_projection : 8; // 8x1 bit - u32 tevindref_bi0 : 3; u32 tevindref_bc0 : 3; u32 tevindref_bi1 : 3; @@ -83,6 +95,7 @@ struct pixel_shader_uid_data u32 tevindref_bc3 : 3; u32 tevindref_bi4 : 3; u32 tevindref_bc4 : 3; + inline void SetTevindrefValues(int index, u32 texcoord, u32 texmap) { if (index == 0) { tevindref_bc0 = texcoord; tevindref_bi0 = texmap; } @@ -98,25 +111,6 @@ struct pixel_shader_uid_data else if (index == 3) { tevindref_bi4 = texmap; } } - u32 alpha_test_comp0 : 3; - u32 alpha_test_comp1 : 3; - u32 alpha_test_logic : 2; - - u32 alpha_test_use_zcomploc_hack : 1; - - u32 fog_proj : 1; - u32 fog_fsel : 3; - u32 fog_RangeBaseEnabled : 1; - - u32 ztex_op : 2; - - u32 fast_depth_calc : 1; - u32 per_pixel_depth : 1; - u32 forced_early_z : 1; - u32 early_ztest : 1; - - u32 xfregs_numTexGen_numTexGens : 4; - struct { // TODO: Can save a lot space by removing the padding bits u32 cc : 24; diff --git a/Source/Core/VideoCommon/Src/RenderBase.cpp b/Source/Core/VideoCommon/Src/RenderBase.cpp index f514af0422..e4e330d6f5 100644 --- a/Source/Core/VideoCommon/Src/RenderBase.cpp +++ b/Source/Core/VideoCommon/Src/RenderBase.cpp @@ -254,9 +254,6 @@ void Renderer::SetScreenshot(const char *filename) // Create On-Screen-Messages void Renderer::DrawDebugText() { - if (!g_Config.bOSDHotKey) - return; - // OSD Menu messages if (OSDChoice > 0) { diff --git a/Source/Core/VideoCommon/Src/ShaderGenCommon.h b/Source/Core/VideoCommon/Src/ShaderGenCommon.h index ec4fe27416..a804c08f13 100644 --- a/Source/Core/VideoCommon/Src/ShaderGenCommon.h +++ b/Source/Core/VideoCommon/Src/ShaderGenCommon.h @@ -173,7 +173,7 @@ private: }; template<class T> -static void WriteRegister(T& object, API_TYPE ApiType, const char *prefix, const u32 num) +static inline void WriteRegister(T& object, API_TYPE ApiType, const char *prefix, const u32 num) { if (ApiType == API_OPENGL) return; // Nothing to do here @@ -182,7 +182,7 @@ static void WriteRegister(T& object, API_TYPE ApiType, const char *prefix, const } template<class T> -static void WriteLocation(T& object, API_TYPE ApiType, bool using_ubos) +static inline void WriteLocation(T& object, API_TYPE ApiType, bool using_ubos) { if (using_ubos) return; @@ -191,7 +191,7 @@ static void WriteLocation(T& object, API_TYPE ApiType, bool using_ubos) } template<class T> -static void DeclareUniform(T& object, API_TYPE api_type, bool using_ubos, const u32 num, const char* type, const char* name) +static inline void DeclareUniform(T& object, API_TYPE api_type, bool using_ubos, const u32 num, const char* type, const char* name) { WriteLocation(object, api_type, using_ubos); object.Write("%s %s ", type, name); diff --git a/Source/Core/VideoCommon/Src/VertexShaderGen.cpp b/Source/Core/VideoCommon/Src/VertexShaderGen.cpp index a682b4ea21..ad090fb839 100644 --- a/Source/Core/VideoCommon/Src/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/VertexShaderGen.cpp @@ -38,7 +38,7 @@ static void DefineVSOutputStructMember(T& object, API_TYPE api_type, const char* } template<class T> -static void GenerateVSOutputStruct(T& object, u32 components, API_TYPE api_type) +static inline void GenerateVSOutputStruct(T& object, u32 components, API_TYPE api_type) { object.Write("struct VS_OUTPUT {\n"); DefineVSOutputStructMember(object, api_type, "float4", "pos", -1, "POSITION"); @@ -67,7 +67,7 @@ static void GenerateVSOutputStruct(T& object, u32 components, API_TYPE api_type) } template<class T> -static void GenerateVertexShader(T& out, u32 components, API_TYPE api_type) +static inline void GenerateVertexShader(T& out, u32 components, API_TYPE api_type) { // Non-uid template parameters will write to the dummy data (=> gets optimized out) vertex_shader_uid_data dummy_data; @@ -75,22 +75,23 @@ static void GenerateVertexShader(T& out, u32 components, API_TYPE api_type) ? out.template GetUidData<vertex_shader_uid_data>() : dummy_data; out.SetBuffer(text); + const bool is_writing_shadercode = (out.GetBuffer() != NULL); #ifndef ANDROID locale_t locale; locale_t old_locale; - if (out.GetBuffer() != NULL) + if (is_writing_shadercode) { locale = newlocale(LC_NUMERIC_MASK, "C", NULL); // New locale for compilation old_locale = uselocale(locale); // Apply the locale for this thread } #endif - text[sizeof(text) - 1] = 0x7C; // canary + + if (is_writing_shadercode) + 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); - // uniforms if (g_ActiveConfig.backend_info.bSupportsGLSLUBO) out.Write("layout(std140) uniform VSBlock {\n"); @@ -174,19 +175,9 @@ static void GenerateVertexShader(T& out, u32 components, API_TYPE api_type) if (components & VB_HAS_NRM0) out.Write(" float3 rawnorm0 : NORMAL0,\n"); if (components & VB_HAS_NRM1) - { - if (is_d3d) - out.Write(" float3 rawnorm1 : NORMAL1,\n"); - else - out.Write(" float3 rawnorm1 : ATTR%d,\n", SHADER_NORM1_ATTRIB); - } + out.Write(" float3 rawnorm1 : NORMAL1,\n"); if (components & VB_HAS_NRM2) - { - if (is_d3d) - out.Write(" float3 rawnorm2 : NORMAL2,\n"); - else - out.Write(" float3 rawnorm2 : ATTR%d,\n", SHADER_NORM2_ATTRIB); - } + out.Write(" float3 rawnorm2 : NORMAL2,\n"); if (components & VB_HAS_COL0) out.Write(" float4 color0 : COLOR0,\n"); if (components & VB_HAS_COL1) @@ -198,12 +189,7 @@ static void GenerateVertexShader(T& out, u32 components, API_TYPE api_type) out.Write(" float%d tex%d : TEXCOORD%d,\n", hastexmtx ? 3 : 2, i, i); } if (components & VB_HAS_POSMTXIDX) - { - if (is_d3d) - out.Write(" float4 blend_indices : BLENDINDICES,\n"); - else - out.Write(" float fposmtx : ATTR%d,\n", SHADER_POSMTX_ATTRIB); - } + out.Write(" float4 blend_indices : BLENDINDICES,\n"); out.Write(" float4 rawpos : POSITION) {\n"); } out.Write("VS_OUTPUT o;\n"); @@ -225,7 +211,7 @@ static void GenerateVertexShader(T& out, u32 components, API_TYPE api_type) out.Write("int posmtx = int(fposmtx);\n"); } - if (DriverDetails::HasBug(DriverDetails::BUG_NODYNUBOACCESS)) + if (is_writing_shadercode && DriverDetails::HasBug(DriverDetails::BUG_NODYNUBOACCESS)) { // This'll cause issues, but it can't be helped out.Write("float4 pos = float4(dot(" I_TRANSFORMMATRICES"[0], rawpos), dot(" I_TRANSFORMMATRICES"[1], rawpos), dot(" I_TRANSFORMMATRICES"[2], rawpos), 1);\n"); @@ -353,7 +339,7 @@ static void GenerateVertexShader(T& out, u32 components, API_TYPE api_type) // transform the light dir into tangent space uid_data.texMtxInfo[i].embosslightshift = xfregs.texMtxInfo[i].embosslightshift; uid_data.texMtxInfo[i].embosssourceshift = xfregs.texMtxInfo[i].embosssourceshift; - out.Write("ldir = normalize(%s.xyz - pos.xyz);\n", LightPos(I_LIGHTS, texinfo.embosslightshift)); + out.Write("ldir = normalize(" LIGHT_POS".xyz - pos.xyz);\n", LIGHT_POS_PARAMS(I_LIGHTS, texinfo.embosslightshift)); out.Write("o.tex%d.xyz = o.tex%d.xyz + float3(dot(ldir, _norm1), dot(ldir, _norm2), 0.0f);\n", i, texinfo.embosssourceshift); } else @@ -468,7 +454,7 @@ static void GenerateVertexShader(T& out, u32 components, API_TYPE api_type) //write the true depth value, if the game uses depth textures pixel shaders will override with the correct values //if not early z culling will improve speed - if (is_d3d) + if (api_type & API_D3D9 || api_type == API_D3D11) { out.Write("o.pos.z = " I_DEPTHPARAMS".x * o.pos.w + o.pos.z * " I_DEPTHPARAMS".y;\n"); } @@ -547,16 +533,16 @@ static void GenerateVertexShader(T& out, u32 components, API_TYPE api_type) out.Write("return o;\n}\n"); } - if (text[sizeof(text) - 1] != 0x7C) - PanicAlert("VertexShader generator - buffer too small, canary has been eaten!"); + if (is_writing_shadercode) + { + if (text[sizeof(text) - 1] != 0x7C) + PanicAlert("VertexShader generator - buffer too small, canary has been eaten!"); #ifndef ANDROID - if (out.GetBuffer() != NULL) - { uselocale(old_locale); // restore locale freelocale(locale); - } #endif + } } void GetVertexShaderUid(VertexShaderUid& object, u32 components, API_TYPE api_type) diff --git a/Source/Core/VideoCommon/Src/VertexShaderGen.h b/Source/Core/VideoCommon/Src/VertexShaderGen.h index eef0646e6f..ab9a378107 100644 --- a/Source/Core/VideoCommon/Src/VertexShaderGen.h +++ b/Source/Core/VideoCommon/Src/VertexShaderGen.h @@ -69,12 +69,12 @@ struct vertex_shader_uid_data { u32 NumValues() const { return sizeof(vertex_shader_uid_data); } - u32 components; - u32 numColorChans : 2; + u32 components : 23; u32 numTexGens : 4; - + u32 numColorChans : 2; u32 dualTexTrans_enabled : 1; u32 pixel_lighting : 1; + u32 pad0 : 1; u32 texMtxInfo_n_projection : 16; // Stored separately to guarantee that the texMtxInfo struct is 8 bits wide struct { diff --git a/Source/Core/VideoCommon/Src/VideoBackendBase.cpp b/Source/Core/VideoCommon/Src/VideoBackendBase.cpp new file mode 100644 index 0000000000..4769ede3a0 --- /dev/null +++ b/Source/Core/VideoCommon/Src/VideoBackendBase.cpp @@ -0,0 +1,82 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "VideoBackendBase.h" + +// TODO: ugly +#ifdef _WIN32 +#include "../../../Plugins/Plugin_VideoDX9/Src/VideoBackend.h" +#include "../../../Plugins/Plugin_VideoDX11/Src/VideoBackend.h" +#endif +#if !defined(USE_GLES) || USE_GLES3 +#include "../../../Plugins/Plugin_VideoOGL/Src/VideoBackend.h" +#endif +#include "../../../Plugins/Plugin_VideoSoftware/Src/VideoBackend.h" + +std::vector<VideoBackend*> g_available_video_backends; +VideoBackend* g_video_backend = NULL; +static VideoBackend* s_default_backend = NULL; + +#ifdef _WIN32 +#include <windows.h> + +// http://msdn.microsoft.com/en-us/library/ms725491.aspx +static bool IsGteVista() +{ + OSVERSIONINFOEX osvi; + DWORDLONG dwlConditionMask = 0; + + ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + osvi.dwMajorVersion = 6; + + VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL); + + return VerifyVersionInfo(&osvi, VER_MAJORVERSION, dwlConditionMask) != FALSE; +} +#endif + +void VideoBackend::PopulateList() +{ + VideoBackend* backends[4] = { NULL }; + + // D3D11 > OGL > D3D9 > SW +#ifdef _WIN32 + g_available_video_backends.push_back(backends[2] = new DX9::VideoBackend); + if (IsGteVista()) + g_available_video_backends.push_back(backends[0] = new DX11::VideoBackend); +#endif +#if !defined(USE_GLES) || USE_GLES3 + g_available_video_backends.push_back(backends[1] = new OGL::VideoBackend); +#endif + g_available_video_backends.push_back(backends[3] = new SW::VideoSoftware); + + for (int i = 0; i < 4; ++i) + { + if (backends[i]) + { + s_default_backend = g_video_backend = backends[i]; + break; + } + } +} + +void VideoBackend::ClearList() +{ + while (!g_available_video_backends.empty()) + { + delete g_available_video_backends.back(); + g_available_video_backends.pop_back(); + } +} + +void VideoBackend::ActivateBackend(const std::string& name) +{ + if (name.length() == 0) // If NULL, set it to the default backend (expected behavior) + g_video_backend = s_default_backend; + + for (std::vector<VideoBackend*>::const_iterator it = g_available_video_backends.begin(); it != g_available_video_backends.end(); ++it) + if (name == (*it)->GetName()) + g_video_backend = *it; +} diff --git a/Source/Core/VideoCommon/Src/VideoBackendBase.h b/Source/Core/VideoCommon/Src/VideoBackendBase.h new file mode 100644 index 0000000000..9c591d05a5 --- /dev/null +++ b/Source/Core/VideoCommon/Src/VideoBackendBase.h @@ -0,0 +1,185 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#ifndef VIDEO_BACKEND_H_ +#define VIDEO_BACKEND_H_ + +#include <string> +#include <vector> + +#include "ChunkFile.h" +#include "../../VideoCommon/Src/PerfQueryBase.h" + +typedef void (*writeFn16)(const u16,const u32); +typedef void (*writeFn32)(const u32,const u32); +typedef void (*readFn16)(u16&, const u32); + + +enum FieldType +{ + FIELD_PROGRESSIVE = 0, + FIELD_UPPER, + FIELD_LOWER +}; + +enum EFBAccessType +{ + PEEK_Z = 0, + POKE_Z, + PEEK_COLOR, + POKE_COLOR +}; + +struct SCPFifoStruct +{ + // fifo registers + volatile u32 CPBase; + volatile u32 CPEnd; + u32 CPHiWatermark; + u32 CPLoWatermark; + volatile u32 CPReadWriteDistance; + volatile u32 CPWritePointer; + volatile u32 CPReadPointer; + volatile u32 CPBreakpoint; + volatile u32 SafeCPReadPointer; + // Super Monkey Ball Adventure require this. + // Because the read&check-PEToken-loop stays in its JITed block I suppose. + // So no possiblity to ack the Token irq by the scheduler until some sort of PPC watchdog do its mess. + volatile u16 PEToken; + + volatile u32 bFF_GPLinkEnable; + volatile u32 bFF_GPReadEnable; + volatile u32 bFF_BPEnable; + volatile u32 bFF_BPInt; + volatile u32 bFF_Breakpoint; + + volatile u32 CPCmdIdle; + volatile u32 CPReadIdle; + + volatile u32 bFF_LoWatermarkInt; + volatile u32 bFF_HiWatermarkInt; + + volatile u32 bFF_LoWatermark; + volatile u32 bFF_HiWatermark; + + // for GP watchdog hack + volatile u32 Fake_GPWDToken; // cicular incrementer + volatile u32 isGpuReadingData; +}; + +class VideoBackend +{ +public: + virtual ~VideoBackend() {} + + virtual void EmuStateChange(EMUSTATE_CHANGE) = 0; + + virtual void UpdateFPSDisplay(const char*) = 0; + + virtual unsigned int PeekMessages() = 0; + + virtual bool Initialize(void *&) = 0; + virtual void Shutdown() = 0; + virtual void RunLoop(bool enable) = 0; + + virtual std::string GetName() = 0; + virtual std::string GetDisplayName() { return GetName(); } + + virtual void ShowConfig(void*) {} + + virtual void Video_Prepare() = 0; + virtual void Video_EnterLoop() = 0; + virtual void Video_ExitLoop() = 0; + virtual void Video_Cleanup() = 0; // called from gl/d3d thread + + virtual void Video_BeginField(u32, FieldType, u32, u32) = 0; + virtual void Video_EndField() = 0; + + virtual u32 Video_AccessEFB(EFBAccessType, u32, u32, u32) = 0; + virtual u32 Video_GetQueryResult(PerfQueryType type) = 0; + + virtual void Video_AddMessage(const char* pstr, unsigned int milliseconds) = 0; + virtual void Video_ClearMessages() = 0; + virtual bool Video_Screenshot(const char* filename) = 0; + + virtual void Video_SetRendering(bool bEnabled) = 0; + + virtual void Video_GatherPipeBursted() = 0; + + virtual bool Video_IsPossibleWaitingSetDrawDone() = 0; + virtual bool Video_IsHiWatermarkActive() = 0; + virtual void Video_AbortFrame() = 0; + + virtual readFn16 Video_CPRead16() = 0; + virtual writeFn16 Video_CPWrite16() = 0; + virtual readFn16 Video_PERead16() = 0; + virtual writeFn16 Video_PEWrite16() = 0; + virtual writeFn32 Video_PEWrite32() = 0; + + static void PopulateList(); + static void ClearList(); + static void ActivateBackend(const std::string& name); + + // waits until is paused and fully idle, and acquires a lock on that state. + // or, if doLock is false, releases a lock on that state and optionally unpauses. + // calls must be balanced and non-recursive (once with doLock true, then once with doLock false). + virtual void PauseAndLock(bool doLock, bool unpauseOnUnlock=true) = 0; + + // the implementation needs not do synchronization logic, because calls to it are surrounded by PauseAndLock now + virtual void DoState(PointerWrap &p) = 0; + + virtual void CheckInvalidState() = 0; +}; + +extern std::vector<VideoBackend*> g_available_video_backends; +extern VideoBackend* g_video_backend; + +// inherited by dx9/dx11/ogl backends +class VideoBackendHardware : public VideoBackend +{ + void RunLoop(bool enable); + bool Initialize(void *&) { InitializeShared(); return true; } + + void EmuStateChange(EMUSTATE_CHANGE); + + void Video_EnterLoop(); + void Video_ExitLoop(); + void Video_BeginField(u32, FieldType, u32, u32); + void Video_EndField(); + + u32 Video_AccessEFB(EFBAccessType, u32, u32, u32); + u32 Video_GetQueryResult(PerfQueryType type); + + void Video_AddMessage(const char* pstr, unsigned int milliseconds); + void Video_ClearMessages(); + bool Video_Screenshot(const char* filename); + + void Video_SetRendering(bool bEnabled); + + void Video_GatherPipeBursted(); + + bool Video_IsPossibleWaitingSetDrawDone(); + bool Video_IsHiWatermarkActive(); + void Video_AbortFrame(); + + readFn16 Video_CPRead16(); + writeFn16 Video_CPWrite16(); + readFn16 Video_PERead16(); + writeFn16 Video_PEWrite16(); + writeFn32 Video_PEWrite32(); + + void PauseAndLock(bool doLock, bool unpauseOnUnlock=true); + void DoState(PointerWrap &p); + + bool m_invalid; + +public: + void CheckInvalidState(); + +protected: + void InitializeShared(); + void InvalidState(); +}; + +#endif diff --git a/Source/Core/VideoCommon/Src/VideoConfig.cpp b/Source/Core/VideoCommon/Src/VideoConfig.cpp index 7827c0008a..6b6c796015 100644 --- a/Source/Core/VideoCommon/Src/VideoConfig.cpp +++ b/Source/Core/VideoCommon/Src/VideoConfig.cpp @@ -11,6 +11,7 @@ #include "FileUtil.h" #include "Core.h" #include "Movie.h" +#include "OnScreenDisplay.h" VideoConfig g_Config; VideoConfig g_ActiveConfig; @@ -92,7 +93,6 @@ void VideoConfig::Load(const char *ini_file) iniFile.Get("Hacks", "EFBAccessEnable", &bEFBAccessEnable, true); iniFile.Get("Hacks", "DlistCachingEnable", &bDlistCachingEnable,false); iniFile.Get("Hacks", "EFBCopyEnable", &bEFBCopyEnable, true); - iniFile.Get("Hacks", "EFBCopyDisableHotKey", &bOSDHotKey, 0); iniFile.Get("Hacks", "EFBToTextureEnable", &bCopyEFBToTexture, true); iniFile.Get("Hacks", "EFBScaledCopy", &bCopyEFBScaled, true); iniFile.Get("Hacks", "EFBCopyCacheEnable", &bEFBCopyCacheEnable, false); @@ -105,6 +105,18 @@ void VideoConfig::Load(const char *ini_file) bool bTmp; iniFile.Get("Interface", "UsePanicHandlers", &bTmp, true); SetEnableAlert(bTmp); + + // Shader Debugging causes a huge slowdown and it's easy to forget about it + // since it's not exposed in the settings dialog. It's only used by + // developers, so displaying an obnoxious message avoids some confusion and + // is not too annoying/confusing for users. + // + // XXX(delroth): This is kind of a bad place to put this, but the current + // VideoCommon is a mess and we don't have a central initialization + // function to do these kind of checks. Instead, the init code is + // triplicated for each video backend. + if (bEnableShaderDebugging) + OSD::AddMessage("Warning: Shader Debugging is enabled, performance will suffer heavily", 15000); } void VideoConfig::GameIniLoad(const char *ini_file) @@ -182,6 +194,7 @@ void VideoConfig::GameIniLoad(const char *ini_file) iniFile.GetIfExists("Video", "PH_ZFar", &sPhackvalue[1]); iniFile.GetIfExists("Video", "ZTPSpeedupHack", &bZTPSpeedHack); iniFile.GetIfExists("Video", "UseBBox", &bUseBBox); + iniFile.GetIfExists("Video", "PerfQueriesEnable", &bPerfQueriesEnable); } void VideoConfig::VerifyValidity() @@ -248,7 +261,6 @@ void VideoConfig::Save(const char *ini_file) iniFile.Set("Hacks", "EFBAccessEnable", bEFBAccessEnable); iniFile.Set("Hacks", "DlistCachingEnable", bDlistCachingEnable); iniFile.Set("Hacks", "EFBCopyEnable", bEFBCopyEnable); - iniFile.Set("Hacks", "EFBCopyDisableHotKey", bOSDHotKey); iniFile.Set("Hacks", "EFBToTextureEnable", bCopyEFBToTexture); iniFile.Set("Hacks", "EFBScaledCopy", bCopyEFBScaled); iniFile.Set("Hacks", "EFBCopyCacheEnable", bEFBCopyCacheEnable); diff --git a/Source/Core/VideoCommon/Src/VideoConfig.h b/Source/Core/VideoCommon/Src/VideoConfig.h index 741521c728..b856683595 100644 --- a/Source/Core/VideoCommon/Src/VideoConfig.h +++ b/Source/Core/VideoCommon/Src/VideoConfig.h @@ -108,11 +108,11 @@ struct VideoConfig // Hacks bool bEFBAccessEnable; bool bDlistCachingEnable; + bool bPerfQueriesEnable; bool bEFBCopyEnable; bool bEFBCopyCacheEnable; bool bEFBEmulateFormatChanges; - bool bOSDHotKey; bool bCopyEFBToTexture; bool bCopyEFBScaled; int iSafeTextureCache_ColorSamples; diff --git a/Source/Core/VideoCommon/Src/XFStructs.cpp b/Source/Core/VideoCommon/Src/XFStructs.cpp index 98bef38f00..a2f2097e07 100644 --- a/Source/Core/VideoCommon/Src/XFStructs.cpp +++ b/Source/Core/VideoCommon/Src/XFStructs.cpp @@ -172,7 +172,7 @@ void XFRegWritten(int transferSize, u32 baseAddress, u32 *pData) case 0x104d: case 0x104e: case 0x104f: - DEBUG_LOG(VIDEO, "Possible Normal Mtx XF reg?: %x=%x\n", address, newValue); + DEBUG_LOG(VIDEO, "Possible Normal Mtx XF reg?: %x=%x", address, newValue); break; case 0x1013: @@ -182,7 +182,7 @@ void XFRegWritten(int transferSize, u32 baseAddress, u32 *pData) case 0x1017: default: - WARN_LOG(VIDEO, "Unknown XF Reg: %x=%x\n", address, newValue); + WARN_LOG(VIDEO, "Unknown XF Reg: %x=%x", address, newValue); break; } @@ -199,7 +199,7 @@ void LoadXFReg(u32 transferSize, u32 baseAddress, u32 *pData) // do not allow writes past registers if (baseAddress + transferSize > 0x1058) { - INFO_LOG(VIDEO, "XF load exceeds address space: %x %d bytes\n", baseAddress, transferSize); + INFO_LOG(VIDEO, "XF load exceeds address space: %x %d bytes", baseAddress, transferSize); if (baseAddress >= 0x1058) transferSize = 0; diff --git a/Source/Core/VideoCommon/VideoCommon.vcxproj b/Source/Core/VideoCommon/VideoCommon.vcxproj index 1e7a56f578..c5896af1a6 100644 --- a/Source/Core/VideoCommon/VideoCommon.vcxproj +++ b/Source/Core/VideoCommon/VideoCommon.vcxproj @@ -213,6 +213,7 @@ <ClCompile Include="Src\VertexManagerBase.cpp" /> <ClCompile Include="Src\VertexShaderGen.cpp" /> <ClCompile Include="Src\VertexShaderManager.cpp" /> + <ClCompile Include="Src\VideoBackendBase.cpp" /> <ClCompile Include="Src\VideoConfig.cpp" /> <ClCompile Include="Src\VideoState.cpp" /> <ClCompile Include="Src\x64DLCache.cpp" /> @@ -266,6 +267,7 @@ <ClInclude Include="Src\VertexShaderGen.h" /> <ClInclude Include="Src\VertexShaderManager.h" /> <ClInclude Include="Src\VideoCommon.h" /> + <ClInclude Include="Src\VideoBackendBase.h" /> <ClInclude Include="Src\VideoConfig.h" /> <ClInclude Include="Src\VideoState.h" /> <ClInclude Include="Src\XFMemory.h" /> diff --git a/Source/Core/VideoCommon/VideoCommon.vcxproj.filters b/Source/Core/VideoCommon/VideoCommon.vcxproj.filters index 785e55877f..3f864b0e7e 100644 --- a/Source/Core/VideoCommon/VideoCommon.vcxproj.filters +++ b/Source/Core/VideoCommon/VideoCommon.vcxproj.filters @@ -4,6 +4,7 @@ <ClCompile Include="Src\CommandProcessor.cpp" /> <ClCompile Include="Src\memcpy_amd.cpp" /> <ClCompile Include="Src\PixelEngine.cpp" /> + <ClCompile Include="Src\VideoBackendBase.cpp" /> <ClCompile Include="Src\VideoConfig.cpp" /> <ClCompile Include="Src\VertexLoader.cpp"> <Filter>Vertex Loading</Filter> @@ -128,6 +129,7 @@ <ClInclude Include="Src\NativeVertexFormat.h" /> <ClInclude Include="Src\PixelEngine.h" /> <ClInclude Include="Src\VideoCommon.h" /> + <ClInclude Include="Src\VideoBackendBase.h" /> <ClInclude Include="Src\VideoConfig.h" /> <ClInclude Include="Src\DataReader.h"> <Filter>Vertex Loading</Filter> |
