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