diff options
| author | Yuri Kunde Schlesner <yuriks@yuriks.net> | 2016-07-02 02:18:46 -0700 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2016-07-02 02:18:46 -0700 | 
| commit | 45c91bf87b5419184630931fcd62b304d2c547b6 (patch) | |
| tree | 52aea0b215230dd40606698d123999e53bb5957f /src/video_core | |
| parent | de79b6fc4857fde1df3c8a4a2b38d231f2cc961d (diff) | |
| parent | ecf6ecf32537634db15946630d62ac3bdc4fe8c9 (diff) | |
Merge pull request #1933 from yuriks/scissor
PICA: Implement scissor test
Diffstat (limited to 'src/video_core')
| -rw-r--r-- | src/video_core/pica.h | 24 | ||||
| -rw-r--r-- | src/video_core/rasterizer.cpp | 23 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 34 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 13 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.cpp | 20 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/pica_to_gl.h | 1 | 
6 files changed, 112 insertions, 3 deletions
| diff --git a/src/video_core/pica.h b/src/video_core/pica.h index 09702d46a..7099c31a0 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h @@ -115,7 +115,28 @@ struct Regs {          BitField<24, 5, Semantic> map_w;      } vs_output_attributes[7]; -    INSERT_PADDING_WORDS(0x11); +    INSERT_PADDING_WORDS(0xe); + +    enum class ScissorMode : u32 { +        Disabled = 0, +        Exclude = 1, // Exclude pixels inside the scissor box + +        Include = 3 // Exclude pixels outside the scissor box +    }; + +    struct { +        BitField<0, 2, ScissorMode> mode; + +        union { +            BitField< 0, 16, u32> x1; +            BitField<16, 16, u32> y1; +        }; + +        union { +            BitField< 0, 16, u32> x2; +            BitField<16, 16, u32> y2; +        }; +    } scissor_test;      union {          BitField< 0, 10, s32> x; @@ -1328,6 +1349,7 @@ ASSERT_REG_POSITION(viewport_depth_range, 0x4d);  ASSERT_REG_POSITION(viewport_depth_near_plane, 0x4e);  ASSERT_REG_POSITION(vs_output_attributes[0], 0x50);  ASSERT_REG_POSITION(vs_output_attributes[1], 0x51); +ASSERT_REG_POSITION(scissor_test, 0x65);  ASSERT_REG_POSITION(viewport_corner, 0x68);  ASSERT_REG_POSITION(depthmap_enable, 0x6D);  ASSERT_REG_POSITION(texture0_enable, 0x80); diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index a84170094..6f369a00e 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp @@ -338,12 +338,26 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0,              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});      u16 max_x = std::max({vtxpos[0].x, vtxpos[1].x, vtxpos[2].x});      u16 max_y = std::max({vtxpos[0].y, vtxpos[1].y, vtxpos[2].y}); +    // Convert the scissor box coordinates to 12.4 fixed point +    u16 scissor_x1 = (u16)( regs.scissor_test.x1      << 4); +    u16 scissor_y1 = (u16)( regs.scissor_test.y1      << 4); +    // x2,y2 have +1 added to cover the entire sub-pixel area +    u16 scissor_x2 = (u16)((regs.scissor_test.x2 + 1) << 4); +    u16 scissor_y2 = (u16)((regs.scissor_test.y2 + 1) << 4); + +    if (regs.scissor_test.mode == Regs::ScissorMode::Include) { +        // Calculate the new bounds +        min_x = std::max(min_x, scissor_x1); +        min_y = std::max(min_y, scissor_y1); +        max_x = std::min(max_x, scissor_x2); +        max_y = std::min(max_y, scissor_y2); +    } +      min_x &= Fix12P4::IntMask();      min_y &= Fix12P4::IntMask();      max_x = ((max_x + Fix12P4::FracMask()) & Fix12P4::IntMask()); @@ -383,6 +397,13 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0,      for (u16 y = min_y + 8; y < max_y; y += 0x10) {          for (u16 x = min_x + 8; x < max_x; x += 0x10) { +            // Do not process the pixel if it's inside the scissor box and the scissor mode is set to Exclude +            if (regs.scissor_test.mode == Regs::ScissorMode::Exclude) { +                if (x >= scissor_x1 && x < scissor_x2 && +                    y >= scissor_y1 && y < scissor_y2) +                    continue; +            } +              // Calculate the barycentric coordinates w0, w1 and w2              int w0 = bias0 + SignedArea(vtxpos[1].xy(), vtxpos[2].xy(), {x, y});              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..f8393c618 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -196,6 +196,14 @@ void RasterizerOpenGL::DrawTriangles() {                 (GLint)(rect.bottom + regs.viewport_corner.y * color_surface->res_scale_height),                 (GLsizei)(viewport_width * color_surface->res_scale_width), (GLsizei)(viewport_height * color_surface->res_scale_height)); +    if (uniform_block_data.data.framebuffer_scale[0] != color_surface->res_scale_width || +        uniform_block_data.data.framebuffer_scale[1] != color_surface->res_scale_height) { + +        uniform_block_data.data.framebuffer_scale[0] = color_surface->res_scale_width; +        uniform_block_data.data.framebuffer_scale[1] = color_surface->res_scale_height; +        uniform_block_data.dirty = true; +    } +      // Sync and bind the texture surfaces      const auto pica_textures = regs.GetTextures();      for (unsigned texture_index = 0; texture_index < pica_textures.size(); ++texture_index) { @@ -353,6 +361,15 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {          SyncColorWriteMask();          break; +    // Scissor test +    case PICA_REG_INDEX(scissor_test.mode): +        shader_dirty = true; +        break; +    case PICA_REG_INDEX(scissor_test.x1): // and y1 +    case PICA_REG_INDEX(scissor_test.x2): // and y2 +        SyncScissorTest(); +        break; +      // Logic op      case PICA_REG_INDEX(output_merger.logic_op):          SyncLogicOp(); @@ -1002,6 +1019,7 @@ void RasterizerOpenGL::SetShader() {          SyncDepthOffset();          SyncAlphaTest();          SyncCombinerColor(); +        SyncScissorTest();          auto& tev_stages = Pica::g_state.regs.GetTevStages();          for (int index = 0; index < tev_stages.size(); ++index)              SyncTevConstColor(index, tev_stages[index]); @@ -1166,6 +1184,22 @@ void RasterizerOpenGL::SyncDepthTest() {                              PicaToGL::CompareFunc(regs.output_merger.depth_test_func) : GL_ALWAYS;  } +void RasterizerOpenGL::SyncScissorTest() { +    const auto& regs = Pica::g_state.regs; + +    if (uniform_block_data.data.scissor_x1 != regs.scissor_test.x1 || +        uniform_block_data.data.scissor_y1 != regs.scissor_test.y1 || +        uniform_block_data.data.scissor_x2 != regs.scissor_test.x2 || +        uniform_block_data.data.scissor_y2 != regs.scissor_test.y2) { + +        uniform_block_data.data.scissor_x1 = regs.scissor_test.x1; +        uniform_block_data.data.scissor_y1 = regs.scissor_test.y1; +        uniform_block_data.data.scissor_x2 = regs.scissor_test.x2; +        uniform_block_data.data.scissor_y2 = regs.scissor_test.y2; +        uniform_block_data.dirty = true; +    } +} +  void RasterizerOpenGL::SyncCombinerColor() {      auto combiner_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.tev_combiner_buffer_color.raw);      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..c5029432b 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 {          const auto& regs = Pica::g_state.regs; +        state.scissor_test_mode = regs.scissor_test.mode; +          state.depthmap_enable = regs.depthmap_enable;          state.alpha_test_func = regs.output_merger.alpha_test.enable ? @@ -172,6 +174,7 @@ union PicaShaderConfig {      struct State {          Pica::Regs::CompareFunc alpha_test_func; +        Pica::Regs::ScissorMode scissor_test_mode;          Pica::Regs::TextureConfig::TextureType texture0_type;          std::array<TevStageConfigRaw, 6> tev_stages;          u8 combiner_buffer_input; @@ -325,9 +328,14 @@ private:      //       the end of a uniform block is included in UNIFORM_BLOCK_DATA_SIZE or not.      //       Not following that rule will cause problems on some AMD drivers.      struct UniformData { +        alignas(8) GLvec2 framebuffer_scale;          GLint alphatest_ref;          GLfloat depth_scale;          GLfloat depth_offset; +        GLint scissor_x1; +        GLint scissor_y1; +        GLint scissor_x2; +        GLint scissor_y2;          alignas(16) GLvec3 fog_color;          alignas(16) GLvec3 lighting_global_ambient;          LightSrc light_src[8]; @@ -335,7 +343,7 @@ private:          alignas(16) GLvec4 tev_combiner_buffer_color;      }; -    static_assert(sizeof(UniformData) == 0x3A0, "The size of the UniformData structure has changed, update the structure in the shader"); +    static_assert(sizeof(UniformData) == 0x3C0, "The size of the UniformData structure has changed, update the structure in the shader");      static_assert(sizeof(UniformData) < 16384, "UniformData structure must be less than 16kb as per the OpenGL spec");      /// Sets the OpenGL shader in accordance with the current PICA register state @@ -384,6 +392,9 @@ private:      /// Syncs the depth test states to match the PICA register      void SyncDepthTest(); +    /// Syncs the scissor test state to match the PICA register +    void SyncScissorTest(); +      /// Syncs the TEV combiner color buffer to match the PICA register      void SyncCombinerColor(); diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 3bace7f01..36513dedc 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;  in vec4 normquat;  in vec3 view; +in vec4 gl_FragCoord; +  out vec4 color;  struct LightSrc { @@ -552,9 +554,14 @@ struct LightSrc {  };  layout (std140) uniform shader_data { +    vec2 framebuffer_scale;      int alphatest_ref;      float depth_scale;      float depth_offset; +    int scissor_x1; +    int scissor_y1; +    int scissor_x2; +    int scissor_y2;      vec3 fog_color;      vec3 lighting_global_ambient;      LightSrc light_src[NUM_LIGHTS]; @@ -582,6 +589,19 @@ vec4 secondary_fragment_color = vec4(0.0);          return out;      } +    // Append the scissor test +    if (state.scissor_test_mode != Regs::ScissorMode::Disabled) { +        out += "if ("; +        // Negate the condition if we have to keep only the pixels outside the scissor box +        if (state.scissor_test_mode == Regs::ScissorMode::Include) +            out += "!"; +        // x2,y2 have +1 added to cover the entire pixel area +        out += "(gl_FragCoord.x >= scissor_x1 * framebuffer_scale.x && " +                "gl_FragCoord.y >= scissor_y1 * framebuffer_scale.y && " +                "gl_FragCoord.x < (scissor_x2 + 1) * framebuffer_scale.x && " +                "gl_FragCoord.y < (scissor_y2 + 1) * framebuffer_scale.y)) discard;\n"; +    } +      out += "float z_over_w = 1.0 - gl_FragCoord.z * 2.0;\n";      out += "float depth = z_over_w * depth_scale + depth_offset;\n";      if (state.depthmap_enable == Pica::Regs::DepthBuffering::WBuffering) { diff --git a/src/video_core/renderer_opengl/pica_to_gl.h b/src/video_core/renderer_opengl/pica_to_gl.h index 6dc2758c5..d9b9c9cc2 100644 --- a/src/video_core/renderer_opengl/pica_to_gl.h +++ b/src/video_core/renderer_opengl/pica_to_gl.h @@ -17,6 +17,7 @@  #include "video_core/pica.h" +using GLvec2 = std::array<GLfloat, 2>;  using GLvec3 = std::array<GLfloat, 3>;  using GLvec4 = std::array<GLfloat, 4>; | 
