diff --git a/CMakeLists.txt b/CMakeLists.txt index ce647f7040..0aec870bff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1291,8 +1291,6 @@ set(GPU_D3D9 GPU/Directx9/DepalettizeShaderDX9.h GPU/Directx9/DrawEngineDX9.cpp GPU/Directx9/DrawEngineDX9.h - GPU/Directx9/PixelShaderGeneratorDX9.cpp - GPU/Directx9/PixelShaderGeneratorDX9.h GPU/Directx9/FramebufferManagerDX9.cpp GPU/Directx9/FramebufferManagerDX9.h GPU/Directx9/GPU_DX9.cpp @@ -1306,8 +1304,10 @@ set(GPU_D3D9 GPU/Directx9/TextureCacheDX9.h GPU/Directx9/TextureScalerDX9.cpp GPU/Directx9/TextureScalerDX9.h - GPU/Directx9/VertexShaderGeneratorDX9.cpp - GPU/Directx9/VertexShaderGeneratorDX9.h + GPU/Directx9/FragmentShaderGeneratorHLSL.cpp + GPU/Directx9/FragmentShaderGeneratorHLSL.h + GPU/Directx9/VertexShaderGeneratorHLSL.cpp + GPU/Directx9/VertexShaderGeneratorHLSL.h ) set(GPU_D3D11 @@ -1315,8 +1315,6 @@ set(GPU_D3D11 GPU/D3D11/DepalettizeShaderD3D11.h GPU/D3D11/DrawEngineD3D11.cpp GPU/D3D11/DrawEngineD3D11.h - GPU/D3D11/FragmentShaderGeneratorD3D11.cpp - GPU/D3D11/FragmentShaderGeneratorD3D11.h GPU/D3D11/FramebufferManagerD3D11.cpp GPU/D3D11/FramebufferManagerD3D11.h GPU/D3D11/GPU_D3D11.cpp @@ -1332,8 +1330,6 @@ set(GPU_D3D11 GPU/D3D11/TextureCacheD3D11.h GPU/D3D11/TextureScalerD3D11.cpp GPU/D3D11/TextureScalerD3D11.h - GPU/D3D11/VertexShaderGeneratorD3D11.cpp - GPU/D3D11/VertexShaderGeneratorD3D11.h ) # We build Vulkan even on Apple to avoid annoying build differences. diff --git a/GPU/Common/ShaderCommon.h b/GPU/Common/ShaderCommon.h index 3280c765b6..a2a2823245 100644 --- a/GPU/Common/ShaderCommon.h +++ b/GPU/Common/ShaderCommon.h @@ -131,3 +131,21 @@ protected: struct TBuiltInResource; void init_resources(TBuiltInResource &Resources); + +enum DoLightComputation { + LIGHT_OFF, + LIGHT_SHADE, + LIGHT_FULL, +}; + +struct GLSLShaderCompat { + const char *varying; + const char *attribute; + const char *fragColor0; + const char *fragColor1; + const char *texture; + const char *texelFetch; + const char *lastFragData; + bool glslES30; + bool bitwiseOps; +}; diff --git a/GPU/Common/ShaderId.h b/GPU/Common/ShaderId.h index 3adc7f4c2b..60eba9e460 100644 --- a/GPU/Common/ShaderId.h +++ b/GPU/Common/ShaderId.h @@ -159,6 +159,8 @@ protected: void SetBit(int bit, bool value = true) { if (value) { d[bit >> 5] |= 1 << (bit & 31); + } else { + d[bit >> 5] &= ~(1 << (bit & 31)); } } void SetBits(int bit, int count, int value) { diff --git a/GPU/Common/ShaderUniforms.h b/GPU/Common/ShaderUniforms.h index 5915297818..5acf973588 100644 --- a/GPU/Common/ShaderUniforms.h +++ b/GPU/Common/ShaderUniforms.h @@ -46,30 +46,30 @@ struct UB_VS_FS_Base { }; static const char *ub_baseStr = -R"( mat4 proj_mtx; - mat4 proj_through_mtx; - mat3x4 view_mtx; - mat3x4 world_mtx; - mat3x4 tex_mtx; - vec4 uvscaleoffset; - vec4 depthRange; - vec2 fogcoef; - float stencilReplace; - vec4 matambientalpha; - uint spline_counts; - uint depal_mask_shift_off_fmt; - int pad2; - int pad3; - vec4 cullRangeMin; - vec4 cullRangeMax; - vec3 fogcolor; - vec3 texenv; - ivec4 alphacolorref; - ivec4 alphacolormask; - vec3 blendFixA; - vec3 blendFixB; - vec4 texclamp; - vec2 texclampoff; +R"( mat4 u_proj; + mat4 u_proj_through; + mat3x4 u_view; + mat3x4 u_world; + mat3x4 u_tex; + vec4 u_uvscaleoffset; + vec4 u_depthRange; + vec2 u_fogcoef; + float u_stencilReplaceValue; + vec4 u_matambientalpha; + uint u_spline_counts; + uint u_depal_mask_shift_off_fmt; + int u_pad2; + int u_pad3; + vec4 u_cullRangeMin; + vec4 u_cullRangeMax; + vec3 u_fogcolor; + vec3 u_texenv; + ivec4 u_alphacolorref; + ivec4 u_alphacolormask; + vec3 u_blendFixA; + vec3 u_blendFixB; + vec4 u_texclamp; + vec2 u_texclampoff; )"; // HLSL code is shared so these names are changed to match those in DX9. @@ -118,16 +118,37 @@ struct UB_VS_Lights { static const char *ub_vs_lightsStr = R"( vec4 u_ambient; - vec3 matdiffuse; - vec4 matspecular; - vec3 matemissive; - vec3 pos[4]; - vec3 dir[4]; - vec3 att[4]; - vec2 angle_spotCoef[4]; - vec3 ambient[4]; - vec3 diffuse[4]; - vec3 specular[4]; + vec3 u_matdiffuse; + vec4 u_matspecular; + vec3 u_matemissive; + vec3 u_lightpos0; + vec3 u_lightpos1; + vec3 u_lightpos2; + vec3 u_lightpos3; + vec3 u_lightdir0; + vec3 u_lightdir1; + vec3 u_lightdir2; + vec3 u_lightdir3; + vec3 u_lightatt0; + vec3 u_lightatt1; + vec3 u_lightatt2; + vec3 u_lightatt3; + vec4 u_lightangle_spotCoef0; + vec4 u_lightangle_spotCoef1; + vec4 u_lightangle_spotCoef2; + vec4 u_lightangle_spotCoef3; + vec3 u_lightambient0; + vec3 u_lightambient1; + vec3 u_lightambient2; + vec3 u_lightambient3; + vec3 u_lightdiffuse0; + vec3 u_lightdiffuse1; + vec3 u_lightdiffuse2; + vec3 u_lightdiffuse3; + vec3 u_lightspecular0; + vec3 u_lightspecular1; + vec3 u_lightspecular2; + vec3 u_lightspecular3; )"; // HLSL code is shared so these names are changed to match those in DX9. @@ -167,13 +188,13 @@ R"( float4 u_ambient; )"; // With some cleverness, we could get away with uploading just half this when only the four or five first -// bones are being used. This is 512b, 256b would be great. +// bones are being used. This is 384b. struct UB_VS_Bones { float bones[8][12]; }; static const char *ub_vs_bonesStr = -R"( mat3x4 m[8]; +R"( mat3x4 u_bone[8]; )"; // HLSL code is shared so these names are changed to match those in DX9. diff --git a/GPU/D3D11/D3D11Util.cpp b/GPU/D3D11/D3D11Util.cpp index ee6ad435d3..acbdfc8e35 100644 --- a/GPU/D3D11/D3D11Util.cpp +++ b/GPU/D3D11/D3D11Util.cpp @@ -19,7 +19,7 @@ #include "D3D11Util.h" -static std::vector CompileShaderToBytecode(const char *code, size_t codeSize, const char *target, UINT flags) { +std::vector CompileShaderToBytecodeD3D11(const char *code, size_t codeSize, const char *target, UINT flags) { ID3DBlob *compiledCode = nullptr; ID3DBlob *errorMsgs = nullptr; HRESULT result = ptr_D3DCompile(code, codeSize, nullptr, nullptr, nullptr, "main", target, flags, 0, &compiledCode, &errorMsgs); @@ -31,8 +31,10 @@ static std::vector CompileShaderToBytecode(const char *code, size_t cod errorMsgs->Release(); } if (compiledCode) { + // Success! const uint8_t *buf = (const uint8_t *)compiledCode->GetBufferPointer(); std::vector compiled = std::vector(buf, buf + compiledCode->GetBufferSize()); + _assert_(compiled.size() != 0); compiledCode->Release(); return compiled; } @@ -41,7 +43,7 @@ static std::vector CompileShaderToBytecode(const char *code, size_t cod ID3D11VertexShader *CreateVertexShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize, std::vector *byteCodeOut, D3D_FEATURE_LEVEL featureLevel, UINT flags) { const char *profile = featureLevel <= D3D_FEATURE_LEVEL_9_3 ? "vs_4_0_level_9_1" : "vs_4_0"; - std::vector byteCode = CompileShaderToBytecode(code, codeSize, profile, flags); + std::vector byteCode = CompileShaderToBytecodeD3D11(code, codeSize, profile, flags); if (byteCode.empty()) return nullptr; @@ -54,7 +56,7 @@ ID3D11VertexShader *CreateVertexShaderD3D11(ID3D11Device *device, const char *co ID3D11PixelShader *CreatePixelShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize, D3D_FEATURE_LEVEL featureLevel, UINT flags) { const char *profile = featureLevel <= D3D_FEATURE_LEVEL_9_3 ? "ps_4_0_level_9_1" : "ps_4_0"; - std::vector byteCode = CompileShaderToBytecode(code, codeSize, profile, flags); + std::vector byteCode = CompileShaderToBytecodeD3D11(code, codeSize, profile, flags); if (byteCode.empty()) return nullptr; @@ -66,7 +68,7 @@ ID3D11PixelShader *CreatePixelShaderD3D11(ID3D11Device *device, const char *code ID3D11ComputeShader *CreateComputeShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize, D3D_FEATURE_LEVEL featureLevel, UINT flags) { if (featureLevel <= D3D_FEATURE_LEVEL_9_3) return nullptr; - std::vector byteCode = CompileShaderToBytecode(code, codeSize, "cs_4_0", flags); + std::vector byteCode = CompileShaderToBytecodeD3D11(code, codeSize, "cs_4_0", flags); if (byteCode.empty()) return nullptr; @@ -78,7 +80,7 @@ ID3D11ComputeShader *CreateComputeShaderD3D11(ID3D11Device *device, const char * ID3D11GeometryShader *CreateGeometryShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize, D3D_FEATURE_LEVEL featureLevel, UINT flags) { if (featureLevel <= D3D_FEATURE_LEVEL_9_3) return nullptr; - std::vector byteCode = CompileShaderToBytecode(code, codeSize, "gs_5_0", flags); + std::vector byteCode = CompileShaderToBytecodeD3D11(code, codeSize, "gs_5_0", flags); if (byteCode.empty()) return nullptr; diff --git a/GPU/D3D11/D3D11Util.h b/GPU/D3D11/D3D11Util.h index 11dba6ee4c..e9ae76ad42 100644 --- a/GPU/D3D11/D3D11Util.h +++ b/GPU/D3D11/D3D11Util.h @@ -18,6 +18,8 @@ #pragma once #include +#include + #include class PushBufferD3D11 { @@ -71,6 +73,8 @@ private: bool nextMapDiscard_ = false; }; +std::vector CompileShaderToBytecodeD3D11(const char *code, size_t codeSize, const char *target, UINT flags); + ID3D11VertexShader *CreateVertexShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize, std::vector *byteCodeOut, D3D_FEATURE_LEVEL featureLevel, UINT flags = 0); ID3D11PixelShader *CreatePixelShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize, D3D_FEATURE_LEVEL featureLevel, UINT flags = 0); ID3D11ComputeShader *CreateComputeShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize, D3D_FEATURE_LEVEL featureLevel, UINT flags = 0); @@ -95,4 +99,4 @@ public: if (!SUCCEEDED((x))) \ Crash(); -extern StockObjectsD3D11 stockD3D11; \ No newline at end of file +extern StockObjectsD3D11 stockD3D11; diff --git a/GPU/D3D11/DrawEngineD3D11.h b/GPU/D3D11/DrawEngineD3D11.h index fbc94f2d7a..5225c11052 100644 --- a/GPU/D3D11/DrawEngineD3D11.h +++ b/GPU/D3D11/DrawEngineD3D11.h @@ -28,7 +28,7 @@ #include "GPU/Common/VertexDecoderCommon.h" #include "GPU/Common/DrawEngineCommon.h" #include "GPU/Common/GPUStateUtils.h" -#include "GPU/D3D11/FragmentShaderGeneratorD3D11.h" +#include "GPU/Directx9/FragmentShaderGeneratorHLSL.h" #include "GPU/D3D11/StateMappingD3D11.h" #include "GPU/D3D11/D3D11Util.h" diff --git a/GPU/D3D11/FragmentShaderGeneratorD3D11.cpp b/GPU/D3D11/FragmentShaderGeneratorD3D11.cpp deleted file mode 100644 index 07d37c8d5c..0000000000 --- a/GPU/D3D11/FragmentShaderGeneratorD3D11.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2017- PPSSPP 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 or later versions. - -// 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 git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#include "GPU/Common/ShaderCommon.h" -#include "GPU/D3D11/FragmentShaderGeneratorD3D11.h" -#include "GPU/Directx9/PixelShaderGeneratorDX9.h" - -void GenerateFragmentShaderD3D11(const FShaderID &id, char *buffer, ShaderLanguage lang) { - DX9::GenerateFragmentShaderHLSL(id, buffer, lang); -} diff --git a/GPU/D3D11/FragmentShaderGeneratorD3D11.h b/GPU/D3D11/FragmentShaderGeneratorD3D11.h deleted file mode 100644 index cf94a63200..0000000000 --- a/GPU/D3D11/FragmentShaderGeneratorD3D11.h +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) 2017- PPSSPP 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 or later versions. - -// 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 git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#pragma once - -#include "GPU/Common/ShaderId.h" - -void GenerateFragmentShaderD3D11(const FShaderID &id, char *buffer, ShaderLanguage lang); diff --git a/GPU/D3D11/ShaderManagerD3D11.cpp b/GPU/D3D11/ShaderManagerD3D11.cpp index 4678f4ae65..8a7ac1654c 100644 --- a/GPU/D3D11/ShaderManagerD3D11.cpp +++ b/GPU/D3D11/ShaderManagerD3D11.cpp @@ -35,8 +35,8 @@ #include "GPU/GPUState.h" #include "GPU/ge_constants.h" #include "GPU/D3D11/ShaderManagerD3D11.h" -#include "GPU/D3D11/FragmentShaderGeneratorD3D11.h" -#include "GPU/D3D11/VertexShaderGeneratorD3D11.h" +#include "GPU/Directx9/FragmentShaderGeneratorHLSL.h" +#include "GPU/Directx9/VertexShaderGeneratorHLSL.h" #include "GPU/D3D11/D3D11Util.h" D3D11FragmentShader::D3D11FragmentShader(ID3D11Device *device, D3D_FEATURE_LEVEL featureLevel, FShaderID id, const char *code, bool useHWTransform) @@ -208,7 +208,8 @@ void ShaderManagerD3D11::GetShaders(int prim, u32 vertType, D3D11VertexShader ** D3D11VertexShader *vs; if (vsIter == vsCache_.end()) { // Vertex shader not in cache. Let's compile it. - GenerateVertexShaderD3D11(VSID, codeBuffer_, featureLevel_ <= D3D_FEATURE_LEVEL_9_3 ? HLSL_D3D11_LEVEL9 : HLSL_D3D11); + std::string genErrorString; + GenerateVertexShaderHLSL(VSID, codeBuffer_, featureLevel_ <= D3D_FEATURE_LEVEL_9_3 ? HLSL_D3D11_LEVEL9 : HLSL_D3D11, &genErrorString); vs = new D3D11VertexShader(device_, featureLevel_, VSID, codeBuffer_, vertType, useHWTransform); vsCache_[VSID] = vs; } else { @@ -220,7 +221,8 @@ void ShaderManagerD3D11::GetShaders(int prim, u32 vertType, D3D11VertexShader ** D3D11FragmentShader *fs; if (fsIter == fsCache_.end()) { // Fragment shader not in cache. Let's compile it. - GenerateFragmentShaderD3D11(FSID, codeBuffer_, featureLevel_ <= D3D_FEATURE_LEVEL_9_3 ? HLSL_D3D11_LEVEL9 : HLSL_D3D11); + std::string genErrorString; + GenerateFragmentShaderHLSL(FSID, codeBuffer_, featureLevel_ <= D3D_FEATURE_LEVEL_9_3 ? HLSL_D3D11_LEVEL9 : HLSL_D3D11, &genErrorString); fs = new D3D11FragmentShader(device_, featureLevel_, FSID, codeBuffer_, useHWTransform); fsCache_[FSID] = fs; } else { diff --git a/GPU/D3D11/StencilBufferD3D11.cpp b/GPU/D3D11/StencilBufferD3D11.cpp index 4da469ae61..043cbd50d0 100644 --- a/GPU/D3D11/StencilBufferD3D11.cpp +++ b/GPU/D3D11/StencilBufferD3D11.cpp @@ -23,7 +23,7 @@ #include "Core/Reporting.h" #include "GPU/Common/StencilCommon.h" #include "GPU/D3D11/FramebufferManagerD3D11.h" -#include "GPU/D3D11/FragmentShaderGeneratorD3D11.h" +#include "GPU/Directx9/FragmentShaderGeneratorHLSL.h" #include "GPU/D3D11/ShaderManagerD3D11.h" #include "GPU/D3D11/TextureCacheD3D11.h" #include "GPU/D3D11/D3D11Util.h" diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index f7f7582ec3..a989cf353f 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -26,7 +26,6 @@ #include "GPU/ge_constants.h" #include "GPU/GPUState.h" #include "GPU/Common/GPUStateUtils.h" -#include "GPU/D3D11/FragmentShaderGeneratorD3D11.h" #include "GPU/D3D11/TextureCacheD3D11.h" #include "GPU/D3D11/FramebufferManagerD3D11.h" #include "GPU/D3D11/ShaderManagerD3D11.h" diff --git a/GPU/D3D11/VertexShaderGeneratorD3D11.cpp b/GPU/D3D11/VertexShaderGeneratorD3D11.cpp deleted file mode 100644 index 75affc997d..0000000000 --- a/GPU/D3D11/VertexShaderGeneratorD3D11.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2017- PPSSPP 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 or later versions. - -// 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 git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#include "GPU/Common/ShaderCommon.h" -#include "GPU/D3D11/VertexShaderGeneratorD3D11.h" -#include "GPU/Directx9/VertexShaderGeneratorDX9.h" - -void GenerateVertexShaderD3D11(const VShaderID &id, char *buffer, ShaderLanguage lang) { - DX9::GenerateVertexShaderHLSL(id, buffer, lang); -} diff --git a/GPU/D3D11/VertexShaderGeneratorD3D11.h b/GPU/D3D11/VertexShaderGeneratorD3D11.h deleted file mode 100644 index fcf6f7f749..0000000000 --- a/GPU/D3D11/VertexShaderGeneratorD3D11.h +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) 2017- PPSSPP 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 or later versions. - -// 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 git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#pragma once - -#include "GPU/Common/ShaderId.h" - -void GenerateVertexShaderD3D11(const VShaderID &id, char *buffer, ShaderLanguage lang); diff --git a/GPU/Directx9/DrawEngineDX9.h b/GPU/Directx9/DrawEngineDX9.h index 3ddf99b79b..789ebe6209 100644 --- a/GPU/Directx9/DrawEngineDX9.h +++ b/GPU/Directx9/DrawEngineDX9.h @@ -26,7 +26,6 @@ #include "GPU/Common/VertexDecoderCommon.h" #include "GPU/Common/DrawEngineCommon.h" #include "GPU/Common/GPUStateUtils.h" -#include "GPU/Directx9/PixelShaderGeneratorDX9.h" struct DecVtxFormat; struct UVScale; diff --git a/GPU/Directx9/PixelShaderGeneratorDX9.cpp b/GPU/Directx9/FragmentShaderGeneratorHLSL.cpp similarity index 94% rename from GPU/Directx9/PixelShaderGeneratorDX9.cpp rename to GPU/Directx9/FragmentShaderGeneratorHLSL.cpp index 344f6c5542..4cbe2c50ff 100644 --- a/GPU/Directx9/PixelShaderGeneratorDX9.cpp +++ b/GPU/Directx9/FragmentShaderGeneratorHLSL.cpp @@ -19,7 +19,7 @@ #include "Core/Reporting.h" #include "Core/Config.h" -#include "GPU/Directx9/PixelShaderGeneratorDX9.h" +#include "GPU/Directx9/FragmentShaderGeneratorHLSL.h" #include "GPU/ge_constants.h" #include "GPU/Common/GPUStateUtils.h" #include "GPU/GPUState.h" @@ -29,11 +29,9 @@ // #define DEBUG_SHADER -namespace DX9 { - // Missing: Z depth range // Also, logic ops etc, of course, as they are not supported in DX9. -bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguage lang) { +bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguage lang, std::string *errorString) { char *p = buffer; bool lmode = id.Bit(FS_BIT_LMODE); @@ -68,6 +66,21 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguag StencilValueType replaceAlphaWithStencilType = (StencilValueType)id.Bits(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE, 4); + // Output some compatibility defines + switch (lang) { + case ShaderLanguage::HLSL_DX9: + WRITE(p, "#define DISCARD clip(-1)\n"); + break; + case ShaderLanguage::HLSL_D3D11: + case ShaderLanguage::HLSL_D3D11_LEVEL9: + WRITE(p, "#define DISCARD discard\n"); + break; + } + WRITE(p, "#define vec2 float2\n"); + WRITE(p, "#define vec3 float3\n"); + WRITE(p, "#define vec4 float4\n"); + WRITE(p, "#define splat3(x) float3(x, x, x)\n"); + if (lang == HLSL_DX9) { if (doTexture) WRITE(p, "sampler tex : register(s0);\n"); @@ -290,7 +303,7 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguag } else { // NEVER has been logged as used by games, although it makes little sense - statically failing. // Maybe we could discard the drawcall, but it's pretty rare. Let's just statically discard here. - WRITE(p, " clip(-1);\n"); + WRITE(p, " DISCARD;\n"); } } else { const char *alphaTestFuncs[] = { "#", "#", " != ", " == ", " >= ", " > ", " <= ", " < " }; // never/always don't make sense @@ -300,11 +313,11 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguag WRITE(p, " if ((roundAndScaleTo255i(v.a) & u_alphacolormask.a) %s u_alphacolorref.a) discard;\n", alphaTestFuncs[alphaTestFunc]); } else { // TODO: Use a texture to lookup bitwise ops? - WRITE(p, " if (roundAndScaleTo255f(v.a) %s u_alphacolorref.a) clip(-1);\n", alphaTestFuncs[alphaTestFunc]); + WRITE(p, " if (roundAndScaleTo255f(v.a) %s u_alphacolorref.a) DISCARD;\n", alphaTestFuncs[alphaTestFunc]); } } else { // This means NEVER. See above. - WRITE(p, lang == HLSL_DX9 ? " clip(-1);\n" : " discard;\n"); + WRITE(p, " DISCARD;\n"); } } } @@ -319,14 +332,14 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguag // When testing against 0 (common), we can avoid some math. // 0.002 is approximately half of 1.0 / 255.0. if (colorTestFunc == GE_COMP_NOTEQUAL) { - WRITE(p, " if (v.r < 0.002 && v.g < 0.002 && v.b < 0.002) clip(-1);\n"); + WRITE(p, " if (v.r < 0.002 && v.g < 0.002 && v.b < 0.002) DISCARD;\n"); } else if (colorTestFunc != GE_COMP_NEVER) { // Anything else is a test for == 0. - WRITE(p, " if (v.r > 0.002 || v.g > 0.002 || v.b > 0.002) clip(-1);\n"); + WRITE(p, " if (v.r > 0.002 || v.g > 0.002 || v.b > 0.002) DISCARD;\n"); } else { // NEVER has been logged as used by games, although it makes little sense - statically failing. // Maybe we could discard the drawcall, but it's pretty rare. Let's just statically discard here. - WRITE(p, lang == HLSL_DX9 ? " clip(-1);\n" : " discard;\n"); + WRITE(p, " DISCARD;\n"); } } else { const char *colorTestFuncs[] = { "#", "#", " != ", " == " }; // never/always don't make sense @@ -337,15 +350,15 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguag WRITE(p, " uint3 v_masked = v_scaled & u_alphacolormask.rgb;\n"); WRITE(p, " uint3 colorTestRef = u_alphacolorref.rgb & u_alphacolormask.rgb;\n"); // We have to test the components separately, or we get incorrect results. See #10629. - WRITE(p, " if (v_masked.r %s colorTestRef.r && v_masked.g %s colorTestRef.g && v_masked.b %s colorTestRef.b) discard;\n", test, test, test); + WRITE(p, " if (v_masked.r %s colorTestRef.r && v_masked.g %s colorTestRef.g && v_masked.b %s colorTestRef.b) DISCARD;\n", test, test, test); } else { // TODO: Use a texture to lookup bitwise ops instead? WRITE(p, " float3 colortest = roundAndScaleTo255v(v.rgb);\n"); - WRITE(p, " if ((colortest.r %s u_alphacolorref.r) && (colortest.g %s u_alphacolorref.g) && (colortest.b %s u_alphacolorref.b)) clip(-1);\n", test, test, test); + WRITE(p, " if ((colortest.r %s u_alphacolorref.r) && (colortest.g %s u_alphacolorref.g) && (colortest.b %s u_alphacolorref.b)) DISCARD;\n", test, test, test); } } else { - WRITE(p, lang == HLSL_DX9 ? " clip(-1);\n" : " discard;\n"); + WRITE(p, " DISCARD;\n"); } } } @@ -372,6 +385,10 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguag case GE_SRCBLEND_FIXA: srcFactor = "u_blendFixA"; break; default: srcFactor = "u_blendFixA"; break; } + if (!strcmp(srcFactor, "ERROR")) { + *errorString = "Bad srcfactor in replace blend"; + return false; + } WRITE(p, " v.rgb = v.rgb * %s;\n", srcFactor); } @@ -379,8 +396,8 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguag if ((lang == HLSL_D3D11 || lang == HLSL_D3D11_LEVEL9) && replaceBlend == REPLACE_BLEND_COPY_FBO) { WRITE(p, " float4 destColor = fboTex.Load(int3((int)In.pixelPos.x, (int)In.pixelPos.y, 0));\n"); - const char *srcFactor = "float3(1.0)"; - const char *dstFactor = "float3(0.0)"; + const char *srcFactor = nullptr; + const char *dstFactor = nullptr; switch (replaceBlendFuncA) { case GE_SRCBLEND_DSTCOLOR: srcFactor = "destColor.rgb"; break; @@ -408,7 +425,7 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguag case GE_DSTBLEND_DOUBLEDSTALPHA: dstFactor = "destColor.aaa * 2.0"; break; case GE_DSTBLEND_DOUBLEINVDSTALPHA: dstFactor = "float3(1.0, 1.0, 1.0) - destColor.aaa * 2.0"; break; case GE_DSTBLEND_FIXB: dstFactor = "u_blendFixB"; break; - default: srcFactor = "u_blendFixB"; break; + default: dstFactor = "u_blendFixB"; break; } switch (replaceBlendEq) { @@ -430,6 +447,9 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguag case GE_BLENDMODE_ABSDIFF: WRITE(p, " v.rgb = abs(v.rgb - destColor.rgb);\n"); break; + default: + *errorString = "Bad replace blend eq"; + return false; } } @@ -535,5 +555,3 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguag WRITE(p, "}\n"); return true; } - -}; diff --git a/GPU/Directx9/PixelShaderGeneratorDX9.h b/GPU/Directx9/FragmentShaderGeneratorHLSL.h similarity index 95% rename from GPU/Directx9/PixelShaderGeneratorDX9.h rename to GPU/Directx9/FragmentShaderGeneratorHLSL.h index 15623439ff..5dcaa52e54 100644 --- a/GPU/Directx9/PixelShaderGeneratorDX9.h +++ b/GPU/Directx9/FragmentShaderGeneratorHLSL.h @@ -20,9 +20,7 @@ #include "GPU/Common/ShaderId.h" #include "GPU/Common/ShaderCommon.h" -namespace DX9 { - -bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguage lang = HLSL_DX9); +bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguage lang, std::string *errorString); #define CONST_PS_TEXENV 0 #define CONST_PS_ALPHACOLORREF 1 @@ -37,5 +35,3 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, ShaderLanguag // For stencil upload #define CONST_PS_STENCILVALUE 10 - -}; diff --git a/GPU/Directx9/ShaderManagerDX9.cpp b/GPU/Directx9/ShaderManagerDX9.cpp index f7c331907e..bce4de6770 100644 --- a/GPU/Directx9/ShaderManagerDX9.cpp +++ b/GPU/Directx9/ShaderManagerDX9.cpp @@ -584,15 +584,21 @@ VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellat } VSCache::iterator vsIter = vsCache_.find(VSID); - VSShader *vs; + VSShader *vs = nullptr; if (vsIter == vsCache_.end()) { // Vertex shader not in cache. Let's compile it. - GenerateVertexShaderHLSL(VSID, codeBuffer_); - vs = new VSShader(device_, VSID, codeBuffer_, useHWTransform); - - if (vs->Failed()) { + std::string genErrorString; + if (GenerateVertexShaderHLSL(VSID, codeBuffer_, HLSL_DX9, &genErrorString)) { + vs = new VSShader(device_, VSID, codeBuffer_, useHWTransform); + } + if (!vs || vs->Failed()) { auto gr = GetI18NCategory("Graphics"); - ERROR_LOG(G3D, "Shader compilation failed, falling back to software transform"); + if (!vs) { + // TODO: Report this? + ERROR_LOG(G3D, "Shader generation failed, falling back to software transform"); + } else { + ERROR_LOG(G3D, "Shader compilation failed, falling back to software transform"); + } if (!g_Config.bHideSlowWarnings) { host->NotifyUserMessage(gr->T("hardware transform error - falling back to software"), 2.5f, 0xFF3030FF); } @@ -605,7 +611,8 @@ VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellat // next time and we'll do this over and over... // Can still work with software transform. - GenerateVertexShaderHLSL(VSID, codeBuffer_); + bool success = GenerateVertexShaderHLSL(VSID, codeBuffer_, HLSL_DX9, &genErrorString); + _assert_(success); vs = new VSShader(device_, VSID, codeBuffer_, false); } @@ -619,7 +626,10 @@ VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellat PSShader *fs; if (fsIter == fsCache_.end()) { // Fragment shader not in cache. Let's compile it. - GenerateFragmentShaderHLSL(FSID, codeBuffer_); + std::string errorString; + bool success = GenerateFragmentShaderHLSL(FSID, codeBuffer_, HLSL_DX9, &errorString); + // We're supposed to handle all possible cases. + _assert_(success); fs = new PSShader(device_, FSID, codeBuffer_); fsCache_[FSID] = fs; } else { diff --git a/GPU/Directx9/ShaderManagerDX9.h b/GPU/Directx9/ShaderManagerDX9.h index a71b95d2e5..706a627938 100644 --- a/GPU/Directx9/ShaderManagerDX9.h +++ b/GPU/Directx9/ShaderManagerDX9.h @@ -21,8 +21,8 @@ #include #include "Common/Common.h" -#include "GPU/Directx9/VertexShaderGeneratorDX9.h" -#include "GPU/Directx9/PixelShaderGeneratorDX9.h" +#include "GPU/Directx9/VertexShaderGeneratorHLSL.h" +#include "GPU/Directx9/FragmentShaderGeneratorHLSL.h" #include "GPU/Common/ShaderCommon.h" #include "GPU/Common/ShaderId.h" #include "Common/Math/lin/matrix4x4.h" diff --git a/GPU/Directx9/StateMappingDX9.cpp b/GPU/Directx9/StateMappingDX9.cpp index a3ae081396..cbe47ead46 100644 --- a/GPU/Directx9/StateMappingDX9.cpp +++ b/GPU/Directx9/StateMappingDX9.cpp @@ -31,7 +31,6 @@ #include "GPU/Directx9/ShaderManagerDX9.h" #include "GPU/Directx9/TextureCacheDX9.h" #include "GPU/Directx9/FramebufferManagerDX9.h" -#include "GPU/Directx9/PixelShaderGeneratorDX9.h" namespace DX9 { diff --git a/GPU/Directx9/StencilBufferDX9.cpp b/GPU/Directx9/StencilBufferDX9.cpp index d938e4339a..be617417f0 100644 --- a/GPU/Directx9/StencilBufferDX9.cpp +++ b/GPU/Directx9/StencilBufferDX9.cpp @@ -22,7 +22,6 @@ #include "Core/Reporting.h" #include "GPU/Common/StencilCommon.h" #include "GPU/Directx9/FramebufferManagerDX9.h" -#include "GPU/Directx9/PixelShaderGeneratorDX9.h" #include "GPU/Directx9/ShaderManagerDX9.h" #include "GPU/Directx9/TextureCacheDX9.h" diff --git a/GPU/Directx9/TextureCacheDX9.cpp b/GPU/Directx9/TextureCacheDX9.cpp index c867418a3f..f2373e0a6b 100644 --- a/GPU/Directx9/TextureCacheDX9.cpp +++ b/GPU/Directx9/TextureCacheDX9.cpp @@ -21,8 +21,8 @@ #include "Core/MemMap.h" #include "Core/Reporting.h" #include "GPU/ge_constants.h" + #include "GPU/GPUState.h" -#include "GPU/Directx9/PixelShaderGeneratorDX9.h" #include "GPU/Directx9/TextureCacheDX9.h" #include "GPU/Directx9/FramebufferManagerDX9.h" #include "GPU/Directx9/ShaderManagerDX9.h" diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.h b/GPU/Directx9/VertexShaderGeneratorDX9.h deleted file mode 100644 index aecc113ea3..0000000000 --- a/GPU/Directx9/VertexShaderGeneratorDX9.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) 2012- PPSSPP 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 or later versions. - -// 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 git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#pragma once - -#include "GPU/Common/ShaderID.h" - -namespace DX9 { - - void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage lang = HLSL_DX9); - - enum { - CONST_VS_PROJ = 0, - CONST_VS_PROJ_THROUGH = 4, - CONST_VS_VIEW = 8, - CONST_VS_WORLD = 11, - CONST_VS_TEXMTX = 14, - CONST_VS_UVSCALEOFFSET = 17, - CONST_VS_FOGCOEF = 18, - CONST_VS_AMBIENT = 19, - CONST_VS_MATAMBIENTALPHA = 20, - CONST_VS_MATDIFFUSE = 21, - CONST_VS_MATSPECULAR = 22, - CONST_VS_MATEMISSIVE = 23, - CONST_VS_LIGHTPOS = 24, - CONST_VS_LIGHTDIR = 28, - CONST_VS_LIGHTATT = 32, - CONST_VS_LIGHTANGLE_SPOTCOEF = 36, - CONST_VS_LIGHTDIFFUSE = 40, - CONST_VS_LIGHTSPECULAR = 44, - CONST_VS_LIGHTAMBIENT = 48, - CONST_VS_DEPTHRANGE = 52, - CONST_VS_BONE0 = 53, - CONST_VS_BONE1 = 56, - CONST_VS_BONE2 = 59, - CONST_VS_BONE3 = 62, - CONST_VS_BONE4 = 65, - CONST_VS_BONE5 = 68, - CONST_VS_BONE6 = 71, - CONST_VS_BONE7 = 74, - CONST_VS_BONE8 = 77, - CONST_VS_CULLRANGEMIN = 80, - CONST_VS_CULLRANGEMAX = 81, - }; - -}; diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.cpp b/GPU/Directx9/VertexShaderGeneratorHLSL.cpp similarity index 98% rename from GPU/Directx9/VertexShaderGeneratorDX9.cpp rename to GPU/Directx9/VertexShaderGeneratorHLSL.cpp index cdc3cdbff7..c8b87305cb 100644 --- a/GPU/Directx9/VertexShaderGeneratorDX9.cpp +++ b/GPU/Directx9/VertexShaderGeneratorHLSL.cpp @@ -18,16 +18,12 @@ #include #include -#if defined(_WIN32) && defined(_DEBUG) -#include "Common/CommonWindows.h" -#endif - #include "Common/StringUtils.h" #include "GPU/ge_constants.h" #include "GPU/GPUState.h" #include "Core/Config.h" -#include "GPU/Directx9/VertexShaderGeneratorDX9.h" +#include "GPU/Directx9/VertexShaderGeneratorHLSL.h" #include "GPU/Common/VertexDecoderCommon.h" #include "GPU/Common/ShaderUniforms.h" @@ -35,8 +31,6 @@ #define WRITE p+=sprintf -namespace DX9 { - static const char * const boneWeightAttrDecl[9] = { "#ERROR#", "float a_w1:TEXCOORD1;\n", @@ -49,13 +43,7 @@ static const char * const boneWeightAttrDecl[9] = { "float4 a_w1:TEXCOORD1;\n float4 a_w2:TEXCOORD2;\n", }; -enum DoLightComputation { - LIGHT_OFF, - LIGHT_SHADE, - LIGHT_FULL, -}; - -void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage lang) { +bool GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage lang, std::string *errorString) { char *p = buffer; bool isModeThrough = id.Bit(VS_BIT_IS_THROUGH); @@ -107,6 +95,12 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage numBoneWeights = 1 + id.Bits(VS_BIT_BONES, 3); } + // Output some compatibility defines + WRITE(p, "#define vec2 float2\n"); + WRITE(p, "#define vec3 float3\n"); + WRITE(p, "#define vec4 float4\n"); + WRITE(p, "#define splat3(x) float3(x, x, x)\n"); + if (lang == HLSL_DX9) { WRITE(p, "#pragma warning( disable : 3571 )\n"); if (isModeThrough) { @@ -730,8 +724,9 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage break; default: - // ILLEGAL - break; + // Should be unreachable. + _assert_(false); + return false; } } @@ -756,6 +751,5 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage WRITE(p, " return Out;\n"); WRITE(p, "}\n"); + return true; } - -}; diff --git a/GPU/Directx9/VertexShaderGeneratorHLSL.h b/GPU/Directx9/VertexShaderGeneratorHLSL.h new file mode 100644 index 0000000000..08adab846c --- /dev/null +++ b/GPU/Directx9/VertexShaderGeneratorHLSL.h @@ -0,0 +1,57 @@ +// Copyright (c) 2012- PPSSPP 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 or later versions. + +// 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 git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#pragma once + +#include +#include "GPU/Common/ShaderID.h" + +bool GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage lang, std::string *errorString); + +enum { + CONST_VS_PROJ = 0, + CONST_VS_PROJ_THROUGH = 4, + CONST_VS_VIEW = 8, + CONST_VS_WORLD = 11, + CONST_VS_TEXMTX = 14, + CONST_VS_UVSCALEOFFSET = 17, + CONST_VS_FOGCOEF = 18, + CONST_VS_AMBIENT = 19, + CONST_VS_MATAMBIENTALPHA = 20, + CONST_VS_MATDIFFUSE = 21, + CONST_VS_MATSPECULAR = 22, + CONST_VS_MATEMISSIVE = 23, + CONST_VS_LIGHTPOS = 24, + CONST_VS_LIGHTDIR = 28, + CONST_VS_LIGHTATT = 32, + CONST_VS_LIGHTANGLE_SPOTCOEF = 36, + CONST_VS_LIGHTDIFFUSE = 40, + CONST_VS_LIGHTSPECULAR = 44, + CONST_VS_LIGHTAMBIENT = 48, + CONST_VS_DEPTHRANGE = 52, + CONST_VS_BONE0 = 53, + CONST_VS_BONE1 = 56, + CONST_VS_BONE2 = 59, + CONST_VS_BONE3 = 62, + CONST_VS_BONE4 = 65, + CONST_VS_BONE5 = 68, + CONST_VS_BONE6 = 71, + CONST_VS_BONE7 = 74, + CONST_VS_BONE8 = 77, + CONST_VS_CULLRANGEMIN = 80, + CONST_VS_CULLRANGEMAX = 81, +}; diff --git a/GPU/GLES/FragmentShaderGeneratorGLES.cpp b/GPU/GLES/FragmentShaderGeneratorGLES.cpp index 82586c3ea6..66365bff31 100644 --- a/GPU/GLES/FragmentShaderGeneratorGLES.cpp +++ b/GPU/GLES/FragmentShaderGeneratorGLES.cpp @@ -36,22 +36,22 @@ // #define DEBUG_SHADER // Missing: Z depth range -bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniformMask) { +bool GenerateFragmentShaderGLSL(const FShaderID &id, char *buffer, uint64_t *uniformMask, std::string *errorString) { char *p = buffer; *uniformMask = 0; // In GLSL ES 3.0, you use "in" variables instead of varying. - bool glslES30 = false; - const char *varying = "varying"; - const char *fragColor0 = "gl_FragColor"; - const char *fragColor1 = "fragColor1"; - const char *texture = "texture2D"; - const char *texelFetch = NULL; + GLSLShaderCompat compat{}; + compat.varying = "varying"; + compat.fragColor0 = "gl_FragColor"; + compat.fragColor1 = "fragColor1"; + compat.texture = "texture2D"; + compat.texelFetch = NULL; + compat.bitwiseOps = false; + compat.lastFragData = nullptr; bool highpFog = false; bool highpTexcoord = false; - bool bitwiseOps = false; - const char *lastFragData = nullptr; ReplaceAlphaType stencilToAlpha = static_cast(id.Bits(FS_BIT_STENCIL_TO_ALPHA, 2)); @@ -59,11 +59,11 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform // ES doesn't support dual source alpha :( if (gstate_c.Supports(GPU_SUPPORTS_GLSL_ES_300)) { WRITE(p, "#version 300 es\n"); // GLSL ES 3.0 - fragColor0 = "fragColor0"; - texture = "texture"; - glslES30 = true; - bitwiseOps = true; - texelFetch = "texelFetch"; + compat.fragColor0 = "fragColor0"; + compat.texture = "texture"; + compat.glslES30 = true; + compat.bitwiseOps = true; + compat.texelFetch = "texelFetch"; if (stencilToAlpha == REPLACE_ALPHA_DUALSOURCE && gl_extensions.EXT_blend_func_extended) { WRITE(p, "#extension GL_EXT_blend_func_extended : require\n"); @@ -72,12 +72,12 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform WRITE(p, "#version 100\n"); // GLSL ES 1.0 if (gl_extensions.EXT_gpu_shader4) { WRITE(p, "#extension GL_EXT_gpu_shader4 : enable\n"); - bitwiseOps = true; - texelFetch = "texelFetch2D"; + compat.bitwiseOps = true; + compat.texelFetch = "texelFetch2D"; } if (gl_extensions.EXT_blend_func_extended) { // Oldy moldy GLES, so use the fixed output name. - fragColor1 = "gl_SecondaryFragColorEXT"; + compat.fragColor1 = "gl_SecondaryFragColorEXT"; if (stencilToAlpha == REPLACE_ALPHA_DUALSOURCE && gl_extensions.EXT_blend_func_extended) { WRITE(p, "#extension GL_EXT_blend_func_extended : require\n"); @@ -93,17 +93,17 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform if (gstate_c.Supports(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH)) { if (gstate_c.Supports(GPU_SUPPORTS_GLSL_ES_300) && gl_extensions.EXT_shader_framebuffer_fetch) { WRITE(p, "#extension GL_EXT_shader_framebuffer_fetch : require\n"); - lastFragData = "fragColor0"; + compat.lastFragData = "fragColor0"; } else if (gl_extensions.EXT_shader_framebuffer_fetch) { WRITE(p, "#extension GL_EXT_shader_framebuffer_fetch : require\n"); - lastFragData = "gl_LastFragData[0]"; + compat.lastFragData = "gl_LastFragData[0]"; } else if (gl_extensions.NV_shader_framebuffer_fetch) { // GL_NV_shader_framebuffer_fetch is available on mobile platform and ES 2.0 only but not on desktop. WRITE(p, "#extension GL_NV_shader_framebuffer_fetch : require\n"); - lastFragData = "gl_LastFragData[0]"; + compat.lastFragData = "gl_LastFragData[0]"; } else if (gl_extensions.ARM_shader_framebuffer_fetch) { WRITE(p, "#extension GL_ARM_shader_framebuffer_fetch : require\n"); - lastFragData = "gl_LastFragColorARM"; + compat.lastFragData = "gl_LastFragColorARM"; } } @@ -111,16 +111,16 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform } else { if (!gl_extensions.ForceGL2 || gl_extensions.IsCoreContext) { if (gl_extensions.VersionGEThan(3, 3, 0)) { - fragColor0 = "fragColor0"; - texture = "texture"; - glslES30 = true; - bitwiseOps = true; - texelFetch = "texelFetch"; + compat.fragColor0 = "fragColor0"; + compat.texture = "texture"; + compat.glslES30 = true; + compat.bitwiseOps = true; + compat.texelFetch = "texelFetch"; WRITE(p, "#version 330\n"); } else if (gl_extensions.VersionGEThan(3, 0, 0)) { - fragColor0 = "fragColor0"; - bitwiseOps = true; - texelFetch = "texelFetch"; + compat.fragColor0 = "fragColor0"; + compat.bitwiseOps = true; + compat.texelFetch = "texelFetch"; WRITE(p, "#version 130\n"); if (gl_extensions.EXT_gpu_shader4) { WRITE(p, "#extension GL_EXT_gpu_shader4 : enable\n"); @@ -129,8 +129,8 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform WRITE(p, "#version 110\n"); if (gl_extensions.EXT_gpu_shader4) { WRITE(p, "#extension GL_EXT_gpu_shader4 : enable\n"); - bitwiseOps = true; - texelFetch = "texelFetch2D"; + compat.bitwiseOps = true; + compat.texelFetch = "texelFetch2D"; } } } @@ -141,8 +141,8 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform WRITE(p, "#define highp\n"); } - if (glslES30 || gl_extensions.IsCoreContext) { - varying = "in"; + if (compat.glslES30 || gl_extensions.IsCoreContext) { + compat.varying = "in"; } bool lmode = id.Bit(FS_BIT_LMODE); @@ -180,7 +180,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform } const char *shading = ""; - if (glslES30) + if (compat.glslES30) shading = doFlatShading ? "flat" : ""; if (doTexture) @@ -189,7 +189,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform if (!isModeClear && replaceBlend > REPLACE_BLEND_STANDARD) { *uniformMask |= DIRTY_SHADERBLEND; if (!gstate_c.Supports(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH) && replaceBlend == REPLACE_BLEND_COPY_FBO) { - if (!texelFetch) { + if (!compat.texelFetch) { WRITE(p, "uniform vec2 u_fbotexSize;\n"); } WRITE(p, "uniform sampler2D fbotex;\n"); @@ -216,7 +216,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform } else { *uniformMask |= DIRTY_ALPHACOLORREF; WRITE(p, "uniform vec4 u_alphacolorref;\n"); - if (bitwiseOps && ((enableColorTest && !colorTestAgainstZero) || (enableAlphaTest && !alphaTestAgainstZero))) { + if (compat.bitwiseOps && ((enableColorTest && !colorTestAgainstZero) || (enableAlphaTest && !alphaTestAgainstZero))) { *uniformMask |= DIRTY_ALPHACOLORMASK; WRITE(p, "uniform ivec4 u_alphacolormask;\n"); } @@ -239,21 +239,21 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform WRITE(p, "uniform vec3 u_texenv;\n"); } - WRITE(p, "%s %s vec4 v_color0;\n", shading, varying); + WRITE(p, "%s %s vec4 v_color0;\n", shading, compat.varying); if (lmode) - WRITE(p, "%s %s vec3 v_color1;\n", shading, varying); + WRITE(p, "%s %s vec3 v_color1;\n", shading, compat.varying); if (enableFog) { *uniformMask |= DIRTY_FOGCOLOR; WRITE(p, "uniform vec3 u_fogcolor;\n"); - WRITE(p, "%s %s float v_fogdepth;\n", varying, highpFog ? "highp" : "mediump"); + WRITE(p, "%s %s float v_fogdepth;\n", compat.varying, highpFog ? "highp" : "mediump"); } if (doTexture) { - WRITE(p, "%s %s vec3 v_texcoord;\n", varying, highpTexcoord ? "highp" : "mediump"); + WRITE(p, "%s %s vec3 v_texcoord;\n", compat.varying, highpTexcoord ? "highp" : "mediump"); } if (!g_Config.bFragmentTestCache) { if (enableAlphaTest && !alphaTestAgainstZero) { - if (bitwiseOps) { + if (compat.bitwiseOps) { WRITE(p, "int roundAndScaleTo255i(in float x) { return int(floor(x * 255.0 + 0.5)); }\n"); } else if (gl_extensions.gpuVendor == GPU_VENDOR_IMGTEC) { WRITE(p, "float roundTo255thf(in mediump float x) { mediump float y = x + (0.5/255.0); return y - fract(y * 255.0) * (1.0 / 255.0); }\n"); @@ -262,7 +262,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform } } if (enableColorTest && !colorTestAgainstZero) { - if (bitwiseOps) { + if (compat.bitwiseOps) { WRITE(p, "ivec3 roundAndScaleTo255iv(in vec3 x) { return ivec3(floor(x * 255.0 + 0.5)); }\n"); } else if (gl_extensions.gpuVendor == GPU_VENDOR_IMGTEC) { WRITE(p, "vec3 roundTo255thv(in vec3 x) { vec3 y = x + (0.5/255.0); return y - fract(y * 255.0) * (1.0 / 255.0); }\n"); @@ -272,9 +272,9 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform } } - if (!strcmp(fragColor0, "fragColor0")) { + if (!strcmp(compat.fragColor0, "fragColor0")) { const char *qualifierColor0 = "out"; - if (lastFragData && !strcmp(lastFragData, fragColor0)) { + if (compat.lastFragData && !strcmp(compat.lastFragData, compat.fragColor0)) { qualifierColor0 = "inout"; } // Output the output color definitions. @@ -353,9 +353,9 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform if (!shaderDepal) { if (doTextureProjection) { - WRITE(p, " vec4 t = %sProj(tex, %s);\n", texture, texcoord); + WRITE(p, " vec4 t = %sProj(tex, %s);\n", compat.texture, texcoord); } else { - WRITE(p, " vec4 t = %s(tex, %s.xy);\n", texture, texcoord); + WRITE(p, " vec4 t = %s(tex, %s.xy);\n", compat.texture, texcoord); } } else { if (doTextureProjection) { @@ -375,10 +375,10 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform WRITE(p, " } else {\n"); WRITE(p, " uv_round = uv;\n"); WRITE(p, " }\n"); - WRITE(p, " vec4 t = %s(tex, uv_round);\n", texture); - WRITE(p, " vec4 t1 = %sOffset(tex, uv_round, ivec2(1, 0));\n", texture); - WRITE(p, " vec4 t2 = %sOffset(tex, uv_round, ivec2(0, 1));\n", texture); - WRITE(p, " vec4 t3 = %sOffset(tex, uv_round, ivec2(1, 1));\n", texture); + WRITE(p, " vec4 t = %s(tex, uv_round);\n", compat.texture); + WRITE(p, " vec4 t1 = %sOffset(tex, uv_round, ivec2(1, 0));\n", compat.texture); + WRITE(p, " vec4 t2 = %sOffset(tex, uv_round, ivec2(0, 1));\n", compat.texture); + WRITE(p, " vec4 t3 = %sOffset(tex, uv_round, ivec2(1, 1));\n", compat.texture); WRITE(p, " int depalMask = (u_depal & 0xFF);\n"); WRITE(p, " int depalShift = ((u_depal >> 8) & 0xFF);\n"); WRITE(p, " int depalOffset = (((u_depal >> 16) & 0xFF) << 4);\n"); @@ -552,12 +552,12 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform WRITE(p, " %s\n", discardStatement); } } else if (g_Config.bFragmentTestCache) { - WRITE(p, " float aResult = %s(testtex, vec2(%s, 0)).a;\n", texture, alphaTestXCoord.c_str()); + WRITE(p, " float aResult = %s(testtex, vec2(%s, 0)).a;\n", compat.texture, alphaTestXCoord.c_str()); WRITE(p, " if (aResult < 0.5) %s\n", discardStatement); } else { const char *alphaTestFuncs[] = { "#", "#", " != ", " == ", " >= ", " > ", " <= ", " < " }; if (alphaTestFuncs[alphaTestFunc][0] != '#') { - if (bitwiseOps) { + if (compat.bitwiseOps) { WRITE(p, " if ((roundAndScaleTo255i(v.a) & u_alphacolormask.a) %s int(u_alphacolorref.a)) %s\n", alphaTestFuncs[alphaTestFunc], discardStatement); } else if (gl_extensions.gpuVendor == GPU_VENDOR_IMGTEC) { // Work around bad PVR driver problem where equality check + discard just doesn't work. @@ -589,9 +589,9 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform WRITE(p, " %s\n", discardStatement); } } else if (g_Config.bFragmentTestCache) { - WRITE(p, " float rResult = %s(testtex, vec2(vScale256.r, 0)).r;\n", texture); - WRITE(p, " float gResult = %s(testtex, vec2(vScale256.g, 0)).g;\n", texture); - WRITE(p, " float bResult = %s(testtex, vec2(vScale256.b, 0)).b;\n", texture); + WRITE(p, " float rResult = %s(testtex, vec2(vScale256.r, 0)).r;\n", compat.texture); + WRITE(p, " float gResult = %s(testtex, vec2(vScale256.g, 0)).g;\n", compat.texture); + WRITE(p, " float bResult = %s(testtex, vec2(vScale256.b, 0)).b;\n", compat.texture); if (colorTestFunc == GE_COMP_EQUAL) { // Equal means all parts must be equal (so discard if any is not.) WRITE(p, " if (rResult < 0.5 || gResult < 0.5 || bResult < 0.5) %s\n", discardStatement); @@ -602,7 +602,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform } else { const char *colorTestFuncs[] = { "#", "#", " != ", " == " }; if (colorTestFuncs[colorTestFunc][0] != '#') { - if (bitwiseOps) { + if (compat.bitwiseOps) { // Apparently GLES3 does not support vector bitwise ops. WRITE(p, " ivec3 v_scaled = roundAndScaleTo255iv(v.rgb);\n"); const char *maskedFragColor = "ivec3(v_scaled.r & u_alphacolormask.r, v_scaled.g & u_alphacolormask.g, v_scaled.b & u_alphacolormask.b)"; @@ -649,11 +649,11 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform // If we have NV_shader_framebuffer_fetch / EXT_shader_framebuffer_fetch, we skip the blit. // We can just read the prev value more directly. if (gstate_c.Supports(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH)) { - WRITE(p, " lowp vec4 destColor = %s;\n", lastFragData); - } else if (!texelFetch) { - WRITE(p, " lowp vec4 destColor = %s(fbotex, gl_FragCoord.xy * u_fbotexSize.xy);\n", texture); + WRITE(p, " lowp vec4 destColor = %s;\n", compat.lastFragData); + } else if (!compat.texelFetch) { + WRITE(p, " lowp vec4 destColor = %s(fbotex, gl_FragCoord.xy * u_fbotexSize.xy);\n", compat.texture); } else { - WRITE(p, " lowp vec4 destColor = %s(fbotex, ivec2(gl_FragCoord.x, gl_FragCoord.y), 0);\n", texelFetch); + WRITE(p, " lowp vec4 destColor = %s(fbotex, ivec2(gl_FragCoord.x, gl_FragCoord.y), 0);\n", compat.texelFetch); } const char *srcFactor = "vec3(1.0)"; @@ -755,48 +755,39 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform switch (stencilToAlpha) { case REPLACE_ALPHA_DUALSOURCE: - WRITE(p, " %s = vec4(v.rgb, %s);\n", fragColor0, replacedAlpha.c_str()); - WRITE(p, " %s = vec4(0.0, 0.0, 0.0, v.a);\n", fragColor1); + WRITE(p, " %s = vec4(v.rgb, %s);\n", compat.fragColor0, replacedAlpha.c_str()); + WRITE(p, " %s = vec4(0.0, 0.0, 0.0, v.a);\n", compat.fragColor1); break; case REPLACE_ALPHA_YES: - WRITE(p, " %s = vec4(v.rgb, %s);\n", fragColor0, replacedAlpha.c_str()); + WRITE(p, " %s = vec4(v.rgb, %s);\n", compat.fragColor0, replacedAlpha.c_str()); break; case REPLACE_ALPHA_NO: - WRITE(p, " %s = v;\n", fragColor0); + WRITE(p, " %s = v;\n", compat.fragColor0); break; default: - ERROR_LOG(G3D, "Bad stencil-to-alpha type, corrupt ID?"); + *errorString = "Bad stencil-to-alpha type, corrupt ID?"; return false; } LogicOpReplaceType replaceLogicOpType = (LogicOpReplaceType)id.Bits(FS_BIT_REPLACE_LOGIC_OP_TYPE, 2); switch (replaceLogicOpType) { case LOGICOPTYPE_ONE: - WRITE(p, " %s.rgb = vec3(1.0, 1.0, 1.0);\n", fragColor0); + WRITE(p, " %s.rgb = vec3(1.0, 1.0, 1.0);\n", compat.fragColor0); break; case LOGICOPTYPE_INVERT: - WRITE(p, " %s.rgb = vec3(1.0, 1.0, 1.0) - %s.rgb;\n", fragColor0, fragColor0); + WRITE(p, " %s.rgb = vec3(1.0, 1.0, 1.0) - %s.rgb;\n", compat.fragColor0, compat.fragColor0); break; case LOGICOPTYPE_NORMAL: break; default: - ERROR_LOG(G3D, "Bad logic op type, corrupt ID?"); + *errorString = "Bad logic op type, corrupt ID?"; return false; } -#ifdef DEBUG_SHADER - if (doTexture) { - WRITE(p, " %s = texture2D(tex, v_texcoord.xy);\n", fragColor0); - WRITE(p, " %s += vec4(0.3,0,0.3,0.3);\n", fragColor0); - } else { - WRITE(p, " %s = vec4(1,0,1,1);\n", fragColor0); - } -#endif - if (gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT)) { const double scale = DepthSliceFactor() * 65535.0; diff --git a/GPU/GLES/FragmentShaderGeneratorGLES.h b/GPU/GLES/FragmentShaderGeneratorGLES.h index 1d190e5e96..6f0aa73b23 100644 --- a/GPU/GLES/FragmentShaderGeneratorGLES.h +++ b/GPU/GLES/FragmentShaderGeneratorGLES.h @@ -19,4 +19,4 @@ struct FShaderID; -bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniformMask); +bool GenerateFragmentShaderGLSL(const FShaderID &id, char *buffer, uint64_t *uniformMask, std::string *errorString); diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index e4e3d4fda4..eda3294c0e 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -629,7 +629,9 @@ void ShaderManagerGLES::DirtyLastShader() { Shader *ShaderManagerGLES::CompileFragmentShader(FShaderID FSID) { uint64_t uniformMask; - if (!GenerateFragmentShader(FSID, codeBuffer_, &uniformMask)) { + std::string errorString; + if (!GenerateFragmentShaderGLSL(FSID, codeBuffer_, &uniformMask, &errorString)) { + ERROR_LOG(G3D, "Shader gen error: %s", errorString.c_str()); return nullptr; } std::string desc = FragmentShaderDesc(FSID); @@ -640,7 +642,11 @@ Shader *ShaderManagerGLES::CompileVertexShader(VShaderID VSID) { bool useHWTransform = VSID.Bit(VS_BIT_USE_HW_TRANSFORM); uint32_t attrMask; uint64_t uniformMask; - GenerateVertexShader(VSID, codeBuffer_, &attrMask, &uniformMask); + std::string errorString; + if (!GenerateVertexShaderGLSL(VSID, codeBuffer_, &attrMask, &uniformMask, &errorString)) { + ERROR_LOG(G3D, "Shader gen error: %s", errorString.c_str()); + return nullptr; + } std::string desc = VertexShaderDesc(VSID); return new Shader(render_, codeBuffer_, desc, GL_VERTEX_SHADER, useHWTransform, attrMask, uniformMask); } diff --git a/GPU/GLES/VertexShaderGeneratorGLES.cpp b/GPU/GLES/VertexShaderGeneratorGLES.cpp index 8f775d2647..3e8f03e5d4 100644 --- a/GPU/GLES/VertexShaderGeneratorGLES.cpp +++ b/GPU/GLES/VertexShaderGeneratorGLES.cpp @@ -21,10 +21,6 @@ #include "Common/GPU/OpenGL/GLFeatures.h" -#if defined(_WIN32) && defined(_DEBUG) -#include "Common/CommonWindows.h" -#endif - #include "Common/StringUtils.h" #include "GPU/ge_constants.h" #include "GPU/GPUState.h" @@ -62,13 +58,6 @@ static const char * const boneWeightInDecl[9] = { "in mediump vec4 w1, w2;\n", }; -enum DoLightComputation { - LIGHT_OFF, - LIGHT_SHADE, - LIGHT_FULL, -}; - - // Depth range and viewport // // After the multiplication with the projection matrix, we have a 4D vector in clip space. @@ -98,32 +87,32 @@ enum DoLightComputation { // TODO: Skip all this if we can actually get a 16-bit depth buffer along with stencil, which // is a bit of a rare configuration, although quite common on mobile. - -void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, uint64_t *uniformMask) { +bool GenerateVertexShaderGLSL(const VShaderID &id, char *buffer, uint32_t *attrMask, uint64_t *uniformMask, std::string *errorString) { char *p = buffer; *attrMask = 0; *uniformMask = 0; // #define USE_FOR_LOOP // In GLSL ES 3.0, you use "out" variables instead. - bool glslES30 = false; - const char *varying = "varying"; - const char *attribute = "attribute"; + GLSLShaderCompat compat{}; + compat.glslES30 = false; + compat.varying = "varying"; + compat.attribute = "attribute"; const char * const * boneWeightDecl = boneWeightAttrDecl; - const char *texelFetch = NULL; + compat.texelFetch = NULL; bool highpFog = false; bool highpTexcoord = false; if (gl_extensions.IsGLES) { if (gstate_c.Supports(GPU_SUPPORTS_GLSL_ES_300)) { WRITE(p, "#version 300 es\n"); - glslES30 = true; - texelFetch = "texelFetch"; + compat.glslES30 = true; + compat.texelFetch = "texelFetch"; } else { WRITE(p, "#version 100\n"); // GLSL ES 1.0 if (gl_extensions.EXT_gpu_shader4) { WRITE(p, "#extension GL_EXT_gpu_shader4 : enable\n"); - texelFetch = "texelFetch2D"; + compat.texelFetch = "texelFetch2D"; } } WRITE(p, "precision highp float;\n"); @@ -135,20 +124,20 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, } else { if (!gl_extensions.ForceGL2 || gl_extensions.IsCoreContext) { if (gl_extensions.VersionGEThan(3, 3, 0)) { - glslES30 = true; + compat.glslES30 = true; WRITE(p, "#version 330\n"); - texelFetch = "texelFetch"; + compat.texelFetch = "texelFetch"; } else if (gl_extensions.VersionGEThan(3, 0, 0)) { WRITE(p, "#version 130\n"); if (gl_extensions.EXT_gpu_shader4) { WRITE(p, "#extension GL_EXT_gpu_shader4 : enable\n"); - texelFetch = "texelFetch"; + compat.texelFetch = "texelFetch"; } } else { WRITE(p, "#version 110\n"); if (gl_extensions.EXT_gpu_shader4) { WRITE(p, "#extension GL_EXT_gpu_shader4 : enable\n"); - texelFetch = "texelFetch2D"; + compat.texelFetch = "texelFetch2D"; } } } @@ -158,10 +147,11 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, WRITE(p, "#define mediump\n"); WRITE(p, "#define highp\n"); } + WRITE(p, "#define splat3(x) vec3(x)\n"); - if (glslES30 || gl_extensions.IsCoreContext) { - attribute = "in"; - varying = "out"; + if (compat.glslES30 || gl_extensions.IsCoreContext) { + compat.attribute = "in"; + compat.varying = "out"; boneWeightDecl = boneWeightInDecl; } @@ -197,7 +187,7 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, bool flipNormalTess = id.Bit(VS_BIT_NORM_REVERSE_TESS); const char *shading = ""; - if (glslES30) + if (compat.glslES30) shading = doFlatShading ? "flat " : ""; DoLightComputation doLight[4] = { LIGHT_OFF, LIGHT_OFF, LIGHT_OFF, LIGHT_OFF }; @@ -223,31 +213,31 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, } if (useHWTransform) - WRITE(p, "%s vec3 position;\n", attribute); + WRITE(p, "%s vec3 position;\n", compat.attribute); else - WRITE(p, "%s vec4 position;\n", attribute); // need to pass the fog coord in w + WRITE(p, "%s vec4 position;\n", compat.attribute); // need to pass the fog coord in w *attrMask |= 1 << ATTR_POSITION; if (useHWTransform && hasNormal) { - WRITE(p, "%s mediump vec3 normal;\n", attribute); + WRITE(p, "%s mediump vec3 normal;\n", compat.attribute); *attrMask |= 1 << ATTR_NORMAL; } bool texcoordVec3In = false; if (doTexture && hasTexcoord) { if (!useHWTransform && doTextureProjection && !isModeThrough) { - WRITE(p, "%s vec3 texcoord;\n", attribute); + WRITE(p, "%s vec3 texcoord;\n", compat.attribute); texcoordVec3In = true; } else { - WRITE(p, "%s vec2 texcoord;\n", attribute); + WRITE(p, "%s vec2 texcoord;\n", compat.attribute); } *attrMask |= 1 << ATTR_TEXCOORD; } if (hasColor) { - WRITE(p, "%s lowp vec4 color0;\n", attribute); + WRITE(p, "%s lowp vec4 color0;\n", compat.attribute); *attrMask |= 1 << ATTR_COLOR0; if (lmode && !useHWTransform) { // only software transform supplies color1 as vertex data - WRITE(p, "%s lowp vec3 color1;\n", attribute); + WRITE(p, "%s lowp vec3 color1;\n", compat.attribute); *attrMask |= 1 << ATTR_COLOR1; } } @@ -346,21 +336,21 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, *uniformMask |= DIRTY_CULLRANGE; } - WRITE(p, "%s%s lowp vec4 v_color0;\n", shading, varying); + WRITE(p, "%s%s lowp vec4 v_color0;\n", shading, compat.varying); if (lmode) { - WRITE(p, "%s%s lowp vec3 v_color1;\n", shading, varying); + WRITE(p, "%s%s lowp vec3 v_color1;\n", shading, compat.varying); } if (doTexture) { - WRITE(p, "%s %s vec3 v_texcoord;\n", varying, highpTexcoord ? "highp" : "mediump"); + WRITE(p, "%s %s vec3 v_texcoord;\n", compat.varying, highpTexcoord ? "highp" : "mediump"); } if (enableFog) { // See the fragment shader generator if (highpFog) { - WRITE(p, "%s highp float v_fogdepth;\n", varying); + WRITE(p, "%s highp float v_fogdepth;\n", compat.varying); } else { - WRITE(p, "%s mediump float v_fogdepth;\n", varying); + WRITE(p, "%s mediump float v_fogdepth;\n", compat.varying); } } @@ -427,17 +417,17 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, for (int j = 0; j < 4; j++) { WRITE(p, " index_u = (%i + point_pos.x);\n", j); WRITE(p, " index_v = (%i + point_pos.y);\n", i); - WRITE(p, " _pos[%i] = %s(u_tess_points, ivec2(index_u, index_v), 0).xyz;\n", i * 4 + j, texelFetch); + WRITE(p, " _pos[%i] = %s(u_tess_points, ivec2(index_u, index_v), 0).xyz;\n", i * 4 + j, compat.texelFetch); if (doTexture && hasTexcoordTess) - WRITE(p, " _tex[%i] = %s(u_tess_points, ivec2(index_u + u_spline_counts, index_v), 0).xy;\n", i * 4 + j, texelFetch); + WRITE(p, " _tex[%i] = %s(u_tess_points, ivec2(index_u + u_spline_counts, index_v), 0).xy;\n", i * 4 + j, compat.texelFetch); if (hasColorTess) - WRITE(p, " _col[%i] = %s(u_tess_points, ivec2(index_u + u_spline_counts * 2, index_v), 0).rgba;\n", i * 4 + j, texelFetch); + WRITE(p, " _col[%i] = %s(u_tess_points, ivec2(index_u + u_spline_counts * 2, index_v), 0).rgba;\n", i * 4 + j, compat.texelFetch); } } // Basis polynomials as weight coefficients - WRITE(p, " vec4 basis_u = %s(u_tess_weights_u, %s, 0);\n", texelFetch, "ivec2(weight_idx.x * 2, 0)"); - WRITE(p, " vec4 basis_v = %s(u_tess_weights_v, %s, 0);\n", texelFetch, "ivec2(weight_idx.y * 2, 0)"); + WRITE(p, " vec4 basis_u = %s(u_tess_weights_u, %s, 0);\n", compat.texelFetch, "ivec2(weight_idx.x * 2, 0)"); + WRITE(p, " vec4 basis_v = %s(u_tess_weights_v, %s, 0);\n", compat.texelFetch, "ivec2(weight_idx.y * 2, 0)"); WRITE(p, " mat4 basis = outerProduct(basis_u, basis_v);\n"); // Tessellate @@ -454,8 +444,8 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, WRITE(p, " tess.col = u_matambientalpha;\n"); if (hasNormalTess) { // Derivatives as weight coefficients - WRITE(p, " vec4 deriv_u = %s(u_tess_weights_u, %s, 0);\n", texelFetch, "ivec2(weight_idx.x * 2 + 1, 0)"); - WRITE(p, " vec4 deriv_v = %s(u_tess_weights_v, %s, 0);\n", texelFetch, "ivec2(weight_idx.y * 2 + 1, 0)"); + WRITE(p, " vec4 deriv_u = %s(u_tess_weights_u, %s, 0);\n", compat.texelFetch, "ivec2(weight_idx.x * 2 + 1, 0)"); + WRITE(p, " vec4 deriv_v = %s(u_tess_weights_v, %s, 0);\n", compat.texelFetch, "ivec2(weight_idx.y * 2 + 1, 0)"); WRITE(p, " vec3 du = tess_sample(_pos, outerProduct(deriv_u, basis_v));\n"); WRITE(p, " vec3 dv = tess_sample(_pos, outerProduct(basis_u, deriv_v));\n"); @@ -849,4 +839,5 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, WRITE(p, " gl_Position = outPos;\n"); WRITE(p, "}\n"); + return true; } diff --git a/GPU/GLES/VertexShaderGeneratorGLES.h b/GPU/GLES/VertexShaderGeneratorGLES.h index 7801b2cd6f..0260d694b5 100644 --- a/GPU/GLES/VertexShaderGeneratorGLES.h +++ b/GPU/GLES/VertexShaderGeneratorGLES.h @@ -23,4 +23,4 @@ struct VShaderID; -void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask, uint64_t *uniformMask); +bool GenerateVertexShaderGLSL(const VShaderID &id, char *buffer, uint32_t *attrMask, uint64_t *uniformMask, std::string *errorString); diff --git a/GPU/GPU.vcxproj b/GPU/GPU.vcxproj index 5d3468b07d..4b0224feee 100644 --- a/GPU/GPU.vcxproj +++ b/GPU/GPU.vcxproj @@ -370,14 +370,12 @@ - - @@ -387,12 +385,12 @@ - + - + @@ -549,7 +547,6 @@ - @@ -557,7 +554,6 @@ - @@ -566,14 +562,14 @@ - + - + diff --git a/GPU/GPU.vcxproj.filters b/GPU/GPU.vcxproj.filters index 04ac5cae2d..cabdce9c90 100644 --- a/GPU/GPU.vcxproj.filters +++ b/GPU/GPU.vcxproj.filters @@ -66,9 +66,6 @@ DirectX9 - - DirectX9 - DirectX9 @@ -81,9 +78,6 @@ DirectX9 - - DirectX9 - Common @@ -219,12 +213,6 @@ D3D11 - - D3D11 - - - D3D11 - D3D11 @@ -288,6 +276,12 @@ Common + + DirectX9 + + + DirectX9 + @@ -326,9 +320,6 @@ DirectX9 - - DirectX9 - DirectX9 @@ -341,9 +332,6 @@ DirectX9 - - DirectX9 - DirectX9 @@ -494,12 +482,6 @@ D3D11 - - D3D11 - - - D3D11 - D3D11 @@ -575,5 +557,11 @@ Common + + DirectX9 + + + DirectX9 + \ No newline at end of file diff --git a/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp b/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp index 3d2ad0d1d5..5bbc257173 100644 --- a/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp +++ b/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp @@ -43,8 +43,7 @@ static const char *vulkan_glsl_preamble = #define WRITE p+=sprintf -// Missing: Z depth range -bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer, uint32_t vulkanVendorId) { +bool GenerateFragmentShaderVulkanGLSL(const FShaderID &id, char *buffer, uint32_t vulkanVendorId, std::string *errorString) { char *p = buffer; const char *lastFragData = nullptr; @@ -93,7 +92,7 @@ bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer, uint32_ WRITE(p, "layout (depth_unchanged) out float gl_FragDepth;\n"); } - WRITE(p, "layout (std140, set = 0, binding = 3) uniform baseUBO {\n%s} base;\n", ub_baseStr); + WRITE(p, "layout (std140, set = 0, binding = 3) uniform baseUBO {\n%s};\n", ub_baseStr); if (doTexture) { WRITE(p, "layout (binding = 0) uniform sampler2D tex;\n"); } @@ -167,18 +166,18 @@ bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer, uint32_ std::string modulo = (gl_extensions.bugs & BUG_PVR_SHADER_PRECISION_BAD) ? "mymod" : "mod"; if (id.Bit(FS_BIT_CLAMP_S)) { - ucoord = "clamp(" + ucoord + ", base.texclamp.z, base.texclamp.x - base.texclamp.z)"; + ucoord = "clamp(" + ucoord + ", u_texclamp.z, u_texclamp.x - u_texclamp.z)"; } else { - ucoord = modulo + "(" + ucoord + ", base.texclamp.x)"; + ucoord = modulo + "(" + ucoord + ", u_texclamp.x)"; } if (id.Bit(FS_BIT_CLAMP_T)) { - vcoord = "clamp(" + vcoord + ", base.texclamp.w, base.texclamp.y - base.texclamp.w)"; + vcoord = "clamp(" + vcoord + ", u_texclamp.w, u_texclamp.y - u_texclamp.w)"; } else { - vcoord = modulo + "(" + vcoord + ", base.texclamp.y)"; + vcoord = modulo + "(" + vcoord + ", u_texclamp.y)"; } if (textureAtOffset) { - ucoord = "(" + ucoord + " + base.texclampoff.x)"; - vcoord = "(" + vcoord + " + base.texclampoff.y)"; + ucoord = "(" + ucoord + " + u_texclampoff.x)"; + vcoord = "(" + vcoord + " + u_texclampoff.y)"; } WRITE(p, " vec2 fixedcoord = vec2(%s, %s);\n", ucoord.c_str(), vcoord.c_str()); @@ -203,7 +202,7 @@ bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer, uint32_ } WRITE(p, " vec2 tsize = textureSize(tex, 0);\n"); WRITE(p, " vec2 fraction;\n"); - WRITE(p, " bool bilinear = (base.depal_mask_shift_off_fmt >> 31) != 0;\n"); + WRITE(p, " bool bilinear = (u_depal_mask_shift_off_fmt >> 31) != 0;\n"); WRITE(p, " if (bilinear) {\n"); WRITE(p, " uv_round = uv * tsize - vec2(0.5, 0.5);\n"); WRITE(p, " fraction = fract(uv_round);\n"); @@ -215,10 +214,10 @@ bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer, uint32_ WRITE(p, " vec4 t1 = textureOffset(tex, uv_round, ivec2(1, 0));\n"); WRITE(p, " vec4 t2 = textureOffset(tex, uv_round, ivec2(0, 1));\n"); WRITE(p, " vec4 t3 = textureOffset(tex, uv_round, ivec2(1, 1));\n"); - WRITE(p, " uint depalMask = (base.depal_mask_shift_off_fmt & 0xFF);\n"); - WRITE(p, " uint depalShift = (base.depal_mask_shift_off_fmt >> 8) & 0xFF;\n"); - WRITE(p, " uint depalOffset = ((base.depal_mask_shift_off_fmt >> 16) & 0xFF) << 4;\n"); - WRITE(p, " uint depalFmt = (base.depal_mask_shift_off_fmt >> 24) & 0x3;\n"); + WRITE(p, " uint depalMask = (u_depal_mask_shift_off_fmt & 0xFF);\n"); + WRITE(p, " uint depalShift = (u_depal_mask_shift_off_fmt >> 8) & 0xFF;\n"); + WRITE(p, " uint depalOffset = ((u_depal_mask_shift_off_fmt >> 16) & 0xFF) << 4;\n"); + WRITE(p, " uint depalFmt = (u_depal_mask_shift_off_fmt >> 24) & 0x3;\n"); WRITE(p, " uvec4 col; uint index0; uint index1; uint index2; uint index3;\n"); WRITE(p, " switch (depalFmt) {\n"); // We might want to include fmt in the shader ID if this is a performance issue. WRITE(p, " case 0:\n"); // 565 @@ -299,7 +298,7 @@ bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer, uint32_ break; case GE_TEXFUNC_BLEND: - WRITE(p, " vec4 v = vec4(mix(p.rgb, base.texenv.rgb, t.rgb), p.a * t.a)%s;\n", secondary); + WRITE(p, " vec4 v = vec4(mix(p.rgb, u_texenv.rgb, t.rgb), p.a * t.a)%s;\n", secondary); break; case GE_TEXFUNC_REPLACE: @@ -326,7 +325,7 @@ bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer, uint32_ break; case GE_TEXFUNC_BLEND: - WRITE(p, " vec4 v = vec4(mix(p.rgb, base.texenv.rgb, t.rgb), p.a)%s;\n", secondary); + WRITE(p, " vec4 v = vec4(mix(p.rgb, u_texenv.rgb, t.rgb), p.a)%s;\n", secondary); break; case GE_TEXFUNC_REPLACE: @@ -374,7 +373,7 @@ bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer, uint32_ } else { const char *alphaTestFuncs[] = { "#", "#", " != ", " == ", " >= ", " > ", " <= ", " < " }; if (alphaTestFuncs[alphaTestFunc][0] != '#') { - WRITE(p, " if ((roundAndScaleTo255i(v.a) & base.alphacolormask.a) %s base.alphacolorref.a) %s\n", alphaTestFuncs[alphaTestFunc], discardStatement); + WRITE(p, " if ((roundAndScaleTo255i(v.a) & u_alphacolormask.a) %s u_alphacolorref.a) %s\n", alphaTestFuncs[alphaTestFunc], discardStatement); } else { // This means NEVER. See above. WRITE(p, " %s\n", discardStatement); @@ -384,7 +383,7 @@ bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer, uint32_ if (enableFog) { WRITE(p, " float fogCoef = clamp(v_fogdepth, 0.0, 1.0);\n"); - WRITE(p, " v = mix(vec4(base.fogcolor, v.a), v, fogCoef);\n"); + WRITE(p, " v = mix(vec4(u_fogcolor, v.a), v, fogCoef);\n"); // WRITE(p, " v.x = v_depth;\n"); } @@ -407,7 +406,7 @@ bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer, uint32_ const char *colorTestFuncs[] = { "#", "#", " != ", " == " }; if (colorTestFuncs[colorTestFunc][0] != '#') { WRITE(p, " ivec3 v_scaled = roundAndScaleTo255iv(v.rgb);\n"); - WRITE(p, " if ((v_scaled & base.alphacolormask.rgb) %s (base.alphacolorref.rgb & base.alphacolormask.rgb)) %s\n", colorTestFuncs[colorTestFunc], discardStatement); + WRITE(p, " if ((v_scaled & u_alphacolormask.rgb) %s (u_alphacolorref.rgb & u_alphacolormask.rgb)) %s\n", colorTestFuncs[colorTestFunc], discardStatement); } else { WRITE(p, " %s\n", discardStatement); } @@ -431,7 +430,12 @@ bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer, uint32_ case GE_SRCBLEND_DOUBLEINVSRCALPHA: srcFactor = "vec3(1.0 - v.a * 2.0)"; break; case GE_SRCBLEND_DOUBLEDSTALPHA: srcFactor = "ERROR"; break; case GE_SRCBLEND_DOUBLEINVDSTALPHA: srcFactor = "ERROR"; break; - case GE_SRCBLEND_FIXA: srcFactor = "base.blendFixA"; break; + case GE_SRCBLEND_FIXA: srcFactor = "u_blendFixA"; break; + } + + if (!strcmp(srcFactor, "ERROR")) { + *errorString = "Bad replaceblend src factor"; + return false; } WRITE(p, " v.rgb = v.rgb * %s;\n", srcFactor); @@ -454,7 +458,7 @@ bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer, uint32_ case GE_SRCBLEND_DOUBLEINVSRCALPHA: srcFactor = "vec3(1.0 - v.a * 2.0)"; break; case GE_SRCBLEND_DOUBLEDSTALPHA: srcFactor = "vec3(destColor.a * 2.0)"; break; case GE_SRCBLEND_DOUBLEINVDSTALPHA: srcFactor = "vec3(1.0 - destColor.a * 2.0)"; break; - case GE_SRCBLEND_FIXA: srcFactor = "base.blendFixA"; break; + case GE_SRCBLEND_FIXA: srcFactor = "u_blendFixA"; break; } switch (replaceBlendFuncB) { case GE_DSTBLEND_SRCCOLOR: dstFactor = "v.rgb"; break; @@ -467,7 +471,7 @@ bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer, uint32_ case GE_DSTBLEND_DOUBLEINVSRCALPHA: dstFactor = "vec3(1.0 - v.a * 2.0)"; break; case GE_DSTBLEND_DOUBLEDSTALPHA: dstFactor = "vec3(destColor.a * 2.0)"; break; case GE_DSTBLEND_DOUBLEINVDSTALPHA: dstFactor = "vec3(1.0 - destColor.a * 2.0)"; break; - case GE_DSTBLEND_FIXB: dstFactor = "base.blendFixB"; break; + case GE_DSTBLEND_FIXB: dstFactor = "u_blendFixB"; break; } switch (replaceBlendEq) { @@ -502,7 +506,7 @@ bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer, uint32_ if (stencilToAlpha != REPLACE_ALPHA_NO) { switch (replaceAlphaWithStencilType) { case STENCIL_VALUE_UNIFORM: - replacedAlpha = "base.stencilReplace"; + replacedAlpha = "u_stencilReplaceValue"; break; case STENCIL_VALUE_ZERO: @@ -550,7 +554,7 @@ bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer, uint32_ break; default: - ERROR_LOG(G3D, "Bad stencil-to-alpha type, corrupt ID?"); + *errorString = "Bad stencil-to-alpha type, corrupt ID?"; return false; } @@ -566,7 +570,7 @@ bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer, uint32_ break; default: - ERROR_LOG(G3D, "Bad logic op type, corrupt ID?"); + *errorString = "Bad logic op type, corrupt ID?"; return false; } diff --git a/GPU/Vulkan/FragmentShaderGeneratorVulkan.h b/GPU/Vulkan/FragmentShaderGeneratorVulkan.h index 7fb02edc62..a3c64828e9 100644 --- a/GPU/Vulkan/FragmentShaderGeneratorVulkan.h +++ b/GPU/Vulkan/FragmentShaderGeneratorVulkan.h @@ -20,4 +20,4 @@ struct FShaderID; -bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer, uint32_t vulkanVendorId); +bool GenerateFragmentShaderVulkanGLSL(const FShaderID &id, char *buffer, uint32_t vulkanVendorId, std::string *errorString); diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index 1dff1d8ce0..dff7f01d64 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -262,7 +262,8 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader VulkanVertexShader *vs = vsCache_.Get(VSID); if (!vs) { // Vertex shader not in cache. Let's compile it. - GenerateVulkanGLSLVertexShader(VSID, codeBuffer_); + std::string genErrorString; + GenerateVertexShaderVulkanGLSL(VSID, codeBuffer_, &genErrorString); vs = new VulkanVertexShader(vulkan_, VSID, codeBuffer_, useHWTransform); vsCache_.Insert(VSID, vs); } @@ -272,7 +273,9 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader if (!fs) { uint32_t vendorID = vulkan_->GetPhysicalDeviceProperties().properties.vendorID; // Fragment shader not in cache. Let's compile it. - GenerateVulkanGLSLFragmentShader(FSID, codeBuffer_, vendorID); + std::string genErrorString; + bool success = GenerateFragmentShaderVulkanGLSL(FSID, codeBuffer_, vendorID, &genErrorString); + _assert_(success); fs = new VulkanFragmentShader(vulkan_, FSID, codeBuffer_); fsCache_.Insert(FSID, fs); } @@ -388,7 +391,10 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) { break; } bool useHWTransform = id.Bit(VS_BIT_USE_HW_TRANSFORM); - GenerateVulkanGLSLVertexShader(id, codeBuffer_); + std::string genErrorString; + if (!GenerateVertexShaderVulkanGLSL(id, codeBuffer_, &genErrorString)) { + return false; + } VulkanVertexShader *vs = new VulkanVertexShader(vulkan_, id, codeBuffer_, useHWTransform); vsCache_.Insert(id, vs); } @@ -399,7 +405,10 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) { ERROR_LOG(G3D, "Vulkan shader cache truncated"); break; } - GenerateVulkanGLSLFragmentShader(id, codeBuffer_, vendorID); + std::string genErrorString; + if (!GenerateFragmentShaderVulkanGLSL(id, codeBuffer_, vendorID, &genErrorString)) { + return false; + } VulkanFragmentShader *fs = new VulkanFragmentShader(vulkan_, id, codeBuffer_); fsCache_.Insert(id, fs); } diff --git a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp index 36574f24ae..f18ea66729 100644 --- a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp +++ b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp @@ -39,7 +39,8 @@ static const char *vulkan_glsl_preamble = "#version 450\n" "#extension GL_ARB_separate_shader_objects : enable\n" -"#extension GL_ARB_shading_language_420pack : enable\n\n"; +"#extension GL_ARB_shading_language_420pack : enable\n" +"#define splat3(x) vec3(x)\n\n"; // "Varying" layout - must match fragment shader // color0 = 0 @@ -63,12 +64,6 @@ static const char * const boneWeightDecl[9] = { "layout(location = 3) in vec4 w1;\nlayout(location = 4) in vec4 w2;\n", }; -enum DoLightComputation { - LIGHT_OFF, - LIGHT_SHADE, - LIGHT_FULL, -}; - // Depth range and viewport // // After the multiplication with the projection matrix, we have a 4D vector in clip space. @@ -94,7 +89,7 @@ enum DoLightComputation { // TODO: Skip all this if we can actually get a 16-bit depth buffer along with stencil, which // is a bit of a rare configuration, although quite common on mobile. -bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { +bool GenerateVertexShaderVulkanGLSL(const VShaderID &id, char *buffer, std::string *errorString) { char *p = buffer; WRITE(p, "%s", vulkan_glsl_preamble); @@ -134,11 +129,11 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { bool flipNormalTess = id.Bit(VS_BIT_NORM_REVERSE_TESS); WRITE(p, "\n"); - WRITE(p, "layout (std140, set = 0, binding = 3) uniform baseVars {\n%s} base;\n", ub_baseStr); + WRITE(p, "layout (std140, set = 0, binding = 3) uniform baseVars {\n%s};\n", ub_baseStr); if (enableLighting || doShadeMapping) - WRITE(p, "layout (std140, set = 0, binding = 4) uniform lightVars {\n%s} light;\n", ub_vs_lightsStr); + WRITE(p, "layout (std140, set = 0, binding = 4) uniform lightVars {\n%s};\n", ub_vs_lightsStr); if (enableBones) - WRITE(p, "layout (std140, set = 0, binding = 5) uniform boneVars {\n%s} bone;\n", ub_vs_bonesStr); + WRITE(p, "layout (std140, set = 0, binding = 5) uniform boneVars {\n%s};\n", ub_vs_bonesStr); const char *shading = doFlatShading ? "flat " : ""; @@ -203,9 +198,9 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { // Apply the projection and viewport to get the Z buffer value, floor to integer, undo the viewport and projection. WRITE(p, "\nvec4 depthRoundZVP(vec4 v) {\n"); WRITE(p, " float z = v.z / v.w;\n"); - WRITE(p, " z = z * base.depthRange.x + base.depthRange.y;\n"); + WRITE(p, " z = z * u_depthRange.x + u_depthRange.y;\n"); WRITE(p, " z = floor(z);\n"); - WRITE(p, " z = (z - base.depthRange.z) * base.depthRange.w;\n"); + WRITE(p, " z = (z - u_depthRange.z) * u_depthRange.w;\n"); WRITE(p, " return vec4(v.x, v.y, z * v.w, v.w);\n"); WRITE(p, "}\n\n"); } @@ -263,7 +258,7 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { WRITE(p, " int index;\n"); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { - WRITE(p, " index = (%i + point_pos.y) * int(base.spline_counts) + (%i + point_pos.x);\n", i, j); + WRITE(p, " index = (%i + point_pos.y) * int(u_spline_counts) + (%i + point_pos.x);\n", i, j); WRITE(p, " _pos[%i] = tess_data.data[index].pos.xyz;\n", i * 4 + j); if (doTexture && hasTexcoordTess) WRITE(p, " _tex[%i] = tess_data.data[index].uv.xy;\n", i * 4 + j); @@ -288,7 +283,7 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { if (hasColorTess) WRITE(p, " tess.col = tess_sample(_col, basis);\n"); else - WRITE(p, " tess.col = base.matambientalpha;\n"); + WRITE(p, " tess.col = u_matambientalpha;\n"); if (hasNormalTess) { // Derivatives as weight coefficients WRITE(p, " vec4 deriv_u = tess_weights_u.data[weight_idx.x].deriv;\n"); @@ -317,7 +312,7 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { if (lmode) WRITE(p, " v_color1 = color1;\n"); } else { - WRITE(p, " v_color0 = base.matambientalpha;\n"); + WRITE(p, " v_color0 = u_matambientalpha;\n"); if (lmode) WRITE(p, " v_color1 = vec3(0.0);\n"); } @@ -325,13 +320,13 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { WRITE(p, " v_fogdepth = position.w;\n"); } if (isModeThrough) { - WRITE(p, " vec4 outPos = base.proj_through_mtx * vec4(position.xyz, 1.0);\n"); + WRITE(p, " vec4 outPos = u_proj_through * vec4(position.xyz, 1.0);\n"); } else { // The viewport is used in this case, so need to compensate for that. if (gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) { - WRITE(p, " vec4 outPos = depthRoundZVP(base.proj_mtx * vec4(position.xyz, 1.0));\n"); + WRITE(p, " vec4 outPos = depthRoundZVP(u_proj * vec4(position.xyz, 1.0));\n"); } else { - WRITE(p, " vec4 outPos = base.proj_mtx * vec4(position.xyz, 1.0);\n"); + WRITE(p, " vec4 outPos = u_proj * vec4(position.xyz, 1.0);\n"); } } } else { @@ -342,17 +337,17 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { WRITE(p, " Tess tess;\n"); WRITE(p, " tessellate(tess);\n"); - WRITE(p, " vec3 worldpos = vec4(tess.pos.xyz, 1.0) * base.world_mtx;\n"); + WRITE(p, " vec3 worldpos = vec4(tess.pos.xyz, 1.0) * u_world;\n"); if (hasNormalTess) { - WRITE(p, " mediump vec3 worldnormal = normalize(vec4(%stess.nrm, 0.0) * base.world_mtx);\n", flipNormalTess ? "-" : ""); + WRITE(p, " mediump vec3 worldnormal = normalize(vec4(%stess.nrm, 0.0) * u_world);\n", flipNormalTess ? "-" : ""); } else { WRITE(p, " mediump vec3 worldnormal = vec3(0.0, 0.0, 1.0);\n"); } } else { // No skinning, just standard T&L. - WRITE(p, " vec3 worldpos = vec4(position.xyz, 1.0) * base.world_mtx;\n"); + WRITE(p, " vec3 worldpos = vec4(position.xyz, 1.0) * u_world;\n"); if (hasNormal) - WRITE(p, " mediump vec3 worldnormal = normalize(vec4(%snormal, 0.0) * base.world_mtx);\n", flipNormal ? "-" : ""); + WRITE(p, " mediump vec3 worldnormal = normalize(vec4(%snormal, 0.0) * u_world);\n", flipNormal ? "-" : ""); else WRITE(p, " mediump vec3 worldnormal = vec3(0.0, 0.0, 1.0);\n"); } @@ -365,10 +360,10 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { "w2.x", "w2.y", "w2.z", "w2.w", }; - WRITE(p, " mat3x4 skinMatrix = w1.x * bone.m[0];\n"); + WRITE(p, " mat3x4 skinMatrix = w1.x * u_bone[0];\n"); if (numBoneWeights > 1) { for (int i = 1; i < numBoneWeights; i++) { - WRITE(p, " skinMatrix += %s * bone.m[%i];\n", boneWeightAttr[i], i); + WRITE(p, " skinMatrix += %s * u_bone[%i];\n", boneWeightAttr[i], i); } } @@ -376,35 +371,35 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { // Trying to simplify this results in bugs in LBP... WRITE(p, " vec3 skinnedpos = (vec4(position, 1.0) * skinMatrix) %s;\n", factor); - WRITE(p, " vec3 worldpos = vec4(skinnedpos, 1.0) * base.world_mtx;\n"); + WRITE(p, " vec3 worldpos = vec4(skinnedpos, 1.0) * u_world;\n"); if (hasNormal) { WRITE(p, " mediump vec3 skinnednormal = vec4(%snormal, 0.0) * skinMatrix %s;\n", flipNormal ? "-" : "", factor); } else { WRITE(p, " mediump vec3 skinnednormal = vec4(0.0, 0.0, %s1.0, 0.0) * skinMatrix %s;\n", flipNormal ? "-" : "", factor); } - WRITE(p, " mediump vec3 worldnormal = normalize(vec4(skinnednormal, 0.0) * base.world_mtx);\n"); + WRITE(p, " mediump vec3 worldnormal = normalize(vec4(skinnednormal, 0.0) * u_world);\n"); } - WRITE(p, " vec4 viewPos = vec4(vec4(worldpos, 1.0) * base.view_mtx, 1.0);\n"); + WRITE(p, " vec4 viewPos = vec4(vec4(worldpos, 1.0) * u_view, 1.0);\n"); // Final view and projection transforms. if (gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) { - WRITE(p, " vec4 outPos = depthRoundZVP(base.proj_mtx * viewPos);\n"); + WRITE(p, " vec4 outPos = depthRoundZVP(u_proj * viewPos);\n"); } else { - WRITE(p, " vec4 outPos = base.proj_mtx * viewPos;\n"); + WRITE(p, " vec4 outPos = u_proj * viewPos;\n"); } // TODO: Declare variables for dots for shade mapping if needed. - const char *ambientStr = ((matUpdate & 1) && hasColor) ? "color0" : "base.matambientalpha"; - const char *diffuseStr = ((matUpdate & 2) && hasColor) ? "color0.rgb" : "light.matdiffuse"; - const char *specularStr = ((matUpdate & 4) && hasColor) ? "color0.rgb" : "light.matspecular.rgb"; + const char *ambientStr = ((matUpdate & 1) && hasColor) ? "color0" : "u_matambientalpha"; + const char *diffuseStr = ((matUpdate & 2) && hasColor) ? "color0.rgb" : "u_matdiffuse"; + const char *specularStr = ((matUpdate & 4) && hasColor) ? "color0.rgb" : "u_matspecular.rgb"; if (doBezier || doSpline) { // TODO: Probably, should use hasColorTess but FF4 has a problem with drawing the background. - ambientStr = (matUpdate & 1) && hasColor ? "tess.col" : "base.matambientalpha"; - diffuseStr = (matUpdate & 2) && hasColor ? "tess.col.rgb" : "light.matdiffuse"; - specularStr = (matUpdate & 4) && hasColor ? "tess.col.rgb" : "light.matspecular.rgb"; + ambientStr = (matUpdate & 1) && hasColor ? "tess.col" : "u_matambientalpha"; + diffuseStr = (matUpdate & 2) && hasColor ? "tess.col.rgb" : "u_matdiffuse"; + specularStr = (matUpdate & 4) && hasColor ? "tess.col.rgb" : "u_matspecular.rgb"; } bool diffuseIsZero = true; @@ -412,7 +407,7 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { bool distanceNeeded = false; if (enableLighting) { - WRITE(p, " vec4 lightSum0 = light.u_ambient * %s + vec4(light.matemissive, 0.0);\n", ambientStr); + WRITE(p, " vec4 lightSum0 = u_ambient * %s + vec4(u_matemissive, 0.0);\n", ambientStr); for (int i = 0; i < 4; i++) { GELightType type = static_cast(id.Bits(VS_BIT_LIGHT0_TYPE + 4 * i, 2)); @@ -450,9 +445,9 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { if (type == GE_LIGHTTYPE_DIRECTIONAL) { // We prenormalize light positions for directional lights. - WRITE(p, " toLight = light.pos[%i];\n", i); + WRITE(p, " toLight = u_lightpos%d;\n", i); } else { - WRITE(p, " toLight = light.pos[%i] - worldpos;\n", i); + WRITE(p, " toLight = u_lightpos%d - worldpos;\n", i); WRITE(p, " distance = length(toLight);\n"); WRITE(p, " toLight /= distance;\n"); } @@ -464,10 +459,10 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { if (poweredDiffuse) { // pow(0.0, 0.0) may be undefined, but the PSP seems to treat it as 1.0. // Seen in Tales of the World: Radiant Mythology (#2424.) - WRITE(p, " if (light.matspecular.a <= 0.0) {\n"); + WRITE(p, " if (u_matspecular.a <= 0.0) {\n"); WRITE(p, " dot%i = 1.0;\n", i); WRITE(p, " } else {\n"); - WRITE(p, " dot%i = pow(max(dot%i, 0.0), light.matspecular.a);\n", i, i); + WRITE(p, " dot%i = pow(max(dot%i, 0.0), u_matspecular.a);\n", i, i); WRITE(p, " }\n"); } @@ -479,13 +474,13 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { timesLightScale = ""; break; case GE_LIGHTTYPE_POINT: - WRITE(p, " lightScale = clamp(1.0 / dot(light.att[%i], vec3(1.0, distance, distance*distance)), 0.0, 1.0);\n", i); + WRITE(p, " lightScale = clamp(1.0 / dot(u_lightatt%d, vec3(1.0, distance, distance*distance)), 0.0, 1.0);\n", i); break; case GE_LIGHTTYPE_SPOT: case GE_LIGHTTYPE_UNKNOWN: - WRITE(p, " float angle%i = length(light.dir[%i]) == 0.0 ? 0.0 : dot(normalize(light.dir[%i]), toLight);\n", i, i, i); - WRITE(p, " if (angle%i >= light.angle_spotCoef[%i].x) {\n", i, i); - WRITE(p, " lightScale = clamp(1.0 / dot(light.att[%i], vec3(1.0, distance, distance*distance)), 0.0, 1.0) * (light.angle_spotCoef[%i].y <= 0.0 ? 1.0 : pow(angle%i, light.angle_spotCoef[%i].y));\n", i, i, i, i); + WRITE(p, " float angle%i = length(u_lightdir%d) == 0.0 ? 0.0 : dot(normalize(u_lightdir%d), toLight);\n", i, i, i); + WRITE(p, " if (angle%i >= u_lightangle_spotCoef%d.x) {\n", i, i); + WRITE(p, " lightScale = clamp(1.0 / dot(u_lightatt%d, vec3(1.0, distance, distance*distance)), 0.0, 1.0) * (u_lightangle_spotCoef%d.y <= 0.0 ? 1.0 : pow(angle%i, u_lightangle_spotCoef%d.y));\n", i, i, i, i); WRITE(p, " } else {\n"); WRITE(p, " lightScale = 0.0;\n"); WRITE(p, " }\n"); @@ -495,20 +490,20 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { break; } - WRITE(p, " diffuse = (light.diffuse[%i] * %s) * max(dot%i, 0.0);\n", i, diffuseStr, i); + WRITE(p, " diffuse = (u_lightdiffuse%d * %s) * max(dot%i, 0.0);\n", i, diffuseStr, i); if (doSpecular) { WRITE(p, " if (dot%i >= 0.0) {\n", i); WRITE(p, " dot%i = dot(normalize(toLight + vec3(0.0, 0.0, 1.0)), worldnormal);\n", i); - WRITE(p, " if (light.matspecular.a <= 0.0) {\n"); + WRITE(p, " if (u_matspecular.a <= 0.0) {\n"); WRITE(p, " dot%i = 1.0;\n", i); WRITE(p, " } else {\n"); - WRITE(p, " dot%i = pow(max(dot%i, 0.0), light.matspecular.a);\n", i, i); + WRITE(p, " dot%i = pow(max(dot%i, 0.0), u_matspecular.a);\n", i, i); WRITE(p, " }\n"); WRITE(p, " if (dot%i > 0.0)\n", i); - WRITE(p, " lightSum1 += light.specular[%i] * %s * dot%i %s;\n", i, specularStr, i, timesLightScale); + WRITE(p, " lightSum1 += u_lightspecular%d * %s * dot%i %s;\n", i, specularStr, i, timesLightScale); WRITE(p, " }\n"); } - WRITE(p, " lightSum0.rgb += (light.ambient[%i] * %s.rgb + diffuse)%s;\n", i, ambientStr, timesLightScale); + WRITE(p, " lightSum0.rgb += (u_lightambient%d * %s.rgb + diffuse)%s;\n", i, ambientStr, timesLightScale); } if (enableLighting) { @@ -536,7 +531,7 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { else WRITE(p, " v_color0 = color0;\n"); } else { - WRITE(p, " v_color0 = base.matambientalpha;\n"); + WRITE(p, " v_color0 = u_matambientalpha;\n"); } if (lmode) { WRITE(p, " v_color1 = vec3(0.0);\n"); @@ -553,17 +548,17 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { if (scaleUV) { if (hasTexcoord) { if (doBezier || doSpline) - WRITE(p, " v_texcoord = vec3(tess.tex.xy * base.uvscaleoffset.xy + base.uvscaleoffset.zw, 0.0);\n"); + WRITE(p, " v_texcoord = vec3(tess.tex.xy * u_uvscaleoffset.xy + u_uvscaleoffset.zw, 0.0);\n"); else - WRITE(p, " v_texcoord = vec3(texcoord.xy * base.uvscaleoffset.xy, 0.0);\n"); + WRITE(p, " v_texcoord = vec3(texcoord.xy * u_uvscaleoffset.xy, 0.0);\n"); } else { WRITE(p, " v_texcoord = vec3(0.0);\n"); } } else { if (hasTexcoord) { - WRITE(p, " v_texcoord = vec3(texcoord.xy * base.uvscaleoffset.xy + base.uvscaleoffset.zw, 0.0);\n"); + WRITE(p, " v_texcoord = vec3(texcoord.xy * u_uvscaleoffset.xy + u_uvscaleoffset.zw, 0.0);\n"); } else { - WRITE(p, " v_texcoord = vec3(base.uvscaleoffset.zw, 0.0);\n"); + WRITE(p, " v_texcoord = vec3(u_uvscaleoffset.zw, 0.0);\n"); } } break; @@ -599,15 +594,15 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { break; } // Transform by texture matrix. XYZ as we are doing projection mapping. - WRITE(p, " v_texcoord = (%s * base.tex_mtx).xyz * vec3(base.uvscaleoffset.xy, 1.0);\n", temp_tc.c_str()); + WRITE(p, " v_texcoord = (%s * u_tex).xyz * vec3(u_uvscaleoffset.xy, 1.0);\n", temp_tc.c_str()); } break; case GE_TEXMAP_ENVIRONMENT_MAP: // Shade mapping - use dots from light sources. { - std::string lightFactor0 = StringFromFormat("(length(light.pos[%i]) == 0.0 ? worldnormal.z : dot(normalize(light.pos[%i]), worldnormal))", ls0, ls0); - std::string lightFactor1 = StringFromFormat("(length(light.pos[%i]) == 0.0 ? worldnormal.z : dot(normalize(light.pos[%i]), worldnormal))", ls1, ls1); - WRITE(p, " v_texcoord = vec3(base.uvscaleoffset.xy * vec2(1.0 + %s, 1.0 + %s) * 0.5, 1.0);\n", lightFactor0.c_str(), lightFactor1.c_str()); + std::string lightFactor0 = StringFromFormat("(length(u_lightpos%d) == 0.0 ? worldnormal.z : dot(normalize(u_lightpos%d), worldnormal))", ls0, ls0); + std::string lightFactor1 = StringFromFormat("(length(u_lightpos%d) == 0.0 ? worldnormal.z : dot(normalize(u_lightpos%d), worldnormal))", ls1, ls1); + WRITE(p, " v_texcoord = vec3(u_uvscaleoffset.xy * vec2(1.0 + %s, 1.0 + %s) * 0.5, 1.0);\n", lightFactor0.c_str(), lightFactor1.c_str()); } break; @@ -619,17 +614,17 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) { // Compute fogdepth if (enableFog) - WRITE(p, " v_fogdepth = (viewPos.z + base.fogcoef.x) * base.fogcoef.y;\n"); + WRITE(p, " v_fogdepth = (viewPos.z + u_fogcoef.x) * u_fogcoef.y;\n"); } if (!isModeThrough && gstate_c.Supports(GPU_SUPPORTS_VS_RANGE_CULLING)) { WRITE(p, " vec3 projPos = outPos.xyz / outPos.w;\n"); // Vertex range culling doesn't happen when depth is clamped, so only do this if in range. - WRITE(p, " if (base.cullRangeMin.w <= 0.0 || (projPos.z >= base.cullRangeMin.z && projPos.z <= base.cullRangeMax.z)) {\n"); - const char *outMin = "projPos.x < base.cullRangeMin.x || projPos.y < base.cullRangeMin.y || projPos.z < base.cullRangeMin.z"; - const char *outMax = "projPos.x > base.cullRangeMax.x || projPos.y > base.cullRangeMax.y || projPos.z > base.cullRangeMax.z"; + WRITE(p, " if (u_cullRangeMin.w <= 0.0 || (projPos.z >= u_cullRangeMin.z && projPos.z <= u_cullRangeMax.z)) {\n"); + const char *outMin = "projPos.x < u_cullRangeMin.x || projPos.y < u_cullRangeMin.y || projPos.z < u_cullRangeMin.z"; + const char *outMax = "projPos.x > u_cullRangeMax.x || projPos.y > u_cullRangeMax.y || projPos.z > u_cullRangeMax.z"; WRITE(p, " if (%s || %s) {\n", outMin, outMax); - WRITE(p, " outPos.xyzw = vec4(base.cullRangeMax.w);\n"); + WRITE(p, " outPos.xyzw = vec4(u_cullRangeMax.w);\n"); WRITE(p, " }\n"); WRITE(p, " }\n"); } diff --git a/GPU/Vulkan/VertexShaderGeneratorVulkan.h b/GPU/Vulkan/VertexShaderGeneratorVulkan.h index 1501c1cdae..51f2b56d55 100644 --- a/GPU/Vulkan/VertexShaderGeneratorVulkan.h +++ b/GPU/Vulkan/VertexShaderGeneratorVulkan.h @@ -2,4 +2,4 @@ #include "GPU/Common/ShaderId.h" -bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer); +bool GenerateVertexShaderVulkanGLSL(const VShaderID &id, char *buffer, std::string *errorString); diff --git a/UWP/GPU_UWP/GPU_UWP.vcxproj b/UWP/GPU_UWP/GPU_UWP.vcxproj index be5fdc1a1f..6b735f6a38 100644 --- a/UWP/GPU_UWP/GPU_UWP.vcxproj +++ b/UWP/GPU_UWP/GPU_UWP.vcxproj @@ -404,22 +404,20 @@ - - - - + + @@ -466,7 +464,6 @@ - @@ -474,14 +471,13 @@ - - - + + diff --git a/UWP/GPU_UWP/GPU_UWP.vcxproj.filters b/UWP/GPU_UWP/GPU_UWP.vcxproj.filters index 261335da46..1a11e78ecd 100644 --- a/UWP/GPU_UWP/GPU_UWP.vcxproj.filters +++ b/UWP/GPU_UWP/GPU_UWP.vcxproj.filters @@ -29,7 +29,6 @@ - @@ -37,14 +36,13 @@ - - - + + @@ -86,22 +84,20 @@ - - - - + + diff --git a/libretro/Makefile.common b/libretro/Makefile.common index 0c03333b9d..11b8998bd6 100644 --- a/libretro/Makefile.common +++ b/libretro/Makefile.common @@ -526,7 +526,7 @@ ifeq ($(WITH_DYNAREC),1) $(COREDIR)/MIPS/ARM/ArmJit.cpp \ $(COREDIR)/MIPS/ARM/ArmRegCache.cpp \ $(COREDIR)/MIPS/ARM/ArmRegCacheFPU.cpp \ - $(EXTDIR)/disarm.cpp \ + $(EXTDIR)/disarm.cpp \ $(GPUCOMMONDIR)/VertexDecoderArm.cpp ifeq ($(HAVE_NEON),1) @@ -663,7 +663,7 @@ ifeq ($(PLATFORM_EXT), win32) SOURCES_CXX += \ $(GPUDIR)/Directx9/DepalettizeShaderDX9.cpp \ $(GPUDIR)/Directx9/DrawEngineDX9.cpp \ - $(GPUDIR)/Directx9/PixelShaderGeneratorDX9.cpp \ + $(GPUDIR)/Directx9/FragmentShaderGeneratorHLSL.cpp \ $(GPUDIR)/Directx9/FramebufferManagerDX9.cpp \ $(GPUDIR)/Directx9/GPU_DX9.cpp \ $(GPUDIR)/Directx9/ShaderManagerDX9.cpp \ @@ -671,12 +671,11 @@ SOURCES_CXX += \ $(GPUDIR)/Directx9/StencilBufferDX9.cpp \ $(GPUDIR)/Directx9/TextureCacheDX9.cpp \ $(GPUDIR)/Directx9/TextureScalerDX9.cpp \ - $(GPUDIR)/Directx9/VertexShaderGeneratorDX9.cpp + $(GPUDIR)/Directx9/VertexShaderGeneratorHLSL.cpp SOURCES_CXX += \ $(GPUDIR)/D3D11/DepalettizeShaderD3D11.cpp \ $(GPUDIR)/D3D11/DrawEngineD3D11.cpp \ - $(GPUDIR)/D3D11/FragmentShaderGeneratorD3D11.cpp \ $(GPUDIR)/D3D11/FramebufferManagerD3D11.cpp \ $(GPUDIR)/D3D11/GPU_D3D11.cpp \ $(GPUDIR)/D3D11/D3D11Util.cpp \ @@ -685,7 +684,6 @@ SOURCES_CXX += \ $(GPUDIR)/D3D11/StencilBufferD3D11.cpp \ $(GPUDIR)/D3D11/TextureCacheD3D11.cpp \ $(GPUDIR)/D3D11/TextureScalerD3D11.cpp \ - $(GPUDIR)/D3D11/VertexShaderGeneratorD3D11.cpp \ $(LIBRETRODIR)/LibretroD3D11Context.cpp SOURCES_CXX += \ diff --git a/unittest/TestShaderGenerators.cpp b/unittest/TestShaderGenerators.cpp new file mode 100644 index 0000000000..e295ffd91d --- /dev/null +++ b/unittest/TestShaderGenerators.cpp @@ -0,0 +1,195 @@ +#include "Common/StringUtils.h" + +#include "GPU/Common/ShaderId.h" +#include "GPU/Common/ShaderCommon.h" +#include "Common/Data/Random/Rng.h" + +#include "GPU/Vulkan/VulkanContext.h" + +#include "GPU/Vulkan/FragmentShaderGeneratorVulkan.h" +#include "GPU/Directx9/FragmentShaderGeneratorHLSL.h" +#include "GPU/GLES/FragmentShaderGeneratorGLES.h" + +#include "GPU/Vulkan/VertexShaderGeneratorVulkan.h" +#include "GPU/Directx9/VertexShaderGeneratorHLSL.h" +#include "GPU/GLES/VertexShaderGeneratorGLES.h" + +#include "GPU/D3D11/D3D11Util.h" +#include "GPU/D3D11/D3D11Loader.h" + +#include "GPU/D3D9/D3DCompilerLoader.h" +#include "GPU/D3D9/D3D9ShaderCompiler.h" + +bool GenerateFShader(FShaderID id, char *buffer, ShaderLanguage lang, std::string *errorString) { + switch (lang) { + case ShaderLanguage::HLSL_D3D11: + return GenerateFragmentShaderHLSL(id, buffer, ShaderLanguage::HLSL_D3D11, errorString); + case ShaderLanguage::HLSL_DX9: + GenerateFragmentShaderHLSL(id, buffer, ShaderLanguage::HLSL_DX9, errorString); + // TODO: Need a device :( Returning false here so it doesn't get tried. + return false; + case ShaderLanguage::GLSL_VULKAN: + return GenerateFragmentShaderVulkanGLSL(id, buffer, 0, errorString); + case ShaderLanguage::GLSL_140: + case ShaderLanguage::GLSL_300: + // TODO: Need a device - except that maybe glslang could be used to verify these .... + return false; + default: + return false; + } +} + +bool GenerateVShader(VShaderID id, char *buffer, ShaderLanguage lang, std::string *errorString) { + switch (lang) { + case ShaderLanguage::HLSL_D3D11: + return GenerateVertexShaderHLSL(id, buffer, ShaderLanguage::HLSL_D3D11, errorString); + case ShaderLanguage::HLSL_DX9: + GenerateVertexShaderHLSL(id, buffer, ShaderLanguage::HLSL_DX9, errorString); + // TODO: Need a device :( Returning false here so it doesn't get tried. + return false; + // return DX9::GenerateFragmentShaderHLSL(id, buffer, ShaderLanguage::HLSL_DX9); + case ShaderLanguage::GLSL_VULKAN: + return GenerateVertexShaderVulkanGLSL(id, buffer, errorString); + default: + return false; + } +} + +bool TestCompileShader(const char *buffer, ShaderLanguage lang, bool vertex) { + switch (lang) { + case ShaderLanguage::HLSL_D3D11: + { + auto output = CompileShaderToBytecodeD3D11(buffer, strlen(buffer), vertex ? "vs_4_0" : "ps_4_0", 0); + return !output.empty(); + } + case ShaderLanguage::HLSL_DX9: + return false; + case ShaderLanguage::GLSL_VULKAN: + { + std::vector spirv; + std::string errorMessage; + bool result = GLSLtoSPV(vertex ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT, buffer, spirv, &errorMessage); + if (!result) { + printf("GLSLtoSPV ERROR:\n%s\n\n", errorMessage.c_str()); + } + return result; + } + case ShaderLanguage::GLSL_140: + + return false; + case ShaderLanguage::GLSL_300: + + return false; + default: + return false; + } +} + +bool TestShaderGenerators() { + LoadD3D11(); + init_glslang(); + LoadD3DCompilerDynamic(); + + ShaderLanguage languages[] = { + ShaderLanguage::HLSL_D3D11, + ShaderLanguage::GLSL_VULKAN, + ShaderLanguage::GLSL_140, + ShaderLanguage::GLSL_300, + ShaderLanguage::HLSL_DX9, + }; + const int numLanguages = ARRAY_SIZE(languages); + + char *buffer[numLanguages]; + + for (int i = 0; i < numLanguages; i++) { + buffer[i] = new char[65536]; + } + GMRng rng; + int successes = 0; + int count = 200; + + // Generate a bunch of random fragment shader IDs, try to generate shader source. + // Then compile it and check that it's ok. + for (int i = 0; i < count; i++) { + uint32_t bottom = rng.R32(); + uint32_t top = rng.R32(); + FShaderID id; + id.d[0] = bottom; + id.d[1] = top; + + bool generateSuccess[numLanguages]{}; + + for (int j = 0; j < numLanguages; j++) { + std::string genErrorString; + generateSuccess[j] = GenerateFShader(id, buffer[j], languages[j], &genErrorString); + if (!genErrorString.empty()) { + printf("%s\n", genErrorString.c_str()); + } + // We ignore the contents of the error string here, not even gonna try to compile if it errors. + } + + // Now that we have the strings ready for easy comparison (buffer,4 in the watch window), + // let's try to compile them. + for (int j = 0; j < numLanguages; j++) { + if (generateSuccess[j]) { + if (!TestCompileShader(buffer[j], languages[j], false)) { + printf("Error compiling fragment shader:\n\n%s\n\n", LineNumberString(buffer[j]).c_str()); + return false; + } + successes++; + } + } + } + + printf("%d/%d fragment shaders generated (it's normal that it's not all, there are invalid bit combos)\n", successes, count * numLanguages); + + successes = 0; + count = 200; + + // Generate a bunch of random vertex shader IDs, try to generate shader source. + // Then compile it and check that it's ok. + for (int i = 0; i < count; i++) { + uint32_t bottom = rng.R32(); + uint32_t top = rng.R32(); + VShaderID id; + id.d[0] = bottom; + id.d[1] = top; + + // Skip testing beziers for now. I'll deal with those bugs later. + id.SetBit(VS_BIT_BEZIER, false); + id.SetBit(VS_BIT_SPLINE, false); + + bool generateSuccess[numLanguages]{}; + + for (int j = 0; j < numLanguages; j++) { + std::string genErrorString; + generateSuccess[j] = GenerateVShader(id, buffer[j], languages[j], &genErrorString); + if (!genErrorString.empty()) { + printf("%s\n", genErrorString.c_str()); + } + } + + // Now that we have the strings ready for easy comparison (buffer,4 in the watch window), + // let's try to compile them. + for (int j = 0; j < numLanguages; j++) { + if (generateSuccess[j]) { + if (!TestCompileShader(buffer[j], languages[j], true)) { + printf("Error compiling vertex shader:\n\n%s\n\n", LineNumberString(buffer[j]).c_str()); + return false; + } + successes++; + } + } + } + + printf("%d/%d vertex shaders generated (it's normal that it's not all, there are invalid bit combos)\n", successes, count * numLanguages); + + successes = 0; + count = 200; + + for (int i = 0; i < numLanguages; i++) { + delete[] buffer[i]; + } + + return true; +} diff --git a/unittest/UnitTest.cpp b/unittest/UnitTest.cpp index a310999360..b5beb3cefa 100644 --- a/unittest/UnitTest.cpp +++ b/unittest/UnitTest.cpp @@ -571,6 +571,7 @@ struct TestItem { bool TestArmEmitter(); bool TestArm64Emitter(); bool TestX64Emitter(); +bool TestShaderGenerators(); TestItem availableTests[] = { #if PPSSPP_ARCH(ARM64) || PPSSPP_ARCH(AMD64) || PPSSPP_ARCH(X86) @@ -593,7 +594,7 @@ TestItem availableTests[] = { TEST_ITEM(ParseLBN), TEST_ITEM(QuickTexHash), TEST_ITEM(CLZ), - TEST_ITEM(MemMap), + TEST_ITEM(ShaderGenerators), }; int main(int argc, const char *argv[]) { diff --git a/unittest/UnitTests.vcxproj b/unittest/UnitTests.vcxproj index a401a081b7..f585ee5feb 100644 --- a/unittest/UnitTests.vcxproj +++ b/unittest/UnitTests.vcxproj @@ -382,6 +382,7 @@ true true + @@ -426,4 +427,4 @@ - + \ No newline at end of file diff --git a/unittest/UnitTests.vcxproj.filters b/unittest/UnitTests.vcxproj.filters index fd685e86b1..511e700f67 100644 --- a/unittest/UnitTests.vcxproj.filters +++ b/unittest/UnitTests.vcxproj.filters @@ -11,6 +11,7 @@ Windows +