summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Tony Wasserka2014-12-13 21:39:42 +0100
committerGravatar Tony Wasserka2014-12-31 16:32:55 +0100
commit0f494240228e24e21c88bf9f3178aaa68db4fb45 (patch)
treeb23513ade2000339485bf9585a988aece11c1019 /src
parentPica/Rasterizer: Textures seem to be laid out flipped vertically. (diff)
downloadyuzu-0f494240228e24e21c88bf9f3178aaa68db4fb45.tar.gz
yuzu-0f494240228e24e21c88bf9f3178aaa68db4fb45.tar.xz
yuzu-0f494240228e24e21c88bf9f3178aaa68db4fb45.zip
Pica/Rasterizer: Implement backface culling.
Diffstat (limited to 'src')
-rw-r--r--src/video_core/pica.h16
-rw-r--r--src/video_core/rasterizer.cpp30
2 files changed, 36 insertions, 10 deletions
diff --git a/src/video_core/pica.h b/src/video_core/pica.h
index 810a926c9..f5771ed84 100644
--- a/src/video_core/pica.h
+++ b/src/video_core/pica.h
@@ -50,7 +50,19 @@ struct Regs {
50 50
51 u32 trigger_irq; 51 u32 trigger_irq;
52 52
53 INSERT_PADDING_WORDS(0x30); 53 INSERT_PADDING_WORDS(0x2f);
54
55 enum class CullMode : u32 {
56 // Select which polygons are considered to be "frontfacing".
57 KeepAll = 0,
58 KeepClockWise = 1,
59 KeepCounterClockWise = 2,
60 // TODO: What does the third value imply?
61 };
62
63 union {
64 BitField<0, 2, CullMode> cull_mode;
65 };
54 66
55 BitField<0, 24, u32> viewport_size_x; 67 BitField<0, 24, u32> viewport_size_x;
56 68
@@ -659,6 +671,7 @@ struct Regs {
659 } while(false) 671 } while(false)
660 672
661 ADD_FIELD(trigger_irq); 673 ADD_FIELD(trigger_irq);
674 ADD_FIELD(cull_mode);
662 ADD_FIELD(viewport_size_x); 675 ADD_FIELD(viewport_size_x);
663 ADD_FIELD(viewport_size_y); 676 ADD_FIELD(viewport_size_y);
664 ADD_FIELD(viewport_depth_range); 677 ADD_FIELD(viewport_depth_range);
@@ -730,6 +743,7 @@ private:
730#define ASSERT_REG_POSITION(field_name, position) static_assert(offsetof(Regs, field_name) == position * 4, "Field "#field_name" has invalid position") 743#define ASSERT_REG_POSITION(field_name, position) static_assert(offsetof(Regs, field_name) == position * 4, "Field "#field_name" has invalid position")
731 744
732ASSERT_REG_POSITION(trigger_irq, 0x10); 745ASSERT_REG_POSITION(trigger_irq, 0x10);
746ASSERT_REG_POSITION(cull_mode, 0x40);
733ASSERT_REG_POSITION(viewport_size_x, 0x41); 747ASSERT_REG_POSITION(viewport_size_x, 0x41);
734ASSERT_REG_POSITION(viewport_size_y, 0x43); 748ASSERT_REG_POSITION(viewport_size_y, 0x43);
735ASSERT_REG_POSITION(viewport_depth_range, 0x4d); 749ASSERT_REG_POSITION(viewport_depth_range, 0x4d);
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp
index 08b649fb6..9148745dc 100644
--- a/src/video_core/rasterizer.cpp
+++ b/src/video_core/rasterizer.cpp
@@ -82,10 +82,31 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0,
82 auto ScreenToRasterizerCoordinates = [FloatToFix](const Math::Vec3<float24> vec) { 82 auto ScreenToRasterizerCoordinates = [FloatToFix](const Math::Vec3<float24> vec) {
83 return Math::Vec3<Fix12P4>{FloatToFix(vec.x), FloatToFix(vec.y), FloatToFix(vec.z)}; 83 return Math::Vec3<Fix12P4>{FloatToFix(vec.x), FloatToFix(vec.y), FloatToFix(vec.z)};
84 }; 84 };
85 static auto orient2d = [](const Math::Vec2<Fix12P4>& vtx1,
86 const Math::Vec2<Fix12P4>& vtx2,
87 const Math::Vec2<Fix12P4>& vtx3) {
88 const auto vec1 = Math::MakeVec(vtx2 - vtx1, 0);
89 const auto vec2 = Math::MakeVec(vtx3 - vtx1, 0);
90 // TODO: There is a very small chance this will overflow for sizeof(int) == 4
91 return Math::Cross(vec1, vec2).z;
92 };
93
85 Math::Vec3<Fix12P4> vtxpos[3]{ ScreenToRasterizerCoordinates(v0.screenpos), 94 Math::Vec3<Fix12P4> vtxpos[3]{ ScreenToRasterizerCoordinates(v0.screenpos),
86 ScreenToRasterizerCoordinates(v1.screenpos), 95 ScreenToRasterizerCoordinates(v1.screenpos),
87 ScreenToRasterizerCoordinates(v2.screenpos) }; 96 ScreenToRasterizerCoordinates(v2.screenpos) };
88 97
98 if (registers.cull_mode == Regs::CullMode::KeepClockWise) {
99 // Reverse vertex order and use the CCW code path.
100 std::swap(vtxpos[1], vtxpos[2]);
101 }
102
103 if (registers.cull_mode != Regs::CullMode::KeepAll) {
104 // Cull away triangles which are wound clockwise.
105 // TODO: A check for degenerate triangles ("== 0") should be considered for CullMode::KeepAll
106 if (orient2d(vtxpos[0].xy(), vtxpos[1].xy(), vtxpos[2].xy()) <= 0)
107 return;
108 }
109
89 // TODO: Proper scissor rect test! 110 // TODO: Proper scissor rect test!
90 u16 min_x = std::min({vtxpos[0].x, vtxpos[1].x, vtxpos[2].x}); 111 u16 min_x = std::min({vtxpos[0].x, vtxpos[1].x, vtxpos[2].x});
91 u16 min_y = std::min({vtxpos[0].y, vtxpos[1].y, vtxpos[2].y}); 112 u16 min_y = std::min({vtxpos[0].y, vtxpos[1].y, vtxpos[2].y});
@@ -128,15 +149,6 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0,
128 for (u16 x = min_x; x < max_x; x += 0x10) { 149 for (u16 x = min_x; x < max_x; x += 0x10) {
129 150
130 // Calculate the barycentric coordinates w0, w1 and w2 151 // Calculate the barycentric coordinates w0, w1 and w2
131 auto orient2d = [](const Math::Vec2<Fix12P4>& vtx1,
132 const Math::Vec2<Fix12P4>& vtx2,
133 const Math::Vec2<Fix12P4>& vtx3) {
134 const auto vec1 = Math::MakeVec(vtx2 - vtx1, 0);
135 const auto vec2 = Math::MakeVec(vtx3 - vtx1, 0);
136 // TODO: There is a very small chance this will overflow for sizeof(int) == 4
137 return Math::Cross(vec1, vec2).z;
138 };
139
140 int w0 = bias0 + orient2d(vtxpos[1].xy(), vtxpos[2].xy(), {x, y}); 152 int w0 = bias0 + orient2d(vtxpos[1].xy(), vtxpos[2].xy(), {x, y});
141 int w1 = bias1 + orient2d(vtxpos[2].xy(), vtxpos[0].xy(), {x, y}); 153 int w1 = bias1 + orient2d(vtxpos[2].xy(), vtxpos[0].xy(), {x, y});
142 int w2 = bias2 + orient2d(vtxpos[0].xy(), vtxpos[1].xy(), {x, y}); 154 int w2 = bias2 + orient2d(vtxpos[0].xy(), vtxpos[1].xy(), {x, y});