radv: Implement VK_EXT_discard_rectangles.
[mesa.git] / src / amd / vulkan / radv_cmd_buffer.c
index 665ee876a9d91c9e2e08458d7c9b1c6bb558fecf..4b5556bcc62e2460b4e30f4d9aba6ff054e406e8 100644 (file)
@@ -91,80 +91,91 @@ radv_bind_dynamic_state(struct radv_cmd_buffer *cmd_buffer,
         */
        dest->viewport.count = src->viewport.count;
        dest->scissor.count = src->scissor.count;
+       dest->discard_rectangle.count = src->discard_rectangle.count;
 
-       if (copy_mask & (1 << VK_DYNAMIC_STATE_VIEWPORT)) {
+       if (copy_mask & RADV_DYNAMIC_VIEWPORT) {
                if (memcmp(&dest->viewport.viewports, &src->viewport.viewports,
                           src->viewport.count * sizeof(VkViewport))) {
                        typed_memcpy(dest->viewport.viewports,
                                     src->viewport.viewports,
                                     src->viewport.count);
-                       dest_mask |= 1 << VK_DYNAMIC_STATE_VIEWPORT;
+                       dest_mask |= RADV_DYNAMIC_VIEWPORT;
                }
        }
 
-       if (copy_mask & (1 << VK_DYNAMIC_STATE_SCISSOR)) {
+       if (copy_mask & RADV_DYNAMIC_SCISSOR) {
                if (memcmp(&dest->scissor.scissors, &src->scissor.scissors,
                           src->scissor.count * sizeof(VkRect2D))) {
                        typed_memcpy(dest->scissor.scissors,
                                     src->scissor.scissors, src->scissor.count);
-                       dest_mask |= 1 << VK_DYNAMIC_STATE_SCISSOR;
+                       dest_mask |= RADV_DYNAMIC_SCISSOR;
                }
        }
 
-       if (copy_mask & (1 << VK_DYNAMIC_STATE_LINE_WIDTH)) {
+       if (copy_mask & RADV_DYNAMIC_LINE_WIDTH) {
                if (dest->line_width != src->line_width) {
                        dest->line_width = src->line_width;
-                       dest_mask |= 1 << VK_DYNAMIC_STATE_LINE_WIDTH;
+                       dest_mask |= RADV_DYNAMIC_LINE_WIDTH;
                }
        }
 
-       if (copy_mask & (1 << VK_DYNAMIC_STATE_DEPTH_BIAS)) {
+       if (copy_mask & RADV_DYNAMIC_DEPTH_BIAS) {
                if (memcmp(&dest->depth_bias, &src->depth_bias,
                           sizeof(src->depth_bias))) {
                        dest->depth_bias = src->depth_bias;
-                       dest_mask |= 1 << VK_DYNAMIC_STATE_DEPTH_BIAS;
+                       dest_mask |= RADV_DYNAMIC_DEPTH_BIAS;
                }
        }
 
-       if (copy_mask & (1 << VK_DYNAMIC_STATE_BLEND_CONSTANTS)) {
+       if (copy_mask & RADV_DYNAMIC_BLEND_CONSTANTS) {
                if (memcmp(&dest->blend_constants, &src->blend_constants,
                           sizeof(src->blend_constants))) {
                        typed_memcpy(dest->blend_constants,
                                     src->blend_constants, 4);
-                       dest_mask |= 1 << VK_DYNAMIC_STATE_BLEND_CONSTANTS;
+                       dest_mask |= RADV_DYNAMIC_BLEND_CONSTANTS;
                }
        }
 
-       if (copy_mask & (1 << VK_DYNAMIC_STATE_DEPTH_BOUNDS)) {
+       if (copy_mask & RADV_DYNAMIC_DEPTH_BOUNDS) {
                if (memcmp(&dest->depth_bounds, &src->depth_bounds,
                           sizeof(src->depth_bounds))) {
                        dest->depth_bounds = src->depth_bounds;
-                       dest_mask |= 1 << VK_DYNAMIC_STATE_DEPTH_BOUNDS;
+                       dest_mask |= RADV_DYNAMIC_DEPTH_BOUNDS;
                }
        }
 
-       if (copy_mask & (1 << VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK)) {
+       if (copy_mask & RADV_DYNAMIC_STENCIL_COMPARE_MASK) {
                if (memcmp(&dest->stencil_compare_mask,
                           &src->stencil_compare_mask,
                           sizeof(src->stencil_compare_mask))) {
                        dest->stencil_compare_mask = src->stencil_compare_mask;
-                       dest_mask |= 1 << VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK;
+                       dest_mask |= RADV_DYNAMIC_STENCIL_COMPARE_MASK;
                }
        }
 
-       if (copy_mask & (1 << VK_DYNAMIC_STATE_STENCIL_WRITE_MASK)) {
+       if (copy_mask & RADV_DYNAMIC_STENCIL_WRITE_MASK) {
                if (memcmp(&dest->stencil_write_mask, &src->stencil_write_mask,
                           sizeof(src->stencil_write_mask))) {
                        dest->stencil_write_mask = src->stencil_write_mask;
-                       dest_mask |= 1 << VK_DYNAMIC_STATE_STENCIL_WRITE_MASK;
+                       dest_mask |= RADV_DYNAMIC_STENCIL_WRITE_MASK;
                }
        }
 
-       if (copy_mask & (1 << VK_DYNAMIC_STATE_STENCIL_REFERENCE)) {
+       if (copy_mask & RADV_DYNAMIC_STENCIL_REFERENCE) {
                if (memcmp(&dest->stencil_reference, &src->stencil_reference,
                           sizeof(src->stencil_reference))) {
                        dest->stencil_reference = src->stencil_reference;
-                       dest_mask |= 1 << VK_DYNAMIC_STATE_STENCIL_REFERENCE;
+                       dest_mask |= RADV_DYNAMIC_STENCIL_REFERENCE;
+               }
+       }
+
+       if (copy_mask & RADV_DYNAMIC_DISCARD_RECTANGLE) {
+               if (memcmp(&dest->discard_rectangle.rectangles, &src->discard_rectangle.rectangles,
+                          src->discard_rectangle.count * sizeof(VkRect2D))) {
+                       typed_memcpy(dest->discard_rectangle.rectangles,
+                                    src->discard_rectangle.rectangles,
+                                    src->discard_rectangle.count);
+                       dest_mask |= RADV_DYNAMIC_DISCARD_RECTANGLE;
                }
        }
 
@@ -1098,6 +1109,8 @@ radv_emit_graphics_pipeline(struct radv_cmd_buffer *cmd_buffer)
        }
        radeon_set_context_reg(cmd_buffer->cs, R_028A6C_VGT_GS_OUT_PRIM_TYPE, pipeline->graphics.gs_out);
 
+       radeon_set_context_reg(cmd_buffer->cs, R_02820C_PA_SC_CLIPRECT_RULE, pipeline->graphics.pa_sc_cliprect_rule);
+
        if (unlikely(cmd_buffer->device->trace_bo))
                radv_save_pipeline(cmd_buffer, pipeline, RING_GFX);
 
@@ -1134,6 +1147,22 @@ radv_emit_scissor(struct radv_cmd_buffer *cmd_buffer)
                               cmd_buffer->state.pipeline->graphics.ms.pa_sc_mode_cntl_0 | S_028A48_VPORT_SCISSOR_ENABLE(count ? 1 : 0));
 }
 
+static void
+radv_emit_discard_rectangle(struct radv_cmd_buffer *cmd_buffer)
+{
+       if (!cmd_buffer->state.dynamic.discard_rectangle.count)
+               return;
+
+       radeon_set_context_reg_seq(cmd_buffer->cs, R_028210_PA_SC_CLIPRECT_0_TL,
+                                  cmd_buffer->state.dynamic.discard_rectangle.count * 2);
+       for (unsigned i = 0; i < cmd_buffer->state.dynamic.discard_rectangle.count; ++i) {
+               VkRect2D rect = cmd_buffer->state.dynamic.discard_rectangle.rectangles[i];
+               radeon_emit(cmd_buffer->cs, S_028210_TL_X(rect.offset.x) | S_028210_TL_Y(rect.offset.y));
+               radeon_emit(cmd_buffer->cs, S_028214_BR_X(rect.offset.x + rect.extent.width) |
+                                           S_028214_BR_Y(rect.offset.y + rect.extent.height));
+       }
+}
+
 static void
 radv_emit_line_width(struct radv_cmd_buffer *cmd_buffer)
 {
@@ -1627,6 +1656,9 @@ radv_cmd_buffer_flush_dynamic_state(struct radv_cmd_buffer *cmd_buffer)
                                       RADV_CMD_DIRTY_DYNAMIC_DEPTH_BIAS))
                radv_emit_depth_biais(cmd_buffer);
 
+       if (cmd_buffer->state.dirty & RADV_CMD_DIRTY_DYNAMIC_DISCARD_RECTANGLE)
+               radv_emit_discard_rectangle(cmd_buffer);
+
        cmd_buffer->state.dirty &= ~RADV_CMD_DIRTY_DYNAMIC_ALL;
 }
 
@@ -2733,15 +2765,28 @@ void radv_CmdSetViewport(
        const VkViewport*                           pViewports)
 {
        RADV_FROM_HANDLE(radv_cmd_buffer, cmd_buffer, commandBuffer);
+       struct radv_cmd_state *state = &cmd_buffer->state;
        MAYBE_UNUSED const uint32_t total_count = firstViewport + viewportCount;
 
        assert(firstViewport < MAX_VIEWPORTS);
        assert(total_count >= 1 && total_count <= MAX_VIEWPORTS);
 
-       memcpy(cmd_buffer->state.dynamic.viewport.viewports + firstViewport,
-              pViewports, viewportCount * sizeof(*pViewports));
+       if (cmd_buffer->device->physical_device->has_scissor_bug) {
+               /* Try to skip unnecessary PS partial flushes when the viewports
+                * don't change.
+                */
+               if (!(state->dirty & (RADV_CMD_DIRTY_DYNAMIC_VIEWPORT |
+                                     RADV_CMD_DIRTY_DYNAMIC_SCISSOR)) &&
+                   !memcmp(state->dynamic.viewport.viewports + firstViewport,
+                           pViewports, viewportCount * sizeof(*pViewports))) {
+                       return;
+               }
+       }
+
+       memcpy(state->dynamic.viewport.viewports + firstViewport, pViewports,
+              viewportCount * sizeof(*pViewports));
 
-       cmd_buffer->state.dirty |= RADV_CMD_DIRTY_DYNAMIC_VIEWPORT;
+       state->dirty |= RADV_CMD_DIRTY_DYNAMIC_VIEWPORT;
 }
 
 void radv_CmdSetScissor(
@@ -2751,14 +2796,28 @@ void radv_CmdSetScissor(
        const VkRect2D*                             pScissors)
 {
        RADV_FROM_HANDLE(radv_cmd_buffer, cmd_buffer, commandBuffer);
+       struct radv_cmd_state *state = &cmd_buffer->state;
        MAYBE_UNUSED const uint32_t total_count = firstScissor + scissorCount;
 
        assert(firstScissor < MAX_SCISSORS);
        assert(total_count >= 1 && total_count <= MAX_SCISSORS);
 
-       memcpy(cmd_buffer->state.dynamic.scissor.scissors + firstScissor,
-              pScissors, scissorCount * sizeof(*pScissors));
-       cmd_buffer->state.dirty |= RADV_CMD_DIRTY_DYNAMIC_SCISSOR;
+       if (cmd_buffer->device->physical_device->has_scissor_bug) {
+               /* Try to skip unnecessary PS partial flushes when the scissors
+                * don't change.
+                */
+               if (!(state->dirty & (RADV_CMD_DIRTY_DYNAMIC_VIEWPORT |
+                                     RADV_CMD_DIRTY_DYNAMIC_SCISSOR)) &&
+                   !memcmp(state->dynamic.scissor.scissors + firstScissor,
+                           pScissors, scissorCount * sizeof(*pScissors))) {
+                       return;
+               }
+       }
+
+       memcpy(state->dynamic.scissor.scissors + firstScissor, pScissors,
+              scissorCount * sizeof(*pScissors));
+
+       state->dirty |= RADV_CMD_DIRTY_DYNAMIC_SCISSOR;
 }
 
 void radv_CmdSetLineWidth(
@@ -2855,6 +2914,25 @@ void radv_CmdSetStencilReference(
        cmd_buffer->state.dirty |= RADV_CMD_DIRTY_DYNAMIC_STENCIL_REFERENCE;
 }
 
+void radv_CmdSetDiscardRectangleEXT(
+       VkCommandBuffer                             commandBuffer,
+       uint32_t                                    firstDiscardRectangle,
+       uint32_t                                    discardRectangleCount,
+       const VkRect2D*                             pDiscardRectangles)
+{
+       RADV_FROM_HANDLE(radv_cmd_buffer, cmd_buffer, commandBuffer);
+       struct radv_cmd_state *state = &cmd_buffer->state;
+       MAYBE_UNUSED const uint32_t total_count = firstDiscardRectangle + discardRectangleCount;
+
+       assert(firstDiscardRectangle < MAX_DISCARD_RECTANGLES);
+       assert(total_count >= 1 && total_count <= MAX_DISCARD_RECTANGLES);
+
+       typed_memcpy(&state->dynamic.discard_rectangle.rectangles[firstDiscardRectangle],
+                    pDiscardRectangles, discardRectangleCount);
+
+       state->dirty |= RADV_CMD_DIRTY_DYNAMIC_DISCARD_RECTANGLE;
+}
+
 void radv_CmdExecuteCommands(
        VkCommandBuffer                             commandBuffer,
        uint32_t                                    commandBufferCount,