mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	Pica/Rasterizer: Implement backface culling.
This commit is contained in:
		
							parent
							
								
									3b78af904e
								
							
						
					
					
						commit
						0f49424022
					
				
					 2 changed files with 36 additions and 10 deletions
				
			
		|  | @ -50,7 +50,19 @@ struct Regs { | |||
| 
 | ||||
|     u32 trigger_irq; | ||||
| 
 | ||||
|     INSERT_PADDING_WORDS(0x30); | ||||
|     INSERT_PADDING_WORDS(0x2f); | ||||
| 
 | ||||
|     enum class CullMode : u32 { | ||||
|         // Select which polygons are considered to be "frontfacing".
 | ||||
|         KeepAll              = 0, | ||||
|         KeepClockWise        = 1, | ||||
|         KeepCounterClockWise = 2, | ||||
|         // TODO: What does the third value imply?
 | ||||
|     }; | ||||
| 
 | ||||
|     union { | ||||
|         BitField<0, 2, CullMode> cull_mode; | ||||
|     }; | ||||
| 
 | ||||
|     BitField<0, 24, u32> viewport_size_x; | ||||
| 
 | ||||
|  | @ -659,6 +671,7 @@ struct Regs { | |||
|             } while(false) | ||||
| 
 | ||||
|         ADD_FIELD(trigger_irq); | ||||
|         ADD_FIELD(cull_mode); | ||||
|         ADD_FIELD(viewport_size_x); | ||||
|         ADD_FIELD(viewport_size_y); | ||||
|         ADD_FIELD(viewport_depth_range); | ||||
|  | @ -730,6 +743,7 @@ private: | |||
| #define ASSERT_REG_POSITION(field_name, position) static_assert(offsetof(Regs, field_name) == position * 4, "Field "#field_name" has invalid position") | ||||
| 
 | ||||
| ASSERT_REG_POSITION(trigger_irq, 0x10); | ||||
| ASSERT_REG_POSITION(cull_mode, 0x40); | ||||
| ASSERT_REG_POSITION(viewport_size_x, 0x41); | ||||
| ASSERT_REG_POSITION(viewport_size_y, 0x43); | ||||
| ASSERT_REG_POSITION(viewport_depth_range, 0x4d); | ||||
|  |  | |||
|  | @ -82,10 +82,31 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0, | |||
|     auto ScreenToRasterizerCoordinates = [FloatToFix](const Math::Vec3<float24> vec) { | ||||
|                                              return Math::Vec3<Fix12P4>{FloatToFix(vec.x), FloatToFix(vec.y), FloatToFix(vec.z)}; | ||||
|                                          }; | ||||
|     static auto orient2d = [](const Math::Vec2<Fix12P4>& vtx1, | ||||
|                               const Math::Vec2<Fix12P4>& vtx2, | ||||
|                               const Math::Vec2<Fix12P4>& vtx3) { | ||||
|         const auto vec1 = Math::MakeVec(vtx2 - vtx1, 0); | ||||
|         const auto vec2 = Math::MakeVec(vtx3 - vtx1, 0); | ||||
|         // TODO: There is a very small chance this will overflow for sizeof(int) == 4
 | ||||
|         return Math::Cross(vec1, vec2).z; | ||||
|     }; | ||||
| 
 | ||||
|     Math::Vec3<Fix12P4> vtxpos[3]{ ScreenToRasterizerCoordinates(v0.screenpos), | ||||
|                                    ScreenToRasterizerCoordinates(v1.screenpos), | ||||
|                                    ScreenToRasterizerCoordinates(v2.screenpos) }; | ||||
| 
 | ||||
|     if (registers.cull_mode == Regs::CullMode::KeepClockWise) { | ||||
|         // Reverse vertex order and use the CCW code path.
 | ||||
|         std::swap(vtxpos[1], vtxpos[2]); | ||||
|     } | ||||
| 
 | ||||
|     if (registers.cull_mode != Regs::CullMode::KeepAll) { | ||||
|         // Cull away triangles which are wound clockwise.
 | ||||
|         // TODO: A check for degenerate triangles ("== 0") should be considered for CullMode::KeepAll
 | ||||
|         if (orient2d(vtxpos[0].xy(), vtxpos[1].xy(), vtxpos[2].xy()) <= 0) | ||||
|             return; | ||||
|     } | ||||
| 
 | ||||
|     // TODO: Proper scissor rect test!
 | ||||
|     u16 min_x = std::min({vtxpos[0].x, vtxpos[1].x, vtxpos[2].x}); | ||||
|     u16 min_y = std::min({vtxpos[0].y, vtxpos[1].y, vtxpos[2].y}); | ||||
|  | @ -128,15 +149,6 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0, | |||
|         for (u16 x = min_x; x < max_x; x += 0x10) { | ||||
| 
 | ||||
|             // Calculate the barycentric coordinates w0, w1 and w2
 | ||||
|             auto orient2d = [](const Math::Vec2<Fix12P4>& vtx1, | ||||
|                                const Math::Vec2<Fix12P4>& vtx2, | ||||
|                                const Math::Vec2<Fix12P4>& vtx3) { | ||||
|                 const auto vec1 = Math::MakeVec(vtx2 - vtx1, 0); | ||||
|                 const auto vec2 = Math::MakeVec(vtx3 - vtx1, 0); | ||||
|                 // TODO: There is a very small chance this will overflow for sizeof(int) == 4
 | ||||
|                 return Math::Cross(vec1, vec2).z; | ||||
|             }; | ||||
| 
 | ||||
|             int w0 = bias0 + orient2d(vtxpos[1].xy(), vtxpos[2].xy(), {x, y}); | ||||
|             int w1 = bias1 + orient2d(vtxpos[2].xy(), vtxpos[0].xy(), {x, y}); | ||||
|             int w2 = bias2 + orient2d(vtxpos[0].xy(), vtxpos[1].xy(), {x, y}); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue