From ca28381ddd401162d885171b59b1f98b88f630a7 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Sun, 13 Jun 2021 20:53:23 +1000 Subject: [PATCH] GPU/ShaderGen: Use lower precision where possible --- src/core/gpu_hw_shadergen.cpp | 77 ++++++++++++++++++----------------- src/core/shadergen.cpp | 47 +++++++++++++++++---- 2 files changed, 77 insertions(+), 47 deletions(-) diff --git a/src/core/gpu_hw_shadergen.cpp b/src/core/gpu_hw_shadergen.cpp index afe1d5648..e0be53f3a 100644 --- a/src/core/gpu_hw_shadergen.cpp +++ b/src/core/gpu_hw_shadergen.cpp @@ -20,12 +20,12 @@ void GPU_HW_ShaderGen::WriteCommonFunctions(std::stringstream& ss) { DefineMacro(ss, "MULTISAMPLING", UsingMSAA()); - ss << "CONSTANT uint RESOLUTION_SCALE = " << m_resolution_scale << "u;\n"; - ss << "CONSTANT uint2 VRAM_SIZE = uint2(" << VRAM_WIDTH << ", " << VRAM_HEIGHT << ") * RESOLUTION_SCALE;\n"; - ss << "CONSTANT float2 RCP_VRAM_SIZE = float2(1.0, 1.0) / float2(VRAM_SIZE);\n"; - ss << "CONSTANT uint2 NATIVE_VRAM_SIZE = uint2(" << VRAM_WIDTH << ", " << VRAM_HEIGHT << ");\n"; - ss << "CONSTANT float2 RCP_NATIVE_VRAM_SIZE = float2(1.0, 1.0) / float2(NATIVE_VRAM_SIZE);\n"; - ss << "CONSTANT uint MULTISAMPLES = " << m_multisamples << "u;\n"; + ss << "CONSTANT min16uint RESOLUTION_SCALE = " << m_resolution_scale << "u;\n"; + ss << "CONSTANT min16uint2 VRAM_SIZE = uint2(" << VRAM_WIDTH << ", " << VRAM_HEIGHT << ") * RESOLUTION_SCALE;\n"; + ss << "CONSTANT min16float2 RCP_VRAM_SIZE = float2(1.0, 1.0) / float2(VRAM_SIZE);\n"; + ss << "CONSTANT min16uint2 NATIVE_VRAM_SIZE = uint2(" << VRAM_WIDTH << ", " << VRAM_HEIGHT << ");\n"; + ss << "CONSTANT min16float2 RCP_NATIVE_VRAM_SIZE = float2(1.0, 1.0) / float2(NATIVE_VRAM_SIZE);\n"; + ss << "CONSTANT min16uint MULTISAMPLES = " << m_multisamples << "u;\n"; ss << "CONSTANT bool PER_SAMPLE_SHADING = " << (m_per_sample_shading ? "true" : "false") << ";\n"; ss << R"( @@ -47,7 +47,7 @@ uint fixYCoord(uint y) #endif } -uint fixNativeYCoord(uint y) +min16uint fixNativeYCoord(min16uint y) { #if API_OPENGL || API_OPENGL_ES return NATIVE_VRAM_SIZE.y - y - 1u; @@ -56,7 +56,7 @@ uint fixNativeYCoord(uint y) #endif } -uint RGBA8ToRGBA5551(float4 v) +uint RGBA8ToRGBA5551(min16float4 v) { uint r = uint(roundEven(v.r * 31.0)); uint g = uint(roundEven(v.g * 31.0)); @@ -65,7 +65,7 @@ uint RGBA8ToRGBA5551(float4 v) return (r) | (g << 5) | (b << 10) | (a << 15); } -float4 RGBA5551ToRGBA8(uint v) +min16float4 RGBA5551ToRGBA8(uint v) { uint r = (v & 31u); uint g = ((v >> 5) & 31u); @@ -748,14 +748,14 @@ std::string GPU_HW_ShaderGen::GenerateBatchFragmentShader(GPU_HW::BatchRenderMod ss << "};\n"; ss << R"( -uint3 ApplyDithering(uint2 coord, uint3 icol) +min16uint3 ApplyDithering(min16uint2 coord, min16uint3 icol) { #if DITHERING_SCALED - uint2 fc = coord & uint2(3u, 3u); + min16uint2 fc = coord & uint2(3u, 3u); #else - uint2 fc = (coord / uint2(RESOLUTION_SCALE, RESOLUTION_SCALE)) & uint2(3u, 3u); + min16uint2 fc = (coord / uint2(RESOLUTION_SCALE, RESOLUTION_SCALE)) & uint2(3u, 3u); #endif - int offset = s_dither_values[fc.y * 4u + fc.x]; + min16int offset = s_dither_values[fc.y * 4u + fc.x]; #if !TRUE_COLOR return uint3(clamp((int3(icol) + int3(offset, offset, offset)) >> 3, 0, 31)); @@ -767,32 +767,32 @@ uint3 ApplyDithering(uint2 coord, uint3 icol) #if TEXTURED CONSTANT float4 TRANSPARENT_PIXEL_COLOR = float4(0.0, 0.0, 0.0, 0.0); -uint2 ApplyTextureWindow(uint2 coords) +min16uint2 ApplyTextureWindow(min16uint2 coords) { - uint x = (uint(coords.x) & u_texture_window_and.x) | u_texture_window_or.x; - uint y = (uint(coords.y) & u_texture_window_and.y) | u_texture_window_or.y; + min16uint x = (uint(coords.x) & u_texture_window_and.x) | u_texture_window_or.x; + min16uint y = (uint(coords.y) & u_texture_window_and.y) | u_texture_window_or.y; return uint2(x, y); } -uint2 ApplyUpscaledTextureWindow(uint2 coords) +min16uint2 ApplyUpscaledTextureWindow(min16uint2 coords) { - uint2 native_coords = coords / uint2(RESOLUTION_SCALE, RESOLUTION_SCALE); - uint2 coords_offset = coords % uint2(RESOLUTION_SCALE, RESOLUTION_SCALE); + min16uint2 native_coords = coords / uint2(RESOLUTION_SCALE, RESOLUTION_SCALE); + min16uint2 coords_offset = coords % uint2(RESOLUTION_SCALE, RESOLUTION_SCALE); return (ApplyTextureWindow(native_coords) * uint2(RESOLUTION_SCALE, RESOLUTION_SCALE)) + coords_offset; } -uint2 FloatToIntegerCoords(float2 coords) +min16uint2 FloatToIntegerCoords(min16float2 coords) { // With the vertex offset applied at 1x resolution scale, we want to round the texture coordinates. // Floor them otherwise, as it currently breaks when upscaling as the vertex offset is not applied. return uint2((RESOLUTION_SCALE == 1u) ? roundEven(coords) : floor(coords)); } -float4 SampleFromVRAM(uint4 texpage, float2 coords) +min16float4 SampleFromVRAM(min16uint4 texpage, min16float2 coords) { #if PALETTE - uint2 icoord = ApplyTextureWindow(FloatToIntegerCoords(coords)); - uint2 index_coord = icoord; + min16uint2 icoord = ApplyTextureWindow(FloatToIntegerCoords(coords)); + min16uint2 index_coord = icoord; #if PALETTE_4_BIT index_coord.x /= 4u; #elif PALETTE_8_BIT @@ -800,8 +800,9 @@ float4 SampleFromVRAM(uint4 texpage, float2 coords) #endif // load palette index - uint2 vicoord = uint2(texpage.x + index_coord.x, fixNativeYCoord(texpage.y + index_coord.y)); - float4 texel = SAMPLE_TEXTURE(samp0, float2(vicoord) * RCP_NATIVE_VRAM_SIZE); + min16uint2 vicoord = uint2(texpage.x + index_coord.x, fixNativeYCoord(texpage.y + index_coord.y)); + min16float2 vncoord = float2(vicoord) * RCP_NATIVE_VRAM_SIZE; + min16float4 texel = SAMPLE_TEXTURE(samp0, vncoord); uint vram_value = RGBA8ToRGBA5551(texel); // apply palette @@ -814,7 +815,7 @@ float4 SampleFromVRAM(uint4 texpage, float2 coords) #endif // sample palette - uint2 palette_icoord = uint2(texpage.z + palette_index, fixNativeYCoord(texpage.w)); + min16uint2 palette_icoord = uint2(texpage.z + palette_index, fixNativeYCoord(texpage.w)); return SAMPLE_TEXTURE(samp0, float2(palette_icoord) * RCP_NATIVE_VRAM_SIZE); #else // Direct texturing. Render-to-texture effects. Use upscaled coordinates. @@ -852,12 +853,12 @@ float4 SampleFromVRAM(uint4 texpage, float2 coords) ss << R"( { - uint3 vertcol = uint3(v_col0.rgb); + min16uint3 vertcol = uint3(v_col0.rgb); bool semitransparent; - uint3 icolor; - float ialpha; - float oalpha; + min16uint3 icolor; + min16float ialpha; + min16float oalpha; #if INTERLACING if ((fixYCoord(uint(v_pos.y)) & 1u) == u_interlaced_displayed_field) @@ -865,7 +866,7 @@ float4 SampleFromVRAM(uint4 texpage, float2 coords) #endif #if TEXTURED - float4 texcol; + min16float4 texcol; #if TEXTURE_FILTERING FilteredSampleFromVRAM(v_texpage, v_tex0, v_uv_limits, texcol, ialpha); if (ialpha < 0.5) @@ -928,12 +929,12 @@ float4 SampleFromVRAM(uint4 texpage, float2 coords) #endif // Premultiply alpha so we don't need to use a colour output for it. - float premultiply_alpha = ialpha; + min16float premultiply_alpha = ialpha; #if TRANSPARENCY premultiply_alpha = ialpha * (semitransparent ? u_src_alpha_factor : 1.0); #endif - float3 color; + min16float3 color; #if !TRUE_COLOR // We want to apply the alpha before the truncation to 16-bit, otherwise we'll be passing a 32-bit precision color // into the blend unit, which can cause a small amount of error to accumulate. @@ -1302,7 +1303,7 @@ std::string GPU_HW_ShaderGen::GenerateVRAMCopyFragmentShader() DeclareFragmentEntryPoint(ss, 0, 1, {}, true, 1, true, false, false, msaa); ss << R"( { - uint2 dst_coords = uint2(v_pos.xy); + min16uint2 dst_coords = uint2(v_pos.xy); // make sure it's not oversized and out of range if ((dst_coords.x < u_dst_coords.x && dst_coords.x >= u_end_coords.x) || @@ -1312,18 +1313,18 @@ std::string GPU_HW_ShaderGen::GenerateVRAMCopyFragmentShader() } // find offset from the start of the row/column - uint2 offset; + min16uint2 offset; offset.x = (dst_coords.x < u_dst_coords.x) ? (VRAM_SIZE.x - u_dst_coords.x + dst_coords.x) : (dst_coords.x - u_dst_coords.x); offset.y = (dst_coords.y < u_dst_coords.y) ? (VRAM_SIZE.y - u_dst_coords.y + dst_coords.y) : (dst_coords.y - u_dst_coords.y); // find the source coordinates to copy from - uint2 src_coords = (u_src_coords + offset) % VRAM_SIZE; + min16uint2 src_coords = (u_src_coords + offset) % VRAM_SIZE; // sample and apply mask bit #if MSAA_COPY - float4 color = LOAD_TEXTURE_MS(samp0, int2(src_coords), f_sample_index); + min16float4 color = LOAD_TEXTURE_MS(samp0, int2(src_coords), f_sample_index); #else - float4 color = LOAD_TEXTURE(samp0, int2(src_coords), 0); + min16float4 color = LOAD_TEXTURE(samp0, int2(src_coords), 0); #endif o_col0 = float4(color.xyz, u_set_mask_bit ? 1.0 : color.a); #if !PGXP_DEPTH diff --git a/src/core/shadergen.cpp b/src/core/shadergen.cpp index e17adc8be..c1eac90e8 100644 --- a/src/core/shadergen.cpp +++ b/src/core/shadergen.cpp @@ -139,13 +139,13 @@ void ShaderGen::WriteHeader(std::stringstream& ss) { ss << "precision highp float;\n"; ss << "precision highp int;\n"; - ss << "precision highp sampler2D;\n"; + ss << "precision mediump sampler2D;\n"; if (GLAD_GL_ES_VERSION_3_1) - ss << "precision highp sampler2DMS;\n"; + ss << "precision mediump sampler2DMS;\n"; if (GLAD_GL_ES_VERSION_3_2) - ss << "precision highp usamplerBuffer;\n"; + ss << "precision mediump usamplerBuffer;\n"; ss << "\n"; } @@ -170,6 +170,19 @@ void ShaderGen::WriteHeader(std::stringstream& ss) ss << "#define frac fract\n"; ss << "#define lerp mix\n"; + ss << "#define min16int mediump int\n"; + ss << "#define min16uint mediump uint\n"; + ss << "#define min16float mediump float\n"; + ss << "#define min16float2 mediump vec2\n"; + ss << "#define min16float3 mediump vec3\n"; + ss << "#define min16float4 mediump vec4\n"; + ss << "#define min16int2 mediump ivec2\n"; + ss << "#define min16int3 mediump ivec3\n"; + ss << "#define min16int4 mediump ivec4\n"; + ss << "#define min16uint2 mediump uvec2\n"; + ss << "#define min16uint3 mediump uvec3\n"; + ss << "#define min16uint4 mediump uvec4\n"; + ss << "#define CONSTANT const\n"; ss << "#define GLOBAL\n"; ss << "#define VECTOR_EQ(a, b) ((a) == (b))\n"; @@ -211,6 +224,22 @@ void ShaderGen::WriteHeader(std::stringstream& ss) ss << "#define mat2 float2x2\n"; ss << "#define mat3 float3x3\n"; ss << "#define mat4 float4x4\n"; + +#if 0 + ss << "#define min16int int\n"; + ss << "#define min16uint uint\n"; + ss << "#define min16float float\n"; + ss << "#define min16float2 float2\n"; + ss << "#define min16float3 float3\n"; + ss << "#define min16float4 float4\n"; + ss << "#define min16int2 ivec2\n"; + ss << "#define min16int3 ivec3\n"; + ss << "#define min16int4 ivec4\n"; + ss << "#define min16uint2 uint2\n"; + ss << "#define min16uint3 uint3\n"; + ss << "#define min16uint4 uint4\n"; +#endif + ss << "#define CONSTANT static const\n"; ss << "#define GLOBAL static\n"; ss << "#define VECTOR_EQ(a, b) (all((a) == (b)))\n"; @@ -348,7 +377,7 @@ void ShaderGen::DeclareVertexEntryPoint( ss << "out VertexData" << output_block_suffix << " {\n"; for (u32 i = 0; i < num_color_outputs; i++) - ss << " " << qualifier << "float4 v_col" << i << ";\n"; + ss << " " << qualifier << "min16float4 v_col" << i << ";\n"; for (u32 i = 0; i < num_texcoord_outputs; i++) ss << " " << qualifier << "float2 v_tex" << i << ";\n"; @@ -365,7 +394,7 @@ void ShaderGen::DeclareVertexEntryPoint( const char* qualifier = GetInterpolationQualifier(false, centroid_interpolation, sample_interpolation, true); for (u32 i = 0; i < num_color_outputs; i++) - ss << qualifier << "out float4 v_col" << i << ";\n"; + ss << qualifier << "out min16float4 v_col" << i << ";\n"; for (u32 i = 0; i < num_texcoord_outputs; i++) ss << qualifier << "out float2 v_tex" << i << ";\n"; @@ -406,7 +435,7 @@ void ShaderGen::DeclareVertexEntryPoint( } for (u32 i = 0; i < num_color_outputs; i++) - ss << " " << qualifier << "out float4 v_col" << i << " : COLOR" << i << ",\n"; + ss << " " << qualifier << "out min16float4 v_col" << i << " : COLOR" << i << ",\n"; for (u32 i = 0; i < num_texcoord_outputs; i++) ss << " " << qualifier << "out float2 v_tex" << i << " : TEXCOORD" << i << ",\n"; @@ -441,7 +470,7 @@ void ShaderGen::DeclareFragmentEntryPoint( ss << "in VertexData {\n"; for (u32 i = 0; i < num_color_inputs; i++) - ss << " " << qualifier << "float4 v_col" << i << ";\n"; + ss << " " << qualifier << "min16float4 v_col" << i << ";\n"; for (u32 i = 0; i < num_texcoord_inputs; i++) ss << " " << qualifier << "float2 v_tex" << i << ";\n"; @@ -458,7 +487,7 @@ void ShaderGen::DeclareFragmentEntryPoint( const char* qualifier = GetInterpolationQualifier(false, centroid_interpolation, sample_interpolation, false); for (u32 i = 0; i < num_color_inputs; i++) - ss << qualifier << "in float4 v_col" << i << ";\n"; + ss << qualifier << "in min16float4 v_col" << i << ";\n"; for (u32 i = 0; i < num_texcoord_inputs; i++) ss << qualifier << "in float2 v_tex" << i << ";\n"; @@ -510,7 +539,7 @@ void ShaderGen::DeclareFragmentEntryPoint( ss << "void main(\n"; for (u32 i = 0; i < num_color_inputs; i++) - ss << " " << qualifier << "in float4 v_col" << i << " : COLOR" << i << ",\n"; + ss << " " << qualifier << "in min16float4 v_col" << i << " : COLOR" << i << ",\n"; for (u32 i = 0; i < num_texcoord_inputs; i++) ss << " " << qualifier << "in float2 v_tex" << i << " : TEXCOORD" << i << ",\n";