diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index 2c17f94d24..9fc2d2c6b5 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -136,6 +136,7 @@ bool IsColorTestTriviallyTrue() { } } +// TODO: Pack into 16-bit integer. const bool nonAlphaSrcFactors[16] = { true, // GE_SRCBLEND_DSTCOLOR, true, // GE_SRCBLEND_INVDSTCOLOR, diff --git a/GPU/Common/ShaderCommon.h b/GPU/Common/ShaderCommon.h index 5f17e236dc..ab03277e58 100644 --- a/GPU/Common/ShaderCommon.h +++ b/GPU/Common/ShaderCommon.h @@ -76,6 +76,8 @@ enum : uint64_t { DIRTY_TEXCLAMP = 1ULL << 19, DIRTY_DEPTHRANGE = 1ULL << 19, + DIRTY_GUARDBAND = 1ULL << 20, + DIRTY_WORLDMATRIX = 1ULL << 21, DIRTY_VIEWMATRIX = 1ULL << 22, DIRTY_TEXMATRIX = 1ULL << 23, diff --git a/GPU/Common/ShaderUniforms.cpp b/GPU/Common/ShaderUniforms.cpp index 4e3a3deab4..f54c3f16d3 100644 --- a/GPU/Common/ShaderUniforms.cpp +++ b/GPU/Common/ShaderUniforms.cpp @@ -23,6 +23,25 @@ static void ConvertProjMatrixToD3D11(Matrix4x4 &in) { in.translateAndScale(trans, scale); } +void ComputeGuardband(float gb[4], float zmin) { + float vpWidth = fabsf(gstate_c.vpWidth); + float vpHeight = fabsf(gstate_c.vpHeight); + // Avoid bad values during initialization. Doubt these are really needed. + if (vpWidth == 0.0) + vpWidth = 480; + if (vpHeight == 0.0) + vpHeight = 272; + + // We assume a symmetric guardband, even though it's not entirely correct to do so - but nearly everything does it + // this way and we have space for the NAN in the uniform. + // We also assume that everything behind the near clipping plane gets clipped and will thus not in reality + // exceed the guardband. This is a bit rough but should be ok. + gb[0] = (2048.0f / (vpWidth*0.5f)); + gb[1] = (2048.0f / (vpHeight*0.5f)); + gb[2] = zmin; + gb[3] = NAN; +} + void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipViewport) { if (dirtyUniforms & DIRTY_TEXENV) { Uint8x3ToFloat4(ub->texEnvColor, gstate.texenvcolor); @@ -56,7 +75,11 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView ub->texClampOffset[0] = gstate_c.curTextureXOffset * invW; ub->texClampOffset[1] = gstate_c.curTextureYOffset * invH; } - + if (dirtyUniforms & DIRTY_GUARDBAND) { + float gb[4]; + ComputeGuardband(gb, 0.0f); + memcpy(ub->guardband, gb, sizeof(float) * 4); + } if (dirtyUniforms & DIRTY_PROJMATRIX) { Matrix4x4 flippedMatrix; memcpy(&flippedMatrix, gstate.projMatrix, 16 * sizeof(float)); @@ -98,6 +121,7 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView if (g_Config.iRenderingMode == 0 && g_display_rotation != DisplayRotation::ROTATE_0) { proj_through = proj_through * g_display_rot_matrix; } + // proj_through.translateAndScale(Vec3(0, 0, 0), Vec3(1.0f / debugscale, 1.0f / debugscale, 0)); CopyMatrix4x4(ub->proj_through, proj_through.getReadPtr()); } diff --git a/GPU/Common/ShaderUniforms.h b/GPU/Common/ShaderUniforms.h index 55f08f7658..c1b04e8bf3 100644 --- a/GPU/Common/ShaderUniforms.h +++ b/GPU/Common/ShaderUniforms.h @@ -10,7 +10,7 @@ enum : uint64_t { DIRTY_BASE_UNIFORMS = DIRTY_WORLDMATRIX | DIRTY_PROJTHROUGHMATRIX | DIRTY_VIEWMATRIX | DIRTY_TEXMATRIX | DIRTY_ALPHACOLORREF | - DIRTY_PROJMATRIX | DIRTY_FOGCOLOR | DIRTY_FOGCOEF | DIRTY_TEXENV | DIRTY_STENCILREPLACEVALUE | + DIRTY_PROJMATRIX | DIRTY_FOGCOLOR | DIRTY_FOGCOEF | DIRTY_TEXENV | DIRTY_STENCILREPLACEVALUE | DIRTY_GUARDBAND | DIRTY_ALPHACOLORMASK | DIRTY_SHADERBLEND | DIRTY_UVSCALEOFFSET | DIRTY_TEXCLAMP | DIRTY_DEPTHRANGE | DIRTY_MATAMBIENTALPHA | DIRTY_BEZIERSPLINE, DIRTY_LIGHT_UNIFORMS = @@ -34,6 +34,7 @@ struct UB_VS_FS_Base { int spline_count_v; int spline_type_u; int spline_type_v; + float guardband[4]; // Fragment data float fogColor[4]; float texEnvColor[4]; @@ -59,6 +60,8 @@ R"( mat4 proj_mtx; int spline_count_v; int spline_type_u; int spline_type_v; + vec4 guardband; + // Fragment vec3 fogcolor; vec3 texenv; ivec4 alphacolorref; @@ -84,6 +87,8 @@ R"( float4x4 u_proj; int u_spline_count_v; int u_spline_type_u; int u_spline_type_v; + float4 u_guardband; + // Fragment float3 u_fogcolor; float3 u_texenv; uint4 u_alphacolorref; @@ -184,3 +189,5 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView void LightUpdateUniforms(UB_VS_Lights *ub, uint64_t dirtyUniforms); void BoneUpdateUniforms(UB_VS_Bones *ub, uint64_t dirtyUniforms); +// Shared helper functions +void ComputeGuardband(float gb[4], float zmin); diff --git a/GPU/Directx9/ShaderManagerDX9.cpp b/GPU/Directx9/ShaderManagerDX9.cpp index 05da5bba0b..cfd0f5cff2 100644 --- a/GPU/Directx9/ShaderManagerDX9.cpp +++ b/GPU/Directx9/ShaderManagerDX9.cpp @@ -35,6 +35,7 @@ #include "GPU/Math3D.h" #include "GPU/GPUState.h" #include "GPU/ge_constants.h" +#include "GPU/Common/ShaderUniforms.h" #include "GPU/Directx9/ShaderManagerDX9.h" #include "GPU/Directx9/DrawEngineDX9.h" #include "GPU/Directx9/FramebufferDX9.h" @@ -378,6 +379,11 @@ void ShaderManagerDX9::VSUpdateUniforms(u64 dirtyUniforms) { #endif VSSetFloatArray(CONST_VS_FOGCOEF, fogcoef, 2); } + if (dirtyUniforms & DIRTY_GUARDBAND) { + float gb[4]; + ComputeGuardband(gb, 0.0f); + VSSetFloatUniform4(CONST_VS_GUARDBAND, gb); + } // TODO: Could even set all bones in one go if they're all dirty. #ifdef USE_BONE_ARRAY if (u_bone != 0) { diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.cpp b/GPU/Directx9/VertexShaderGeneratorDX9.cpp index 152e2c3fa6..fb5826c7a1 100644 --- a/GPU/Directx9/VertexShaderGeneratorDX9.cpp +++ b/GPU/Directx9/VertexShaderGeneratorDX9.cpp @@ -38,6 +38,13 @@ namespace DX9 { +// The PSP does not have a proper triangle clipper on the sides. It does have on for the front plane. +// It has a guard band though and can rasterize rather large +// triangles that go outside the viewport. However, there are limits, and it will drop triangles that are very +// large. Some games appear to draw broken geometry, probably game bugs that were never discovered because the PSP +// would drop the geometry, including Parappa The Rapper in an obscure case and Outrun. Try to get rid of those +// triangles by setting the W of one of the vertices to NaN if they are discovered. + static const char * const boneWeightAttrDecl[9] = { "#ERROR#", "float a_w1:TEXCOORD1;\n", @@ -56,6 +63,26 @@ enum DoLightComputation { LIGHT_FULL, }; +// #define COLORGUARDBAND + +#ifdef COLORGUARDBAND +// Coloring debug version +static void WriteGuardBand(char *&p) { + WRITE(p, " if (outPos.w >= 0.0) {\n"); + WRITE(p, " float3 projPos = outPos.xyz / outPos.w; \n"); + WRITE(p, " if (projPos.z >= 0.0 && projPos.z <= 1.0 && (abs(projPos.x) > u_guardband.x || projPos.y > u_guardband.y)) colorOverride.g = 0.0;\n");//outPos.w = u_guardband.w;\n"); + WRITE(p, " } else { colorOverride.b = 0.0; } \n"); +} +#else +// NOTE: We are skipping the bottom check. This fixes TOCA but I am dubious about it... +static void WriteGuardBand(char *&p) { + WRITE(p, " if (outPos.w >= 0.0) {\n"); + WRITE(p, " float3 projPos = outPos.xyz / outPos.w; \n"); + WRITE(p, " if (projPos.z >= 0.0 && projPos.z <= 1.0 && (abs(projPos.x) > u_guardband.x || abs(projPos.y) > u_guardband.y)) outPos.w = u_guardband.w;\n"); + WRITE(p, " }\n"); +} +#endif + void GenerateVertexShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage lang) { char *p = buffer; const u32 vertType = gstate.vertType; @@ -119,6 +146,7 @@ void GenerateVertexShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage l WRITE(p, "float4x4 u_proj : register(c%i);\n", CONST_VS_PROJ); // Add all the uniforms we'll need to transform properly. } + WRITE(p, "float4 u_guardband : register(c%i);\n", CONST_VS_GUARDBAND); if (enableFog) { WRITE(p, "float2 u_fogcoef : register(c%i);\n", CONST_VS_FOGCOEF); @@ -350,6 +378,9 @@ void GenerateVertexShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage l WRITE(p, "VS_OUT main(VS_IN In) {\n"); WRITE(p, " VS_OUT Out;\n"); +#ifdef COLORGUARDBAND + WRITE(p, " float4 colorOverride = float4(1.0, 1.0, 1.0, 1.0);\n"); +#endif if (!useHWTransform) { // Simple pass-through of vertex data to fragment shader if (doTexture) { @@ -373,26 +404,30 @@ void GenerateVertexShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage l } if (lang == HLSL_D3D11 || lang == HLSL_D3D11_LEVEL9) { if (gstate.isModeThrough()) { - WRITE(p, " Out.gl_Position = mul(u_proj_through, float4(In.position.xyz, 1.0));\n"); + WRITE(p, " float4 outPos = mul(u_proj_through, float4(In.position.xyz, 1.0));\n"); } else { if (gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) { - WRITE(p, " Out.gl_Position = depthRoundZVP(mul(u_proj, float4(In.position.xyz, 1.0)));\n"); + WRITE(p, " float4 outPos = depthRoundZVP(mul(u_proj, float4(In.position.xyz, 1.0)));\n"); } else { - WRITE(p, " Out.gl_Position = mul(u_proj, float4(In.position.xyz, 1.0));\n"); + WRITE(p, " float4 outPos = mul(u_proj, float4(In.position.xyz, 1.0));\n"); } } } else { if (gstate.isModeThrough()) { - WRITE(p, " Out.gl_Position = mul(float4(In.position.xyz, 1.0), u_proj_through);\n"); + WRITE(p, " float4 outPos = mul(float4(In.position.xyz, 1.0), u_proj_through);\n"); } else { if (gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) { - WRITE(p, " Out.gl_Position = depthRoundZVP(mul(float4(In.position.xyz, 1.0), u_proj));\n"); + WRITE(p, " float4 outPos = depthRoundZVP(mul(float4(In.position.xyz, 1.0), u_proj));\n"); } else { - WRITE(p, " Out.gl_Position = mul(float4(In.position.xyz, 1.0), u_proj);\n"); + WRITE(p, " float4 outPos = mul(float4(In.position.xyz, 1.0), u_proj);\n"); } } } - } else { + if (lang != HLSL_DX9) { + WriteGuardBand(p); + } + WRITE(p, " Out.gl_Position = outPos;\n"); + } else { // Step 1: World Transform / Skinning if (!enableBones) { // Hardware tessellation @@ -578,18 +613,20 @@ void GenerateVertexShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage l if (lang == HLSL_D3D11 || lang == HLSL_D3D11_LEVEL9) { // Final view and projection transforms. if (gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) { - WRITE(p, " Out.gl_Position = depthRoundZVP(mul(u_proj, viewPos));\n"); + WRITE(p, " float4 outPos = depthRoundZVP(mul(u_proj, viewPos));\n"); } else { - WRITE(p, " Out.gl_Position = mul(u_proj, viewPos);\n"); + WRITE(p, " float4 outPos = mul(u_proj, viewPos);\n"); } } else { // Final view and projection transforms. if (gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) { - WRITE(p, " Out.gl_Position = depthRoundZVP(mul(viewPos, u_proj));\n"); + WRITE(p, " float4 outPos = depthRoundZVP(mul(viewPos, u_proj));\n"); } else { - WRITE(p, " Out.gl_Position = mul(viewPos, u_proj);\n"); + WRITE(p, " float4 outPos = mul(viewPos, u_proj);\n"); } } + WriteGuardBand(p); + WRITE(p, " Out.gl_Position = outPos;\n"); // TODO: Declare variables for dots for shade mapping if needed. @@ -807,6 +844,9 @@ void GenerateVertexShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage l } } +#ifdef COLORGUARDBAND + WRITE(p, " Out.v_color0 *= colorOverride;\n"); +#endif WRITE(p, " return Out;\n"); WRITE(p, "}\n"); } diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.h b/GPU/Directx9/VertexShaderGeneratorDX9.h index 690e133979..b941d4d2fe 100644 --- a/GPU/Directx9/VertexShaderGeneratorDX9.h +++ b/GPU/Directx9/VertexShaderGeneratorDX9.h @@ -55,5 +55,6 @@ namespace DX9 { #define CONST_VS_LIGHTSPECULAR 75 #define CONST_VS_LIGHTAMBIENT 79 #define CONST_VS_DEPTHRANGE 83 +#define CONST_VS_GUARDBAND 84 }; diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index c6ebda7579..b01fe1f228 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -41,6 +41,7 @@ #include "ext/native/gfx/GLStateCache.h" #include "GPU/GLES/ShaderManagerGLES.h" #include "GPU/GLES/DrawEngineGLES.h" +#include "GPU/Common/ShaderUniforms.h" #include "FramebufferManagerGLES.h" Shader::Shader(const char *code, uint32_t glShaderType, bool useHWTransform) @@ -210,6 +211,7 @@ LinkedShader::LinkedShader(ShaderID VSID, Shader *vs, ShaderID FSID, Shader *fs, u_uvscaleoffset = glGetUniformLocation(program, "u_uvscaleoffset"); u_texclamp = glGetUniformLocation(program, "u_texclamp"); u_texclampoff = glGetUniformLocation(program, "u_texclampoff"); + u_guardband = glGetUniformLocation(program, "u_guardband"); for (int i = 0; i < 4; i++) { char temp[64]; @@ -268,7 +270,8 @@ LinkedShader::LinkedShader(ShaderID VSID, Shader *vs, ShaderID FSID, Shader *fs, if (u_blendFixA != -1 || u_blendFixB != -1 || u_fbotexSize != -1) availableUniforms |= DIRTY_SHADERBLEND; if (u_depthRange != -1) availableUniforms |= DIRTY_DEPTHRANGE; - + if (u_guardband != -1) + availableUniforms |= DIRTY_GUARDBAND; // Looping up to numBones lets us avoid checking u_bone[i] #ifdef USE_BONE_ARRAY if (u_bone != -1) { @@ -601,6 +604,13 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid) { if (dirty & DIRTY_TEXMATRIX) { SetMatrix4x3(u_texmtx, gstate.tgenMatrix); } + + if (dirty & DIRTY_GUARDBAND) { + float gb[4]; + ComputeGuardband(gb, 0.0f); + SetFloatUniform4(u_guardband, gb); + } + if ((dirty & DIRTY_DEPTHRANGE) && u_depthRange != -1) { // Since depth is [-1, 1] mapping to [minz, maxz], this is easyish. float vpZScale = gstate.getViewportZScale(); diff --git a/GPU/GLES/ShaderManagerGLES.h b/GPU/GLES/ShaderManagerGLES.h index 0f1065a25c..4a7b2c00d7 100644 --- a/GPU/GLES/ShaderManagerGLES.h +++ b/GPU/GLES/ShaderManagerGLES.h @@ -96,6 +96,9 @@ public: int u_texclamp; int u_texclampoff; + // Clipping + int u_guardband; + // Lighting int u_ambient; int u_matambientalpha; diff --git a/GPU/GLES/VertexShaderGeneratorGLES.cpp b/GPU/GLES/VertexShaderGeneratorGLES.cpp index 719b5cd159..571915f0de 100644 --- a/GPU/GLES/VertexShaderGeneratorGLES.cpp +++ b/GPU/GLES/VertexShaderGeneratorGLES.cpp @@ -69,6 +69,12 @@ enum DoLightComputation { LIGHT_FULL, }; +static void WriteGuardBand(char *&p) { + WRITE(p, " vec3 projPos = outPos.xyz / outPos.w; \n"); + WRITE(p, " if (outPos.w >= u_guardband.z) {\n"); + WRITE(p, " if (abs(projPos.x) > u_guardband.x || projPos.y < -u_guardband.y) outPos.w = u_guardband.w;\n"); + WRITE(p, " }\n"); +} // Depth range and viewport // @@ -95,6 +101,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. +// NOTE: We are skipping the bottom check. This fixes TOCA but I am dubious about it... void GenerateVertexShader(const ShaderID &id, char *buffer) { char *p = buffer; @@ -247,6 +254,7 @@ void GenerateVertexShader(const ShaderID &id, char *buffer) { WRITE(p, "uniform mat4 u_proj;\n"); // Add all the uniforms we'll need to transform properly. } + WRITE(p, "uniform vec4 u_guardband;\n"); bool scaleUV = !throughmode && (uvGenMode == GE_TEXMAP_TEXTURE_COORDS || uvGenMode == GE_TEXMAP_UNKNOWN); @@ -452,15 +460,17 @@ void GenerateVertexShader(const ShaderID &id, char *buffer) { WRITE(p, " v_fogdepth = position.w;\n"); } if (isModeThrough) { - WRITE(p, " gl_Position = u_proj_through * 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, " gl_Position = depthRoundZVP(u_proj * vec4(position.xyz, 1.0));\n"); + WRITE(p, " vec4 outPos = depthRoundZVP(u_proj * vec4(position.xyz, 1.0));\n"); } else { - WRITE(p, " gl_Position = u_proj * vec4(position.xyz, 1.0);\n"); + WRITE(p, " vec4 outPos = u_proj * vec4(position.xyz, 1.0);\n"); } } + WriteGuardBand(p); + WRITE(p, " gl_Position = outPos;\n"); } else { // Step 1: World Transform / Skinning if (!enableBones) { @@ -652,10 +662,12 @@ void GenerateVertexShader(const ShaderID &id, char *buffer) { // Final view and projection transforms. if (gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) { - WRITE(p, " gl_Position = depthRoundZVP(u_proj * viewPos);\n"); + WRITE(p, " vec4 outPos = depthRoundZVP(u_proj * viewPos);\n"); } else { - WRITE(p, " gl_Position = u_proj * viewPos;\n"); + WRITE(p, " vec4 outPos = u_proj * viewPos;\n"); } + WriteGuardBand(p); + WRITE(p, " gl_Position = outPos;\n"); // TODO: Declare variables for dots for shade mapping if needed. diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index a873beced6..3ceac395c5 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -172,12 +172,12 @@ const CommonCommandTableEntry commonCommandTable[] = { { GE_CMD_ANTIALIASENABLE, FLAG_FLUSHBEFOREONCHANGE }, // Viewport. - { GE_CMD_OFFSETX, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VIEWPORTSCISSOR_STATE }, - { GE_CMD_OFFSETY, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VIEWPORTSCISSOR_STATE }, - { GE_CMD_VIEWPORTXSCALE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_VIEWPORTSCISSOR_STATE }, - { GE_CMD_VIEWPORTYSCALE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_VIEWPORTSCISSOR_STATE }, - { GE_CMD_VIEWPORTXCENTER, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_VIEWPORTSCISSOR_STATE }, - { GE_CMD_VIEWPORTYCENTER, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_VIEWPORTSCISSOR_STATE }, + { GE_CMD_OFFSETX, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_GUARDBAND}, + { GE_CMD_OFFSETY, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_GUARDBAND}, + { GE_CMD_VIEWPORTXSCALE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_GUARDBAND}, + { GE_CMD_VIEWPORTYSCALE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_GUARDBAND}, + { GE_CMD_VIEWPORTXCENTER, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_GUARDBAND}, + { GE_CMD_VIEWPORTYCENTER, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_GUARDBAND}, { GE_CMD_VIEWPORTZSCALE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_DEPTHRANGE | DIRTY_PROJMATRIX | DIRTY_VIEWPORTSCISSOR_STATE }, { GE_CMD_VIEWPORTZCENTER, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_DEPTHRANGE | DIRTY_PROJMATRIX | DIRTY_VIEWPORTSCISSOR_STATE }, { GE_CMD_CLIPENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VIEWPORTSCISSOR_STATE }, diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index fc2d3cae86..1911cbdfbf 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -22,6 +22,7 @@ #include #include "base/logging.h" +#include "base/stringutil.h" #include "math/lin/matrix4x4.h" #include "math/math_util.h" #include "math/dataconv.h" @@ -64,7 +65,7 @@ VulkanFragmentShader::VulkanFragmentShader(VulkanContext *vulkan, ShaderID id, c #ifdef SHADERLOG OutputDebugStringA("Messages:\n"); OutputDebugStringA(errorMessage.c_str()); - OutputDebugStringA(code); + OutputDebugStringA(LineNumberString(code).c_str()); #endif Reporting::ReportMessage("Vulkan error in shader compilation: info: %s / code: %s", errorMessage.c_str(), code); } else { diff --git a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp index b3e9ae7e13..e7f7307681 100644 --- a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp +++ b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp @@ -47,11 +47,7 @@ static const char *vulkan_glsl_preamble = // texcoord = 2 // fog = 3 - - - #undef WRITE - #define WRITE p+=sprintf static const char * const boneWeightDecl[9] = { @@ -72,6 +68,13 @@ enum DoLightComputation { LIGHT_FULL, }; +static void WriteGuardBand(char *&p) { + WRITE(p, " vec3 projPos = outPos.xyz / outPos.w; \n"); + WRITE(p, " if (outPos.w >= base.guardband.z) {\n"); + WRITE(p, " if (abs(projPos.x) > base.guardband.x || projPos.y < -base.guardband.y) outPos.w = base.guardband.w;\n"); + WRITE(p, " }\n"); +} + // Depth range and viewport // // After the multiplication with the projection matrix, we have a 4D vector in clip space. @@ -317,15 +320,17 @@ bool GenerateVulkanGLSLVertexShader(const ShaderID &id, char *buffer, bool *uses WRITE(p, " v_fogdepth = position.w;\n"); } if (isModeThrough) { - WRITE(p, " gl_Position = base.proj_through_mtx * vec4(position.xyz, 1.0);\n"); + WRITE(p, " vec4 outPos = base.proj_through_mtx * 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, " gl_Position = depthRoundZVP(base.proj_mtx * vec4(position.xyz, 1.0));\n"); + WRITE(p, " vec4 outPos = depthRoundZVP(base.proj_mtx * vec4(position.xyz, 1.0));\n"); } else { - WRITE(p, " gl_Position = base.proj_mtx * vec4(position.xyz, 1.0);\n"); + WRITE(p, " vec4 outPos = base.proj_mtx * vec4(position.xyz, 1.0);\n"); } } + WriteGuardBand(p); + WRITE(p, " gl_Position = outPos;\n"); } else { // Step 1: World Transform / Skinning if (!enableBones) { @@ -469,10 +474,12 @@ bool GenerateVulkanGLSLVertexShader(const ShaderID &id, char *buffer, bool *uses // Final view and projection transforms. if (gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) { - WRITE(p, " gl_Position = depthRoundZVP(base.proj_mtx * viewPos);\n"); + WRITE(p, " vec4 outPos = depthRoundZVP(base.proj_mtx * viewPos);\n"); } else { - WRITE(p, " gl_Position = base.proj_mtx * viewPos;\n"); + WRITE(p, " vec4 outPos = base.proj_mtx * viewPos;\n"); } + WriteGuardBand(p); + WRITE(p, " gl_Position = outPos;\n"); // TODO: Declare variables for dots for shade mapping if needed.