Parcourir la source

GPU: Bind and clear the render target when the CLEAR_BUFFERS register is written to.

Subv il y a 8 ans
Parent
commit
be51120d23

+ 11 - 0
src/video_core/engines/maxwell_3d.cpp

@@ -126,6 +126,10 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
         DrawArrays();
         break;
     }
+    case MAXWELL3D_REG_INDEX(clear_buffers): {
+        ProcessClearBuffers();
+        break;
+    }
     case MAXWELL3D_REG_INDEX(query.query_get): {
         ProcessQueryGet();
         break;
@@ -415,5 +419,12 @@ bool Maxwell3D::IsShaderStageEnabled(Regs::ShaderStage stage) const {
     UNREACHABLE();
 }
 
+void Maxwell3D::ProcessClearBuffers() {
+    ASSERT(regs.clear_buffers.R && regs.clear_buffers.G && regs.clear_buffers.B &&
+           regs.clear_buffers.A);
+
+    VideoCore::g_renderer->Rasterizer()->Clear();
+}
+
 } // namespace Engines
 } // namespace Tegra

+ 3 - 0
src/video_core/rasterizer_interface.h

@@ -19,6 +19,9 @@ public:
     /// Draw the current batch of vertex arrays
     virtual void DrawArrays() = 0;
 
+    /// Clear the current framebuffer
+    virtual void Clear() = 0;
+
     /// Notify rasterizer that the specified Maxwell register has been changed
     virtual void NotifyMaxwellRegisterChanged(u32 method) = 0;
 

+ 71 - 0
src/video_core/renderer_opengl/gl_rasterizer.cpp

@@ -297,6 +297,77 @@ bool RasterizerOpenGL::AccelerateDrawBatch(bool is_indexed) {
     return true;
 }
 
+void RasterizerOpenGL::Clear() {
+    const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
+
+    // TODO(bunnei): Implement these
+    const bool has_stencil = false;
+    const bool using_color_fb = true;
+    const bool using_depth_fb = regs.zeta.Address() != 0;
+    const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[0].GetRect()};
+
+    const bool write_color_fb =
+        state.color_mask.red_enabled == GL_TRUE || state.color_mask.green_enabled == GL_TRUE ||
+        state.color_mask.blue_enabled == GL_TRUE || state.color_mask.alpha_enabled == GL_TRUE;
+
+    const bool write_depth_fb =
+        (state.depth.test_enabled && state.depth.write_mask == GL_TRUE) ||
+        (has_stencil && state.stencil.test_enabled && state.stencil.write_mask != 0);
+
+    Surface color_surface;
+    Surface depth_surface;
+    MathUtil::Rectangle<u32> surfaces_rect;
+    std::tie(color_surface, depth_surface, surfaces_rect) =
+        res_cache.GetFramebufferSurfaces(using_color_fb, using_depth_fb, viewport_rect);
+
+    MathUtil::Rectangle<u32> draw_rect{
+        static_cast<u32>(std::clamp<s32>(static_cast<s32>(surfaces_rect.left) + viewport_rect.left,
+                                         surfaces_rect.left, surfaces_rect.right)), // Left
+        static_cast<u32>(std::clamp<s32>(static_cast<s32>(surfaces_rect.bottom) + viewport_rect.top,
+                                         surfaces_rect.bottom, surfaces_rect.top)), // Top
+        static_cast<u32>(std::clamp<s32>(static_cast<s32>(surfaces_rect.left) + viewport_rect.right,
+                                         surfaces_rect.left, surfaces_rect.right)), // Right
+        static_cast<u32>(
+            std::clamp<s32>(static_cast<s32>(surfaces_rect.bottom) + viewport_rect.bottom,
+                            surfaces_rect.bottom, surfaces_rect.top))}; // Bottom
+
+    // Bind the framebuffer surfaces
+    BindFramebufferSurfaces(color_surface, depth_surface, has_stencil);
+
+    // Sync the viewport
+    SyncViewport(surfaces_rect);
+
+    // TODO(bunnei): Sync scissorbox uniform(s) here
+
+    // Viewport can have negative offsets or larger dimensions than our framebuffer sub-rect. Enable
+    // scissor test to prevent drawing outside of the framebuffer region
+    state.scissor.enabled = true;
+    state.scissor.x = draw_rect.left;
+    state.scissor.y = draw_rect.bottom;
+    state.scissor.width = draw_rect.GetWidth();
+    state.scissor.height = draw_rect.GetHeight();
+    state.Apply();
+
+    // TODO(Subv): Support clearing only partial colors.
+    glClearColor(regs.clear_color[0], regs.clear_color[1], regs.clear_color[2],
+                 regs.clear_color[3]);
+    glClearDepth(regs.clear_depth);
+
+    GLbitfield clear_mask = GL_COLOR_BUFFER_BIT;
+    if (regs.clear_buffers.Z)
+        clear_mask |= GL_DEPTH_BUFFER_BIT;
+
+    glClear(clear_mask);
+
+    // Mark framebuffer surfaces as dirty
+    if (color_surface != nullptr && write_color_fb) {
+        res_cache.MarkSurfaceAsDirty(color_surface);
+    }
+    if (depth_surface != nullptr && write_depth_fb) {
+        res_cache.MarkSurfaceAsDirty(depth_surface);
+    }
+}
+
 void RasterizerOpenGL::DrawArrays() {
     if (accelerate_draw == AccelDraw::Disabled)
         return;

+ 1 - 0
src/video_core/renderer_opengl/gl_rasterizer.h

@@ -28,6 +28,7 @@ public:
     ~RasterizerOpenGL() override;
 
     void DrawArrays() override;
+    void Clear() override;
     void NotifyMaxwellRegisterChanged(u32 method) override;
     void FlushAll() override;
     void FlushRegion(Tegra::GPUVAddr addr, u64 size) override;