regs_lighting.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. // Copyright 2017 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. #include <array>
  6. #include "common/assert.h"
  7. #include "common/bit_field.h"
  8. #include "common/common_funcs.h"
  9. #include "common/common_types.h"
  10. #include "common/vector_math.h"
  11. namespace Pica {
  12. struct LightingRegs {
  13. enum class LightingSampler {
  14. Distribution0 = 0,
  15. Distribution1 = 1,
  16. Fresnel = 3,
  17. ReflectBlue = 4,
  18. ReflectGreen = 5,
  19. ReflectRed = 6,
  20. SpotlightAttenuation = 8,
  21. DistanceAttenuation = 16,
  22. };
  23. static LightingSampler SpotlightAttenuationSampler(unsigned index) {
  24. return static_cast<LightingSampler>(
  25. static_cast<unsigned>(LightingSampler::SpotlightAttenuation) + index);
  26. }
  27. static LightingSampler DistanceAttenuationSampler(unsigned index) {
  28. return static_cast<LightingSampler>(
  29. static_cast<unsigned>(LightingSampler::DistanceAttenuation) + index);
  30. }
  31. /**
  32. * Pica fragment lighting supports using different LUTs for each lighting component: Reflectance
  33. * R, G, and B channels, distribution function for specular components 0 and 1, fresnel factor,
  34. * and spotlight attenuation. Furthermore, which LUTs are used for each channel (or whether a
  35. * channel is enabled at all) is specified by various pre-defined lighting configurations. With
  36. * configurations that require more LUTs, more cycles are required on HW to perform lighting
  37. * computations.
  38. */
  39. enum class LightingConfig : u32 {
  40. Config0 = 0, ///< Reflect Red, Distribution 0, Spotlight
  41. Config1 = 1, ///< Reflect Red, Fresnel, Spotlight
  42. Config2 = 2, ///< Reflect Red, Distribution 0/1
  43. Config3 = 3, ///< Distribution 0/1, Fresnel
  44. Config4 = 4, ///< Reflect Red/Green/Blue, Distribution 0/1, Spotlight
  45. Config5 = 5, ///< Reflect Red/Green/Blue, Distribution 0, Fresnel, Spotlight
  46. Config6 = 6, ///< Reflect Red, Distribution 0/1, Fresnel, Spotlight
  47. Config7 = 8, ///< Reflect Red/Green/Blue, Distribution 0/1, Fresnel, Spotlight
  48. ///< NOTE: '8' is intentional, '7' does not appear to be a valid configuration
  49. };
  50. /// Selects which lighting components are affected by fresnel
  51. enum class LightingFresnelSelector : u32 {
  52. None = 0, ///< Fresnel is disabled
  53. PrimaryAlpha = 1, ///< Primary (diffuse) lighting alpha is affected by fresnel
  54. SecondaryAlpha = 2, ///< Secondary (specular) lighting alpha is affected by fresnel
  55. Both =
  56. PrimaryAlpha |
  57. SecondaryAlpha, ///< Both primary and secondary lighting alphas are affected by fresnel
  58. };
  59. /// Factor used to scale the output of a lighting LUT
  60. enum class LightingScale : u32 {
  61. Scale1 = 0, ///< Scale is 1x
  62. Scale2 = 1, ///< Scale is 2x
  63. Scale4 = 2, ///< Scale is 4x
  64. Scale8 = 3, ///< Scale is 8x
  65. Scale1_4 = 6, ///< Scale is 0.25x
  66. Scale1_2 = 7, ///< Scale is 0.5x
  67. };
  68. enum class LightingLutInput : u32 {
  69. NH = 0, // Cosine of the angle between the normal and half-angle vectors
  70. VH = 1, // Cosine of the angle between the view and half-angle vectors
  71. NV = 2, // Cosine of the angle between the normal and the view vector
  72. LN = 3, // Cosine of the angle between the light and the normal vectors
  73. SP = 4, // Cosine of the angle between the light and the inverse spotlight vectors
  74. CP = 5, // Cosine of the angle between the tangent and projection of half-angle vectors
  75. };
  76. enum class LightingBumpMode : u32 {
  77. None = 0,
  78. NormalMap = 1,
  79. TangentMap = 2,
  80. };
  81. union LightColor {
  82. BitField<0, 10, u32> b;
  83. BitField<10, 10, u32> g;
  84. BitField<20, 10, u32> r;
  85. Math::Vec3f ToVec3f() const {
  86. // These fields are 10 bits wide, however 255 corresponds to 1.0f for each color
  87. // component
  88. return Math::MakeVec((f32)r / 255.f, (f32)g / 255.f, (f32)b / 255.f);
  89. }
  90. };
  91. /// Returns true if the specified lighting sampler is supported by the current Pica lighting
  92. /// configuration
  93. static bool IsLightingSamplerSupported(LightingConfig config, LightingSampler sampler) {
  94. switch (sampler) {
  95. case LightingSampler::Distribution0:
  96. return (config != LightingConfig::Config1);
  97. case LightingSampler::Distribution1:
  98. return (config != LightingConfig::Config0) && (config != LightingConfig::Config1) &&
  99. (config != LightingConfig::Config5);
  100. case LightingSampler::SpotlightAttenuation:
  101. return (config != LightingConfig::Config2) && (config != LightingConfig::Config3);
  102. case LightingSampler::Fresnel:
  103. return (config != LightingConfig::Config0) && (config != LightingConfig::Config2) &&
  104. (config != LightingConfig::Config4);
  105. case LightingSampler::ReflectRed:
  106. return (config != LightingConfig::Config3);
  107. case LightingSampler::ReflectGreen:
  108. case LightingSampler::ReflectBlue:
  109. return (config == LightingConfig::Config4) || (config == LightingConfig::Config5) ||
  110. (config == LightingConfig::Config7);
  111. default:
  112. UNREACHABLE_MSG("Regs::IsLightingSamplerSupported: Reached unreachable section, "
  113. "sampler should be one of Distribution0, Distribution1, "
  114. "SpotlightAttenuation, Fresnel, ReflectRed, ReflectGreen or "
  115. "ReflectBlue, instead got %i",
  116. static_cast<int>(config));
  117. }
  118. }
  119. struct LightSrc {
  120. LightColor specular_0; // material.specular_0 * light.specular_0
  121. LightColor specular_1; // material.specular_1 * light.specular_1
  122. LightColor diffuse; // material.diffuse * light.diffuse
  123. LightColor ambient; // material.ambient * light.ambient
  124. // Encoded as 16-bit floating point
  125. union {
  126. BitField<0, 16, u32> x;
  127. BitField<16, 16, u32> y;
  128. };
  129. union {
  130. BitField<0, 16, u32> z;
  131. };
  132. // inverse spotlight direction vector, encoded as fixed1.1.11
  133. union {
  134. BitField<0, 13, s32> spot_x;
  135. BitField<16, 13, s32> spot_y;
  136. };
  137. union {
  138. BitField<0, 13, s32> spot_z;
  139. };
  140. INSERT_PADDING_WORDS(0x1);
  141. union {
  142. BitField<0, 1, u32> directional;
  143. BitField<1, 1, u32> two_sided_diffuse; // When disabled, clamp dot-product to 0
  144. } config;
  145. BitField<0, 20, u32> dist_atten_bias;
  146. BitField<0, 20, u32> dist_atten_scale;
  147. INSERT_PADDING_WORDS(0x4);
  148. };
  149. static_assert(sizeof(LightSrc) == 0x10 * sizeof(u32), "LightSrc structure must be 0x10 words");
  150. LightSrc light[8];
  151. LightColor global_ambient; // Emission + (material.ambient * lighting.ambient)
  152. INSERT_PADDING_WORDS(0x1);
  153. BitField<0, 3, u32> max_light_index; // Number of enabled lights - 1
  154. union {
  155. BitField<2, 2, LightingFresnelSelector> fresnel_selector;
  156. BitField<4, 4, LightingConfig> config;
  157. BitField<22, 2, u32> bump_selector; // 0: Texture 0, 1: Texture 1, 2: Texture 2
  158. BitField<27, 1, u32> clamp_highlights;
  159. BitField<28, 2, LightingBumpMode> bump_mode;
  160. BitField<30, 1, u32> disable_bump_renorm;
  161. } config0;
  162. union {
  163. u32 raw;
  164. // Each bit specifies whether spot light attenuation should be applied for the corresponding
  165. // light.
  166. BitField<8, 8, u32> disable_spot_atten;
  167. BitField<16, 1, u32> disable_lut_d0;
  168. BitField<17, 1, u32> disable_lut_d1;
  169. // Note: by intuition, BitField<18, 1, u32> should be disable_lut_sp, but it is actually a
  170. // dummy bit which is always set as 1.
  171. BitField<19, 1, u32> disable_lut_fr;
  172. BitField<20, 1, u32> disable_lut_rr;
  173. BitField<21, 1, u32> disable_lut_rg;
  174. BitField<22, 1, u32> disable_lut_rb;
  175. // Each bit specifies whether distance attenuation should be applied for the corresponding
  176. // light.
  177. BitField<24, 8, u32> disable_dist_atten;
  178. } config1;
  179. bool IsDistAttenDisabled(unsigned index) const {
  180. return (config1.disable_dist_atten & (1 << index)) != 0;
  181. }
  182. bool IsSpotAttenDisabled(unsigned index) const {
  183. return (config1.disable_spot_atten & (1 << index)) != 0;
  184. }
  185. union {
  186. BitField<0, 8, u32> index; ///< Index at which to set data in the LUT
  187. BitField<8, 5, u32> type; ///< Type of LUT for which to set data
  188. } lut_config;
  189. BitField<0, 1, u32> disable;
  190. INSERT_PADDING_WORDS(0x1);
  191. // When data is written to any of these registers, it gets written to the lookup table of the
  192. // selected type at the selected index, specified above in the `lut_config` register. With each
  193. // write, `lut_config.index` is incremented. It does not matter which of these registers is
  194. // written to, the behavior will be the same.
  195. u32 lut_data[8];
  196. // These are used to specify if absolute (abs) value should be used for each LUT index. When
  197. // abs mode is disabled, LUT indexes are in the range of (-1.0, 1.0). Otherwise, they are in
  198. // the range of (0.0, 1.0).
  199. union {
  200. BitField<1, 1, u32> disable_d0;
  201. BitField<5, 1, u32> disable_d1;
  202. BitField<9, 1, u32> disable_sp;
  203. BitField<13, 1, u32> disable_fr;
  204. BitField<17, 1, u32> disable_rb;
  205. BitField<21, 1, u32> disable_rg;
  206. BitField<25, 1, u32> disable_rr;
  207. } abs_lut_input;
  208. union {
  209. BitField<0, 3, LightingLutInput> d0;
  210. BitField<4, 3, LightingLutInput> d1;
  211. BitField<8, 3, LightingLutInput> sp;
  212. BitField<12, 3, LightingLutInput> fr;
  213. BitField<16, 3, LightingLutInput> rb;
  214. BitField<20, 3, LightingLutInput> rg;
  215. BitField<24, 3, LightingLutInput> rr;
  216. } lut_input;
  217. union {
  218. BitField<0, 3, LightingScale> d0;
  219. BitField<4, 3, LightingScale> d1;
  220. BitField<8, 3, LightingScale> sp;
  221. BitField<12, 3, LightingScale> fr;
  222. BitField<16, 3, LightingScale> rb;
  223. BitField<20, 3, LightingScale> rg;
  224. BitField<24, 3, LightingScale> rr;
  225. static float GetScale(LightingScale scale) {
  226. switch (scale) {
  227. case LightingScale::Scale1:
  228. return 1.0f;
  229. case LightingScale::Scale2:
  230. return 2.0f;
  231. case LightingScale::Scale4:
  232. return 4.0f;
  233. case LightingScale::Scale8:
  234. return 8.0f;
  235. case LightingScale::Scale1_4:
  236. return 0.25f;
  237. case LightingScale::Scale1_2:
  238. return 0.5f;
  239. }
  240. return 0.0f;
  241. }
  242. } lut_scale;
  243. INSERT_PADDING_WORDS(0x6);
  244. union {
  245. // There are 8 light enable "slots", corresponding to the total number of lights supported
  246. // by Pica. For N enabled lights (specified by register 0x1c2, or 'src_num' above), the
  247. // first N slots below will be set to integers within the range of 0-7, corresponding to the
  248. // actual light that is enabled for each slot.
  249. BitField<0, 3, u32> slot_0;
  250. BitField<4, 3, u32> slot_1;
  251. BitField<8, 3, u32> slot_2;
  252. BitField<12, 3, u32> slot_3;
  253. BitField<16, 3, u32> slot_4;
  254. BitField<20, 3, u32> slot_5;
  255. BitField<24, 3, u32> slot_6;
  256. BitField<28, 3, u32> slot_7;
  257. unsigned GetNum(unsigned index) const {
  258. const unsigned enable_slots[] = {slot_0, slot_1, slot_2, slot_3,
  259. slot_4, slot_5, slot_6, slot_7};
  260. return enable_slots[index];
  261. }
  262. } light_enable;
  263. INSERT_PADDING_WORDS(0x26);
  264. };
  265. static_assert(sizeof(LightingRegs) == 0xC0 * sizeof(u32), "LightingRegs struct has incorrect size");
  266. } // namespace Pica