regs_lighting.h 12 KB

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