diff --git a/src/freedreno/vulkan/tu_cmd_buffer.cc b/src/freedreno/vulkan/tu_cmd_buffer.cc index c47f3f0e517..5de0cf30873 100644 --- a/src/freedreno/vulkan/tu_cmd_buffer.cc +++ b/src/freedreno/vulkan/tu_cmd_buffer.cc @@ -955,6 +955,7 @@ use_hw_binning(struct tu_cmd_buffer *cmd) { const struct tu_framebuffer *fb = cmd->state.framebuffer; const struct tu_tiling_config *tiling = &fb->tiling[cmd->state.gmem_layout]; + const struct tu_vsc_config *vsc = &tiling->vsc; /* XFB commands are emitted for BINNING || SYSMEM, which makes it * incompatible with non-hw binning GMEM rendering. this is required because @@ -963,7 +964,7 @@ use_hw_binning(struct tu_cmd_buffer *cmd) * XFB was used. */ if (cmd->state.rp.xfb_used) { - assert(tiling->binning_possible); + assert(vsc->binning_possible); return true; } @@ -974,11 +975,11 @@ use_hw_binning(struct tu_cmd_buffer *cmd) */ if (cmd->state.rp.has_prim_generated_query_in_rp || cmd->state.prim_generated_query_running_before_rp) { - assert(tiling->binning_possible); + assert(vsc->binning_possible); return true; } - return tiling->binning; + return vsc->binning; } static bool @@ -1013,8 +1014,10 @@ use_sysmem_rendering(struct tu_cmd_buffer *cmd, return true; } + const struct tu_vsc_config *vsc = &cmd->state.tiling->vsc; + /* XFB is incompatible with non-hw binning GMEM rendering, see use_hw_binning */ - if (cmd->state.rp.xfb_used && !cmd->state.tiling->binning_possible) { + if (cmd->state.rp.xfb_used && !vsc->binning_possible) { cmd->state.rp.gmem_disable_reason = "XFB is incompatible with non-hw binning GMEM rendering"; return true; @@ -1025,7 +1028,7 @@ use_sysmem_rendering(struct tu_cmd_buffer *cmd, */ if ((cmd->state.rp.has_prim_generated_query_in_rp || cmd->state.prim_generated_query_running_before_rp) && - !cmd->state.tiling->binning_possible) { + !vsc->binning_possible) { cmd->state.rp.gmem_disable_reason = "QUERY_TYPE_PRIMITIVES_GENERATED is incompatible with non-hw binning GMEM rendering"; return true; @@ -1056,7 +1059,9 @@ static void tu6_emit_cond_for_load_stores(struct tu_cmd_buffer *cmd, struct tu_cs *cs, uint32_t pipe, uint32_t slot, bool skip_wfm) { - if (cmd->state.tiling->binning_possible && + const struct tu_vsc_config *vsc = &cmd->state.tiling->vsc; + + if (vsc->binning_possible && cmd->state.pass->has_cond_load_store) { tu_cs_emit_pkt7(cs, CP_REG_TEST, 1); tu_cs_emit(cs, A6XX_CP_REG_TEST_0_REG(REG_A6XX_VSC_STATE_REG(pipe)) | @@ -1084,6 +1089,7 @@ tu6_emit_tile_select(struct tu_cmd_buffer *cmd, { struct tu_physical_device *phys_dev = cmd->device->physical_device; const struct tu_tiling_config *tiling = cmd->state.tiling; + const struct tu_vsc_config *vsc = &tiling->vsc; bool hw_binning = use_hw_binning(cmd); tu_cs_emit_pkt7(cs, CP_SET_MARKER, 1); @@ -1128,7 +1134,7 @@ tu6_emit_tile_select(struct tu_cmd_buffer *cmd, tu_cs_emit(cs, 0x0); tu_cs_emit_pkt7(cs, CP_SET_BIN_DATA5_OFFSET, abs_mask ? 5 : 4); - tu_cs_emit(cs, tiling->pipe_sizes[tile->pipe] | + tu_cs_emit(cs, vsc->pipe_sizes[tile->pipe] | CP_SET_BIN_DATA5_0_VSC_N(slot) | CP_SET_BIN_DATA5_0_VSC_MASK(tile->slot_mask >> slot) | COND(abs_mask, CP_SET_BIN_DATA5_0_ABS_MASK(ABS_MASK))); @@ -1246,6 +1252,7 @@ tu6_emit_tile_store(struct tu_cmd_buffer *cmd, struct tu_cs *cs) const struct tu_render_pass *pass = cmd->state.pass; const struct tu_subpass *subpass = &pass->subpasses[pass->subpass_count-1]; const struct tu_framebuffer *fb = cmd->state.framebuffer; + const struct tu_vsc_config *vsc = &cmd->state.tiling->vsc; if (pass->has_fdm) tu_cs_set_writeable(cs, true); @@ -1274,7 +1281,7 @@ tu6_emit_tile_store(struct tu_cmd_buffer *cmd, struct tu_cs *cs) for (uint32_t a = 0; a < pass->attachment_count; ++a) { if (pass->attachments[a].gmem) { - const bool cond_exec_allowed = cmd->state.tiling->binning_possible && + const bool cond_exec_allowed = vsc->binning_possible && cmd->state.pass->has_cond_load_store; tu_store_gmem_attachment(cmd, cs, &resolve_group, a, a, fb->layers, subpass->multiview_mask, @@ -1645,17 +1652,18 @@ update_vsc_pipe(struct tu_cmd_buffer *cmd, uint32_t num_vsc_pipes) { const struct tu_tiling_config *tiling = cmd->state.tiling; + const struct tu_vsc_config *vsc = &tiling->vsc; tu_cs_emit_regs(cs, A6XX_VSC_BIN_SIZE(.width = tiling->tile0.width, .height = tiling->tile0.height)); tu_cs_emit_regs(cs, - A6XX_VSC_BIN_COUNT(.nx = tiling->tile_count.width, - .ny = tiling->tile_count.height)); + A6XX_VSC_BIN_COUNT(.nx = vsc->tile_count.width, + .ny = vsc->tile_count.height)); tu_cs_emit_pkt4(cs, REG_A6XX_VSC_PIPE_CONFIG_REG(0), num_vsc_pipes); - tu_cs_emit_array(cs, tiling->pipe_config, num_vsc_pipes); + tu_cs_emit_array(cs, vsc->pipe_config, num_vsc_pipes); tu_cs_emit_regs(cs, A6XX_VSC_PRIM_STRM_PITCH(cmd->vsc_prim_strm_pitch), @@ -1672,8 +1680,9 @@ static void emit_vsc_overflow_test(struct tu_cmd_buffer *cmd, struct tu_cs *cs) { const struct tu_tiling_config *tiling = cmd->state.tiling; + const struct tu_vsc_config *vsc = &tiling->vsc; const uint32_t used_pipe_count = - tiling->pipe_count.width * tiling->pipe_count.height; + vsc->pipe_count.width * vsc->pipe_count.height; for (int i = 0; i < used_pipe_count; i++) { tu_cs_emit_pkt7(cs, CP_COND_WRITE5, 8); @@ -2168,6 +2177,7 @@ tu6_tile_render_begin(struct tu_cmd_buffer *cmd, struct tu_cs *cs, { struct tu_physical_device *phys_dev = cmd->device->physical_device; const struct tu_tiling_config *tiling = cmd->state.tiling; + const struct tu_vsc_config *vsc = &tiling->vsc; tu_lrz_tiling_begin(cmd, cs); tu_cs_emit_pkt7(cs, CP_SKIP_IB2_ENABLE_GLOBAL, 1); @@ -2226,18 +2236,18 @@ tu6_tile_render_begin(struct tu_cmd_buffer *cmd, struct tu_cs *cs, tu_cs_emit_pkt7(cs, CP_SKIP_IB2_ENABLE_LOCAL, 1); tu_cs_emit(cs, 0x1); } else { - if (tiling->binning_possible) { + if (vsc->binning_possible) { /* Mark all tiles as visible for tu6_emit_cond_for_load_stores(), since * the actual binner didn't run. */ - int pipe_count = tiling->pipe_count.width * tiling->pipe_count.height; + int pipe_count = vsc->pipe_count.width * vsc->pipe_count.height; tu_cs_emit_pkt4(cs, REG_A6XX_VSC_STATE_REG(0), pipe_count); for (int i = 0; i < pipe_count; i++) tu_cs_emit(cs, ~0); } } - if (tiling->binning_possible) { + if (vsc->binning_possible) { /* Upload state regs to memory to be restored on skipsaverestore * preemption. */ @@ -2546,6 +2556,7 @@ tu_cmd_render_tiles(struct tu_cmd_buffer *cmd, struct tu_renderpass_result *autotune_result) { const struct tu_tiling_config *tiling = cmd->state.tiling; + const struct tu_vsc_config *vsc = &tiling->vsc; const struct tu_image_view *fdm = NULL; if (cmd->state.pass->fragment_density_map.attachment != VK_ATTACHMENT_UNUSED) { @@ -2572,19 +2583,19 @@ tu_cmd_render_tiles(struct tu_cmd_buffer *cmd, /* Note: we reverse the order of walking the pipes and tiles on every * other row, to improve texture cache locality compared to raster order. */ - for (uint32_t py = 0; py < tiling->pipe_count.height; py++) { - uint32_t pipe_row = py * tiling->pipe_count.width; - for (uint32_t pipe_row_i = 0; pipe_row_i < tiling->pipe_count.width; pipe_row_i++) { + for (uint32_t py = 0; py < vsc->pipe_count.height; py++) { + uint32_t pipe_row = py * vsc->pipe_count.width; + for (uint32_t pipe_row_i = 0; pipe_row_i < vsc->pipe_count.width; pipe_row_i++) { uint32_t px; if (py & 1) - px = tiling->pipe_count.width - 1 - pipe_row_i; + px = vsc->pipe_count.width - 1 - pipe_row_i; else px = pipe_row_i; uint32_t pipe = pipe_row + px; - uint32_t tx1 = px * tiling->pipe0.width; - uint32_t ty1 = py * tiling->pipe0.height; - uint32_t tx2 = MIN2(tx1 + tiling->pipe0.width, tiling->tile_count.width); - uint32_t ty2 = MIN2(ty1 + tiling->pipe0.height, tiling->tile_count.height); + uint32_t tx1 = px * vsc->pipe0.width; + uint32_t ty1 = py * vsc->pipe0.height; + uint32_t tx2 = MIN2(tx1 + vsc->pipe0.width, vsc->tile_count.width); + uint32_t ty2 = MIN2(ty1 + vsc->pipe0.height, vsc->tile_count.height); if (merge_tiles) { tu_render_pipe_fdm(cmd, pipe, tx1, ty1, tx2, ty2, fdm); @@ -4854,6 +4865,7 @@ tu_emit_subpass_begin_gmem(struct tu_cmd_buffer *cmd, struct tu_resolve_group *r { struct tu_cs *cs = &cmd->draw_cs; uint32_t subpass_idx = cmd->state.subpass - cmd->state.pass->subpasses; + const struct tu_vsc_config *vsc = &cmd->state.tiling->vsc; /* If we might choose to bin, then put the loads under a check for geometry * having been binned to this tile. If we don't choose to bin in the end, @@ -4863,7 +4875,7 @@ tu_emit_subpass_begin_gmem(struct tu_cmd_buffer *cmd, struct tu_resolve_group *r * (perf queries), then we can't do this optimization since the * start-of-the-CS geometry condition will have been overwritten. */ - bool cond_load_allowed = cmd->state.tiling->binning && + bool cond_load_allowed = vsc->binning && cmd->state.pass->has_cond_load_store && !cmd->state.rp.draw_cs_writes_to_cond_pred; diff --git a/src/freedreno/vulkan/tu_device.h b/src/freedreno/vulkan/tu_device.h index e5d0057c05c..e8277967a0b 100644 --- a/src/freedreno/vulkan/tu_device.h +++ b/src/freedreno/vulkan/tu_device.h @@ -462,31 +462,35 @@ struct tu_attachment_info struct tu_image_view *attachment; }; -struct tu_tiling_config { - /* size of the first tile */ - VkExtent2D tile0; +struct tu_vsc_config { /* number of tiles */ VkExtent2D tile_count; - /* size of the first VSC pipe */ VkExtent2D pipe0; /* number of VSC pipes */ VkExtent2D pipe_count; - /* Whether using GMEM is even possible with this configuration */ - bool possible; + /* Whether binning could be used for gmem rendering using this framebuffer. */ + bool binning_possible; /* Whether binning should be used for gmem rendering using this framebuffer. */ bool binning; - /* Whether binning could be used for gmem rendering using this framebuffer. */ - bool binning_possible; - /* pipe register values */ uint32_t pipe_config[MAX_VSC_PIPES]; uint32_t pipe_sizes[MAX_VSC_PIPES]; }; +struct tu_tiling_config { + /* size of the first tile */ + VkExtent2D tile0; + + /* Whether using GMEM is even possible with this configuration */ + bool possible; + + struct tu_vsc_config vsc; +}; + struct tu_framebuffer { struct vk_object_base base; diff --git a/src/freedreno/vulkan/tu_tracepoints.py b/src/freedreno/vulkan/tu_tracepoints.py index 93acfc0f964..2decb2c9680 100644 --- a/src/freedreno/vulkan/tu_tracepoints.py +++ b/src/freedreno/vulkan/tu_tracepoints.py @@ -89,7 +89,7 @@ begin_end_tp('render_pass', tp_struct=[Arg(type='uint16_t', name='width', var='fb->width', c_format='%u'), Arg(type='uint16_t', name='height', var='fb->height', c_format='%u'), Arg(type='uint8_t', name='attachment_count', var='fb->attachment_count', c_format='%u'), - Arg(type='uint16_t', name='numberOfBins', var='tiling->tile_count.width * tiling->tile_count.height', c_format='%u'), + Arg(type='uint16_t', name='numberOfBins', var='tiling->vsc.tile_count.width * tiling->vsc.tile_count.height', c_format='%u'), Arg(type='uint16_t', name='binWidth', var='tiling->tile0.width', c_format='%u'), Arg(type='uint16_t', name='binHeight', var='tiling->tile0.height', c_format='%u'),], # Args known only at the end of the renderpass: diff --git a/src/freedreno/vulkan/tu_util.cc b/src/freedreno/vulkan/tu_util.cc index 5b72272e366..cf4b88772f1 100644 --- a/src/freedreno/vulkan/tu_util.cc +++ b/src/freedreno/vulkan/tu_util.cc @@ -220,8 +220,10 @@ tu_tiling_config_update_tile_layout(struct tu_framebuffer *fb, * them, since you shouldn't be doing gmem work if gmem is not possible. */ .tile0 = (VkExtent2D) { ~0, ~0 }, - .tile_count = (VkExtent2D) { .width = 1, .height = 1 }, .possible = false, + .vsc = { + .tile_count = (VkExtent2D) { .width = 1, .height = 1 }, + }, }; /* From the Vulkan 1.3.232 spec, under VkFramebufferCreateInfo: @@ -300,37 +302,37 @@ tu_tiling_config_update_tile_layout(struct tu_framebuffer *fb, abs((int)(tiling->tile0.width - tiling->tile0.height)))) { tiling->possible = true; tiling->tile0 = tile_size; - tiling->tile_count = tile_count; + tiling->vsc.tile_count = tile_count; best_tile_count = tile_count.width * tile_count.height; } } /* If forcing binning, try to get at least 2 tiles in each direction. */ if (TU_DEBUG(FORCEBIN) && tiling->possible) { - if (tiling->tile_count.width == 1 && tiling->tile0.width != tile_align_w) { + if (tiling->vsc.tile_count.width == 1 && tiling->tile0.width != tile_align_w) { tiling->tile0.width = util_align_npot(DIV_ROUND_UP(tiling->tile0.width, 2), tile_align_w); - tiling->tile_count.width = 2; + tiling->vsc.tile_count.width = 2; } - if (tiling->tile_count.height == 1 && tiling->tile0.height != tile_align_h) { + if (tiling->vsc.tile_count.height == 1 && tiling->tile0.height != tile_align_h) { tiling->tile0.height = align(DIV_ROUND_UP(tiling->tile0.height, 2), tile_align_h); - tiling->tile_count.height = 2; + tiling->vsc.tile_count.height = 2; } } } static bool -is_hw_binning_possible(const struct tu_tiling_config *tiling) +is_hw_binning_possible(const struct tu_vsc_config *vsc) { /* Similar to older gens, # of tiles per pipe cannot be more than 32. * But there are no hangs with 16 or more tiles per pipe in either * X or Y direction, so that limit does not seem to apply. */ - uint32_t tiles_per_pipe = tiling->pipe0.width * tiling->pipe0.height; + uint32_t tiles_per_pipe = vsc->pipe0.width * vsc->pipe0.height; return tiles_per_pipe <= 32; } static void -tu_tiling_config_update_pipe_layout(struct tu_tiling_config *tiling, +tu_tiling_config_update_pipe_layout(struct tu_vsc_config *vsc, const struct tu_device *dev, bool fdm) { @@ -345,94 +347,94 @@ tu_tiling_config_update_pipe_layout(struct tu_tiling_config *tiling, */ if (fdm && dev->physical_device->info->a6xx.has_bin_mask && !TU_DEBUG(NO_BIN_MERGING)) { - tiling->pipe0.width = 4; - tiling->pipe0.height = 8; - tiling->pipe_count.width = - DIV_ROUND_UP(tiling->tile_count.width, tiling->pipe0.width); - tiling->pipe_count.height = - DIV_ROUND_UP(tiling->tile_count.height, tiling->pipe0.height); - tiling->binning_possible = - tiling->pipe_count.width * tiling->pipe_count.height <= max_pipe_count; + vsc->pipe0.width = 4; + vsc->pipe0.height = 8; + vsc->pipe_count.width = + DIV_ROUND_UP(vsc->tile_count.width, vsc->pipe0.width); + vsc->pipe_count.height = + DIV_ROUND_UP(vsc->tile_count.height, vsc->pipe0.height); + vsc->binning_possible = + vsc->pipe_count.width * vsc->pipe_count.height <= max_pipe_count; return; } /* start from 1 tile per pipe */ - tiling->pipe0 = (VkExtent2D) { + vsc->pipe0 = (VkExtent2D) { .width = 1, .height = 1, }; - tiling->pipe_count = tiling->tile_count; + vsc->pipe_count = vsc->tile_count; - while (tiling->pipe_count.width * tiling->pipe_count.height > max_pipe_count) { - if (tiling->pipe0.width < tiling->pipe0.height) { - tiling->pipe0.width += 1; - tiling->pipe_count.width = - DIV_ROUND_UP(tiling->tile_count.width, tiling->pipe0.width); + while (vsc->pipe_count.width * vsc->pipe_count.height > max_pipe_count) { + if (vsc->pipe0.width < vsc->pipe0.height) { + vsc->pipe0.width += 1; + vsc->pipe_count.width = + DIV_ROUND_UP(vsc->tile_count.width, vsc->pipe0.width); } else { - tiling->pipe0.height += 1; - tiling->pipe_count.height = - DIV_ROUND_UP(tiling->tile_count.height, tiling->pipe0.height); + vsc->pipe0.height += 1; + vsc->pipe_count.height = + DIV_ROUND_UP(vsc->tile_count.height, vsc->pipe0.height); } } - tiling->binning_possible = is_hw_binning_possible(tiling); + vsc->binning_possible = is_hw_binning_possible(vsc); } static void -tu_tiling_config_update_pipes(struct tu_tiling_config *tiling, +tu_tiling_config_update_pipes(struct tu_vsc_config *vsc, const struct tu_device *dev) { const uint32_t max_pipe_count = dev->physical_device->info->num_vsc_pipes; const uint32_t used_pipe_count = - tiling->pipe_count.width * tiling->pipe_count.height; + vsc->pipe_count.width * vsc->pipe_count.height; const VkExtent2D last_pipe = { - .width = (tiling->tile_count.width - 1) % tiling->pipe0.width + 1, - .height = (tiling->tile_count.height - 1) % tiling->pipe0.height + 1, + .width = (vsc->tile_count.width - 1) % vsc->pipe0.width + 1, + .height = (vsc->tile_count.height - 1) % vsc->pipe0.height + 1, }; - if (!tiling->binning_possible) + if (!vsc->binning_possible) return; assert(used_pipe_count <= max_pipe_count); - assert(max_pipe_count <= ARRAY_SIZE(tiling->pipe_config)); + assert(max_pipe_count <= ARRAY_SIZE(vsc->pipe_config)); - for (uint32_t y = 0; y < tiling->pipe_count.height; y++) { - for (uint32_t x = 0; x < tiling->pipe_count.width; x++) { - const uint32_t pipe_x = tiling->pipe0.width * x; - const uint32_t pipe_y = tiling->pipe0.height * y; - const uint32_t pipe_w = (x == tiling->pipe_count.width - 1) + for (uint32_t y = 0; y < vsc->pipe_count.height; y++) { + for (uint32_t x = 0; x < vsc->pipe_count.width; x++) { + const uint32_t pipe_x = vsc->pipe0.width * x; + const uint32_t pipe_y = vsc->pipe0.height * y; + const uint32_t pipe_w = (x == vsc->pipe_count.width - 1) ? last_pipe.width - : tiling->pipe0.width; - const uint32_t pipe_h = (y == tiling->pipe_count.height - 1) + : vsc->pipe0.width; + const uint32_t pipe_h = (y == vsc->pipe_count.height - 1) ? last_pipe.height - : tiling->pipe0.height; - const uint32_t n = tiling->pipe_count.width * y + x; + : vsc->pipe0.height; + const uint32_t n = vsc->pipe_count.width * y + x; - tiling->pipe_config[n] = A6XX_VSC_PIPE_CONFIG_REG_X(pipe_x) | + vsc->pipe_config[n] = A6XX_VSC_PIPE_CONFIG_REG_X(pipe_x) | A6XX_VSC_PIPE_CONFIG_REG_Y(pipe_y) | A6XX_VSC_PIPE_CONFIG_REG_W(pipe_w) | A6XX_VSC_PIPE_CONFIG_REG_H(pipe_h); - tiling->pipe_sizes[n] = CP_SET_BIN_DATA5_0_VSC_SIZE(pipe_w * pipe_h); + vsc->pipe_sizes[n] = CP_SET_BIN_DATA5_0_VSC_SIZE(pipe_w * pipe_h); } } - memset(tiling->pipe_config + used_pipe_count, 0, + memset(vsc->pipe_config + used_pipe_count, 0, sizeof(uint32_t) * (max_pipe_count - used_pipe_count)); } static void -tu_tiling_config_update_binning(struct tu_tiling_config *tiling, const struct tu_device *device) +tu_tiling_config_update_binning(struct tu_vsc_config *vsc, const struct tu_device *device) { - if (tiling->binning_possible) { - tiling->binning = (tiling->tile_count.width * tiling->tile_count.height) > 2; + if (vsc->binning_possible) { + vsc->binning = (vsc->tile_count.width * vsc->tile_count.height) > 2; if (TU_DEBUG(FORCEBIN)) - tiling->binning = true; + vsc->binning = true; if (TU_DEBUG(NOBIN)) - tiling->binning = false; + vsc->binning = false; } else { - tiling->binning = false; + vsc->binning = false; } } @@ -448,9 +450,10 @@ tu_framebuffer_tiling_config(struct tu_framebuffer *fb, if (!tiling->possible) continue; - tu_tiling_config_update_pipe_layout(tiling, device, pass->has_fdm); - tu_tiling_config_update_pipes(tiling, device); - tu_tiling_config_update_binning(tiling, device); + struct tu_vsc_config *vsc = &tiling->vsc; + tu_tiling_config_update_pipe_layout(vsc, device, pass->has_fdm); + tu_tiling_config_update_pipes(vsc, device); + tu_tiling_config_update_binning(vsc, device); } }