texture_advanced.frag.hlsl 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. cbuffer Constants : register(b0, space3)
  2. {
  3. float scRGB_output;
  4. float texture_type;
  5. float input_type;
  6. float color_scale;
  7. float4 texel_size;
  8. float tonemap_method;
  9. float tonemap_factor1;
  10. float tonemap_factor2;
  11. float sdr_white_point;
  12. float4 Yoffset;
  13. float4 Rcoeff;
  14. float4 Gcoeff;
  15. float4 Bcoeff;
  16. };
  17. Texture2D texture0 : register(t0, space2);
  18. Texture2D texture1 : register(t1, space2);
  19. Texture2D texture2 : register(t2, space2);
  20. SamplerState sampler0 : register(s0, space2);
  21. SamplerState sampler1 : register(s1, space2);
  22. struct PSInput {
  23. float4 v_color : COLOR0;
  24. float2 v_uv : TEXCOORD0;
  25. };
  26. struct PSOutput {
  27. float4 o_color : SV_Target;
  28. };
  29. // These should mirror the definitions in SDL_render_gpu.c
  30. static const float TONEMAP_NONE = 0;
  31. static const float TONEMAP_LINEAR = 1;
  32. static const float TONEMAP_CHROME = 2;
  33. static const float TEXTURETYPE_NONE = 0;
  34. static const float TEXTURETYPE_RGB = 1;
  35. static const float TEXTURETYPE_RGB_PIXELART = 2;
  36. static const float TEXTURETYPE_RGBA = 3;
  37. static const float TEXTURETYPE_RGBA_PIXELART = 4;
  38. static const float TEXTURETYPE_PALETTE = 5;
  39. static const float TEXTURETYPE_PALETTE_PIXELART = 6;
  40. static const float TEXTURETYPE_NV12 = 7;
  41. static const float TEXTURETYPE_NV21 = 8;
  42. static const float TEXTURETYPE_YUV = 9;
  43. static const float INPUTTYPE_UNSPECIFIED = 0;
  44. static const float INPUTTYPE_SRGB = 1;
  45. static const float INPUTTYPE_SCRGB = 2;
  46. static const float INPUTTYPE_HDR10 = 3;
  47. static const float3x3 mat709to2020 = {
  48. { 0.627404, 0.329283, 0.043313 },
  49. { 0.069097, 0.919541, 0.011362 },
  50. { 0.016391, 0.088013, 0.895595 }
  51. };
  52. static const float3x3 mat2020to709 = {
  53. { 1.660496, -0.587656, -0.072840 },
  54. { -0.124547, 1.132895, -0.008348 },
  55. { -0.018154, -0.100597, 1.118751 }
  56. };
  57. float sRGBtoLinear(float v)
  58. {
  59. if (v <= 0.04045) {
  60. v = (v / 12.92);
  61. } else {
  62. v = pow(abs(v + 0.055) / 1.055, 2.4);
  63. }
  64. return v;
  65. }
  66. float sRGBfromLinear(float v)
  67. {
  68. if (v <= 0.0031308) {
  69. v = (v * 12.92);
  70. } else {
  71. v = (pow(abs(v), 1.0 / 2.4) * 1.055 - 0.055);
  72. }
  73. return v;
  74. }
  75. float3 PQtoLinear(float3 v)
  76. {
  77. const float c1 = 0.8359375;
  78. const float c2 = 18.8515625;
  79. const float c3 = 18.6875;
  80. const float oo_m1 = 1.0 / 0.1593017578125;
  81. const float oo_m2 = 1.0 / 78.84375;
  82. float3 num = max(pow(abs(v), oo_m2) - c1, 0.0);
  83. float3 den = c2 - c3 * pow(abs(v), oo_m2);
  84. return (10000.0 * pow(abs(num / den), oo_m1) / sdr_white_point);
  85. }
  86. float3 ApplyTonemap(float3 v)
  87. {
  88. if (tonemap_method == TONEMAP_LINEAR) {
  89. v *= tonemap_factor1;
  90. } else if (tonemap_method == TONEMAP_CHROME) {
  91. if (input_type == INPUTTYPE_SCRGB) {
  92. // Convert to BT.2020 colorspace for tone mapping
  93. v = mul(mat709to2020, v);
  94. }
  95. float vmax = max(v.r, max(v.g, v.b));
  96. if (vmax > 0.0) {
  97. float scale = (1.0 + tonemap_factor1 * vmax) / (1.0 + tonemap_factor2 * vmax);
  98. v *= scale;
  99. }
  100. if (input_type == INPUTTYPE_SCRGB) {
  101. // Convert to BT.709 colorspace after tone mapping
  102. v = mul(mat2020to709, v);
  103. }
  104. }
  105. return v;
  106. }
  107. float2 GetPixelArtUV(PSInput input)
  108. {
  109. // box filter size in texel units
  110. float2 boxSize = clamp(fwidth(input.v_uv) * texel_size.zw, 1e-5, 1);
  111. // scale uv by texture size to get texel coordinate
  112. float2 tx = input.v_uv * texel_size.zw - 0.5 * boxSize;
  113. // compute offset for pixel-sized box filter
  114. float2 txOffset = smoothstep(1 - boxSize, 1, frac(tx));
  115. // compute bilinear sample uv coordinates
  116. float2 uv = (floor(tx) + 0.5 + txOffset) * texel_size.xy;
  117. return uv;
  118. }
  119. float4 GetInputColor(PSInput input)
  120. {
  121. float4 rgba;
  122. if (texture_type == TEXTURETYPE_NONE) {
  123. rgba = 1.0;
  124. } else if (texture_type == TEXTURETYPE_RGBA) {
  125. rgba = texture0.Sample(sampler0, input.v_uv);
  126. } else if (texture_type == TEXTURETYPE_RGBA_PIXELART) {
  127. float2 uv = GetPixelArtUV(input);
  128. rgba = texture0.SampleGrad(sampler0, uv, ddx(input.v_uv), ddy(input.v_uv));
  129. } else if (texture_type == TEXTURETYPE_RGB) {
  130. rgba = float4(texture0.Sample(sampler0, input.v_uv).rgb, 1.0);
  131. } else if (texture_type == TEXTURETYPE_RGB_PIXELART) {
  132. float2 uv = GetPixelArtUV(input);
  133. rgba = float4(texture0.SampleGrad(sampler0, uv, ddx(input.v_uv), ddy(input.v_uv)).rgb, 1.0);
  134. } else if (texture_type == TEXTURETYPE_PALETTE) {
  135. float index = texture0.Sample(sampler0, input.v_uv).r * 255;
  136. rgba = texture1.Sample(sampler1, float2((index + 0.5) / 256, 0.5));
  137. } else if (texture_type == TEXTURETYPE_PALETTE_PIXELART) {
  138. float2 uv = GetPixelArtUV(input);
  139. float index = texture0.SampleGrad(sampler0, uv, ddx(input.v_uv), ddy(input.v_uv)).r * 255;
  140. rgba = texture1.Sample(sampler1, float2((index + 0.5) / 256, 0.5));
  141. } else if (texture_type == TEXTURETYPE_NV12) {
  142. float3 yuv;
  143. yuv.x = texture0.Sample(sampler0, input.v_uv).r;
  144. yuv.yz = texture1.Sample(sampler0, input.v_uv).rg;
  145. yuv += Yoffset.xyz;
  146. rgba.r = dot(yuv, Rcoeff.xyz);
  147. rgba.g = dot(yuv, Gcoeff.xyz);
  148. rgba.b = dot(yuv, Bcoeff.xyz);
  149. rgba.a = 1.0;
  150. } else if (texture_type == TEXTURETYPE_NV21) {
  151. float3 yuv;
  152. yuv.x = texture0.Sample(sampler0, input.v_uv).r;
  153. yuv.yz = texture1.Sample(sampler0, input.v_uv).gr;
  154. yuv += Yoffset.xyz;
  155. rgba.r = dot(yuv, Rcoeff.xyz);
  156. rgba.g = dot(yuv, Gcoeff.xyz);
  157. rgba.b = dot(yuv, Bcoeff.xyz);
  158. rgba.a = 1.0;
  159. } else if (texture_type == TEXTURETYPE_YUV) {
  160. float3 yuv;
  161. yuv.x = texture0.Sample(sampler0, input.v_uv).r;
  162. yuv.y = texture1.Sample(sampler0, input.v_uv).r;
  163. yuv.z = texture2.Sample(sampler0, input.v_uv).r;
  164. yuv += Yoffset.xyz;
  165. rgba.r = dot(yuv, Rcoeff.xyz);
  166. rgba.g = dot(yuv, Gcoeff.xyz);
  167. rgba.b = dot(yuv, Bcoeff.xyz);
  168. rgba.a = 1.0;
  169. } else {
  170. // Error!
  171. rgba.r = 1.0;
  172. rgba.g = 0.0;
  173. rgba.b = 0.0;
  174. rgba.a = 1.0;
  175. }
  176. return rgba;
  177. }
  178. float4 GetOutputColor(float4 rgba)
  179. {
  180. float4 output;
  181. output.rgb = rgba.rgb * color_scale;
  182. output.a = rgba.a;
  183. return output;
  184. }
  185. float3 GetOutputColorFromSRGB(float3 rgb)
  186. {
  187. float3 output;
  188. if (scRGB_output) {
  189. rgb.r = sRGBtoLinear(rgb.r);
  190. rgb.g = sRGBtoLinear(rgb.g);
  191. rgb.b = sRGBtoLinear(rgb.b);
  192. }
  193. output.rgb = rgb * color_scale;
  194. return output;
  195. }
  196. float3 GetOutputColorFromLinear(float3 rgb)
  197. {
  198. float3 output;
  199. output.rgb = rgb * color_scale;
  200. if (!scRGB_output) {
  201. output.r = sRGBfromLinear(output.r);
  202. output.g = sRGBfromLinear(output.g);
  203. output.b = sRGBfromLinear(output.b);
  204. output.rgb = saturate(output.rgb);
  205. }
  206. return output;
  207. }
  208. float4 AdvancedPixelShader(PSInput input)
  209. {
  210. float4 rgba = GetInputColor(input);
  211. float4 output;
  212. if (input_type == INPUTTYPE_HDR10) {
  213. rgba.rgb = PQtoLinear(rgba.rgb);
  214. }
  215. if (tonemap_method != TONEMAP_NONE) {
  216. rgba.rgb = ApplyTonemap(rgba.rgb);
  217. }
  218. if (input_type == INPUTTYPE_SRGB) {
  219. output.rgb = GetOutputColorFromSRGB(rgba.rgb);
  220. output.a = rgba.a;
  221. } else if (input_type == INPUTTYPE_SCRGB) {
  222. output.rgb = GetOutputColorFromLinear(rgba.rgb);
  223. output.a = rgba.a;
  224. } else if (input_type == INPUTTYPE_HDR10) {
  225. rgba.rgb = mul(mat2020to709, rgba.rgb);
  226. output.rgb = GetOutputColorFromLinear(rgba.rgb);
  227. output.a = rgba.a;
  228. } else {
  229. output = GetOutputColor(rgba);
  230. }
  231. return output * input.v_color;
  232. }
  233. PSOutput main(PSInput input) {
  234. PSOutput output;
  235. output.o_color = AdvancedPixelShader(input);
  236. return output;
  237. }