radv: Fix architecture in radeon_icd.{arch}.json
[mesa.git] / src / amd / vulkan / radv_cmd_buffer.c
index d97c11d230d5d432709c162b3b6367359af15639..9a191cda1c559e0efc0dbc4ba49bfe2b47ef14fe 100644 (file)
@@ -79,10 +79,13 @@ const struct radv_dynamic_state default_dynamic_state = {
 };
 
 static void
-radv_dynamic_state_copy(struct radv_dynamic_state *dest,
-                       const struct radv_dynamic_state *src,
-                       uint32_t copy_mask)
+radv_bind_dynamic_state(struct radv_cmd_buffer *cmd_buffer,
+                       const struct radv_dynamic_state *src)
 {
+       struct radv_dynamic_state *dest = &cmd_buffer->state.dynamic;
+       uint32_t copy_mask = src->mask;
+       uint32_t dest_mask = 0;
+
        /* Make sure to copy the number of viewports/scissors because they can
         * only be specified at pipeline creation time.
         */
@@ -90,35 +93,82 @@ radv_dynamic_state_copy(struct radv_dynamic_state *dest,
        dest->scissor.count = src->scissor.count;
 
        if (copy_mask & (1 << VK_DYNAMIC_STATE_VIEWPORT)) {
-               typed_memcpy(dest->viewport.viewports, src->viewport.viewports,
-                            src->viewport.count);
+               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;
+               }
        }
 
        if (copy_mask & (1 << VK_DYNAMIC_STATE_SCISSOR)) {
-               typed_memcpy(dest->scissor.scissors, src->scissor.scissors,
-                            src->scissor.count);
+               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;
+               }
        }
 
-       if (copy_mask & (1 << VK_DYNAMIC_STATE_LINE_WIDTH))
-               dest->line_width = src->line_width;
+       if (copy_mask & (1 << VK_DYNAMIC_STATE_LINE_WIDTH)) {
+               if (dest->line_width != src->line_width) {
+                       dest->line_width = src->line_width;
+                       dest_mask |= 1 << VK_DYNAMIC_STATE_LINE_WIDTH;
+               }
+       }
 
-       if (copy_mask & (1 << VK_DYNAMIC_STATE_DEPTH_BIAS))
-               dest->depth_bias = src->depth_bias;
+       if (copy_mask & (1 << VK_DYNAMIC_STATE_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;
+               }
+       }
+
+       if (copy_mask & (1 << VK_DYNAMIC_STATE_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;
+               }
+       }
 
-       if (copy_mask & (1 << VK_DYNAMIC_STATE_BLEND_CONSTANTS))
-               typed_memcpy(dest->blend_constants, src->blend_constants, 4);
+       if (copy_mask & (1 << VK_DYNAMIC_STATE_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;
+               }
+       }
 
-       if (copy_mask & (1 << VK_DYNAMIC_STATE_DEPTH_BOUNDS))
-               dest->depth_bounds = src->depth_bounds;
+       if (copy_mask & (1 << VK_DYNAMIC_STATE_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;
+               }
+       }
 
-       if (copy_mask & (1 << VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK))
-               dest->stencil_compare_mask = src->stencil_compare_mask;
+       if (copy_mask & (1 << VK_DYNAMIC_STATE_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;
+               }
+       }
 
-       if (copy_mask & (1 << VK_DYNAMIC_STATE_STENCIL_WRITE_MASK))
-               dest->stencil_write_mask = src->stencil_write_mask;
+       if (copy_mask & (1 << VK_DYNAMIC_STATE_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;
+               }
+       }
 
-       if (copy_mask & (1 << VK_DYNAMIC_STATE_STENCIL_REFERENCE))
-               dest->stencil_reference = src->stencil_reference;
+       cmd_buffer->state.dirty |= dest_mask;
 }
 
 bool radv_cmd_buffer_uses_mec(struct radv_cmd_buffer *cmd_buffer)
@@ -229,8 +279,8 @@ radv_reset_cmd_buffer(struct radv_cmd_buffer *cmd_buffer)
        cmd_buffer->sample_positions_needed = false;
 
        if (cmd_buffer->upload.upload_bo)
-               cmd_buffer->device->ws->cs_add_buffer(cmd_buffer->cs,
-                                                     cmd_buffer->upload.upload_bo, 8);
+               radv_cs_add_buffer(cmd_buffer->device->ws, cmd_buffer->cs,
+                                  cmd_buffer->upload.upload_bo, 8);
        cmd_buffer->upload.offset = 0;
 
        cmd_buffer->record_result = VK_SUCCESS;
@@ -263,14 +313,15 @@ radv_cmd_buffer_resize_upload_buf(struct radv_cmd_buffer *cmd_buffer,
        bo = device->ws->buffer_create(device->ws,
                                       new_size, 4096,
                                       RADEON_DOMAIN_GTT,
-                                      RADEON_FLAG_CPU_ACCESS);
+                                      RADEON_FLAG_CPU_ACCESS|
+                                      RADEON_FLAG_NO_INTERPROCESS_SHARING);
 
        if (!bo) {
                cmd_buffer->record_result = VK_ERROR_OUT_OF_DEVICE_MEMORY;
                return false;
        }
 
