UberShaderCommon.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. // Copyright 2017 Dolphin Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "VideoCommon/UberShaderCommon.h"
  4. #include "Common/EnumUtils.h"
  5. #include "VideoCommon/NativeVertexFormat.h"
  6. #include "VideoCommon/ShaderGenCommon.h"
  7. #include "VideoCommon/VideoCommon.h"
  8. #include "VideoCommon/XFMemory.h"
  9. namespace UberShader
  10. {
  11. void WriteLightingFunction(ShaderCode& out)
  12. {
  13. // ==============================================
  14. // Lighting channel calculation helper
  15. // ==============================================
  16. out.Write("int4 CalculateLighting(uint index, uint attnfunc, uint diffusefunc, float3 pos, "
  17. "float3 normal) {{\n"
  18. " float3 ldir, h, cosAttn, distAttn;\n"
  19. " float dist, dist2, attn;\n"
  20. "\n"
  21. " switch (attnfunc) {{\n");
  22. out.Write(" case {:s}:\n", AttenuationFunc::None);
  23. out.Write(" case {:s}:\n", AttenuationFunc::Dir);
  24. out.Write(" ldir = normalize(" I_LIGHTS "[index].pos.xyz - pos.xyz);\n"
  25. " attn = 1.0;\n"
  26. " if (length(ldir) == 0.0)\n"
  27. " ldir = normal;\n"
  28. " break;\n\n");
  29. out.Write(" case {:s}:\n", AttenuationFunc::Spec);
  30. out.Write(" ldir = normalize(" I_LIGHTS "[index].pos.xyz - pos.xyz);\n"
  31. " attn = (dot(normal, ldir) >= 0.0) ? max(0.0, dot(normal, " I_LIGHTS
  32. "[index].dir.xyz)) : 0.0;\n"
  33. " cosAttn = " I_LIGHTS "[index].cosatt.xyz;\n");
  34. out.Write(" if (diffusefunc == {:s})\n", DiffuseFunc::None);
  35. out.Write(" distAttn = " I_LIGHTS "[index].distatt.xyz;\n"
  36. " else\n"
  37. " distAttn = normalize(" I_LIGHTS "[index].distatt.xyz);\n"
  38. " attn = max(0.0, dot(cosAttn, float3(1.0, attn, attn*attn))) / dot(distAttn, "
  39. "float3(1.0, attn, attn*attn));\n"
  40. " break;\n\n");
  41. out.Write(" case {:s}:\n", AttenuationFunc::Spot);
  42. out.Write(" ldir = " I_LIGHTS "[index].pos.xyz - pos.xyz;\n"
  43. " dist2 = dot(ldir, ldir);\n"
  44. " dist = sqrt(dist2);\n"
  45. " ldir = ldir / dist;\n"
  46. " attn = max(0.0, dot(ldir, " I_LIGHTS "[index].dir.xyz));\n"
  47. " attn = max(0.0, " I_LIGHTS "[index].cosatt.x + " I_LIGHTS
  48. "[index].cosatt.y * attn + " I_LIGHTS "[index].cosatt.z * attn * attn) / dot(" I_LIGHTS
  49. "[index].distatt.xyz, float3(1.0, dist, dist2));\n"
  50. " break;\n\n");
  51. out.Write(" default:\n"
  52. " attn = 1.0;\n"
  53. " ldir = normal;\n"
  54. " break;\n"
  55. " }}\n"
  56. "\n"
  57. " switch (diffusefunc) {{\n");
  58. out.Write(" case {:s}:\n", DiffuseFunc::None);
  59. out.Write(" return int4(round(attn * float4(" I_LIGHTS "[index].color)));\n\n");
  60. out.Write(" case {:s}:\n", DiffuseFunc::Sign);
  61. out.Write(" return int4(round(attn * dot(ldir, normal) * float4(" I_LIGHTS
  62. "[index].color)));\n\n");
  63. out.Write(" case {:s}:\n", DiffuseFunc::Clamp);
  64. out.Write(" return int4(round(attn * max(0.0, dot(ldir, normal)) * float4(" I_LIGHTS
  65. "[index].color)));\n\n");
  66. out.Write(" default:\n"
  67. " return int4(0, 0, 0, 0);\n"
  68. " }}\n"
  69. "}}\n\n");
  70. }
  71. void WriteVertexLighting(ShaderCode& out, APIType api_type, std::string_view world_pos_var,
  72. std::string_view normal_var, std::string_view in_color_0_var,
  73. std::string_view in_color_1_var, std::string_view out_color_0_var,
  74. std::string_view out_color_1_var)
  75. {
  76. out.Write("// Lighting\n");
  77. out.Write("for (uint chan = 0u; chan < {}u; chan++) {{\n", NUM_XF_COLOR_CHANNELS);
  78. out.Write(" uint colorreg = xfmem_color(chan);\n"
  79. " uint alphareg = xfmem_alpha(chan);\n"
  80. " int4 mat = " I_MATERIALS "[chan + 2u]; \n"
  81. " int4 lacc = int4(255, 255, 255, 255);\n"
  82. "\n");
  83. out.Write(" if ({} != 0u)\n", BitfieldExtract<&LitChannel::matsource>("colorreg"));
  84. out.Write(" mat.xyz = int3(round(((chan == 0u) ? {}.xyz : {}.xyz) * 255.0));\n",
  85. in_color_0_var, in_color_1_var);
  86. out.Write(" if ({} != 0u)\n", BitfieldExtract<&LitChannel::matsource>("alphareg"));
  87. out.Write(" mat.w = int(round(((chan == 0u) ? {}.w : {}.w) * 255.0));\n", in_color_0_var,
  88. in_color_1_var);
  89. out.Write(" else\n"
  90. " mat.w = " I_MATERIALS " [chan + 2u].w;\n"
  91. "\n");
  92. out.Write(" if ({} != 0u) {{\n", BitfieldExtract<&LitChannel::enablelighting>("colorreg"));
  93. out.Write(" if ({} != 0u)\n", BitfieldExtract<&LitChannel::ambsource>("colorreg"));
  94. out.Write(" lacc.xyz = int3(round(((chan == 0u) ? {}.xyz : {}.xyz) * 255.0));\n",
  95. in_color_0_var, in_color_1_var);
  96. out.Write(" else\n"
  97. " lacc.xyz = " I_MATERIALS " [chan].xyz;\n"
  98. "\n");
  99. out.Write(" uint light_mask = {} | ({} << 4u);\n",
  100. BitfieldExtract<&LitChannel::lightMask0_3>("colorreg"),
  101. BitfieldExtract<&LitChannel::lightMask4_7>("colorreg"));
  102. out.Write(" uint attnfunc = {};\n", BitfieldExtract<&LitChannel::attnfunc>("colorreg"));
  103. out.Write(" uint diffusefunc = {};\n", BitfieldExtract<&LitChannel::diffusefunc>("colorreg"));
  104. out.Write(
  105. " for (uint light_index = 0u; light_index < 8u; light_index++) {{\n"
  106. " if ((light_mask & (1u << light_index)) != 0u)\n"
  107. " lacc.xyz += CalculateLighting(light_index, attnfunc, diffusefunc, {}, {}).xyz;\n",
  108. world_pos_var, normal_var);
  109. out.Write(" }}\n"
  110. " }}\n"
  111. "\n");
  112. out.Write(" if ({} != 0u) {{\n", BitfieldExtract<&LitChannel::enablelighting>("alphareg"));
  113. out.Write(" if ({} != 0u) {{\n", BitfieldExtract<&LitChannel::ambsource>("alphareg"));
  114. out.Write(" if ((components & ({}u << chan)) != 0u) // VB_HAS_COL0\n",
  115. Common::ToUnderlying(VB_HAS_COL0));
  116. out.Write(" lacc.w = int(round(((chan == 0u) ? {}.w : {}.w) * 255.0));\n", in_color_0_var,
  117. in_color_1_var);
  118. out.Write(" else if ((components & {}u) != 0u) // VB_HAS_COLO0\n",
  119. Common::ToUnderlying(VB_HAS_COL0));
  120. out.Write(" lacc.w = int(round({}.w * 255.0));\n", in_color_0_var);
  121. out.Write(" else\n"
  122. " lacc.w = 255;\n"
  123. " }} else {{\n"
  124. " lacc.w = " I_MATERIALS " [chan].w;\n"
  125. " }}\n"
  126. "\n");
  127. out.Write(" uint light_mask = {} | ({} << 4u);\n",
  128. BitfieldExtract<&LitChannel::lightMask0_3>("alphareg"),
  129. BitfieldExtract<&LitChannel::lightMask4_7>("alphareg"));
  130. out.Write(" uint attnfunc = {};\n", BitfieldExtract<&LitChannel::attnfunc>("alphareg"));
  131. out.Write(" uint diffusefunc = {};\n", BitfieldExtract<&LitChannel::diffusefunc>("alphareg"));
  132. out.Write(" for (uint light_index = 0u; light_index < 8u; light_index++) {{\n\n"
  133. " if ((light_mask & (1u << light_index)) != 0u)\n\n"
  134. " lacc.w += CalculateLighting(light_index, attnfunc, diffusefunc, {}, {}).w;\n",
  135. world_pos_var, normal_var);
  136. out.Write(" }}\n"
  137. " }}\n"
  138. "\n");
  139. out.Write(" lacc = clamp(lacc, 0, 255);\n"
  140. "\n"
  141. " // Hopefully GPUs that can support dynamic indexing will optimize this.\n"
  142. " float4 lit_color = float4((mat * (lacc + (lacc >> 7))) >> 8) / 255.0;\n"
  143. " switch (chan) {{\n"
  144. " case 0u: {} = lit_color; break;\n",
  145. out_color_0_var);
  146. out.Write(" case 1u: {} = lit_color; break;\n", out_color_1_var);
  147. out.Write(" }}\n"
  148. "}}\n"
  149. "\n");
  150. }
  151. } // namespace UberShader