Atlas - texture_advanced.frag.hlsl
Home / ext / SDL / src / render / gpu / shaders Lines: 1 | Size: 8887 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1 2cbuffer Constants : register(b0, space3) 3{ 4 float scRGB_output; 5 float texture_type; 6 float input_type; 7 float color_scale; 8 float4 texel_size; 9 10 float tonemap_method; 11 float tonemap_factor1; 12 float tonemap_factor2; 13 float sdr_white_point; 14 15 float4 Yoffset; 16 float4 Rcoeff; 17 float4 Gcoeff; 18 float4 Bcoeff; 19}; 20 21Texture2D texture0 : register(t0, space2); 22Texture2D texture1 : register(t1, space2); 23Texture2D texture2 : register(t2, space2); 24SamplerState sampler0 : register(s0, space2); 25SamplerState sampler1 : register(s1, space2); 26 27struct PSInput { 28 float4 v_color : COLOR0; 29 float2 v_uv : TEXCOORD0; 30}; 31 32struct PSOutput { 33 float4 o_color : SV_Target; 34}; 35 36// These should mirror the definitions in SDL_render_gpu.c 37static const float TONEMAP_NONE = 0; 38static const float TONEMAP_LINEAR = 1; 39static const float TONEMAP_CHROME = 2; 40 41static const float TEXTURETYPE_NONE = 0; 42static const float TEXTURETYPE_RGB = 1; 43static const float TEXTURETYPE_RGB_PIXELART = 2; 44static const float TEXTURETYPE_RGBA = 3; 45static const float TEXTURETYPE_RGBA_PIXELART = 4; 46static const float TEXTURETYPE_PALETTE_NEAREST = 5; 47static const float TEXTURETYPE_PALETTE_LINEAR = 6; 48static const float TEXTURETYPE_PALETTE_PIXELART = 7; 49static const float TEXTURETYPE_NV12 = 8; 50static const float TEXTURETYPE_NV21 = 9; 51static const float TEXTURETYPE_YUV = 10; 52 53static const float INPUTTYPE_UNSPECIFIED = 0; 54static const float INPUTTYPE_SRGB = 1; 55static const float INPUTTYPE_SCRGB = 2; 56static const float INPUTTYPE_HDR10 = 3; 57 58static const float3x3 mat709to2020 = { 59 { 0.627404, 0.329283, 0.043313 }, 60 { 0.069097, 0.919541, 0.011362 }, 61 { 0.016391, 0.088013, 0.895595 } 62}; 63 64static const float3x3 mat2020to709 = { 65 { 1.660496, -0.587656, -0.072840 }, 66 { -0.124547, 1.132895, -0.008348 }, 67 { -0.018154, -0.100597, 1.118751 } 68}; 69 70float sRGBtoLinear(float v) 71{ 72 if (v <= 0.04045) { 73 v = (v / 12.92); 74 } else { 75 v = pow(abs(v + 0.055) / 1.055, 2.4); 76 } 77 return v; 78} 79 80float sRGBfromLinear(float v) 81{ 82 if (v <= 0.0031308) { 83 v = (v * 12.92); 84 } else { 85 v = (pow(abs(v), 1.0 / 2.4) * 1.055 - 0.055); 86 } 87 return v; 88} 89 90float3 PQtoLinear(float3 v) 91{ 92 const float c1 = 0.8359375; 93 const float c2 = 18.8515625; 94 const float c3 = 18.6875; 95 const float oo_m1 = 1.0 / 0.1593017578125; 96 const float oo_m2 = 1.0 / 78.84375; 97 98 float3 num = max(pow(abs(v), oo_m2) - c1, 0.0); 99 float3 den = c2 - c3 * pow(abs(v), oo_m2); 100 return (10000.0 * pow(abs(num / den), oo_m1) / sdr_white_point); 101} 102 103float3 ApplyTonemap(float3 v) 104{ 105 if (tonemap_method == TONEMAP_LINEAR) { 106 v *= tonemap_factor1; 107 } else if (tonemap_method == TONEMAP_CHROME) { 108 if (input_type == INPUTTYPE_SCRGB) { 109 // Convert to BT.2020 colorspace for tone mapping 110 v = mul(mat709to2020, v); 111 } 112 113 float vmax = max(v.r, max(v.g, v.b)); 114 if (vmax > 0.0) { 115 float scale = (1.0 + tonemap_factor1 * vmax) / (1.0 + tonemap_factor2 * vmax); 116 v *= scale; 117 } 118 119 if (input_type == INPUTTYPE_SCRGB) { 120 // Convert to BT.709 colorspace after tone mapping 121 v = mul(mat2020to709, v); 122 } 123 } 124 return v; 125} 126 127float4 SamplePaletteNearest(float2 uv) 128{ 129 float index = texture0.Sample(sampler0, uv).r * 255; 130 return texture1.Sample(sampler1, float2((index + 0.5) / 256, 0.5)); 131} 132 133// Implementation with thanks from bgolus: 134// https://discussions.unity.com/t/how-to-make-data-shader-support-bilinear-trilinear/598639/8 135float4 SamplePaletteLinear(float2 uv) 136{ 137 // scale & offset uvs to integer values at texel centers 138 float2 uv_texels = uv * texel_size.zw + 0.5; 139 140 // get uvs for the center of the 4 surrounding texels by flooring 141 float4 uv_min_max = float4((floor(uv_texels) - 0.5) * texel_size.xy, (floor(uv_texels) + 0.5) * texel_size.xy); 142 143 // blend factor 144 float2 uv_frac = frac(uv_texels); 145 146 // sample all 4 texels 147 float4 texelA = SamplePaletteNearest(uv_min_max.xy); 148 float4 texelB = SamplePaletteNearest(uv_min_max.xw); 149 float4 texelC = SamplePaletteNearest(uv_min_max.zy); 150 float4 texelD = SamplePaletteNearest(uv_min_max.zw); 151 152 // bilinear interpolation 153 return lerp(lerp(texelA, texelB, uv_frac.y), lerp(texelC, texelD, uv_frac.y), uv_frac.x); 154} 155 156float2 GetPixelArtUV(float2 uv) 157{ 158 // box filter size in texel units 159 float2 boxSize = clamp(fwidth(uv) * texel_size.zw, 1e-5, 1); 160 161 // scale uv by texture size to get texel coordinate 162 float2 tx = uv * texel_size.zw - 0.5 * boxSize; 163 164 // compute offset for pixel-sized box filter 165 float2 txOffset = smoothstep(1 - boxSize, 1, frac(tx)); 166 167 // compute bilinear sample uv coordinates 168 return (floor(tx) + 0.5 + txOffset) * texel_size.xy; 169} 170 171float4 GetInputColor(PSInput input) 172{ 173 float4 rgba; 174 175 if (texture_type == TEXTURETYPE_NONE) { 176 rgba = 1.0; 177 } else if (texture_type == TEXTURETYPE_RGBA) { 178 rgba = texture0.Sample(sampler0, input.v_uv); 179 } else if (texture_type == TEXTURETYPE_RGBA_PIXELART) { 180 float2 uv = GetPixelArtUV(input.v_uv); 181 rgba = texture0.SampleGrad(sampler0, uv, ddx(input.v_uv), ddy(input.v_uv)); 182 } else if (texture_type == TEXTURETYPE_RGB) { 183 rgba = float4(texture0.Sample(sampler0, input.v_uv).rgb, 1.0); 184 } else if (texture_type == TEXTURETYPE_RGB_PIXELART) { 185 float2 uv = GetPixelArtUV(input.v_uv); 186 rgba = float4(texture0.SampleGrad(sampler0, uv, ddx(input.v_uv), ddy(input.v_uv)).rgb, 1.0); 187 } else if (texture_type == TEXTURETYPE_PALETTE_NEAREST) { 188 rgba = SamplePaletteNearest(input.v_uv); 189 } else if (texture_type == TEXTURETYPE_PALETTE_LINEAR) { 190 rgba = SamplePaletteLinear(input.v_uv); 191 } else if (texture_type == TEXTURETYPE_PALETTE_PIXELART) { 192 float2 uv = GetPixelArtUV(input.v_uv); 193 rgba = SamplePaletteLinear(uv); 194 } else if (texture_type == TEXTURETYPE_NV12) { 195 float3 yuv; 196 yuv.x = texture0.Sample(sampler0, input.v_uv).r; 197 yuv.yz = texture1.Sample(sampler0, input.v_uv).rg; 198 199 yuv += Yoffset.xyz; 200 rgba.r = dot(yuv, Rcoeff.xyz); 201 rgba.g = dot(yuv, Gcoeff.xyz); 202 rgba.b = dot(yuv, Bcoeff.xyz); 203 rgba.a = 1.0; 204 } else if (texture_type == TEXTURETYPE_NV21) { 205 float3 yuv; 206 yuv.x = texture0.Sample(sampler0, input.v_uv).r; 207 yuv.yz = texture1.Sample(sampler0, input.v_uv).gr; 208 209 yuv += Yoffset.xyz; 210 rgba.r = dot(yuv, Rcoeff.xyz); 211 rgba.g = dot(yuv, Gcoeff.xyz); 212 rgba.b = dot(yuv, Bcoeff.xyz); 213 rgba.a = 1.0; 214 } else if (texture_type == TEXTURETYPE_YUV) { 215 float3 yuv; 216 yuv.x = texture0.Sample(sampler0, input.v_uv).r; 217 yuv.y = texture1.Sample(sampler0, input.v_uv).r; 218 yuv.z = texture2.Sample(sampler0, input.v_uv).r; 219 220 yuv += Yoffset.xyz; 221 rgba.r = dot(yuv, Rcoeff.xyz); 222 rgba.g = dot(yuv, Gcoeff.xyz); 223 rgba.b = dot(yuv, Bcoeff.xyz); 224 rgba.a = 1.0; 225 } else { 226 // Error! 227 rgba.r = 1.0; 228 rgba.g = 0.0; 229 rgba.b = 1.0; 230 rgba.a = 1.0; 231 } 232 return rgba; 233} 234 235float4 GetOutputColor(float4 rgba) 236{ 237 float4 output; 238 239 output.rgb = rgba.rgb * color_scale; 240 output.a = rgba.a; 241 242 return output; 243} 244 245float3 GetOutputColorFromSRGB(float3 rgb) 246{ 247 float3 output; 248 249 if (scRGB_output) { 250 rgb.r = sRGBtoLinear(rgb.r); 251 rgb.g = sRGBtoLinear(rgb.g); 252 rgb.b = sRGBtoLinear(rgb.b); 253 } 254 255 output.rgb = rgb * color_scale; 256 257 return output; 258} 259 260float3 GetOutputColorFromLinear(float3 rgb) 261{ 262 float3 output; 263 264 output.rgb = rgb * color_scale; 265 266 if (!scRGB_output) { 267 output.r = sRGBfromLinear(output.r); 268 output.g = sRGBfromLinear(output.g); 269 output.b = sRGBfromLinear(output.b); 270 output.rgb = saturate(output.rgb); 271 } 272 273 return output; 274} 275 276float4 AdvancedPixelShader(PSInput input) 277{ 278 float4 rgba = GetInputColor(input); 279 float4 output; 280 281 if (input_type == INPUTTYPE_HDR10) { 282 rgba.rgb = PQtoLinear(rgba.rgb); 283 } 284 285 if (tonemap_method != TONEMAP_NONE) { 286 rgba.rgb = ApplyTonemap(rgba.rgb); 287 } 288 289 if (input_type == INPUTTYPE_SRGB) { 290 output.rgb = GetOutputColorFromSRGB(rgba.rgb); 291 output.a = rgba.a; 292 } else if (input_type == INPUTTYPE_SCRGB) { 293 output.rgb = GetOutputColorFromLinear(rgba.rgb); 294 output.a = rgba.a; 295 } else if (input_type == INPUTTYPE_HDR10) { 296 rgba.rgb = mul(mat2020to709, rgba.rgb); 297 output.rgb = GetOutputColorFromLinear(rgba.rgb); 298 output.a = rgba.a; 299 } else { 300 output = GetOutputColor(rgba); 301 } 302 303 return output * input.v_color; 304} 305 306PSOutput main(PSInput input) { 307 PSOutput output; 308 output.o_color = AdvancedPixelShader(input); 309 return output; 310} 311[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.