-       device->ws->cs_add_buffer(cmd_buffer->cs, bo, 8);
+       radv_cs_add_buffer(device->ws, cmd_buffer->cs, bo, 8);
        if (cmd_buffer->upload.upload_bo) {
                upload = malloc(sizeof(*upload));
 
@@ -364,7 +415,7 @@ void radv_cmd_buffer_trace_emit(struct radv_cmd_buffer *cmd_buffer)
        MAYBE_UNUSED unsigned cdw_max = radeon_check_space(cmd_buffer->device->ws, cmd_buffer->cs, 7);
 
        ++cmd_buffer->state.trace_id;
-       device->ws->cs_add_buffer(cs, device->trace_bo, 8);
+       radv_cs_add_buffer(device->ws, cs, device->trace_bo, 8);
        radv_emit_write_data_packet(cs, va, 1, &cmd_buffer->state.trace_id);
        radeon_emit(cs, PKT3(PKT3_NOP, 0, 0));
        radeon_emit(cs, AC_ENCODE_TRACE_POINT(cmd_buffer->state.trace_id));
@@ -421,10 +472,23 @@ radv_save_pipeline(struct radv_cmd_buffer *cmd_buffer,
        data[0] = (uintptr_t)pipeline;
        data[1] = (uintptr_t)pipeline >> 32;
 
-       device->ws->cs_add_buffer(cs, device->trace_bo, 8);
+       radv_cs_add_buffer(device->ws, cs, device->trace_bo, 8);
        radv_emit_write_data_packet(cs, va, 2, data);
 }
 
+void radv_set_descriptor_set(struct radv_cmd_buffer *cmd_buffer,
+                            struct radv_descriptor_set *set,
+                            unsigned idx)
+{
+       cmd_buffer->descriptors[idx] = set;
+       if (set)
+               cmd_buffer->state.valid_descriptors |= (1u << idx);
+       else
+               cmd_buffer->state.valid_descriptors &= ~(1u << idx);
+       cmd_buffer->state.descriptors_dirty |= (1u << idx);
+
+}
+
 static void
 radv_save_descriptors(struct radv_cmd_buffer *cmd_buffer)
 {
@@ -432,25 +496,19 @@ radv_save_descriptors(struct radv_cmd_buffer *cmd_buffer)
        struct radeon_winsys_cs *cs = cmd_buffer->cs;
        uint32_t data[MAX_SETS * 2] = {};
        uint64_t va;
-
-       if (!device->trace_bo)
-               return;
-
+       unsigned i;
        va = radv_buffer_get_va(device->trace_bo) + 24;
 
        MAYBE_UNUSED unsigned cdw_max = radeon_check_space(device->ws,
                                                           cmd_buffer->cs, 4 + MAX_SETS * 2);
 
-       for (int i = 0; i < MAX_SETS; i++) {
-               struct radv_descriptor_set *set = cmd_buffer->state.descriptors[i];
-               if (!set)
-                       continue;
-
+       for_each_bit(i, cmd_buffer->state.valid_descriptors) {
+               struct radv_descriptor_set *set = cmd_buffer->descriptors[i];
                data[i * 2] = (uintptr_t)set;
                data[i * 2 + 1] = (uintptr_t)set >> 32;
        }
 
-       device->ws->cs_add_buffer(cs, device->trace_bo, 8);
+       radv_cs_add_buffer(device->ws, cs, device->trace_bo, 8);
        radv_emit_write_data_packet(cs, va, MAX_SETS * 2, data);
 }
 
@@ -516,7 +574,7 @@ radv_emit_userdata_address(struct radv_cmd_buffer *cmd_buffer,
                           int idx, uint64_t va)
 {
        struct ac_userdata_info *loc = radv_lookup_user_sgpr(pipeline, stage, idx);
-       uint32_t base_reg = radv_shader_stage_to_user_data_0(stage, cmd_buffer->device->physical_device->rad_info.chip_class, radv_pipeline_has_gs(pipeline), radv_pipeline_has_tess(pipeline));
+       uint32_t base_reg = pipeline->user_data_0[stage];
        if (loc->sgpr_idx == -1)
                return;
        assert(loc->num_sgprs == 2);
@@ -551,14 +609,14 @@ radv_update_multisample_state(struct radv_cmd_buffer *cmd_buffer,
        radv_cayman_emit_msaa_sample_locs(cmd_buffer->cs, num_samples);
 
        /* GFX9: Flush DFSM when the AA mode changes. */
-       if (cmd_buffer->device->physical_device->rad_info.chip_class >= GFX9) {
+       if (cmd_buffer->device->dfsm_allowed) {
                radeon_emit(cmd_buffer->cs, PKT3(PKT3_EVENT_WRITE, 0, 0));
                radeon_emit(cmd_buffer->cs, EVENT_TYPE(V_028A90_FLUSH_DFSM) | EVENT_INDEX(0));
        }
        if (pipeline->shaders[MESA_SHADER_FRAGMENT]->info.info.ps.needs_sample_positions) {
                uint32_t offset;
                struct ac_userdata_info *loc = radv_lookup_user_sgpr(pipeline, MESA_SHADER_FRAGMENT, AC_UD_PS_SAMPLE_POS_OFFSET);
-               uint32_t base_reg = radv_shader_stage_to_user_data_0(MESA_SHADER_FRAGMENT, cmd_buffer->device->physical_device->rad_info.chip_class, radv_pipeline_has_gs(pipeline), radv_pipeline_has_tess(pipeline));
+               uint32_t base_reg = pipeline->user_data_0[MESA_SHADER_FRAGMENT];
                if (loc->sgpr_idx == -1)
                        return;
                assert(loc->num_sgprs == 1);
@@ -615,11 +673,28 @@ radv_emit_shader_prefetch(struct radv_cmd_buffer *cmd_buffer,
 
        va = radv_buffer_get_va(shader->bo) + shader->bo_offset;
 
-       ws->cs_add_buffer(cs, shader->bo, 8);
+       radv_cs_add_buffer(ws, cs, shader->bo, 8);
        if (cmd_buffer->device->physical_device->rad_info.chip_class >= CIK)
                si_cp_dma_prefetch(cmd_buffer, va, shader->code_size);
 }
 
+static void
+radv_emit_shaders_prefetch(struct radv_cmd_buffer *cmd_buffer,
+                          struct radv_pipeline *pipeline)
+{
+       radv_emit_shader_prefetch(cmd_buffer,
+                                 pipeline->shaders[MESA_SHADER_VERTEX]);
+       radv_emit_shader_prefetch(cmd_buffer,
+                                 pipeline->shaders[MESA_SHADER_TESS_CTRL]);
+       radv_emit_shader_prefetch(cmd_buffer,
+                                 pipeline->shaders[MESA_SHADER_TESS_EVAL]);
+       radv_emit_shader_prefetch(cmd_buffer,
+                                 pipeline->shaders[MESA_SHADER_GEOMETRY]);
+       radv_emit_shader_prefetch(cmd_buffer, pipeline->gs_copy_shader);
+       radv_emit_shader_prefetch(cmd_buffer,
+                                 pipeline->shaders[MESA_SHADER_FRAGMENT]);
+}
+
 static void
 radv_emit_hw_vs(struct radv_cmd_buffer *cmd_buffer,
                struct radv_pipeline *pipeline,
@@ -629,8 +704,6 @@ radv_emit_hw_vs(struct radv_cmd_buffer *cmd_buffer,
        uint64_t va = radv_buffer_get_va(shader->bo) + shader->bo_offset;
        unsigned export_count;
 
-       radv_emit_shader_prefetch(cmd_buffer, shader);
-
        export_count = MAX2(1, outinfo->param_exports);
        radeon_set_context_reg(cmd_buffer->cs, R_0286C4_SPI_VS_OUT_CONFIG,
                               S_0286C4_VS_EXPORT_COUNT(export_count - 1));
@@ -676,8 +749,6 @@ radv_emit_hw_es(struct radv_cmd_buffer *cmd_buffer,
 {
        uint64_t va = radv_buffer_get_va(shader->bo) + shader->bo_offset;
 
-       radv_emit_shader_prefetch(cmd_buffer, shader);
-
        radeon_set_context_reg(cmd_buffer->cs, R_028AAC_VGT_ESGS_RING_ITEMSIZE,
                               outinfo->esgs_itemsize / 4);
        radeon_set_sh_reg_seq(cmd_buffer->cs, R_00B320_SPI_SHADER_PGM_LO_ES, 4);
@@ -694,8 +765,6 @@ radv_emit_hw_ls(struct radv_cmd_buffer *cmd_buffer,
        uint64_t va = radv_buffer_get_va(shader->bo) + shader->bo_offset;
        uint32_t rsrc2 = shader->rsrc2;
 
-       radv_emit_shader_prefetch(cmd_buffer, shader);
-
        radeon_set_sh_reg_seq(cmd_buffer->cs, R_00B520_SPI_SHADER_PGM_LO_LS, 2);
        radeon_emit(cmd_buffer->cs, va >> 8);
        radeon_emit(cmd_buffer->cs, va >> 40);
@@ -716,8 +785,6 @@ radv_emit_hw_hs(struct radv_cmd_buffer *cmd_buffer,
 {
        uint64_t va = radv_buffer_get_va(shader->bo) + shader->bo_offset;
 
-       radv_emit_shader_prefetch(cmd_buffer, shader);
-
        if (cmd_buffer->device->physical_device->rad_info.chip_class >= GFX9) {
                radeon_set_sh_reg_seq(cmd_buffer->cs, R_00B410_SPI_SHADER_PGM_LO_LS, 2);
                radeon_emit(cmd_buffer->cs, va >> 8);
@@ -793,7 +860,7 @@ radv_emit_tess_shaders(struct radv_cmd_buffer *cmd_buffer,
 
        loc = radv_lookup_user_sgpr(pipeline, MESA_SHADER_TESS_CTRL, AC_UD_TCS_OFFCHIP_LAYOUT);
        if (loc->sgpr_idx != -1) {
-               uint32_t base_reg = radv_shader_stage_to_user_data_0(MESA_SHADER_TESS_CTRL, cmd_buffer->device->physical_device->rad_info.chip_class, radv_pipeline_has_gs(pipeline), radv_pipeline_has_tess(pipeline));
+               uint32_t base_reg = pipeline->user_data_0[MESA_SHADER_TESS_CTRL];
                assert(loc->num_sgprs == 4);
                assert(!loc->indirect);
                radeon_set_sh_reg_seq(cmd_buffer->cs, base_reg + loc->sgpr_idx * 4, 4);
@@ -806,7 +873,7 @@ radv_emit_tess_shaders(struct radv_cmd_buffer *cmd_buffer,
 
        loc = radv_lookup_user_sgpr(pipeline, MESA_SHADER_TESS_EVAL, AC_UD_TES_OFFCHIP_LAYOUT);
        if (loc->sgpr_idx != -1) {
-               uint32_t base_reg = radv_shader_stage_to_user_data_0(MESA_SHADER_TESS_EVAL, cmd_buffer->device->physical_device->rad_info.chip_class, radv_pipeline_has_gs(pipeline), radv_pipeline_has_tess(pipeline));
+               uint32_t base_reg = pipeline->user_data_0[MESA_SHADER_TESS_EVAL];
                assert(loc->num_sgprs == 1);
                assert(!loc->indirect);
 
@@ -816,7 +883,7 @@ radv_emit_tess_shaders(struct radv_cmd_buffer *cmd_buffer,
 
        loc = radv_lookup_user_sgpr(pipeline, MESA_SHADER_VERTEX, AC_UD_VS_LS_TCS_IN_LAYOUT);
        if (loc->sgpr_idx != -1) {
-               uint32_t base_reg = radv_shader_stage_to_user_data_0(MESA_SHADER_VERTEX, cmd_buffer->device->physical_device->rad_info.chip_class, radv_pipeline_has_gs(pipeline), radv_pipeline_has_tess(pipeline));
+               uint32_t base_reg = pipeline->user_data_0[MESA_SHADER_VERTEX];
                assert(loc->num_sgprs == 1);
                assert(!loc->indirect);
 
@@ -863,8 +930,6 @@ radv_emit_geometry_shader(struct radv_cmd_buffer *cmd_buffer,
 
        va = radv_buffer_get_va(gs->bo) + gs->bo_offset;
 
-       radv_emit_shader_prefetch(cmd_buffer, gs);
-
        if (cmd_buffer->device->physical_device->rad_info.chip_class >= GFX9) {
                radeon_set_sh_reg_seq(cmd_buffer->cs, R_00B210_SPI_SHADER_PGM_LO_ES, 2);
                radeon_emit(cmd_buffer->cs, va >> 8);
@@ -918,8 +983,6 @@ radv_emit_fragment_shader(struct radv_cmd_buffer *cmd_buffer,
        ps = pipeline->shaders[MESA_SHADER_FRAGMENT];
        va = radv_buffer_get_va(ps->bo) + ps->bo_offset;
 
-       radv_emit_shader_prefetch(cmd_buffer, ps);
-
        radeon_set_sh_reg_seq(cmd_buffer->cs, R_00B020_SPI_SHADER_PGM_LO_PS, 4);
        radeon_emit(cmd_buffer->cs, va >> 8);
        radeon_emit(cmd_buffer->cs, va >> 40);
@@ -951,7 +1014,7 @@ radv_emit_fragment_shader(struct radv_cmd_buffer *cmd_buffer,
        radeon_set_context_reg(cmd_buffer->cs, R_028238_CB_TARGET_MASK, blend->cb_target_mask);
        radeon_set_context_reg(cmd_buffer->cs, R_02823C_CB_SHADER_MASK, blend->cb_shader_mask);
 
-       if (cmd_buffer->device->physical_device->rad_info.chip_class >= GFX9) {
+       if (cmd_buffer->device->dfsm_allowed) {
                /* optimise this? */
                radeon_emit(cmd_buffer->cs, PKT3(PKT3_EVENT_WRITE, 0, 0));
                radeon_emit(cmd_buffer->cs, EVENT_TYPE(V_028A90_FLUSH_DFSM) | EVENT_INDEX(0));
@@ -1247,7 +1310,7 @@ radv_set_depth_clear_regs(struct radv_cmd_buffer *cmd_buffer,
        if (aspects & VK_IMAGE_ASPECT_DEPTH_BIT)
                ++reg_count;
 
-       cmd_buffer->device->ws->cs_add_buffer(cmd_buffer->cs, image->bo, 8);
+       radv_cs_add_buffer(cmd_buffer->device->ws, cmd_buffer->cs, image->bo, 8);
 
        radeon_emit(cmd_buffer->cs, PKT3(PKT3_WRITE_DATA, 2 + reg_count, 0));
        radeon_emit(cmd_buffer->cs, S_370_DST_SEL(V_370_MEM_ASYNC) |
@@ -1277,7 +1340,6 @@ radv_load_depth_clear_regs(struct radv_cmd_buffer *cmd_buffer,
        if (!image->surface.htile_size)
                return;
 
-       cmd_buffer->device->ws->cs_add_buffer(cmd_buffer->cs, image->bo, 8);
 
        radeon_emit(cmd_buffer->cs, PKT3(PKT3_COPY_DATA, 4, 0));
        radeon_emit(cmd_buffer->cs, COPY_DATA_SRC_SEL(COPY_DATA_MEM) |
@@ -1309,7 +1371,7 @@ radv_set_dcc_need_cmask_elim_pred(struct radv_cmd_buffer *cmd_buffer,
        if (!image->surface.dcc_size)
                return;
 
-       cmd_buffer->device->ws->cs_add_buffer(cmd_buffer->cs, image->bo, 8);
+       radv_cs_add_buffer(cmd_buffer->device->ws, cmd_buffer->cs, image->bo, 8);
 
        radeon_emit(cmd_buffer->cs, PKT3(PKT3_WRITE_DATA, 4, 0));
        radeon_emit(cmd_buffer->cs, S_370_DST_SEL(V_370_MEM_ASYNC) |
@@ -1333,7 +1395,7 @@ radv_set_color_clear_regs(struct radv_cmd_buffer *cmd_buffer,
        if (!image->cmask.size && !image->surface.dcc_size)
                return;
 
-       cmd_buffer->device->ws->cs_add_buffer(cmd_buffer->cs, image->bo, 8);
+       radv_cs_add_buffer(cmd_buffer->device->ws, cmd_buffer->cs, image->bo, 8);
 
        radeon_emit(cmd_buffer->cs, PKT3(PKT3_WRITE_DATA, 4, 0));
        radeon_emit(cmd_buffer->cs, S_370_DST_SEL(V_370_MEM_ASYNC) |
@@ -1361,7 +1423,6 @@ radv_load_color_clear_regs(struct radv_cmd_buffer *cmd_buffer,
                return;
 
        uint32_t reg = R_028C8C_CB_COLOR0_CLEAR_WORD0 + idx * 0x3c;
-       cmd_buffer->device->ws->cs_add_buffer(cmd_buffer->cs, image->bo, 8);
 
        radeon_emit(cmd_buffer->cs, PKT3(PKT3_COPY_DATA, 4, cmd_buffer->state.predicating));
        radeon_emit(cmd_buffer->cs, COPY_DATA_SRC_SEL(COPY_DATA_MEM) |
@@ -1397,7 +1458,7 @@ radv_emit_framebuffer_state(struct radv_cmd_buffer *cmd_buffer)
                int idx = subpass->color_attachments[i].attachment;
                struct radv_attachment_info *att = &framebuffer->attachments[idx];
 
-               cmd_buffer->device->ws->cs_add_buffer(cmd_buffer->cs, att->attachment->bo, 8);
+               radv_cs_add_buffer(cmd_buffer->device->ws, cmd_buffer->cs, att->attachment->bo, 8);
 
                assert(att->attachment->aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT);
                radv_emit_fb_color_state(cmd_buffer, i, &att->cb);
@@ -1410,7 +1471,7 @@ radv_emit_framebuffer_state(struct radv_cmd_buffer *cmd_buffer)
                VkImageLayout layout = subpass->depth_stencil_attachment.layout;
                struct radv_attachment_info *att = &framebuffer->attachments[idx];
                struct radv_image *image = att->attachment->image;
-               cmd_buffer->device->ws->cs_add_buffer(cmd_buffer->cs, att->attachment->bo, 8);
+               radv_cs_add_buffer(cmd_buffer->device->ws, cmd_buffer->cs, att->attachment->bo, 8);
                MAYBE_UNUSED uint32_t queue_mask = radv_image_queue_family_mask(image,
                                                                                cmd_buffer->queue_family_index,
                                                                                cmd_buffer->queue_family_index);
@@ -1438,7 +1499,7 @@ radv_emit_framebuffer_state(struct radv_cmd_buffer *cmd_buffer)
                               S_028208_BR_X(framebuffer->width) |
                               S_028208_BR_Y(framebuffer->height));
 
-       if (cmd_buffer->device->physical_device->rad_info.chip_class >= GFX9) {
+       if (cmd_buffer->device->dfsm_allowed) {
                radeon_emit(cmd_buffer->cs, PKT3(PKT3_EVENT_WRITE, 0, 0));
                radeon_emit(cmd_buffer->cs, EVENT_TYPE(V_028A90_BREAK_BATCH) | EVENT_INDEX(0));
        }
@@ -1518,8 +1579,7 @@ radv_cmd_buffer_flush_dynamic_state(struct radv_cmd_buffer *cmd_buffer)
                                       RADV_CMD_DIRTY_DYNAMIC_STENCIL_COMPARE_MASK))
                radv_emit_stencil(cmd_buffer);
 
-       if (cmd_buffer->state.dirty & (RADV_CMD_DIRTY_PIPELINE |
-                                      RADV_CMD_DIRTY_DYNAMIC_DEPTH_BOUNDS))
+       if (cmd_buffer->state.dirty & RADV_CMD_DIRTY_DYNAMIC_DEPTH_BOUNDS)
                radv_emit_depth_bounds(cmd_buffer);
 
        if (cmd_buffer->state.dirty & (RADV_CMD_DIRTY_PIPELINE |
@@ -1537,7 +1597,7 @@ emit_stage_descriptor_set_userdata(struct radv_cmd_buffer *cmd_buffer,
                                   gl_shader_stage stage)
 {
        struct ac_userdata_info *desc_set_loc = &pipeline->shaders[stage]->info.user_sgprs_locs.descriptor_sets[idx];
-       uint32_t base_reg = radv_shader_stage_to_user_data_0(stage, cmd_buffer->device->physical_device->rad_info.chip_class, radv_pipeline_has_gs(pipeline), radv_pipeline_has_tess(pipeline));
+       uint32_t base_reg = pipeline->user_data_0[stage];
 
        if (desc_set_loc->sgpr_idx == -1 || desc_set_loc->indirect)
                return;
@@ -1600,8 +1660,8 @@ radv_flush_indirect_descriptor_sets(struct radv_cmd_buffer *cmd_buffer)
        for (unsigned i = 0; i < MAX_SETS; i++) {
                uint32_t *uptr = ((uint32_t *)ptr) + i * 2;
                uint64_t set_va = 0;
-               struct radv_descriptor_set *set = cmd_buffer->state.descriptors[i];
-               if (set)
+               struct radv_descriptor_set *set = cmd_buffer->descriptors[i];
+               if (cmd_buffer->state.valid_descriptors & (1u << i))
                        set_va = set->va;
                uptr[0] = set_va & 0xffffffff;
                uptr[1] = set_va >> 32;
@@ -1659,8 +1719,8 @@ radv_flush_descriptors(struct radv_cmd_buffer *cmd_buffer,
                                                           MAX_SETS * MESA_SHADER_STAGES * 4);
 
        for_each_bit(i, cmd_buffer->state.descriptors_dirty) {
-               struct radv_descriptor_set *set = cmd_buffer->state.descriptors[i];
-               if (!set)
+               struct radv_descriptor_set *set = cmd_buffer->descriptors[i];
+               if (!(cmd_buffer->state.valid_descriptors & (1u << i)))
                        continue;
 
                radv_emit_descriptor_set_userdata(cmd_buffer, stages, set, i);
@@ -1668,7 +1728,8 @@ radv_flush_descriptors(struct radv_cmd_buffer *cmd_buffer,
        cmd_buffer->state.descriptors_dirty = 0;
        cmd_buffer->state.push_descriptors_dirty = false;
 
-       radv_save_descriptors(cmd_buffer);
+       if (cmd_buffer->device->trace_bo)
+               radv_save_descriptors(cmd_buffer);
 
        assert(cmd_buffer->cs->cdw <= cdw_max);
 }
@@ -1714,11 +1775,11 @@ radv_flush_constants(struct radv_cmd_buffer *cmd_buffer,
 }
 
 static bool
-radv_cmd_buffer_update_vertex_descriptors(struct radv_cmd_buffer *cmd_buffer)
+radv_cmd_buffer_update_vertex_descriptors(struct radv_cmd_buffer *cmd_buffer, bool pipeline_is_dirty)
 {
        struct radv_device *device = cmd_buffer->device;
 
-       if ((cmd_buffer->state.pipeline != cmd_buffer->state.emitted_pipeline || cmd_buffer->state.vb_dirty) &&
+       if ((pipeline_is_dirty || cmd_buffer->state.vb_dirty) &&
            cmd_buffer->state.pipeline->vertex_elements.count &&
            radv_get_vertex_shader(cmd_buffer->state.pipeline)->info.info.vs.has_vertex_buffers) {
                struct radv_vertex_elements_info *velems = &cmd_buffer->state.pipeline->vertex_elements;
@@ -1737,13 +1798,13 @@ radv_cmd_buffer_update_vertex_descriptors(struct radv_cmd_buffer *cmd_buffer)
                        uint32_t *desc = &((uint32_t *)vb_ptr)[i * 4];
                        uint32_t offset;
                        int vb = velems->binding[i];
-                       struct radv_buffer *buffer = cmd_buffer->state.vertex_bindings[vb].buffer;
+                       struct radv_buffer *buffer = cmd_buffer->vertex_bindings[vb].buffer;
                        uint32_t stride = cmd_buffer->state.pipeline->binding_stride[vb];
 
-                       device->ws->cs_add_buffer(cmd_buffer->cs, buffer->bo, 8);
+                       radv_cs_add_buffer(device->ws, cmd_buffer->cs, buffer->bo, 8);
                        va = radv_buffer_get_va(buffer->bo);
 
-                       offset = cmd_buffer->state.vertex_bindings[vb].offset + velems->offset[i];
+                       offset = cmd_buffer->vertex_bindings[vb].offset + velems->offset[i];
                        va += offset + buffer->offset;
                        desc[0] = va;
                        desc[1] = S_008F04_BASE_ADDRESS_HI(va >> 32) | S_008F04_STRIDE(stride);
@@ -1765,6 +1826,19 @@ radv_cmd_buffer_update_vertex_descriptors(struct radv_cmd_buffer *cmd_buffer)
        return true;
 }
 
+static bool
+radv_upload_graphics_shader_descriptors(struct radv_cmd_buffer *cmd_buffer, bool pipeline_is_dirty)
+{
+       if (!radv_cmd_buffer_update_vertex_descriptors(cmd_buffer, pipeline_is_dirty))
+               return false;
+
+       radv_flush_descriptors(cmd_buffer, VK_SHADER_STAGE_ALL_GRAPHICS);
+       radv_flush_constants(cmd_buffer, cmd_buffer->state.pipeline,
+                            VK_SHADER_STAGE_ALL_GRAPHICS);
+
+       return true;
+}
+
 static void
 radv_emit_draw_registers(struct radv_cmd_buffer *cmd_buffer, bool indexed_draw,
                         bool instanced_draw, bool indirect_draw,
@@ -2124,7 +2198,7 @@ static void emit_gfx_buffer_state(struct radv_cmd_buffer *cmd_buffer)
        struct radv_device *device = cmd_buffer->device;
        if (device->gfx_init) {
                uint64_t va = radv_buffer_get_va(device->gfx_init);
-               device->ws->cs_add_buffer(cmd_buffer->cs, device->gfx_init, 8);
+               radv_cs_add_buffer(device->ws, cmd_buffer->cs, device->gfx_init, 8);
                radeon_emit(cmd_buffer->cs, PKT3(PKT3_INDIRECT_BUFFER_CIK, 2, 0));
                radeon_emit(cmd_buffer->cs, va);
                radeon_emit(cmd_buffer->cs, va >> 32);
@@ -2190,15 +2264,29 @@ void radv_CmdBindVertexBuffers(
        const VkDeviceSize*                         pOffsets)
 {
        RADV_FROM_HANDLE(radv_cmd_buffer, cmd_buffer, commandBuffer);
-       struct radv_vertex_binding *vb = cmd_buffer->state.vertex_bindings;
+       struct radv_vertex_binding *vb = cmd_buffer->vertex_bindings;
+       bool changed = false;
 
        /* We have to defer setting up vertex buffer since we need the buffer
         * stride from the pipeline. */
 
        assert(firstBinding + bindingCount <= MAX_VBS);
        for (uint32_t i = 0; i < bindingCount; i++) {
-               vb[firstBinding + i].buffer = radv_buffer_from_handle(pBuffers[i]);
-               vb[firstBinding + i].offset = pOffsets[i];
+               uint32_t idx = firstBinding + i;
+
+               if (!changed &&
+                   (vb[idx].buffer != radv_buffer_from_handle(pBuffers[i]) ||
+                    vb[idx].offset != pOffsets[i])) {
+                       changed = true;
+               }
+
+               vb[idx].buffer = radv_buffer_from_handle(pBuffers[i]);
+               vb[idx].offset = pOffsets[i];
+       }
+
+       if (!changed) {
+               /* No state changes. */
+               return;
        }
 
        cmd_buffer->state.vb_dirty = true;
@@ -2213,6 +2301,15 @@ void radv_CmdBindIndexBuffer(
        RADV_FROM_HANDLE(radv_cmd_buffer, cmd_buffer, commandBuffer);
        RADV_FROM_HANDLE(radv_buffer, index_buffer, buffer);
 
+       if (cmd_buffer->state.index_buffer == index_buffer &&
+           cmd_buffer->state.index_offset == offset &&
+           cmd_buffer->state.index_type == indexType) {
+               /* No state changes. */
+               return;
+       }
+
+       cmd_buffer->state.index_buffer = index_buffer;
+       cmd_buffer->state.index_offset = offset;
        cmd_buffer->state.index_type = indexType; /* vk matches hw */
        cmd_buffer->state.index_va = radv_buffer_get_va(index_buffer->bo);
        cmd_buffer->state.index_va += index_buffer->offset + offset;
@@ -2220,18 +2317,17 @@ void radv_CmdBindIndexBuffer(
        int index_size_shift = cmd_buffer->state.index_type ? 2 : 1;
        cmd_buffer->state.max_index_count = (index_buffer->size - offset) >> index_size_shift;
        cmd_buffer->state.dirty |= RADV_CMD_DIRTY_INDEX_BUFFER;
-       cmd_buffer->device->ws->cs_add_buffer(cmd_buffer->cs, index_buffer->bo, 8);
+       radv_cs_add_buffer(cmd_buffer->device->ws, cmd_buffer->cs, index_buffer->bo, 8);
 }
 
 
-void radv_bind_descriptor_set(struct radv_cmd_buffer *cmd_buffer,
-                             struct radv_descriptor_set *set,
-                             unsigned idx)
+static void
+radv_bind_descriptor_set(struct radv_cmd_buffer *cmd_buffer,
+                        struct radv_descriptor_set *set, unsigned idx)
 {
        struct radeon_winsys *ws = cmd_buffer->device->ws;
 
-       cmd_buffer->state.descriptors[idx] = set;
-       cmd_buffer->state.descriptors_dirty |= (1u << idx);
+       radv_set_descriptor_set(cmd_buffer, set, idx);
        if (!set)
                return;
 
@@ -2239,10 +2335,10 @@ void radv_bind_descriptor_set(struct radv_cmd_buffer *cmd_buffer,
 
        for (unsigned j = 0; j < set->layout->buffer_count; ++j)
                if (set->descriptors[j])
-                       ws->cs_add_buffer(cmd_buffer->cs, set->descriptors[j], 7);
+                       radv_cs_add_buffer(ws, cmd_buffer->cs, set->descriptors[j], 7);
 
        if(set->bo)
-               ws->cs_add_buffer(cmd_buffer->cs, set->bo, 8);
+               radv_cs_add_buffer(ws, cmd_buffer->cs, set->bo, 8);
 }
 
 void radv_CmdBindDescriptorSets(
@@ -2343,8 +2439,7 @@ void radv_meta_push_descriptor_set(
                                    radv_descriptor_set_to_handle(push_set),
                                    descriptorWriteCount, pDescriptorWrites, 0, NULL);
 
-       cmd_buffer->state.descriptors[set] = push_set;
-       cmd_buffer->state.descriptors_dirty |= (1u << set);
+       radv_set_descriptor_set(cmd_buffer, push_set, set);
 }
 
 void radv_CmdPushDescriptorSetKHR(
@@ -2368,8 +2463,7 @@ void radv_CmdPushDescriptorSetKHR(
                                    radv_descriptor_set_to_handle(push_set),
                                    descriptorWriteCount, pDescriptorWrites, 0, NULL);
 
-       cmd_buffer->state.descriptors[set] = push_set;
-       cmd_buffer->state.descriptors_dirty |= (1u << set);
+       radv_set_descriptor_set(cmd_buffer, push_set, set);
        cmd_buffer->state.push_descriptors_dirty = true;
 }
 
@@ -2392,8 +2486,7 @@ void radv_CmdPushDescriptorSetWithTemplateKHR(
        radv_update_descriptor_set_with_template(cmd_buffer->device, cmd_buffer, push_set,
                                                 descriptorUpdateTemplate, pData);
 
-       cmd_buffer->state.descriptors[set] = push_set;
-       cmd_buffer->state.descriptors_dirty |= (1u << set);
+       radv_set_descriptor_set(cmd_buffer, push_set, set);
        cmd_buffer->state.push_descriptors_dirty = true;
 }
 
@@ -2420,6 +2513,8 @@ VkResult radv_EndCommandBuffer(
                si_emit_cache_flush(cmd_buffer);
        }
 
+       vk_free(&cmd_buffer->pool->alloc, cmd_buffer->state.attachments);
+
        if (!cmd_buffer->device->ws->cs_finalize(cmd_buffer->cs))
                return VK_ERROR_OUT_OF_DEVICE_MEMORY;
 
@@ -2441,8 +2536,6 @@ radv_emit_compute_pipeline(struct radv_cmd_buffer *cmd_buffer)
        compute_shader = pipeline->shaders[MESA_SHADER_COMPUTE];
        va = radv_buffer_get_va(compute_shader->bo) + compute_shader->bo_offset;
 
-       radv_emit_shader_prefetch(cmd_buffer, compute_shader);
-
        MAYBE_UNUSED unsigned cdw_max = radeon_check_space(cmd_buffer->device->ws,
                                                           cmd_buffer->cs, 16);
 
@@ -2478,10 +2571,7 @@ radv_emit_compute_pipeline(struct radv_cmd_buffer *cmd_buffer)
 
 static void radv_mark_descriptor_sets_dirty(struct radv_cmd_buffer *cmd_buffer)
 {
-       for (unsigned i = 0; i < MAX_SETS; i++) {
-               if (cmd_buffer->state.descriptors[i])
-                       cmd_buffer->state.descriptors_dirty |= (1u << i);
-       }
+       cmd_buffer->state.descriptors_dirty |= cmd_buffer->state.valid_descriptors;
 }
 
 void radv_CmdBindPipeline(
@@ -2513,11 +2603,7 @@ void radv_CmdBindPipeline(
                cmd_buffer->state.dirty |= RADV_CMD_DIRTY_PIPELINE;
                cmd_buffer->push_constant_stages |= pipeline->active_stages;
 
-               /* Apply the dynamic state from the pipeline */
-               cmd_buffer->state.dirty |= pipeline->dynamic_state_mask;
-               radv_dynamic_state_copy(&cmd_buffer->state.dynamic,
-                                       &pipeline->dynamic_state,
-                                       pipeline->dynamic_state_mask);
+               radv_bind_dynamic_state(cmd_buffer, &pipeline->dynamic_state);
 
                if (pipeline->graphics.esgs_ring_size > cmd_buffer->esgs_ring_size_needed)
                        cmd_buffer->esgs_ring_size_needed = pipeline->graphics.esgs_ring_size;
@@ -2890,7 +2976,7 @@ static void radv_emit_view_index(struct radv_cmd_buffer *cmd_buffer, unsigned in
                struct ac_userdata_info *loc = radv_lookup_user_sgpr(pipeline, stage, AC_UD_VIEW_INDEX);
                if (loc->sgpr_idx == -1)
                        continue;
-               uint32_t base_reg = radv_shader_stage_to_user_data_0(stage, cmd_buffer->device->physical_device->rad_info.chip_class, radv_pipeline_has_gs(pipeline), radv_pipeline_has_tess(pipeline));
+               uint32_t base_reg = pipeline->user_data_0[stage];
                radeon_set_sh_reg(cmd_buffer->cs, base_reg + loc->sgpr_idx * 4, index);
 
        }
@@ -2936,7 +3022,7 @@ radv_cs_emit_indirect_draw_packet(struct radv_cmd_buffer *cmd_buffer,
        struct radeon_winsys_cs *cs = cmd_buffer->cs;
        unsigned di_src_sel = indexed ? V_0287F0_DI_SRC_SEL_DMA
                                      : V_0287F0_DI_SRC_SEL_AUTO_INDEX;
-       bool draw_id_enable = cmd_buffer->state.pipeline->shaders[MESA_SHADER_VERTEX]->info.info.vs.needs_draw_id;
+       bool draw_id_enable = radv_get_vertex_shader(cmd_buffer->state.pipeline)->info.info.vs.needs_draw_id;
        uint32_t base_reg = cmd_buffer->state.pipeline->graphics.vtx_base_sgpr;
        assert(base_reg);
 
@@ -3024,7 +3110,7 @@ radv_emit_draw_packets(struct radv_cmd_buffer *cmd_buffer,
 
                va += info->indirect->offset + info->indirect_offset;
 
-               ws->cs_add_buffer(cs, info->indirect->bo, 8);
+               radv_cs_add_buffer(ws, cs, info->indirect->bo, 8);
 
                radeon_emit(cs, PKT3(PKT3_SET_BASE, 2, 0));
                radeon_emit(cs, 1);
@@ -3036,7 +3122,7 @@ radv_emit_draw_packets(struct radv_cmd_buffer *cmd_buffer,
                        count_va += info->count_buffer->offset +
                                    info->count_buffer_offset;
 
-                       ws->cs_add_buffer(cs, info->count_buffer->bo, 8);
+                       radv_cs_add_buffer(ws, cs, info->count_buffer->bo, 8);
                }
 
                if (!state->subpass->view_mask) {
@@ -3107,16 +3193,9 @@ radv_emit_draw_packets(struct radv_cmd_buffer *cmd_buffer,
 }
 
 static void
-radv_draw(struct radv_cmd_buffer *cmd_buffer,
-         const struct radv_draw_info *info)
+radv_emit_all_graphics_states(struct radv_cmd_buffer *cmd_buffer,
+                             const struct radv_draw_info *info)
 {
-       MAYBE_UNUSED unsigned cdw_max =
-               radeon_check_space(cmd_buffer->device->ws,
-                                  cmd_buffer->cs, 4096);
-
-       if (!radv_cmd_buffer_update_vertex_descriptors(cmd_buffer))
-               return;
-
        if (cmd_buffer->state.dirty & RADV_CMD_DIRTY_PIPELINE)
                radv_emit_graphics_pipeline(cmd_buffer);
 
@@ -3135,19 +3214,75 @@ radv_draw(struct radv_cmd_buffer *cmd_buffer,
                        cmd_buffer->state.dirty |= RADV_CMD_DIRTY_INDEX_BUFFER;
        }
 
+       radv_cmd_buffer_flush_dynamic_state(cmd_buffer);
+
        radv_emit_draw_registers(cmd_buffer, info->indexed,
                                 info->instance_count > 1, info->indirect,
                                 info->indirect ? 0 : info->count);
+}
 
-       radv_cmd_buffer_flush_dynamic_state(cmd_buffer);
+static void
+radv_draw(struct radv_cmd_buffer *cmd_buffer,
+         const struct radv_draw_info *info)
+{
+       bool pipeline_is_dirty =
+               (cmd_buffer->state.dirty & RADV_CMD_DIRTY_PIPELINE) &&
+               cmd_buffer->state.pipeline &&
+               cmd_buffer->state.pipeline != cmd_buffer->state.emitted_pipeline;
 
-       radv_flush_descriptors(cmd_buffer, VK_SHADER_STAGE_ALL_GRAPHICS);
-       radv_flush_constants(cmd_buffer, cmd_buffer->state.pipeline,
-                            VK_SHADER_STAGE_ALL_GRAPHICS);
+       MAYBE_UNUSED unsigned cdw_max =
+               radeon_check_space(cmd_buffer->device->ws,
+                                  cmd_buffer->cs, 4096);
 
-       si_emit_cache_flush(cmd_buffer);
+       /* Use optimal packet order based on whether we need to sync the
+        * pipeline.
+        */
+       if (cmd_buffer->state.flush_bits & (RADV_CMD_FLAG_FLUSH_AND_INV_CB |
+                                           RADV_CMD_FLAG_FLUSH_AND_INV_DB |
+                                           RADV_CMD_FLAG_PS_PARTIAL_FLUSH |
+                                           RADV_CMD_FLAG_CS_PARTIAL_FLUSH)) {
+               /* If we have to wait for idle, set all states first, so that
+                * all SET packets are processed in parallel with previous draw
+                * calls. Then upload descriptors, set shader pointers, and
+                * draw, and prefetch at the end. This ensures that the time
+                * the CUs are idle is very short. (there are only SET_SH
+                * packets between the wait and the draw)
+                */
+               radv_emit_all_graphics_states(cmd_buffer, info);
+               si_emit_cache_flush(cmd_buffer);
+               /* <-- CUs are idle here --> */
+
+               if (!radv_upload_graphics_shader_descriptors(cmd_buffer, pipeline_is_dirty))
+                       return;
 
-       radv_emit_draw_packets(cmd_buffer, info);
+               radv_emit_draw_packets(cmd_buffer, info);
+               /* <-- CUs are busy here --> */
+
+               /* Start prefetches after the draw has been started. Both will
+                * run in parallel, but starting the draw first is more
+                * important.
+                */
+               if (pipeline_is_dirty) {
+                       radv_emit_shaders_prefetch(cmd_buffer,
+                                                  cmd_buffer->state.pipeline);
+               }
+       } else {
+               /* If we don't wait for idle, start prefetches first, then set
+                * states, and draw at the end.
+                */
+               si_emit_cache_flush(cmd_buffer);
+
+               if (pipeline_is_dirty) {
+                       radv_emit_shaders_prefetch(cmd_buffer,
+                                                  cmd_buffer->state.pipeline);
+               }
+
+               if (!radv_upload_graphics_shader_descriptors(cmd_buffer, pipeline_is_dirty))
+                       return;
+
+               radv_emit_all_graphics_states(cmd_buffer, info);
+               radv_emit_draw_packets(cmd_buffer, info);
+       }
 
        assert(cmd_buffer->cs->cdw <= cdw_max);
        radv_cmd_buffer_after_draw(cmd_buffer);
@@ -3332,7 +3467,7 @@ radv_emit_dispatch_packets(struct radv_cmd_buffer *cmd_buffer,
 
                va += info->indirect->offset + info->indirect_offset;
 
-               ws->cs_add_buffer(cs, info->indirect->bo, 8);
+               radv_cs_add_buffer(ws, cs, info->indirect->bo, 8);
 
                if (loc->sgpr_idx != -1) {
                        for (unsigned i = 0; i < grid_used; ++i) {
@@ -3425,18 +3560,65 @@ radv_emit_dispatch_packets(struct radv_cmd_buffer *cmd_buffer,
 }
 
 static void
-radv_dispatch(struct radv_cmd_buffer *cmd_buffer,
-             const struct radv_dispatch_info *info)
+radv_upload_compute_shader_descriptors(struct radv_cmd_buffer *cmd_buffer)
 {
-       radv_emit_compute_pipeline(cmd_buffer);
-
        radv_flush_descriptors(cmd_buffer, VK_SHADER_STAGE_COMPUTE_BIT);
        radv_flush_constants(cmd_buffer, cmd_buffer->state.compute_pipeline,
                             VK_SHADER_STAGE_COMPUTE_BIT);
+}
+
+static void
+radv_dispatch(struct radv_cmd_buffer *cmd_buffer,
+             const struct radv_dispatch_info *info)
+{
+       struct radv_pipeline *pipeline = cmd_buffer->state.compute_pipeline;
+       bool pipeline_is_dirty = pipeline &&
+                                pipeline != cmd_buffer->state.emitted_compute_pipeline;
+
+       if (cmd_buffer->state.flush_bits & (RADV_CMD_FLAG_FLUSH_AND_INV_CB |
+                                           RADV_CMD_FLAG_FLUSH_AND_INV_DB |
+                                           RADV_CMD_FLAG_PS_PARTIAL_FLUSH |
+                                           RADV_CMD_FLAG_CS_PARTIAL_FLUSH)) {
+               /* If we have to wait for idle, set all states first, so that
+                * all SET packets are processed in parallel with previous draw
+                * calls. Then upload descriptors, set shader pointers, and
+                * dispatch, and prefetch at the end. This ensures that the
+                * time the CUs are idle is very short. (there are only SET_SH
+                * packets between the wait and the draw)
+                */
+               radv_emit_compute_pipeline(cmd_buffer);
+               si_emit_cache_flush(cmd_buffer);
+               /* <-- CUs are idle here --> */
 
-       si_emit_cache_flush(cmd_buffer);
+               radv_upload_compute_shader_descriptors(cmd_buffer);
 
-       radv_emit_dispatch_packets(cmd_buffer, info);
+               radv_emit_dispatch_packets(cmd_buffer, info);
+               /* <-- CUs are busy here --> */
+
+               /* Start prefetches after the dispatch has been started. Both
+                * will run in parallel, but starting the dispatch first is
+                * more important.
+                */
+               if (pipeline_is_dirty) {
+                       radv_emit_shader_prefetch(cmd_buffer,
+                                                 pipeline->shaders[MESA_SHADER_COMPUTE]);
+               }
+       } else {
+               /* If we don't wait for idle, start prefetches first, then set
+                * states, and dispatch at the end.
+                */
+               si_emit_cache_flush(cmd_buffer);
+
+               if (pipeline_is_dirty) {
+                       radv_emit_shader_prefetch(cmd_buffer,
+                                                 pipeline->shaders[MESA_SHADER_COMPUTE]);
+               }
+
+               radv_upload_compute_shader_descriptors(cmd_buffer);
+
+               radv_emit_compute_pipeline(cmd_buffer);
+               radv_emit_dispatch_packets(cmd_buffer, info);
+       }
 
        radv_cmd_buffer_after_draw(cmd_buffer);
 }
@@ -3528,16 +3710,15 @@ static void radv_initialize_htile(struct radv_cmd_buffer *cmd_buffer,
        uint64_t size = image->surface.htile_slice_size * layer_count;
        uint64_t offset = image->offset + image->htile_offset +
                          image->surface.htile_slice_size * range->baseArrayLayer;
+       struct radv_cmd_state *state = &cmd_buffer->state;
 
-       cmd_buffer->state.flush_bits |= RADV_CMD_FLAG_FLUSH_AND_INV_DB |
-                                       RADV_CMD_FLAG_FLUSH_AND_INV_DB_META;
+       state->flush_bits |= RADV_CMD_FLAG_FLUSH_AND_INV_DB |
+                            RADV_CMD_FLAG_FLUSH_AND_INV_DB_META;
 
-       radv_fill_buffer(cmd_buffer, image->bo, offset, size, clear_word);
+       state->flush_bits |= radv_fill_buffer(cmd_buffer, image->bo, offset,
+                                             size, clear_word);
 
-       cmd_buffer->state.flush_bits |= RADV_CMD_FLAG_FLUSH_AND_INV_DB_META |
-                                       RADV_CMD_FLAG_CS_PARTIAL_FLUSH |
-                                       RADV_CMD_FLAG_INV_VMEM_L1 |
-                                       RADV_CMD_FLAG_WRITEBACK_GLOBAL_L2;
+       state->flush_bits |= RADV_CMD_FLAG_FLUSH_AND_INV_DB_META;
 }
 
 static void radv_handle_depth_image_transition(struct radv_cmd_buffer *cmd_buffer,
@@ -3583,16 +3764,16 @@ static void radv_handle_depth_image_transition(struct radv_cmd_buffer *cmd_buffe
 void radv_initialise_cmask(struct radv_cmd_buffer *cmd_buffer,
                           struct radv_image *image, uint32_t value)
 {
-       cmd_buffer->state.flush_bits |= RADV_CMD_FLAG_FLUSH_AND_INV_CB |
-                                       RADV_CMD_FLAG_FLUSH_AND_INV_CB_META;
+       struct radv_cmd_state *state = &cmd_buffer->state;
 
-       radv_fill_buffer(cmd_buffer, image->bo, image->offset + image->cmask.offset,
-                        image->cmask.size, value);
+       state->flush_bits |= RADV_CMD_FLAG_FLUSH_AND_INV_CB |
+                           RADV_CMD_FLAG_FLUSH_AND_INV_CB_META;
 
-       cmd_buffer->state.flush_bits |= RADV_CMD_FLAG_FLUSH_AND_INV_CB_META |
-                                       RADV_CMD_FLAG_CS_PARTIAL_FLUSH |
-                                       RADV_CMD_FLAG_INV_VMEM_L1 |
-                                       RADV_CMD_FLAG_WRITEBACK_GLOBAL_L2;
+       state->flush_bits |= radv_fill_buffer(cmd_buffer, image->bo,
+                                             image->offset + image->cmask.offset,
+                                             image->cmask.size, value);
+
+       state->flush_bits |= RADV_CMD_FLAG_FLUSH_AND_INV_CB_META;
 }
 
 static void radv_handle_cmask_image_transition(struct radv_cmd_buffer *cmd_buffer,
@@ -3617,18 +3798,17 @@ static void radv_handle_cmask_image_transition(struct radv_cmd_buffer *cmd_buffe
 void radv_initialize_dcc(struct radv_cmd_buffer *cmd_buffer,
                         struct radv_image *image, uint32_t value)
 {
+       struct radv_cmd_state *state = &cmd_buffer->state;
 
-       cmd_buffer->state.flush_bits |= RADV_CMD_FLAG_FLUSH_AND_INV_CB |
-                                       RADV_CMD_FLAG_FLUSH_AND_INV_CB_META;
+       state->flush_bits |= RADV_CMD_FLAG_FLUSH_AND_INV_CB |
+                            RADV_CMD_FLAG_FLUSH_AND_INV_CB_META;
 
-       radv_fill_buffer(cmd_buffer, image->bo, image->offset + image->dcc_offset,
-                        image->surface.dcc_size, value);
+       state->flush_bits |= radv_fill_buffer(cmd_buffer, image->bo,
+                                             image->offset + image->dcc_offset,
+                                             image->surface.dcc_size, value);
 
-       cmd_buffer->state.flush_bits |= RADV_CMD_FLAG_FLUSH_AND_INV_CB |
-                                       RADV_CMD_FLAG_FLUSH_AND_INV_CB_META |
-                                       RADV_CMD_FLAG_CS_PARTIAL_FLUSH |
-                                       RADV_CMD_FLAG_INV_VMEM_L1 |
-                                       RADV_CMD_FLAG_WRITEBACK_GLOBAL_L2;
+       state->flush_bits |= RADV_CMD_FLAG_FLUSH_AND_INV_CB |
+                            RADV_CMD_FLAG_FLUSH_AND_INV_CB_META;
 }
 
 static void radv_handle_dcc_image_transition(struct radv_cmd_buffer *cmd_buffer,
@@ -3754,7 +3934,7 @@ static void write_event(struct radv_cmd_buffer *cmd_buffer,
        struct radeon_winsys_cs *cs = cmd_buffer->cs;
        uint64_t va = radv_buffer_get_va(event->bo);
 
-       cmd_buffer->device->ws->cs_add_buffer(cs, event->bo, 8);
+       radv_cs_add_buffer(cmd_buffer->device->ws, cs, event->bo, 8);
 
        MAYBE_UNUSED unsigned cdw_max = radeon_check_space(cmd_buffer->device->ws, cs, 18);
 
@@ -3810,7 +3990,7 @@ void radv_CmdWaitEvents(VkCommandBuffer commandBuffer,
                RADV_FROM_HANDLE(radv_event, event, pEvents[i]);
                uint64_t va = radv_buffer_get_va(event->bo);
 
-               cmd_buffer->device->ws->cs_add_buffer(cs, event->bo, 8);
+               radv_cs_add_buffer(cmd_buffer->device->ws, cs, event->bo, 8);
 
                MAYBE_UNUSED unsigned cdw_max = radeon_check_space(cmd_buffer->device->ws, cs, 7);