diff --git a/Common/GPU/OpenGL/GLFeatures.cpp b/Common/GPU/OpenGL/GLFeatures.cpp index 0927402d92..9ae4185c33 100644 --- a/Common/GPU/OpenGL/GLFeatures.cpp +++ b/Common/GPU/OpenGL/GLFeatures.cpp @@ -181,9 +181,10 @@ void CheckGLExtensions() { // Just for reference: Galaxy Y has renderer == "VideoCore IV HW" } else if (vendor == "Vivante Corporation") { gl_extensions.gpuVendor = GPU_VENDOR_VIVANTE; - } else if (vendor == "Apple") { + } else if (vendor == "Apple Inc.") { gl_extensions.gpuVendor = GPU_VENDOR_APPLE; } else { + WARN_LOG(G3D, "Unknown GL vendor: '%s'", vendor.c_str()); gl_extensions.gpuVendor = GPU_VENDOR_UNKNOWN; } } else { diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index 56b040fcd3..fcce3aabbd 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -4,6 +4,8 @@ #include #include +#include "ppsspp_config.h" + #include "Common/Data/Convert/SmallDataConvert.h" #include "Common/Math/math_util.h" #include "Common/Math/lin/matrix4x4.h" @@ -591,6 +593,13 @@ OpenGLContext::OpenGLContext() { bugs_.Infest(Bugs::PVR_GENMIPMAP_HEIGHT_GREATER); } +#if PPSSPP_PLATFORM(IOS) + // For some reason, this bug does not appear on M1. + if (caps_.vendor == GPUVendor::VENDOR_APPLE) { + bugs_.Infest(Bugs::BROKEN_FLAT_IN_SHADER); + } +#endif + shaderLanguageDesc_.Init(GLSL_1xx); shaderLanguageDesc_.glslVersionNumber = gl_extensions.GLSLVersion(); diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index 8318dcb779..40442c8f48 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -315,6 +315,7 @@ public: PVR_GENMIPMAP_HEIGHT_GREATER = 3, BROKEN_NAN_IN_CONDITIONAL = 4, COLORWRITEMASK_BROKEN_WITH_DEPTHTEST = 5, + BROKEN_FLAT_IN_SHADER = 6, }; protected: diff --git a/GPU/Common/FragmentShaderGenerator.cpp b/GPU/Common/FragmentShaderGenerator.cpp index 3fe4764029..22af75c14a 100644 --- a/GPU/Common/FragmentShaderGenerator.cpp +++ b/GPU/Common/FragmentShaderGenerator.cpp @@ -22,6 +22,7 @@ #include "Common/StringUtils.h" #include "Common/GPU/OpenGL/GLFeatures.h" #include "Common/GPU/ShaderWriter.h" +#include "Common/GPU/thin3d.h" #include "Core/Reporting.h" #include "Core/Config.h" #include "GPU/Common/GPUStateUtils.h" @@ -33,7 +34,7 @@ #define WRITE(p, ...) p.F(__VA_ARGS__) -bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLanguageDesc &compat, uint64_t *uniformMask, std::string *errorString) { +bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLanguageDesc &compat, Draw::Bugs bugs, uint64_t *uniformMask, std::string *errorString) { *uniformMask = 0; errorString->clear(); @@ -77,7 +78,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu bool enableColorDoubling = id.Bit(FS_BIT_COLOR_DOUBLE); bool doTextureProjection = id.Bit(FS_BIT_DO_TEXTURE_PROJ); bool doTextureAlpha = id.Bit(FS_BIT_TEXALPHA); - bool doFlatShading = id.Bit(FS_BIT_FLATSHADE); + bool doFlatShading = id.Bit(FS_BIT_FLATSHADE) && !bugs.Has(Draw::Bugs::BROKEN_FLAT_IN_SHADER); bool shaderDepal = id.Bit(FS_BIT_SHADER_DEPAL); bool bgraTexture = id.Bit(FS_BIT_BGRA_TEXTURE); bool colorWriteMask = id.Bit(FS_BIT_COLOR_WRITEMASK); diff --git a/GPU/Common/FragmentShaderGenerator.h b/GPU/Common/FragmentShaderGenerator.h index 2e27d165d0..b7c48eb355 100644 --- a/GPU/Common/FragmentShaderGenerator.h +++ b/GPU/Common/FragmentShaderGenerator.h @@ -18,6 +18,7 @@ #pragma once #include "Common/GPU/Shader.h" +#include "Common/GPU/thin3d.h" struct FShaderID; @@ -37,4 +38,4 @@ struct FShaderID; // For stencil upload #define CONST_PS_STENCILVALUE 10 -bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLanguageDesc &compat, uint64_t *uniformMask, std::string *errorString); +bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLanguageDesc &compat, Draw::Bugs bugs, uint64_t *uniformMask, std::string *errorString); diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index 285dbafdb4..c1e7a9e39a 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -22,6 +22,7 @@ #include "Common/StringUtils.h" #include "Common/GPU/OpenGL/GLFeatures.h" #include "Common/GPU/ShaderWriter.h" +#include "Common/GPU/thin3d.h" #include "Core/Config.h" #include "GPU/ge_constants.h" #include "GPU/GPUState.h" @@ -126,7 +127,7 @@ static const char * const boneWeightDecl[9] = { extern const char *vulkan_glsl_preamble_vs; extern const char *hlsl_preamble_vs; -bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguageDesc &compat, uint32_t *attrMask, uint64_t *uniformMask, std::string *errorString) { +bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguageDesc &compat, Draw::Bugs bugs, uint32_t *attrMask, uint64_t *uniformMask, std::string *errorString) { *attrMask = 0; *uniformMask = 0; @@ -151,7 +152,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag // this is only valid for some settings of uvGenMode GETexProjMapMode uvProjMode = static_cast(id.Bits(VS_BIT_UVPROJ_MODE, 2)); bool doShadeMapping = uvGenMode == GE_TEXMAP_ENVIRONMENT_MAP; - bool doFlatShading = id.Bit(VS_BIT_FLATSHADE); + bool doFlatShading = id.Bit(VS_BIT_FLATSHADE) && !bugs.Has(Draw::Bugs::BROKEN_FLAT_IN_SHADER); bool useHWTransform = id.Bit(VS_BIT_USE_HW_TRANSFORM); bool hasColor = id.Bit(VS_BIT_HAS_COLOR) || !useHWTransform; diff --git a/GPU/Common/VertexShaderGenerator.h b/GPU/Common/VertexShaderGenerator.h index df62f76289..65b151e9f4 100644 --- a/GPU/Common/VertexShaderGenerator.h +++ b/GPU/Common/VertexShaderGenerator.h @@ -21,10 +21,11 @@ #include "Common/CommonTypes.h" #include "Common/GPU/Shader.h" +#include "Common/GPU/thin3d.h" struct VShaderID; -bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguageDesc &compat, uint32_t *attrMask, uint64_t *uniformMask, std::string *errorString); +bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguageDesc &compat, const Draw::Bugs bugs, uint32_t *attrMask, uint64_t *uniformMask, std::string *errorString); // D3D9 constants. enum { diff --git a/GPU/D3D11/ShaderManagerD3D11.cpp b/GPU/D3D11/ShaderManagerD3D11.cpp index 255c547ee9..ddcbc814d5 100644 --- a/GPU/D3D11/ShaderManagerD3D11.cpp +++ b/GPU/D3D11/ShaderManagerD3D11.cpp @@ -210,7 +210,7 @@ void ShaderManagerD3D11::GetShaders(int prim, u32 vertType, D3D11VertexShader ** std::string genErrorString; uint32_t attrMask; uint64_t uniformMask; - GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), &attrMask, &uniformMask, &genErrorString); + GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &genErrorString); vs = new D3D11VertexShader(device_, featureLevel_, VSID, codeBuffer_, vertType, useHWTransform); vsCache_[VSID] = vs; } else { @@ -224,7 +224,7 @@ void ShaderManagerD3D11::GetShaders(int prim, u32 vertType, D3D11VertexShader ** // Fragment shader not in cache. Let's compile it. std::string genErrorString; uint64_t uniformMask; - GenerateFragmentShader(FSID, codeBuffer_, draw_->GetShaderLanguageDesc(), &uniformMask, &genErrorString); + GenerateFragmentShader(FSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &uniformMask, &genErrorString); fs = new D3D11FragmentShader(device_, featureLevel_, FSID, codeBuffer_, useHWTransform); fsCache_[FSID] = fs; } else { diff --git a/GPU/Directx9/ShaderManagerDX9.cpp b/GPU/Directx9/ShaderManagerDX9.cpp index ce5c7b983c..37c0bec628 100644 --- a/GPU/Directx9/ShaderManagerDX9.cpp +++ b/GPU/Directx9/ShaderManagerDX9.cpp @@ -582,7 +582,7 @@ VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellat std::string genErrorString; uint32_t attrMask; uint64_t uniformMask; - if (GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), &attrMask, &uniformMask, &genErrorString)) { + if (GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &genErrorString)) { vs = new VSShader(device_, VSID, codeBuffer_, useHWTransform); } if (!vs || vs->Failed()) { @@ -607,7 +607,7 @@ VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellat // Can still work with software transform. uint32_t attrMask; uint64_t uniformMask; - bool success = GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), &attrMask, &uniformMask, &genErrorString); + bool success = GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &genErrorString); _assert_(success); vs = new VSShader(device_, VSID, codeBuffer_, false); } @@ -624,7 +624,7 @@ VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellat // Fragment shader not in cache. Let's compile it. std::string errorString; uint64_t uniformMask; - bool success = GenerateFragmentShader(FSID, codeBuffer_, draw_->GetShaderLanguageDesc(), &uniformMask, &errorString); + bool success = GenerateFragmentShader(FSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &uniformMask, &errorString); // We're supposed to handle all possible cases. _assert_(success); fs = new PSShader(device_, FSID, codeBuffer_); diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index 99b7dd08bd..250757cb06 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -635,7 +635,7 @@ void ShaderManagerGLES::DirtyLastShader() { Shader *ShaderManagerGLES::CompileFragmentShader(FShaderID FSID) { uint64_t uniformMask; std::string errorString; - if (!GenerateFragmentShader(FSID, codeBuffer_, draw_->GetShaderLanguageDesc(), &uniformMask, &errorString)) { + if (!GenerateFragmentShader(FSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &uniformMask, &errorString)) { ERROR_LOG(G3D, "Shader gen error: %s", errorString.c_str()); return nullptr; } @@ -648,7 +648,7 @@ Shader *ShaderManagerGLES::CompileVertexShader(VShaderID VSID) { uint32_t attrMask; uint64_t uniformMask; std::string errorString; - if (!GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), &attrMask, &uniformMask, &errorString)) { + if (!GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &errorString)) { ERROR_LOG(G3D, "Shader gen error: %s", errorString.c_str()); return nullptr; } diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index 4b54a77d83..965f066a23 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -265,7 +265,7 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader std::string genErrorString; uint64_t uniformMask = 0; // Not used uint32_t attributeMask = 0; // Not used - bool success = GenerateVertexShader(VSID, codeBuffer_, compat_, &attributeMask, &uniformMask, &genErrorString); + bool success = GenerateVertexShader(VSID, codeBuffer_, compat_, draw_->GetBugs(), &attributeMask, &uniformMask, &genErrorString); _assert_(success); vs = new VulkanVertexShader(vulkan_, VSID, codeBuffer_, useHWTransform); vsCache_.Insert(VSID, vs); @@ -278,7 +278,7 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader // Fragment shader not in cache. Let's compile it. std::string genErrorString; uint64_t uniformMask = 0; // Not used - bool success = GenerateFragmentShader(FSID, codeBuffer_, compat_, &uniformMask, &genErrorString); + bool success = GenerateFragmentShader(FSID, codeBuffer_, compat_, draw_->GetBugs(), &uniformMask, &genErrorString); _assert_(success); fs = new VulkanFragmentShader(vulkan_, FSID, codeBuffer_); fsCache_.Insert(FSID, fs); @@ -398,7 +398,7 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) { std::string genErrorString; uint32_t attributeMask = 0; uint64_t uniformMask = 0; - if (!GenerateVertexShader(id, codeBuffer_, compat_, &attributeMask, &uniformMask, &genErrorString)) { + if (!GenerateVertexShader(id, codeBuffer_, compat_, draw_->GetBugs(), &attributeMask, &uniformMask, &genErrorString)) { return false; } VulkanVertexShader *vs = new VulkanVertexShader(vulkan_, id, codeBuffer_, useHWTransform); @@ -414,7 +414,7 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) { } std::string genErrorString; uint64_t uniformMask = 0; - if (!GenerateFragmentShader(id, codeBuffer_, compat_, &uniformMask, &genErrorString)) { + if (!GenerateFragmentShader(id, codeBuffer_, compat_, draw_->GetBugs(), &uniformMask, &genErrorString)) { return false; } VulkanFragmentShader *fs = new VulkanFragmentShader(vulkan_, id, codeBuffer_); diff --git a/unittest/TestShaderGenerators.cpp b/unittest/TestShaderGenerators.cpp index 88fa67f439..a68c8247ba 100644 --- a/unittest/TestShaderGenerators.cpp +++ b/unittest/TestShaderGenerators.cpp @@ -19,67 +19,67 @@ #include "GPU/D3D9/D3DCompilerLoader.h" #include "GPU/D3D9/D3D9ShaderCompiler.h" -bool GenerateFShader(FShaderID id, char *buffer, ShaderLanguage lang, std::string *errorString) { +bool GenerateFShader(FShaderID id, char *buffer, ShaderLanguage lang, Draw::Bugs bugs, std::string *errorString) { uint64_t uniformMask; switch (lang) { case ShaderLanguage::GLSL_VULKAN: { ShaderLanguageDesc compat(ShaderLanguage::GLSL_VULKAN); - return GenerateFragmentShader(id, buffer, compat, &uniformMask, errorString); + return GenerateFragmentShader(id, buffer, compat, bugs, &uniformMask, errorString); } case ShaderLanguage::GLSL_1xx: { ShaderLanguageDesc compat(ShaderLanguage::GLSL_1xx); - return GenerateFragmentShader(id, buffer, compat, &uniformMask, errorString); + return GenerateFragmentShader(id, buffer, compat, bugs, &uniformMask, errorString); } case ShaderLanguage::GLSL_3xx: { ShaderLanguageDesc compat(ShaderLanguage::GLSL_1xx); - return GenerateFragmentShader(id, buffer, compat, &uniformMask, errorString); + return GenerateFragmentShader(id, buffer, compat, bugs, &uniformMask, errorString); } case ShaderLanguage::HLSL_D3D9: { ShaderLanguageDesc compat(ShaderLanguage::HLSL_D3D9); - return GenerateFragmentShader(id, buffer, compat, &uniformMask, errorString); + return GenerateFragmentShader(id, buffer, compat, bugs, &uniformMask, errorString); } case ShaderLanguage::HLSL_D3D11: { ShaderLanguageDesc compat(ShaderLanguage::HLSL_D3D11); - return GenerateFragmentShader(id, buffer, compat, &uniformMask, errorString); + return GenerateFragmentShader(id, buffer, compat, bugs, &uniformMask, errorString); } default: return false; } } -bool GenerateVShader(VShaderID id, char *buffer, ShaderLanguage lang, std::string *errorString) { +bool GenerateVShader(VShaderID id, char *buffer, ShaderLanguage lang, Draw::Bugs bugs, std::string *errorString) { uint32_t attrMask; uint64_t uniformMask; switch (lang) { case ShaderLanguage::GLSL_VULKAN: { ShaderLanguageDesc compat(ShaderLanguage::GLSL_VULKAN); - return GenerateVertexShader(id, buffer, compat, &attrMask, &uniformMask, errorString); + return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, errorString); } case ShaderLanguage::GLSL_1xx: { ShaderLanguageDesc compat(ShaderLanguage::GLSL_1xx); - return GenerateVertexShader(id, buffer, compat, &attrMask, &uniformMask, errorString); + return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, errorString); } case ShaderLanguage::GLSL_3xx: { ShaderLanguageDesc compat(ShaderLanguage::GLSL_1xx); - return GenerateVertexShader(id, buffer, compat, &attrMask, &uniformMask, errorString); + return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, errorString); } case ShaderLanguage::HLSL_D3D9: { ShaderLanguageDesc compat(ShaderLanguage::HLSL_D3D9); - return GenerateVertexShader(id, buffer, compat, &attrMask, &uniformMask, errorString); + return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, errorString); } case ShaderLanguage::HLSL_D3D11: { ShaderLanguageDesc compat(ShaderLanguage::HLSL_D3D11); - return GenerateVertexShader(id, buffer, compat, &attrMask, &uniformMask, errorString); + return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, errorString); } default: return false; @@ -234,6 +234,8 @@ bool TestVertexShaders() { int successes = 0; int count = 700; + Draw::Bugs bugs; + // 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++) { @@ -259,7 +261,7 @@ bool TestVertexShaders() { std::string genErrorString[numLanguages]; for (int j = 0; j < numLanguages; j++) { - generateSuccess[j] = GenerateVShader(id, buffer[j], languages[j], &genErrorString[j]); + generateSuccess[j] = GenerateVShader(id, buffer[j], languages[j], bugs, &genErrorString[j]); if (!genErrorString[j].empty()) { printf("%s\n", genErrorString[j].c_str()); } @@ -297,6 +299,8 @@ bool TestFragmentShaders() { int successes = 0; int count = 300; + Draw::Bugs bugs; + // 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++) { @@ -318,7 +322,7 @@ bool TestFragmentShaders() { std::string genErrorString[numLanguages]; for (int j = 0; j < numLanguages; j++) { - generateSuccess[j] = GenerateFShader(id, buffer[j], languages[j], &genErrorString[j]); + generateSuccess[j] = GenerateFShader(id, buffer[j], languages[j], bugs, &genErrorString[j]); if (!genErrorString[j].empty()) { printf("%s\n", genErrorString[j].c_str()); }