rasterizer_accelerated.cpp
1 // Copyright 2023 Citra Emulator Project 2 // Licensed under GPLv2 or any later version 3 // Refer to the license.txt file included. 4 5 #include "common/alignment.h" 6 #include "core/memory.h" 7 #include "video_core/pica/pica_core.h" 8 #include "video_core/rasterizer_accelerated.h" 9 10 namespace VideoCore { 11 12 using Pica::f24; 13 14 static Common::Vec4f ColorRGBA8(const u32 color) { 15 const auto rgba = 16 Common::Vec4u{color >> 0 & 0xFF, color >> 8 & 0xFF, color >> 16 & 0xFF, color >> 24 & 0xFF}; 17 return rgba / 255.0f; 18 } 19 20 static Common::Vec3f LightColor(const Pica::LightingRegs::LightColor& color) { 21 return Common::Vec3u{color.r, color.g, color.b} / 255.0f; 22 } 23 24 RasterizerAccelerated::HardwareVertex::HardwareVertex(const Pica::OutputVertex& v, 25 bool flip_quaternion) { 26 position[0] = v.pos.x.ToFloat32(); 27 position[1] = v.pos.y.ToFloat32(); 28 position[2] = v.pos.z.ToFloat32(); 29 position[3] = v.pos.w.ToFloat32(); 30 color[0] = v.color.x.ToFloat32(); 31 color[1] = v.color.y.ToFloat32(); 32 color[2] = v.color.z.ToFloat32(); 33 color[3] = v.color.w.ToFloat32(); 34 tex_coord0[0] = v.tc0.x.ToFloat32(); 35 tex_coord0[1] = v.tc0.y.ToFloat32(); 36 tex_coord1[0] = v.tc1.x.ToFloat32(); 37 tex_coord1[1] = v.tc1.y.ToFloat32(); 38 tex_coord2[0] = v.tc2.x.ToFloat32(); 39 tex_coord2[1] = v.tc2.y.ToFloat32(); 40 tex_coord0_w = v.tc0_w.ToFloat32(); 41 normquat[0] = v.quat.x.ToFloat32(); 42 normquat[1] = v.quat.y.ToFloat32(); 43 normquat[2] = v.quat.z.ToFloat32(); 44 normquat[3] = v.quat.w.ToFloat32(); 45 view[0] = v.view.x.ToFloat32(); 46 view[1] = v.view.y.ToFloat32(); 47 view[2] = v.view.z.ToFloat32(); 48 49 if (flip_quaternion) { 50 normquat = -normquat; 51 } 52 } 53 54 RasterizerAccelerated::RasterizerAccelerated(Memory::MemorySystem& memory_, Pica::PicaCore& pica_) 55 : memory{memory_}, pica{pica_}, regs{pica.regs.internal} { 56 fs_uniform_block_data.lighting_lut_dirty.fill(true); 57 } 58 59 /** 60 * This is a helper function to resolve an issue when interpolating opposite quaternions. See below 61 * for a detailed description of this issue (yuriks): 62 * 63 * For any rotation, there are two quaternions Q, and -Q, that represent the same rotation. If you 64 * interpolate two quaternions that are opposite, instead of going from one rotation to another 65 * using the shortest path, you'll go around the longest path. You can test if two quaternions are 66 * opposite by checking if Dot(Q1, Q2) < 0. In that case, you can flip either of them, therefore 67 * making Dot(Q1, -Q2) positive. 68 * 69 * This solution corrects this issue per-vertex before passing the quaternions to OpenGL. This is 70 * correct for most cases but can still rotate around the long way sometimes. An implementation 71 * which did `lerp(lerp(Q1, Q2), Q3)` (with proper weighting), applying the dot product check 72 * between each step would work for those cases at the cost of being more complex to implement. 73 * 74 * Fortunately however, the 3DS hardware happens to also use this exact same logic to work around 75 * these issues, making this basic implementation actually more accurate to the hardware. 76 */ 77 static bool AreQuaternionsOpposite(Common::Vec4<f24> qa, Common::Vec4<f24> qb) { 78 Common::Vec4f a{qa.x.ToFloat32(), qa.y.ToFloat32(), qa.z.ToFloat32(), qa.w.ToFloat32()}; 79 Common::Vec4f b{qb.x.ToFloat32(), qb.y.ToFloat32(), qb.z.ToFloat32(), qb.w.ToFloat32()}; 80 81 return (Common::Dot(a, b) < 0.f); 82 } 83 84 void RasterizerAccelerated::AddTriangle(const Pica::OutputVertex& v0, const Pica::OutputVertex& v1, 85 const Pica::OutputVertex& v2) { 86 vertex_batch.emplace_back(v0, false); 87 vertex_batch.emplace_back(v1, AreQuaternionsOpposite(v0.quat, v1.quat)); 88 vertex_batch.emplace_back(v2, AreQuaternionsOpposite(v0.quat, v2.quat)); 89 } 90 91 RasterizerAccelerated::VertexArrayInfo RasterizerAccelerated::AnalyzeVertexArray( 92 bool is_indexed, u32 stride_alignment) { 93 const auto& vertex_attributes = regs.pipeline.vertex_attributes; 94 95 u32 vertex_min; 96 u32 vertex_max; 97 if (is_indexed) { 98 const auto& index_info = regs.pipeline.index_array; 99 const PAddr address = vertex_attributes.GetPhysicalBaseAddress() + index_info.offset; 100 const u8* index_address_8 = memory.GetPhysicalPointer(address); 101 const u16* index_address_16 = reinterpret_cast<const u16*>(index_address_8); 102 const bool index_u16 = index_info.format != 0; 103 104 vertex_min = 0xFFFF; 105 vertex_max = 0; 106 const u32 size = regs.pipeline.num_vertices * (index_u16 ? 2 : 1); 107 FlushRegion(address, size); 108 for (u32 index = 0; index < regs.pipeline.num_vertices; ++index) { 109 const u32 vertex = index_u16 ? index_address_16[index] : index_address_8[index]; 110 vertex_min = std::min(vertex_min, vertex); 111 vertex_max = std::max(vertex_max, vertex); 112 } 113 } else { 114 vertex_min = regs.pipeline.vertex_offset; 115 vertex_max = regs.pipeline.vertex_offset + regs.pipeline.num_vertices - 1; 116 } 117 118 const u32 vertex_num = vertex_max - vertex_min + 1; 119 u32 vs_input_size = 0; 120 for (const auto& loader : vertex_attributes.attribute_loaders) { 121 if (loader.component_count != 0) { 122 const u32 aligned_stride = 123 Common::AlignUp(static_cast<u32>(loader.byte_count), stride_alignment); 124 vs_input_size += Common::AlignUp(aligned_stride * vertex_num, 4); 125 } 126 } 127 128 return {vertex_min, vertex_max, vs_input_size}; 129 } 130 131 void RasterizerAccelerated::SyncEntireState() { 132 // Sync renderer-specific fixed-function state 133 SyncFixedState(); 134 135 // Sync uniforms 136 SyncClipPlane(); 137 SyncDepthScale(); 138 SyncDepthOffset(); 139 SyncAlphaTest(); 140 SyncCombinerColor(); 141 auto& tev_stages = regs.texturing.GetTevStages(); 142 for (std::size_t index = 0; index < tev_stages.size(); ++index) { 143 SyncTevConstColor(index, tev_stages[index]); 144 } 145 146 SyncGlobalAmbient(); 147 for (u32 light_index = 0; light_index < 8; light_index++) { 148 SyncLightSpecular0(light_index); 149 SyncLightSpecular1(light_index); 150 SyncLightDiffuse(light_index); 151 SyncLightAmbient(light_index); 152 SyncLightPosition(light_index); 153 SyncLightDistanceAttenuationBias(light_index); 154 SyncLightDistanceAttenuationScale(light_index); 155 } 156 157 SyncFogColor(); 158 SyncProcTexNoise(); 159 SyncProcTexBias(); 160 SyncShadowBias(); 161 SyncShadowTextureBias(); 162 163 for (u32 tex_index = 0; tex_index < 3; tex_index++) { 164 SyncTextureLodBias(tex_index); 165 } 166 } 167 168 void RasterizerAccelerated::NotifyPicaRegisterChanged(u32 id) { 169 switch (id) { 170 // Depth modifiers 171 case PICA_REG_INDEX(rasterizer.viewport_depth_range): 172 SyncDepthScale(); 173 break; 174 case PICA_REG_INDEX(rasterizer.viewport_depth_near_plane): 175 SyncDepthOffset(); 176 break; 177 178 // Depth buffering 179 case PICA_REG_INDEX(rasterizer.depthmap_enable): 180 shader_dirty = true; 181 break; 182 183 // Shadow texture 184 case PICA_REG_INDEX(texturing.shadow): 185 SyncShadowTextureBias(); 186 break; 187 188 // Fog state 189 case PICA_REG_INDEX(texturing.fog_color): 190 SyncFogColor(); 191 break; 192 case PICA_REG_INDEX(texturing.fog_lut_data[0]): 193 case PICA_REG_INDEX(texturing.fog_lut_data[1]): 194 case PICA_REG_INDEX(texturing.fog_lut_data[2]): 195 case PICA_REG_INDEX(texturing.fog_lut_data[3]): 196 case PICA_REG_INDEX(texturing.fog_lut_data[4]): 197 case PICA_REG_INDEX(texturing.fog_lut_data[5]): 198 case PICA_REG_INDEX(texturing.fog_lut_data[6]): 199 case PICA_REG_INDEX(texturing.fog_lut_data[7]): 200 fs_uniform_block_data.fog_lut_dirty = true; 201 break; 202 203 // ProcTex state 204 case PICA_REG_INDEX(texturing.proctex): 205 case PICA_REG_INDEX(texturing.proctex_lut): 206 case PICA_REG_INDEX(texturing.proctex_lut_offset): 207 SyncProcTexBias(); 208 shader_dirty = true; 209 break; 210 211 case PICA_REG_INDEX(texturing.proctex_noise_u): 212 case PICA_REG_INDEX(texturing.proctex_noise_v): 213 case PICA_REG_INDEX(texturing.proctex_noise_frequency): 214 SyncProcTexNoise(); 215 break; 216 217 case PICA_REG_INDEX(texturing.proctex_lut_data[0]): 218 case PICA_REG_INDEX(texturing.proctex_lut_data[1]): 219 case PICA_REG_INDEX(texturing.proctex_lut_data[2]): 220 case PICA_REG_INDEX(texturing.proctex_lut_data[3]): 221 case PICA_REG_INDEX(texturing.proctex_lut_data[4]): 222 case PICA_REG_INDEX(texturing.proctex_lut_data[5]): 223 case PICA_REG_INDEX(texturing.proctex_lut_data[6]): 224 case PICA_REG_INDEX(texturing.proctex_lut_data[7]): 225 using Pica::TexturingRegs; 226 switch (regs.texturing.proctex_lut_config.ref_table.Value()) { 227 case TexturingRegs::ProcTexLutTable::Noise: 228 fs_uniform_block_data.proctex_noise_lut_dirty = true; 229 break; 230 case TexturingRegs::ProcTexLutTable::ColorMap: 231 fs_uniform_block_data.proctex_color_map_dirty = true; 232 break; 233 case TexturingRegs::ProcTexLutTable::AlphaMap: 234 fs_uniform_block_data.proctex_alpha_map_dirty = true; 235 break; 236 case TexturingRegs::ProcTexLutTable::Color: 237 fs_uniform_block_data.proctex_lut_dirty = true; 238 break; 239 case TexturingRegs::ProcTexLutTable::ColorDiff: 240 fs_uniform_block_data.proctex_diff_lut_dirty = true; 241 break; 242 } 243 break; 244 245 // Fragment operation mode 246 case PICA_REG_INDEX(framebuffer.output_merger.fragment_operation_mode): 247 shader_dirty = true; 248 break; 249 250 // Alpha test 251 case PICA_REG_INDEX(framebuffer.output_merger.alpha_test): 252 SyncAlphaTest(); 253 shader_dirty = true; 254 break; 255 256 case PICA_REG_INDEX(framebuffer.shadow): 257 SyncShadowBias(); 258 break; 259 260 // Scissor test 261 case PICA_REG_INDEX(rasterizer.scissor_test.mode): 262 shader_dirty = true; 263 break; 264 265 case PICA_REG_INDEX(texturing.main_config): 266 shader_dirty = true; 267 break; 268 269 // Texture 0 type 270 case PICA_REG_INDEX(texturing.texture0.type): 271 shader_dirty = true; 272 break; 273 274 // TEV stages 275 // (This also syncs fog_mode and fog_flip which are part of tev_combiner_buffer_input) 276 case PICA_REG_INDEX(texturing.tev_stage0.color_source1): 277 case PICA_REG_INDEX(texturing.tev_stage0.color_modifier1): 278 case PICA_REG_INDEX(texturing.tev_stage0.color_op): 279 case PICA_REG_INDEX(texturing.tev_stage0.color_scale): 280 case PICA_REG_INDEX(texturing.tev_stage1.color_source1): 281 case PICA_REG_INDEX(texturing.tev_stage1.color_modifier1): 282 case PICA_REG_INDEX(texturing.tev_stage1.color_op): 283 case PICA_REG_INDEX(texturing.tev_stage1.color_scale): 284 case PICA_REG_INDEX(texturing.tev_stage2.color_source1): 285 case PICA_REG_INDEX(texturing.tev_stage2.color_modifier1): 286 case PICA_REG_INDEX(texturing.tev_stage2.color_op): 287 case PICA_REG_INDEX(texturing.tev_stage2.color_scale): 288 case PICA_REG_INDEX(texturing.tev_stage3.color_source1): 289 case PICA_REG_INDEX(texturing.tev_stage3.color_modifier1): 290 case PICA_REG_INDEX(texturing.tev_stage3.color_op): 291 case PICA_REG_INDEX(texturing.tev_stage3.color_scale): 292 case PICA_REG_INDEX(texturing.tev_stage4.color_source1): 293 case PICA_REG_INDEX(texturing.tev_stage4.color_modifier1): 294 case PICA_REG_INDEX(texturing.tev_stage4.color_op): 295 case PICA_REG_INDEX(texturing.tev_stage4.color_scale): 296 case PICA_REG_INDEX(texturing.tev_stage5.color_source1): 297 case PICA_REG_INDEX(texturing.tev_stage5.color_modifier1): 298 case PICA_REG_INDEX(texturing.tev_stage5.color_op): 299 case PICA_REG_INDEX(texturing.tev_stage5.color_scale): 300 case PICA_REG_INDEX(texturing.tev_combiner_buffer_input): 301 shader_dirty = true; 302 break; 303 case PICA_REG_INDEX(texturing.tev_stage0.const_r): 304 SyncTevConstColor(0, regs.texturing.tev_stage0); 305 break; 306 case PICA_REG_INDEX(texturing.tev_stage1.const_r): 307 SyncTevConstColor(1, regs.texturing.tev_stage1); 308 break; 309 case PICA_REG_INDEX(texturing.tev_stage2.const_r): 310 SyncTevConstColor(2, regs.texturing.tev_stage2); 311 break; 312 case PICA_REG_INDEX(texturing.tev_stage3.const_r): 313 SyncTevConstColor(3, regs.texturing.tev_stage3); 314 break; 315 case PICA_REG_INDEX(texturing.tev_stage4.const_r): 316 SyncTevConstColor(4, regs.texturing.tev_stage4); 317 break; 318 case PICA_REG_INDEX(texturing.tev_stage5.const_r): 319 SyncTevConstColor(5, regs.texturing.tev_stage5); 320 break; 321 322 // TEV combiner buffer color 323 case PICA_REG_INDEX(texturing.tev_combiner_buffer_color): 324 SyncCombinerColor(); 325 break; 326 327 // Fragment lighting switches 328 case PICA_REG_INDEX(lighting.disable): 329 case PICA_REG_INDEX(lighting.max_light_index): 330 case PICA_REG_INDEX(lighting.config0): 331 case PICA_REG_INDEX(lighting.config1): 332 case PICA_REG_INDEX(lighting.abs_lut_input): 333 case PICA_REG_INDEX(lighting.lut_input): 334 case PICA_REG_INDEX(lighting.lut_scale): 335 case PICA_REG_INDEX(lighting.light_enable): 336 break; 337 338 // Fragment lighting specular 0 color 339 case PICA_REG_INDEX(lighting.light[0].specular_0): 340 SyncLightSpecular0(0); 341 break; 342 case PICA_REG_INDEX(lighting.light[1].specular_0): 343 SyncLightSpecular0(1); 344 break; 345 case PICA_REG_INDEX(lighting.light[2].specular_0): 346 SyncLightSpecular0(2); 347 break; 348 case PICA_REG_INDEX(lighting.light[3].specular_0): 349 SyncLightSpecular0(3); 350 break; 351 case PICA_REG_INDEX(lighting.light[4].specular_0): 352 SyncLightSpecular0(4); 353 break; 354 case PICA_REG_INDEX(lighting.light[5].specular_0): 355 SyncLightSpecular0(5); 356 break; 357 case PICA_REG_INDEX(lighting.light[6].specular_0): 358 SyncLightSpecular0(6); 359 break; 360 case PICA_REG_INDEX(lighting.light[7].specular_0): 361 SyncLightSpecular0(7); 362 break; 363 364 // Fragment lighting specular 1 color 365 case PICA_REG_INDEX(lighting.light[0].specular_1): 366 SyncLightSpecular1(0); 367 break; 368 case PICA_REG_INDEX(lighting.light[1].specular_1): 369 SyncLightSpecular1(1); 370 break; 371 case PICA_REG_INDEX(lighting.light[2].specular_1): 372 SyncLightSpecular1(2); 373 break; 374 case PICA_REG_INDEX(lighting.light[3].specular_1): 375 SyncLightSpecular1(3); 376 break; 377 case PICA_REG_INDEX(lighting.light[4].specular_1): 378 SyncLightSpecular1(4); 379 break; 380 case PICA_REG_INDEX(lighting.light[5].specular_1): 381 SyncLightSpecular1(5); 382 break; 383 case PICA_REG_INDEX(lighting.light[6].specular_1): 384 SyncLightSpecular1(6); 385 break; 386 case PICA_REG_INDEX(lighting.light[7].specular_1): 387 SyncLightSpecular1(7); 388 break; 389 390 // Fragment lighting diffuse color 391 case PICA_REG_INDEX(lighting.light[0].diffuse): 392 SyncLightDiffuse(0); 393 break; 394 case PICA_REG_INDEX(lighting.light[1].diffuse): 395 SyncLightDiffuse(1); 396 break; 397 case PICA_REG_INDEX(lighting.light[2].diffuse): 398 SyncLightDiffuse(2); 399 break; 400 case PICA_REG_INDEX(lighting.light[3].diffuse): 401 SyncLightDiffuse(3); 402 break; 403 case PICA_REG_INDEX(lighting.light[4].diffuse): 404 SyncLightDiffuse(4); 405 break; 406 case PICA_REG_INDEX(lighting.light[5].diffuse): 407 SyncLightDiffuse(5); 408 break; 409 case PICA_REG_INDEX(lighting.light[6].diffuse): 410 SyncLightDiffuse(6); 411 break; 412 case PICA_REG_INDEX(lighting.light[7].diffuse): 413 SyncLightDiffuse(7); 414 break; 415 416 // Fragment lighting ambient color 417 case PICA_REG_INDEX(lighting.light[0].ambient): 418 SyncLightAmbient(0); 419 break; 420 case PICA_REG_INDEX(lighting.light[1].ambient): 421 SyncLightAmbient(1); 422 break; 423 case PICA_REG_INDEX(lighting.light[2].ambient): 424 SyncLightAmbient(2); 425 break; 426 case PICA_REG_INDEX(lighting.light[3].ambient): 427 SyncLightAmbient(3); 428 break; 429 case PICA_REG_INDEX(lighting.light[4].ambient): 430 SyncLightAmbient(4); 431 break; 432 case PICA_REG_INDEX(lighting.light[5].ambient): 433 SyncLightAmbient(5); 434 break; 435 case PICA_REG_INDEX(lighting.light[6].ambient): 436 SyncLightAmbient(6); 437 break; 438 case PICA_REG_INDEX(lighting.light[7].ambient): 439 SyncLightAmbient(7); 440 break; 441 442 // Fragment lighting position 443 case PICA_REG_INDEX(lighting.light[0].x): 444 case PICA_REG_INDEX(lighting.light[0].z): 445 SyncLightPosition(0); 446 break; 447 case PICA_REG_INDEX(lighting.light[1].x): 448 case PICA_REG_INDEX(lighting.light[1].z): 449 SyncLightPosition(1); 450 break; 451 case PICA_REG_INDEX(lighting.light[2].x): 452 case PICA_REG_INDEX(lighting.light[2].z): 453 SyncLightPosition(2); 454 break; 455 case PICA_REG_INDEX(lighting.light[3].x): 456 case PICA_REG_INDEX(lighting.light[3].z): 457 SyncLightPosition(3); 458 break; 459 case PICA_REG_INDEX(lighting.light[4].x): 460 case PICA_REG_INDEX(lighting.light[4].z): 461 SyncLightPosition(4); 462 break; 463 case PICA_REG_INDEX(lighting.light[5].x): 464 case PICA_REG_INDEX(lighting.light[5].z): 465 SyncLightPosition(5); 466 break; 467 case PICA_REG_INDEX(lighting.light[6].x): 468 case PICA_REG_INDEX(lighting.light[6].z): 469 SyncLightPosition(6); 470 break; 471 case PICA_REG_INDEX(lighting.light[7].x): 472 case PICA_REG_INDEX(lighting.light[7].z): 473 SyncLightPosition(7); 474 break; 475 476 // Fragment spot lighting direction 477 case PICA_REG_INDEX(lighting.light[0].spot_x): 478 case PICA_REG_INDEX(lighting.light[0].spot_z): 479 SyncLightSpotDirection(0); 480 break; 481 case PICA_REG_INDEX(lighting.light[1].spot_x): 482 case PICA_REG_INDEX(lighting.light[1].spot_z): 483 SyncLightSpotDirection(1); 484 break; 485 case PICA_REG_INDEX(lighting.light[2].spot_x): 486 case PICA_REG_INDEX(lighting.light[2].spot_z): 487 SyncLightSpotDirection(2); 488 break; 489 case PICA_REG_INDEX(lighting.light[3].spot_x): 490 case PICA_REG_INDEX(lighting.light[3].spot_z): 491 SyncLightSpotDirection(3); 492 break; 493 case PICA_REG_INDEX(lighting.light[4].spot_x): 494 case PICA_REG_INDEX(lighting.light[4].spot_z): 495 SyncLightSpotDirection(4); 496 break; 497 case PICA_REG_INDEX(lighting.light[5].spot_x): 498 case PICA_REG_INDEX(lighting.light[5].spot_z): 499 SyncLightSpotDirection(5); 500 break; 501 case PICA_REG_INDEX(lighting.light[6].spot_x): 502 case PICA_REG_INDEX(lighting.light[6].spot_z): 503 SyncLightSpotDirection(6); 504 break; 505 case PICA_REG_INDEX(lighting.light[7].spot_x): 506 case PICA_REG_INDEX(lighting.light[7].spot_z): 507 SyncLightSpotDirection(7); 508 break; 509 510 // Fragment lighting light source config 511 case PICA_REG_INDEX(lighting.light[0].config): 512 case PICA_REG_INDEX(lighting.light[1].config): 513 case PICA_REG_INDEX(lighting.light[2].config): 514 case PICA_REG_INDEX(lighting.light[3].config): 515 case PICA_REG_INDEX(lighting.light[4].config): 516 case PICA_REG_INDEX(lighting.light[5].config): 517 case PICA_REG_INDEX(lighting.light[6].config): 518 case PICA_REG_INDEX(lighting.light[7].config): 519 shader_dirty = true; 520 break; 521 522 // Fragment lighting distance attenuation bias 523 case PICA_REG_INDEX(lighting.light[0].dist_atten_bias): 524 SyncLightDistanceAttenuationBias(0); 525 break; 526 case PICA_REG_INDEX(lighting.light[1].dist_atten_bias): 527 SyncLightDistanceAttenuationBias(1); 528 break; 529 case PICA_REG_INDEX(lighting.light[2].dist_atten_bias): 530 SyncLightDistanceAttenuationBias(2); 531 break; 532 case PICA_REG_INDEX(lighting.light[3].dist_atten_bias): 533 SyncLightDistanceAttenuationBias(3); 534 break; 535 case PICA_REG_INDEX(lighting.light[4].dist_atten_bias): 536 SyncLightDistanceAttenuationBias(4); 537 break; 538 case PICA_REG_INDEX(lighting.light[5].dist_atten_bias): 539 SyncLightDistanceAttenuationBias(5); 540 break; 541 case PICA_REG_INDEX(lighting.light[6].dist_atten_bias): 542 SyncLightDistanceAttenuationBias(6); 543 break; 544 case PICA_REG_INDEX(lighting.light[7].dist_atten_bias): 545 SyncLightDistanceAttenuationBias(7); 546 break; 547 548 // Fragment lighting distance attenuation scale 549 case PICA_REG_INDEX(lighting.light[0].dist_atten_scale): 550 SyncLightDistanceAttenuationScale(0); 551 break; 552 case PICA_REG_INDEX(lighting.light[1].dist_atten_scale): 553 SyncLightDistanceAttenuationScale(1); 554 break; 555 case PICA_REG_INDEX(lighting.light[2].dist_atten_scale): 556 SyncLightDistanceAttenuationScale(2); 557 break; 558 case PICA_REG_INDEX(lighting.light[3].dist_atten_scale): 559 SyncLightDistanceAttenuationScale(3); 560 break; 561 case PICA_REG_INDEX(lighting.light[4].dist_atten_scale): 562 SyncLightDistanceAttenuationScale(4); 563 break; 564 case PICA_REG_INDEX(lighting.light[5].dist_atten_scale): 565 SyncLightDistanceAttenuationScale(5); 566 break; 567 case PICA_REG_INDEX(lighting.light[6].dist_atten_scale): 568 SyncLightDistanceAttenuationScale(6); 569 break; 570 case PICA_REG_INDEX(lighting.light[7].dist_atten_scale): 571 SyncLightDistanceAttenuationScale(7); 572 break; 573 574 // Fragment lighting global ambient color (emission + ambient * ambient) 575 case PICA_REG_INDEX(lighting.global_ambient): 576 SyncGlobalAmbient(); 577 break; 578 579 // Fragment lighting lookup tables 580 case PICA_REG_INDEX(lighting.lut_data[0]): 581 case PICA_REG_INDEX(lighting.lut_data[1]): 582 case PICA_REG_INDEX(lighting.lut_data[2]): 583 case PICA_REG_INDEX(lighting.lut_data[3]): 584 case PICA_REG_INDEX(lighting.lut_data[4]): 585 case PICA_REG_INDEX(lighting.lut_data[5]): 586 case PICA_REG_INDEX(lighting.lut_data[6]): 587 case PICA_REG_INDEX(lighting.lut_data[7]): { 588 const auto& lut_config = regs.lighting.lut_config; 589 fs_uniform_block_data.lighting_lut_dirty[lut_config.type] = true; 590 fs_uniform_block_data.lighting_lut_dirty_any = true; 591 break; 592 } 593 594 // Texture LOD biases 595 case PICA_REG_INDEX(texturing.texture0.lod.bias): 596 SyncTextureLodBias(0); 597 break; 598 case PICA_REG_INDEX(texturing.texture1.lod.bias): 599 SyncTextureLodBias(1); 600 break; 601 case PICA_REG_INDEX(texturing.texture2.lod.bias): 602 SyncTextureLodBias(2); 603 break; 604 605 // Texture borders 606 case PICA_REG_INDEX(texturing.texture0.border_color): 607 SyncTextureBorderColor(0); 608 break; 609 case PICA_REG_INDEX(texturing.texture1.border_color): 610 SyncTextureBorderColor(1); 611 break; 612 case PICA_REG_INDEX(texturing.texture2.border_color): 613 SyncTextureBorderColor(2); 614 break; 615 616 // Clipping plane 617 case PICA_REG_INDEX(rasterizer.clip_enable): 618 case PICA_REG_INDEX(rasterizer.clip_coef[0]): 619 case PICA_REG_INDEX(rasterizer.clip_coef[1]): 620 case PICA_REG_INDEX(rasterizer.clip_coef[2]): 621 case PICA_REG_INDEX(rasterizer.clip_coef[3]): 622 SyncClipPlane(); 623 break; 624 } 625 626 // Forward registers that map to fixed function API features to the video backend 627 NotifyFixedFunctionPicaRegisterChanged(id); 628 } 629 630 void RasterizerAccelerated::SyncDepthScale() { 631 const f32 depth_scale = f24::FromRaw(regs.rasterizer.viewport_depth_range).ToFloat32(); 632 633 if (depth_scale != fs_uniform_block_data.data.depth_scale) { 634 fs_uniform_block_data.data.depth_scale = depth_scale; 635 fs_uniform_block_data.dirty = true; 636 } 637 } 638 639 void RasterizerAccelerated::SyncDepthOffset() { 640 const f32 depth_offset = f24::FromRaw(regs.rasterizer.viewport_depth_near_plane).ToFloat32(); 641 642 if (depth_offset != fs_uniform_block_data.data.depth_offset) { 643 fs_uniform_block_data.data.depth_offset = depth_offset; 644 fs_uniform_block_data.dirty = true; 645 } 646 } 647 648 void RasterizerAccelerated::SyncFogColor() { 649 const auto& fog_color_regs = regs.texturing.fog_color; 650 const Common::Vec3f fog_color = { 651 fog_color_regs.r.Value() / 255.0f, 652 fog_color_regs.g.Value() / 255.0f, 653 fog_color_regs.b.Value() / 255.0f, 654 }; 655 656 if (fog_color != fs_uniform_block_data.data.fog_color) { 657 fs_uniform_block_data.data.fog_color = fog_color; 658 fs_uniform_block_data.dirty = true; 659 } 660 } 661 662 void RasterizerAccelerated::SyncProcTexNoise() { 663 const Common::Vec2f proctex_noise_f = { 664 Pica::f16::FromRaw(regs.texturing.proctex_noise_frequency.u).ToFloat32(), 665 Pica::f16::FromRaw(regs.texturing.proctex_noise_frequency.v).ToFloat32(), 666 }; 667 const Common::Vec2f proctex_noise_a = { 668 regs.texturing.proctex_noise_u.amplitude / 4095.0f, 669 regs.texturing.proctex_noise_v.amplitude / 4095.0f, 670 }; 671 const Common::Vec2f proctex_noise_p = { 672 Pica::f16::FromRaw(regs.texturing.proctex_noise_u.phase).ToFloat32(), 673 Pica::f16::FromRaw(regs.texturing.proctex_noise_v.phase).ToFloat32(), 674 }; 675 676 if (proctex_noise_f != fs_uniform_block_data.data.proctex_noise_f || 677 proctex_noise_a != fs_uniform_block_data.data.proctex_noise_a || 678 proctex_noise_p != fs_uniform_block_data.data.proctex_noise_p) { 679 fs_uniform_block_data.data.proctex_noise_f = proctex_noise_f; 680 fs_uniform_block_data.data.proctex_noise_a = proctex_noise_a; 681 fs_uniform_block_data.data.proctex_noise_p = proctex_noise_p; 682 fs_uniform_block_data.dirty = true; 683 } 684 } 685 686 void RasterizerAccelerated::SyncProcTexBias() { 687 const auto proctex_bias = Pica::f16::FromRaw(regs.texturing.proctex.bias_low | 688 (regs.texturing.proctex_lut.bias_high << 8)) 689 .ToFloat32(); 690 if (proctex_bias != fs_uniform_block_data.data.proctex_bias) { 691 fs_uniform_block_data.data.proctex_bias = proctex_bias; 692 fs_uniform_block_data.dirty = true; 693 } 694 } 695 696 void RasterizerAccelerated::SyncAlphaTest() { 697 if (regs.framebuffer.output_merger.alpha_test.ref != 698 static_cast<u32>(fs_uniform_block_data.data.alphatest_ref)) { 699 fs_uniform_block_data.data.alphatest_ref = regs.framebuffer.output_merger.alpha_test.ref; 700 fs_uniform_block_data.dirty = true; 701 } 702 } 703 704 void RasterizerAccelerated::SyncCombinerColor() { 705 const auto combiner_color = ColorRGBA8(regs.texturing.tev_combiner_buffer_color.raw); 706 if (combiner_color != fs_uniform_block_data.data.tev_combiner_buffer_color) { 707 fs_uniform_block_data.data.tev_combiner_buffer_color = combiner_color; 708 fs_uniform_block_data.dirty = true; 709 } 710 } 711 712 void RasterizerAccelerated::SyncTevConstColor( 713 const std::size_t stage_index, const Pica::TexturingRegs::TevStageConfig& tev_stage) { 714 const auto const_color = ColorRGBA8(tev_stage.const_color); 715 716 if (const_color == fs_uniform_block_data.data.const_color[stage_index]) { 717 return; 718 } 719 720 fs_uniform_block_data.data.const_color[stage_index] = const_color; 721 fs_uniform_block_data.dirty = true; 722 } 723 724 void RasterizerAccelerated::SyncGlobalAmbient() { 725 const auto color = LightColor(regs.lighting.global_ambient); 726 if (color != fs_uniform_block_data.data.lighting_global_ambient) { 727 fs_uniform_block_data.data.lighting_global_ambient = color; 728 fs_uniform_block_data.dirty = true; 729 } 730 } 731 732 void RasterizerAccelerated::SyncLightSpecular0(int light_index) { 733 const auto color = LightColor(regs.lighting.light[light_index].specular_0); 734 if (color != fs_uniform_block_data.data.light_src[light_index].specular_0) { 735 fs_uniform_block_data.data.light_src[light_index].specular_0 = color; 736 fs_uniform_block_data.dirty = true; 737 } 738 } 739 740 void RasterizerAccelerated::SyncLightSpecular1(int light_index) { 741 const auto color = LightColor(regs.lighting.light[light_index].specular_1); 742 if (color != fs_uniform_block_data.data.light_src[light_index].specular_1) { 743 fs_uniform_block_data.data.light_src[light_index].specular_1 = color; 744 fs_uniform_block_data.dirty = true; 745 } 746 } 747 748 void RasterizerAccelerated::SyncLightDiffuse(int light_index) { 749 const auto color = LightColor(regs.lighting.light[light_index].diffuse); 750 if (color != fs_uniform_block_data.data.light_src[light_index].diffuse) { 751 fs_uniform_block_data.data.light_src[light_index].diffuse = color; 752 fs_uniform_block_data.dirty = true; 753 } 754 } 755 756 void RasterizerAccelerated::SyncLightAmbient(int light_index) { 757 const auto color = LightColor(regs.lighting.light[light_index].ambient); 758 if (color != fs_uniform_block_data.data.light_src[light_index].ambient) { 759 fs_uniform_block_data.data.light_src[light_index].ambient = color; 760 fs_uniform_block_data.dirty = true; 761 } 762 } 763 764 void RasterizerAccelerated::SyncLightPosition(int light_index) { 765 const Common::Vec3f position = { 766 Pica::f16::FromRaw(regs.lighting.light[light_index].x).ToFloat32(), 767 Pica::f16::FromRaw(regs.lighting.light[light_index].y).ToFloat32(), 768 Pica::f16::FromRaw(regs.lighting.light[light_index].z).ToFloat32(), 769 }; 770 771 if (position != fs_uniform_block_data.data.light_src[light_index].position) { 772 fs_uniform_block_data.data.light_src[light_index].position = position; 773 fs_uniform_block_data.dirty = true; 774 } 775 } 776 777 void RasterizerAccelerated::SyncLightSpotDirection(int light_index) { 778 const auto& light = regs.lighting.light[light_index]; 779 const auto spot_direction = 780 Common::Vec3f{light.spot_x / 2047.0f, light.spot_y / 2047.0f, light.spot_z / 2047.0f}; 781 782 if (spot_direction != fs_uniform_block_data.data.light_src[light_index].spot_direction) { 783 fs_uniform_block_data.data.light_src[light_index].spot_direction = spot_direction; 784 fs_uniform_block_data.dirty = true; 785 } 786 } 787 788 void RasterizerAccelerated::SyncLightDistanceAttenuationBias(int light_index) { 789 const f32 dist_atten_bias = 790 Pica::f20::FromRaw(regs.lighting.light[light_index].dist_atten_bias).ToFloat32(); 791 792 if (dist_atten_bias != fs_uniform_block_data.data.light_src[light_index].dist_atten_bias) { 793 fs_uniform_block_data.data.light_src[light_index].dist_atten_bias = dist_atten_bias; 794 fs_uniform_block_data.dirty = true; 795 } 796 } 797 798 void RasterizerAccelerated::SyncLightDistanceAttenuationScale(int light_index) { 799 const f32 dist_atten_scale = 800 Pica::f20::FromRaw(regs.lighting.light[light_index].dist_atten_scale).ToFloat32(); 801 802 if (dist_atten_scale != fs_uniform_block_data.data.light_src[light_index].dist_atten_scale) { 803 fs_uniform_block_data.data.light_src[light_index].dist_atten_scale = dist_atten_scale; 804 fs_uniform_block_data.dirty = true; 805 } 806 } 807 808 void RasterizerAccelerated::SyncShadowBias() { 809 const auto& shadow = regs.framebuffer.shadow; 810 const f32 constant = Pica::f16::FromRaw(shadow.constant).ToFloat32(); 811 const f32 linear = Pica::f16::FromRaw(shadow.linear).ToFloat32(); 812 813 if (constant != fs_uniform_block_data.data.shadow_bias_constant || 814 linear != fs_uniform_block_data.data.shadow_bias_linear) { 815 fs_uniform_block_data.data.shadow_bias_constant = constant; 816 fs_uniform_block_data.data.shadow_bias_linear = linear; 817 fs_uniform_block_data.dirty = true; 818 } 819 } 820 821 void RasterizerAccelerated::SyncShadowTextureBias() { 822 const s32 bias = regs.texturing.shadow.bias << 1; 823 if (bias != fs_uniform_block_data.data.shadow_texture_bias) { 824 fs_uniform_block_data.data.shadow_texture_bias = bias; 825 fs_uniform_block_data.dirty = true; 826 } 827 } 828 829 void RasterizerAccelerated::SyncTextureLodBias(int tex_index) { 830 const auto pica_textures = regs.texturing.GetTextures(); 831 const f32 bias = pica_textures[tex_index].config.lod.bias / 256.0f; 832 if (bias != fs_uniform_block_data.data.tex_lod_bias[tex_index]) { 833 fs_uniform_block_data.data.tex_lod_bias[tex_index] = bias; 834 fs_uniform_block_data.dirty = true; 835 } 836 } 837 838 void RasterizerAccelerated::SyncTextureBorderColor(int tex_index) { 839 const auto pica_textures = regs.texturing.GetTextures(); 840 const auto params = pica_textures[tex_index].config; 841 const Common::Vec4f border_color = ColorRGBA8(params.border_color.raw); 842 if (border_color != fs_uniform_block_data.data.tex_border_color[tex_index]) { 843 fs_uniform_block_data.data.tex_border_color[tex_index] = border_color; 844 fs_uniform_block_data.dirty = true; 845 } 846 } 847 848 void RasterizerAccelerated::SyncClipPlane() { 849 const u32 enable_clip1 = regs.rasterizer.clip_enable != 0; 850 const auto raw_clip_coef = regs.rasterizer.GetClipCoef(); 851 const Common::Vec4f new_clip_coef = {raw_clip_coef.x.ToFloat32(), raw_clip_coef.y.ToFloat32(), 852 raw_clip_coef.z.ToFloat32(), raw_clip_coef.w.ToFloat32()}; 853 if (enable_clip1 != vs_uniform_block_data.data.enable_clip1 || 854 new_clip_coef != vs_uniform_block_data.data.clip_coef) { 855 vs_uniform_block_data.data.enable_clip1 = enable_clip1; 856 vs_uniform_block_data.data.clip_coef = new_clip_coef; 857 vs_uniform_block_data.dirty = true; 858 } 859 } 860 861 } // namespace VideoCore