diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/pica.h | 32 | ||||
| -rw-r--r-- | src/video_core/rasterizer.cpp | 22 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 26 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 12 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.cpp | 16 |
5 files changed, 105 insertions, 3 deletions
diff --git a/src/video_core/pica.h b/src/video_core/pica.h index 09702d46a..065a3fd0c 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h | |||
| @@ -115,7 +115,36 @@ struct Regs { | |||
| 115 | BitField<24, 5, Semantic> map_w; | 115 | BitField<24, 5, Semantic> map_w; |
| 116 | } vs_output_attributes[7]; | 116 | } vs_output_attributes[7]; |
| 117 | 117 | ||
| 118 | INSERT_PADDING_WORDS(0x11); | 118 | INSERT_PADDING_WORDS(0xe); |
| 119 | |||
| 120 | enum class ScissorMode : u32 { | ||
| 121 | Disabled = 0, | ||
| 122 | Exclude = 1, // Exclude pixels inside the scissor box | ||
| 123 | |||
| 124 | Include = 3 // Exclude pixels outside the scissor box | ||
| 125 | }; | ||
| 126 | |||
| 127 | struct { | ||
| 128 | BitField<0, 2, ScissorMode> mode; | ||
| 129 | |||
| 130 | union { | ||
| 131 | BitField< 0, 16, u32> right; | ||
| 132 | BitField<16, 16, u32> bottom; | ||
| 133 | }; | ||
| 134 | |||
| 135 | union { | ||
| 136 | BitField< 0, 16, u32> left_minus_1; | ||
| 137 | BitField<16, 16, u32> top_minus_1; | ||
| 138 | }; | ||
| 139 | |||
| 140 | u32 GetTop() const { | ||
| 141 | return top_minus_1 + 1; | ||
| 142 | } | ||
| 143 | |||
| 144 | u32 GetLeft() const { | ||
| 145 | return left_minus_1 + 1; | ||
| 146 | } | ||
| 147 | } scissor_test; | ||
| 119 | 148 | ||
| 120 | union { | 149 | union { |
| 121 | BitField< 0, 10, s32> x; | 150 | BitField< 0, 10, s32> x; |
| @@ -1328,6 +1357,7 @@ ASSERT_REG_POSITION(viewport_depth_range, 0x4d); | |||
| 1328 | ASSERT_REG_POSITION(viewport_depth_near_plane, 0x4e); | 1357 | ASSERT_REG_POSITION(viewport_depth_near_plane, 0x4e); |
| 1329 | ASSERT_REG_POSITION(vs_output_attributes[0], 0x50); | 1358 | ASSERT_REG_POSITION(vs_output_attributes[0], 0x50); |
| 1330 | ASSERT_REG_POSITION(vs_output_attributes[1], 0x51); | 1359 | ASSERT_REG_POSITION(vs_output_attributes[1], 0x51); |
| 1360 | ASSERT_REG_POSITION(scissor_test, 0x65); | ||
| 1331 | ASSERT_REG_POSITION(viewport_corner, 0x68); | 1361 | ASSERT_REG_POSITION(viewport_corner, 0x68); |
| 1332 | ASSERT_REG_POSITION(depthmap_enable, 0x6D); | 1362 | ASSERT_REG_POSITION(depthmap_enable, 0x6D); |
| 1333 | ASSERT_REG_POSITION(texture0_enable, 0x80); | 1363 | ASSERT_REG_POSITION(texture0_enable, 0x80); |
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index a84170094..514d64208 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp | |||
| @@ -338,12 +338,25 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0, | |||
| 338 | return; | 338 | return; |
| 339 | } | 339 | } |
| 340 | 340 | ||
| 341 | // TODO: Proper scissor rect test! | ||
| 342 | u16 min_x = std::min({vtxpos[0].x, vtxpos[1].x, vtxpos[2].x}); | 341 | u16 min_x = std::min({vtxpos[0].x, vtxpos[1].x, vtxpos[2].x}); |
| 343 | u16 min_y = std::min({vtxpos[0].y, vtxpos[1].y, vtxpos[2].y}); | 342 | u16 min_y = std::min({vtxpos[0].y, vtxpos[1].y, vtxpos[2].y}); |
| 344 | u16 max_x = std::max({vtxpos[0].x, vtxpos[1].x, vtxpos[2].x}); | 343 | u16 max_x = std::max({vtxpos[0].x, vtxpos[1].x, vtxpos[2].x}); |
| 345 | u16 max_y = std::max({vtxpos[0].y, vtxpos[1].y, vtxpos[2].y}); | 344 | u16 max_y = std::max({vtxpos[0].y, vtxpos[1].y, vtxpos[2].y}); |
| 346 | 345 | ||
| 346 | // Convert the scissor box coordinates to 12.4 fixed point | ||
| 347 | u16 scissor_left = (u16)(regs.scissor_test.GetLeft() << 4); | ||
| 348 | u16 scissor_top = (u16)(regs.scissor_test.GetTop() << 4); | ||
| 349 | u16 scissor_right = (u16)(regs.scissor_test.right << 4); | ||
| 350 | u16 scissor_bottom = (u16)(regs.scissor_test.bottom << 4); | ||
| 351 | |||
| 352 | if (regs.scissor_test.mode == Regs::ScissorMode::Include) { | ||
| 353 | // Calculate the new bounds | ||
| 354 | min_x = std::max(min_x, scissor_right); | ||
| 355 | min_y = std::max(min_y, scissor_bottom); | ||
| 356 | max_x = std::min(max_x, scissor_left); | ||
| 357 | max_y = std::min(max_y, scissor_top); | ||
| 358 | } | ||
| 359 | |||
| 347 | min_x &= Fix12P4::IntMask(); | 360 | min_x &= Fix12P4::IntMask(); |
| 348 | min_y &= Fix12P4::IntMask(); | 361 | min_y &= Fix12P4::IntMask(); |
| 349 | max_x = ((max_x + Fix12P4::FracMask()) & Fix12P4::IntMask()); | 362 | max_x = ((max_x + Fix12P4::FracMask()) & Fix12P4::IntMask()); |
| @@ -383,6 +396,13 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0, | |||
| 383 | for (u16 y = min_y + 8; y < max_y; y += 0x10) { | 396 | for (u16 y = min_y + 8; y < max_y; y += 0x10) { |
| 384 | for (u16 x = min_x + 8; x < max_x; x += 0x10) { | 397 | for (u16 x = min_x + 8; x < max_x; x += 0x10) { |
| 385 | 398 | ||
| 399 | // Do not process the pixel if it's inside the scissor box and the scissor mode is set to Exclude | ||
| 400 | if (regs.scissor_test.mode == Regs::ScissorMode::Exclude && | ||
| 401 | x >= scissor_right && x <= scissor_left && | ||
| 402 | y >= scissor_bottom && y <= scissor_top) { | ||
| 403 | continue; | ||
| 404 | } | ||
| 405 | |||
| 386 | // Calculate the barycentric coordinates w0, w1 and w2 | 406 | // Calculate the barycentric coordinates w0, w1 and w2 |
| 387 | int w0 = bias0 + SignedArea(vtxpos[1].xy(), vtxpos[2].xy(), {x, y}); | 407 | int w0 = bias0 + SignedArea(vtxpos[1].xy(), vtxpos[2].xy(), {x, y}); |
| 388 | int w1 = bias1 + SignedArea(vtxpos[2].xy(), vtxpos[0].xy(), {x, y}); | 408 | int w1 = bias1 + SignedArea(vtxpos[2].xy(), vtxpos[0].xy(), {x, y}); |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 328a4f66b..14ee97d57 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -353,6 +353,15 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { | |||
| 353 | SyncColorWriteMask(); | 353 | SyncColorWriteMask(); |
| 354 | break; | 354 | break; |
| 355 | 355 | ||
| 356 | // Scissor test | ||
| 357 | case PICA_REG_INDEX(scissor_test.mode): | ||
| 358 | shader_dirty = true; | ||
| 359 | break; | ||
| 360 | case PICA_REG_INDEX(scissor_test.right): | ||
| 361 | case PICA_REG_INDEX(scissor_test.left_minus_1): | ||
| 362 | SyncScissorTest(); | ||
| 363 | break; | ||
| 364 | |||
| 356 | // Logic op | 365 | // Logic op |
| 357 | case PICA_REG_INDEX(output_merger.logic_op): | 366 | case PICA_REG_INDEX(output_merger.logic_op): |
| 358 | SyncLogicOp(); | 367 | SyncLogicOp(); |
| @@ -1002,6 +1011,7 @@ void RasterizerOpenGL::SetShader() { | |||
| 1002 | SyncDepthOffset(); | 1011 | SyncDepthOffset(); |
| 1003 | SyncAlphaTest(); | 1012 | SyncAlphaTest(); |
| 1004 | SyncCombinerColor(); | 1013 | SyncCombinerColor(); |
| 1014 | SyncScissorTest(); | ||
| 1005 | auto& tev_stages = Pica::g_state.regs.GetTevStages(); | 1015 | auto& tev_stages = Pica::g_state.regs.GetTevStages(); |
| 1006 | for (int index = 0; index < tev_stages.size(); ++index) | 1016 | for (int index = 0; index < tev_stages.size(); ++index) |
| 1007 | SyncTevConstColor(index, tev_stages[index]); | 1017 | SyncTevConstColor(index, tev_stages[index]); |
| @@ -1166,6 +1176,22 @@ void RasterizerOpenGL::SyncDepthTest() { | |||
| 1166 | PicaToGL::CompareFunc(regs.output_merger.depth_test_func) : GL_ALWAYS; | 1176 | PicaToGL::CompareFunc(regs.output_merger.depth_test_func) : GL_ALWAYS; |
| 1167 | } | 1177 | } |
| 1168 | 1178 | ||
| 1179 | void RasterizerOpenGL::SyncScissorTest() { | ||
| 1180 | const auto& regs = Pica::g_state.regs; | ||
| 1181 | |||
| 1182 | if (uniform_block_data.data.scissor_right != regs.scissor_test.right || | ||
| 1183 | uniform_block_data.data.scissor_bottom != regs.scissor_test.bottom || | ||
| 1184 | uniform_block_data.data.scissor_left != regs.scissor_test.GetLeft() || | ||
| 1185 | uniform_block_data.data.scissor_top != regs.scissor_test.GetTop()) { | ||
| 1186 | |||
| 1187 | uniform_block_data.data.scissor_right = regs.scissor_test.right; | ||
| 1188 | uniform_block_data.data.scissor_bottom = regs.scissor_test.bottom; | ||
| 1189 | uniform_block_data.data.scissor_left = regs.scissor_test.GetLeft(); | ||
| 1190 | uniform_block_data.data.scissor_top = regs.scissor_test.GetTop(); | ||
| 1191 | uniform_block_data.dirty = true; | ||
| 1192 | } | ||
| 1193 | } | ||
| 1194 | |||
| 1169 | void RasterizerOpenGL::SyncCombinerColor() { | 1195 | void RasterizerOpenGL::SyncCombinerColor() { |
| 1170 | auto combiner_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.tev_combiner_buffer_color.raw); | 1196 | auto combiner_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.tev_combiner_buffer_color.raw); |
| 1171 | if (combiner_color != uniform_block_data.data.tev_combiner_buffer_color) { | 1197 | if (combiner_color != uniform_block_data.data.tev_combiner_buffer_color) { |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 42482df4b..193c10291 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -56,6 +56,8 @@ union PicaShaderConfig { | |||
| 56 | 56 | ||
| 57 | const auto& regs = Pica::g_state.regs; | 57 | const auto& regs = Pica::g_state.regs; |
| 58 | 58 | ||
| 59 | state.scissor_test_mode = regs.scissor_test.mode; | ||
| 60 | |||
| 59 | state.depthmap_enable = regs.depthmap_enable; | 61 | state.depthmap_enable = regs.depthmap_enable; |
| 60 | 62 | ||
| 61 | state.alpha_test_func = regs.output_merger.alpha_test.enable ? | 63 | state.alpha_test_func = regs.output_merger.alpha_test.enable ? |
| @@ -172,6 +174,7 @@ union PicaShaderConfig { | |||
| 172 | 174 | ||
| 173 | struct State { | 175 | struct State { |
| 174 | Pica::Regs::CompareFunc alpha_test_func; | 176 | Pica::Regs::CompareFunc alpha_test_func; |
| 177 | Pica::Regs::ScissorMode scissor_test_mode; | ||
| 175 | Pica::Regs::TextureConfig::TextureType texture0_type; | 178 | Pica::Regs::TextureConfig::TextureType texture0_type; |
| 176 | std::array<TevStageConfigRaw, 6> tev_stages; | 179 | std::array<TevStageConfigRaw, 6> tev_stages; |
| 177 | u8 combiner_buffer_input; | 180 | u8 combiner_buffer_input; |
| @@ -328,6 +331,10 @@ private: | |||
| 328 | GLint alphatest_ref; | 331 | GLint alphatest_ref; |
| 329 | GLfloat depth_scale; | 332 | GLfloat depth_scale; |
| 330 | GLfloat depth_offset; | 333 | GLfloat depth_offset; |
| 334 | GLint scissor_right; | ||
| 335 | GLint scissor_bottom; | ||
| 336 | GLint scissor_left; | ||
| 337 | GLint scissor_top; | ||
| 331 | alignas(16) GLvec3 fog_color; | 338 | alignas(16) GLvec3 fog_color; |
| 332 | alignas(16) GLvec3 lighting_global_ambient; | 339 | alignas(16) GLvec3 lighting_global_ambient; |
| 333 | LightSrc light_src[8]; | 340 | LightSrc light_src[8]; |
| @@ -335,7 +342,7 @@ private: | |||
| 335 | alignas(16) GLvec4 tev_combiner_buffer_color; | 342 | alignas(16) GLvec4 tev_combiner_buffer_color; |
| 336 | }; | 343 | }; |
| 337 | 344 | ||
| 338 | static_assert(sizeof(UniformData) == 0x3A0, "The size of the UniformData structure has changed, update the structure in the shader"); | 345 | static_assert(sizeof(UniformData) == 0x3B0, "The size of the UniformData structure has changed, update the structure in the shader"); |
| 339 | static_assert(sizeof(UniformData) < 16384, "UniformData structure must be less than 16kb as per the OpenGL spec"); | 346 | static_assert(sizeof(UniformData) < 16384, "UniformData structure must be less than 16kb as per the OpenGL spec"); |
| 340 | 347 | ||
| 341 | /// Sets the OpenGL shader in accordance with the current PICA register state | 348 | /// Sets the OpenGL shader in accordance with the current PICA register state |
| @@ -384,6 +391,9 @@ private: | |||
| 384 | /// Syncs the depth test states to match the PICA register | 391 | /// Syncs the depth test states to match the PICA register |
| 385 | void SyncDepthTest(); | 392 | void SyncDepthTest(); |
| 386 | 393 | ||
| 394 | /// Syncs the scissor test state to match the PICA register | ||
| 395 | void SyncScissorTest(); | ||
| 396 | |||
| 387 | /// Syncs the TEV combiner color buffer to match the PICA register | 397 | /// Syncs the TEV combiner color buffer to match the PICA register |
| 388 | void SyncCombinerColor(); | 398 | void SyncCombinerColor(); |
| 389 | 399 | ||
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 3bace7f01..10bb44210 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp | |||
| @@ -539,6 +539,8 @@ in float texcoord0_w; | |||
| 539 | in vec4 normquat; | 539 | in vec4 normquat; |
| 540 | in vec3 view; | 540 | in vec3 view; |
| 541 | 541 | ||
| 542 | in vec4 gl_FragCoord; | ||
| 543 | |||
| 542 | out vec4 color; | 544 | out vec4 color; |
| 543 | 545 | ||
| 544 | struct LightSrc { | 546 | struct LightSrc { |
| @@ -555,6 +557,10 @@ layout (std140) uniform shader_data { | |||
| 555 | int alphatest_ref; | 557 | int alphatest_ref; |
| 556 | float depth_scale; | 558 | float depth_scale; |
| 557 | float depth_offset; | 559 | float depth_offset; |
| 560 | int scissor_right; | ||
| 561 | int scissor_bottom; | ||
| 562 | int scissor_left; | ||
| 563 | int scissor_top; | ||
| 558 | vec3 fog_color; | 564 | vec3 fog_color; |
| 559 | vec3 lighting_global_ambient; | 565 | vec3 lighting_global_ambient; |
| 560 | LightSrc light_src[NUM_LIGHTS]; | 566 | LightSrc light_src[NUM_LIGHTS]; |
| @@ -582,6 +588,16 @@ vec4 secondary_fragment_color = vec4(0.0); | |||
| 582 | return out; | 588 | return out; |
| 583 | } | 589 | } |
| 584 | 590 | ||
| 591 | // Append the scissor test | ||
| 592 | if (state.scissor_test_mode == Regs::ScissorMode::Include || state.scissor_test_mode == Regs::ScissorMode::Exclude) { | ||
| 593 | out += "if (scissor_left <= scissor_right || scissor_top <= scissor_bottom) discard;\n"; | ||
| 594 | out += "if ("; | ||
| 595 | // Negate the condition if we have to keep only the pixels outside the scissor box | ||
| 596 | if (state.scissor_test_mode == Regs::ScissorMode::Include) | ||
| 597 | out += "!"; | ||
| 598 | out += "(gl_FragCoord.x >= scissor_right && gl_FragCoord.x <= scissor_left && gl_FragCoord.y >= scissor_bottom && gl_FragCoord.y <= scissor_top)) discard;\n"; | ||
| 599 | } | ||
| 600 | |||
| 585 | out += "float z_over_w = 1.0 - gl_FragCoord.z * 2.0;\n"; | 601 | out += "float z_over_w = 1.0 - gl_FragCoord.z * 2.0;\n"; |
| 586 | out += "float depth = z_over_w * depth_scale + depth_offset;\n"; | 602 | out += "float depth = z_over_w * depth_scale + depth_offset;\n"; |
| 587 | if (state.depthmap_enable == Pica::Regs::DepthBuffering::WBuffering) { | 603 | if (state.depthmap_enable == Pica::Regs::DepthBuffering::WBuffering) { |