X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Ffreedreno%2Fvulkan%2Ftu_cmd_buffer.c;h=e5a3eac30e4475e1f2adb2facbda8cc832ff95c2;hb=54b7a57c22c8de54ae1fbd659ac141a8802eb301;hp=4f057fb7e18de05d9b10c73601fc56b56071cc19;hpb=ba6bcb387cc1e693d85bc11dde3913b4f9133d67;p=mesa.git diff --git a/src/freedreno/vulkan/tu_cmd_buffer.c b/src/freedreno/vulkan/tu_cmd_buffer.c index 4f057fb7e18..e5a3eac30e4 100644 --- a/src/freedreno/vulkan/tu_cmd_buffer.c +++ b/src/freedreno/vulkan/tu_cmd_buffer.c @@ -27,8 +27,12 @@ #include "tu_private.h" +#include "registers/adreno_pm4.xml.h" +#include "registers/adreno_common.xml.h" +#include "registers/a6xx.xml.h" + #include "vk_format.h" -#include "adreno_pm4.xml.h" + #include "tu_cs.h" void @@ -103,6 +107,1070 @@ tu_bo_list_merge(struct tu_bo_list *list, const struct tu_bo_list *other) return VK_SUCCESS; } +static VkResult +tu_tiling_config_update_gmem_layout(struct tu_tiling_config *tiling, + const struct tu_device *dev) +{ + const uint32_t gmem_size = dev->physical_device->gmem_size; + uint32_t offset = 0; + + for (uint32_t i = 0; i < tiling->buffer_count; i++) { + /* 16KB-aligned */ + offset = align(offset, 0x4000); + + tiling->gmem_offsets[i] = offset; + offset += tiling->tile0.extent.width * tiling->tile0.extent.height * + tiling->buffer_cpp[i]; + } + + return offset <= gmem_size ? VK_SUCCESS : VK_ERROR_OUT_OF_DEVICE_MEMORY; +} + +static void +tu_tiling_config_update_tile_layout(struct tu_tiling_config *tiling, + const struct tu_device *dev) +{ + const uint32_t tile_align_w = dev->physical_device->tile_align_w; + const uint32_t tile_align_h = dev->physical_device->tile_align_h; + const uint32_t max_tile_width = 1024; /* A6xx */ + + tiling->tile0.offset = (VkOffset2D) { + .x = tiling->render_area.offset.x & ~(tile_align_w - 1), + .y = tiling->render_area.offset.y & ~(tile_align_h - 1), + }; + + const uint32_t ra_width = + tiling->render_area.extent.width + + (tiling->render_area.offset.x - tiling->tile0.offset.x); + const uint32_t ra_height = + tiling->render_area.extent.height + + (tiling->render_area.offset.y - tiling->tile0.offset.y); + + /* start from 1 tile */ + tiling->tile_count = (VkExtent2D) { + .width = 1, + .height = 1, + }; + tiling->tile0.extent = (VkExtent2D) { + .width = align(ra_width, tile_align_w), + .height = align(ra_height, tile_align_h), + }; + + /* do not exceed max tile width */ + while (tiling->tile0.extent.width > max_tile_width) { + tiling->tile_count.width++; + tiling->tile0.extent.width = + align(ra_width / tiling->tile_count.width, tile_align_w); + } + + /* do not exceed gmem size */ + while (tu_tiling_config_update_gmem_layout(tiling, dev) != VK_SUCCESS) { + if (tiling->tile0.extent.width > tiling->tile0.extent.height) { + tiling->tile_count.width++; + tiling->tile0.extent.width = + align(ra_width / tiling->tile_count.width, tile_align_w); + } else { + tiling->tile_count.height++; + tiling->tile0.extent.height = + align(ra_height / tiling->tile_count.height, tile_align_h); + } + } +} + +static void +tu_tiling_config_update_pipe_layout(struct tu_tiling_config *tiling, + const struct tu_device *dev) +{ + const uint32_t max_pipe_count = 32; /* A6xx */ + + /* start from 1 tile per pipe */ + tiling->pipe0 = (VkExtent2D) { + .width = 1, + .height = 1, + }; + tiling->pipe_count = tiling->tile_count; + + /* do not exceed max pipe count vertically */ + while (tiling->pipe_count.height > max_pipe_count) { + tiling->pipe0.height += 2; + tiling->pipe_count.height = + (tiling->tile_count.height + tiling->pipe0.height - 1) / + tiling->pipe0.height; + } + + /* do not exceed max pipe count */ + while (tiling->pipe_count.width * tiling->pipe_count.height > + max_pipe_count) { + tiling->pipe0.width += 1; + tiling->pipe_count.width = + (tiling->tile_count.width + tiling->pipe0.width - 1) / + tiling->pipe0.width; + } +} + +static void +tu_tiling_config_update_pipes(struct tu_tiling_config *tiling, + const struct tu_device *dev) +{ + const uint32_t max_pipe_count = 32; /* A6xx */ + const uint32_t used_pipe_count = + tiling->pipe_count.width * tiling->pipe_count.height; + const VkExtent2D last_pipe = { + .width = tiling->tile_count.width % tiling->pipe0.width, + .height = tiling->tile_count.height % tiling->pipe0.height, + }; + + assert(used_pipe_count <= max_pipe_count); + assert(max_pipe_count <= ARRAY_SIZE(tiling->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) + ? last_pipe.width + : tiling->pipe0.width; + const uint32_t pipe_h = (y == tiling->pipe_count.height - 1) + ? last_pipe.height + : tiling->pipe0.height; + const uint32_t n = tiling->pipe_count.width * y + x; + + tiling->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); + } + } + + memset(tiling->pipe_config + used_pipe_count, 0, + sizeof(uint32_t) * (max_pipe_count - used_pipe_count)); +} + +static void +tu_tiling_config_update(struct tu_tiling_config *tiling, + const struct tu_device *dev, + const uint32_t *buffer_cpp, + uint32_t buffer_count, + const VkRect2D *render_area) +{ + /* see if there is any real change */ + const bool ra_changed = + render_area && + memcmp(&tiling->render_area, render_area, sizeof(*render_area)); + const bool buf_changed = tiling->buffer_count != buffer_count || + memcmp(tiling->buffer_cpp, buffer_cpp, + sizeof(*buffer_cpp) * buffer_count); + if (!ra_changed && !buf_changed) + return; + + if (ra_changed) + tiling->render_area = *render_area; + + if (buf_changed) { + memcpy(tiling->buffer_cpp, buffer_cpp, + sizeof(*buffer_cpp) * buffer_count); + tiling->buffer_count = buffer_count; + } + + tu_tiling_config_update_tile_layout(tiling, dev); + tu_tiling_config_update_pipe_layout(tiling, dev); + tu_tiling_config_update_pipes(tiling, dev); +} + +static void +tu_tiling_config_get_tile(const struct tu_tiling_config *tiling, + const struct tu_device *dev, + uint32_t tx, + uint32_t ty, + struct tu_tile *tile) +{ + /* find the pipe and the slot for tile (tx, ty) */ + const uint32_t px = tx / tiling->pipe0.width; + const uint32_t py = ty / tiling->pipe0.height; + const uint32_t sx = tx - tiling->pipe0.width * px; + const uint32_t sy = ty - tiling->pipe0.height * py; + + assert(tx < tiling->tile_count.width && ty < tiling->tile_count.height); + assert(px < tiling->pipe_count.width && py < tiling->pipe_count.height); + assert(sx < tiling->pipe0.width && sy < tiling->pipe0.height); + + /* convert to 1D indices */ + tile->pipe = tiling->pipe_count.width * py + px; + tile->slot = tiling->pipe0.width * sy + sx; + + /* get the blit area for the tile */ + tile->begin = (VkOffset2D) { + .x = tiling->tile0.offset.x + tiling->tile0.extent.width * tx, + .y = tiling->tile0.offset.y + tiling->tile0.extent.height * ty, + }; + tile->end.x = + (tx == tiling->tile_count.width - 1) + ? tiling->render_area.offset.x + tiling->render_area.extent.width + : tile->begin.x + tiling->tile0.extent.width; + tile->end.y = + (ty == tiling->tile_count.height - 1) + ? tiling->render_area.offset.y + tiling->render_area.extent.height + : tile->begin.y + tiling->tile0.extent.height; +} + +static enum a3xx_msaa_samples +tu6_msaa_samples(uint32_t samples) +{ + switch (samples) { + case 1: + return MSAA_ONE; + case 2: + return MSAA_TWO; + case 4: + return MSAA_FOUR; + case 8: + return MSAA_EIGHT; + default: + assert(!"invalid sample count"); + return MSAA_ONE; + } +} + +static void +tu6_emit_marker(struct tu_cmd_buffer *cmd, struct tu_cs *cs) +{ + tu_cs_emit_write_reg(cs, cmd->marker_reg, ++cmd->marker_seqno); +} + +void +tu6_emit_event_write(struct tu_cmd_buffer *cmd, + struct tu_cs *cs, + enum vgt_event_type event, + bool need_seqno) +{ + tu_cs_emit_pkt7(cs, CP_EVENT_WRITE, need_seqno ? 4 : 1); + tu_cs_emit(cs, CP_EVENT_WRITE_0_EVENT(event)); + if (need_seqno) { + tu_cs_emit_qw(cs, cmd->scratch_bo.iova); + tu_cs_emit(cs, ++cmd->scratch_seqno); + } +} + +static void +tu6_emit_cache_flush(struct tu_cmd_buffer *cmd, struct tu_cs *cs) +{ + tu6_emit_event_write(cmd, cs, 0x31, false); +} + +static void +tu6_emit_lrz_flush(struct tu_cmd_buffer *cmd, struct tu_cs *cs) +{ + tu6_emit_event_write(cmd, cs, LRZ_FLUSH, false); +} + +static void +tu6_emit_wfi(struct tu_cmd_buffer *cmd, struct tu_cs *cs) +{ + if (cmd->wait_for_idle) { + tu_cs_emit_wfi(cs); + cmd->wait_for_idle = false; + } +} + +static void +tu6_emit_zs(struct tu_cmd_buffer *cmd, struct tu_cs *cs) +{ + const struct tu_subpass *subpass = cmd->state.subpass; + + const uint32_t a = subpass->depth_stencil_attachment.attachment; + if (a == VK_ATTACHMENT_UNUSED) { + tu_cs_emit_pkt4(cs, REG_A6XX_RB_DEPTH_BUFFER_INFO, 6); + tu_cs_emit(cs, A6XX_RB_DEPTH_BUFFER_INFO_DEPTH_FORMAT(DEPTH6_NONE)); + tu_cs_emit(cs, 0x00000000); /* RB_DEPTH_BUFFER_PITCH */ + tu_cs_emit(cs, 0x00000000); /* RB_DEPTH_BUFFER_ARRAY_PITCH */ + tu_cs_emit(cs, 0x00000000); /* RB_DEPTH_BUFFER_BASE_LO */ + tu_cs_emit(cs, 0x00000000); /* RB_DEPTH_BUFFER_BASE_HI */ + tu_cs_emit(cs, 0x00000000); /* RB_DEPTH_BUFFER_BASE_GMEM */ + + tu_cs_emit_pkt4(cs, REG_A6XX_GRAS_SU_DEPTH_BUFFER_INFO, 1); + tu_cs_emit(cs, + A6XX_GRAS_SU_DEPTH_BUFFER_INFO_DEPTH_FORMAT(DEPTH6_NONE)); + + tu_cs_emit_pkt4(cs, REG_A6XX_GRAS_LRZ_BUFFER_BASE_LO, 5); + tu_cs_emit(cs, 0x00000000); /* RB_DEPTH_FLAG_BUFFER_BASE_LO */ + tu_cs_emit(cs, 0x00000000); /* RB_DEPTH_FLAG_BUFFER_BASE_HI */ + tu_cs_emit(cs, 0x00000000); /* GRAS_LRZ_BUFFER_PITCH */ + tu_cs_emit(cs, 0x00000000); /* GRAS_LRZ_FAST_CLEAR_BUFFER_BASE_LO */ + tu_cs_emit(cs, 0x00000000); /* GRAS_LRZ_FAST_CLEAR_BUFFER_BASE_HI */ + + tu_cs_emit_pkt4(cs, REG_A6XX_RB_STENCIL_INFO, 1); + tu_cs_emit(cs, 0x00000000); /* RB_STENCIL_INFO */ + + return; + } + + /* enable zs? */ +} + +static void +tu6_emit_mrt(struct tu_cmd_buffer *cmd, struct tu_cs *cs) +{ + const struct tu_framebuffer *fb = cmd->state.framebuffer; + const struct tu_subpass *subpass = cmd->state.subpass; + const struct tu_tiling_config *tiling = &cmd->state.tiling_config; + unsigned char mrt_comp[MAX_RTS] = { 0 }; + unsigned srgb_cntl = 0; + + uint32_t gmem_index = 0; + for (uint32_t i = 0; i < subpass->color_count; ++i) { + uint32_t a = subpass->color_attachments[i].attachment; + if (a == VK_ATTACHMENT_UNUSED) + continue; + + const struct tu_image_view *iview = fb->attachments[a].attachment; + const struct tu_image_level *slice = + &iview->image->levels[iview->base_mip]; + const enum a6xx_tile_mode tile_mode = TILE6_LINEAR; + uint32_t stride = 0; + uint32_t offset = 0; + + mrt_comp[i] = 0xf; + + if (vk_format_is_srgb(iview->vk_format)) + srgb_cntl |= (1 << i); + + const struct tu_native_format *format = + tu6_get_native_format(iview->vk_format); + assert(format && format->rb >= 0); + + offset = slice->offset + slice->size * iview->base_layer; + stride = slice->pitch * vk_format_get_blocksize(iview->vk_format); + + tu_cs_emit_pkt4(cs, REG_A6XX_RB_MRT_BUF_INFO(i), 6); + tu_cs_emit(cs, A6XX_RB_MRT_BUF_INFO_COLOR_FORMAT(format->rb) | + A6XX_RB_MRT_BUF_INFO_COLOR_TILE_MODE(tile_mode) | + A6XX_RB_MRT_BUF_INFO_COLOR_SWAP(format->swap)); + tu_cs_emit(cs, A6XX_RB_MRT_PITCH(stride)); + tu_cs_emit(cs, A6XX_RB_MRT_ARRAY_PITCH(slice->size)); + tu_cs_emit_qw(cs, iview->image->bo->iova + iview->image->bo_offset + + offset); /* BASE_LO/HI */ + tu_cs_emit( + cs, tiling->gmem_offsets[gmem_index++]); /* RB_MRT[i].BASE_GMEM */ + + tu_cs_emit_pkt4(cs, REG_A6XX_SP_FS_MRT_REG(i), 1); + tu_cs_emit(cs, A6XX_SP_FS_MRT_REG_COLOR_FORMAT(format->rb)); + +#if 0 + /* when we support UBWC, these would be the system memory + * addr/pitch/etc: + */ + tu_cs_emit_pkt4(cs, REG_A6XX_RB_MRT_FLAG_BUFFER(i), 4); + tu_cs_emit(cs, 0x00000000); /* RB_MRT_FLAG_BUFFER[i].ADDR_LO */ + tu_cs_emit(cs, 0x00000000); /* RB_MRT_FLAG_BUFFER[i].ADDR_HI */ + tu_cs_emit(cs, A6XX_RB_MRT_FLAG_BUFFER_PITCH(0)); + tu_cs_emit(cs, A6XX_RB_MRT_FLAG_BUFFER_ARRAY_PITCH(0)); +#endif + } + + tu_cs_emit_pkt4(cs, REG_A6XX_RB_SRGB_CNTL, 1); + tu_cs_emit(cs, srgb_cntl); + + tu_cs_emit_pkt4(cs, REG_A6XX_SP_SRGB_CNTL, 1); + tu_cs_emit(cs, srgb_cntl); + + tu_cs_emit_pkt4(cs, REG_A6XX_RB_RENDER_COMPONENTS, 1); + tu_cs_emit(cs, A6XX_RB_RENDER_COMPONENTS_RT0(mrt_comp[0]) | + A6XX_RB_RENDER_COMPONENTS_RT1(mrt_comp[1]) | + A6XX_RB_RENDER_COMPONENTS_RT2(mrt_comp[2]) | + A6XX_RB_RENDER_COMPONENTS_RT3(mrt_comp[3]) | + A6XX_RB_RENDER_COMPONENTS_RT4(mrt_comp[4]) | + A6XX_RB_RENDER_COMPONENTS_RT5(mrt_comp[5]) | + A6XX_RB_RENDER_COMPONENTS_RT6(mrt_comp[6]) | + A6XX_RB_RENDER_COMPONENTS_RT7(mrt_comp[7])); + + tu_cs_emit_pkt4(cs, REG_A6XX_SP_FS_RENDER_COMPONENTS, 1); + tu_cs_emit(cs, A6XX_SP_FS_RENDER_COMPONENTS_RT0(mrt_comp[0]) | + A6XX_SP_FS_RENDER_COMPONENTS_RT1(mrt_comp[1]) | + A6XX_SP_FS_RENDER_COMPONENTS_RT2(mrt_comp[2]) | + A6XX_SP_FS_RENDER_COMPONENTS_RT3(mrt_comp[3]) | + A6XX_SP_FS_RENDER_COMPONENTS_RT4(mrt_comp[4]) | + A6XX_SP_FS_RENDER_COMPONENTS_RT5(mrt_comp[5]) | + A6XX_SP_FS_RENDER_COMPONENTS_RT6(mrt_comp[6]) | + A6XX_SP_FS_RENDER_COMPONENTS_RT7(mrt_comp[7])); +} + +static void +tu6_emit_msaa(struct tu_cmd_buffer *cmd, struct tu_cs *cs) +{ + const struct tu_subpass *subpass = cmd->state.subpass; + const enum a3xx_msaa_samples samples = + tu6_msaa_samples(subpass->max_sample_count); + + tu_cs_emit_pkt4(cs, REG_A6XX_SP_TP_RAS_MSAA_CNTL, 2); + tu_cs_emit(cs, A6XX_SP_TP_RAS_MSAA_CNTL_SAMPLES(samples)); + tu_cs_emit( + cs, A6XX_SP_TP_DEST_MSAA_CNTL_SAMPLES(samples) | + ((samples == MSAA_ONE) ? A6XX_SP_TP_DEST_MSAA_CNTL_MSAA_DISABLE + : 0)); + + tu_cs_emit_pkt4(cs, REG_A6XX_GRAS_RAS_MSAA_CNTL, 2); + tu_cs_emit(cs, A6XX_GRAS_RAS_MSAA_CNTL_SAMPLES(samples)); + tu_cs_emit( + cs, + A6XX_GRAS_DEST_MSAA_CNTL_SAMPLES(samples) | + ((samples == MSAA_ONE) ? A6XX_GRAS_DEST_MSAA_CNTL_MSAA_DISABLE : 0)); + + tu_cs_emit_pkt4(cs, REG_A6XX_RB_RAS_MSAA_CNTL, 2); + tu_cs_emit(cs, A6XX_RB_RAS_MSAA_CNTL_SAMPLES(samples)); + tu_cs_emit( + cs, + A6XX_RB_DEST_MSAA_CNTL_SAMPLES(samples) | + ((samples == MSAA_ONE) ? A6XX_RB_DEST_MSAA_CNTL_MSAA_DISABLE : 0)); + + tu_cs_emit_pkt4(cs, REG_A6XX_RB_MSAA_CNTL, 1); + tu_cs_emit(cs, A6XX_RB_MSAA_CNTL_SAMPLES(samples)); +} + +static void +tu6_emit_bin_size(struct tu_cmd_buffer *cmd, struct tu_cs *cs, uint32_t flags) +{ + const struct tu_tiling_config *tiling = &cmd->state.tiling_config; + const uint32_t bin_w = tiling->tile0.extent.width; + const uint32_t bin_h = tiling->tile0.extent.height; + + tu_cs_emit_pkt4(cs, REG_A6XX_GRAS_BIN_CONTROL, 1); + tu_cs_emit(cs, A6XX_GRAS_BIN_CONTROL_BINW(bin_w) | + A6XX_GRAS_BIN_CONTROL_BINH(bin_h) | flags); + + tu_cs_emit_pkt4(cs, REG_A6XX_RB_BIN_CONTROL, 1); + tu_cs_emit(cs, A6XX_RB_BIN_CONTROL_BINW(bin_w) | + A6XX_RB_BIN_CONTROL_BINH(bin_h) | flags); + + /* no flag for RB_BIN_CONTROL2... */ + tu_cs_emit_pkt4(cs, REG_A6XX_RB_BIN_CONTROL2, 1); + tu_cs_emit(cs, A6XX_RB_BIN_CONTROL2_BINW(bin_w) | + A6XX_RB_BIN_CONTROL2_BINH(bin_h)); +} + +static void +tu6_emit_render_cntl(struct tu_cmd_buffer *cmd, + struct tu_cs *cs, + bool binning) +{ + uint32_t cntl = 0; + cntl |= A6XX_RB_RENDER_CNTL_UNK4; + if (binning) + cntl |= A6XX_RB_RENDER_CNTL_BINNING; + + tu_cs_emit_pkt7(cs, CP_REG_WRITE, 3); + tu_cs_emit(cs, 0x2); + tu_cs_emit(cs, REG_A6XX_RB_RENDER_CNTL); + tu_cs_emit(cs, cntl); +} + +static void +tu6_emit_blit_scissor(struct tu_cmd_buffer *cmd, struct tu_cs *cs) +{ + const VkRect2D *render_area = &cmd->state.tiling_config.render_area; + const uint32_t x1 = render_area->offset.x; + const uint32_t y1 = render_area->offset.y; + const uint32_t x2 = x1 + render_area->extent.width - 1; + const uint32_t y2 = y1 + render_area->extent.height - 1; + + tu_cs_emit_pkt4(cs, REG_A6XX_RB_BLIT_SCISSOR_TL, 2); + tu_cs_emit(cs, + A6XX_RB_BLIT_SCISSOR_TL_X(x1) | A6XX_RB_BLIT_SCISSOR_TL_Y(y1)); + tu_cs_emit(cs, + A6XX_RB_BLIT_SCISSOR_BR_X(x2) | A6XX_RB_BLIT_SCISSOR_BR_Y(y2)); +} + +static void +tu6_emit_blit_info(struct tu_cmd_buffer *cmd, + struct tu_cs *cs, + const struct tu_image_view *iview, + uint32_t gmem_offset, + uint32_t blit_info) +{ + const struct tu_image_level *slice = + &iview->image->levels[iview->base_mip]; + const uint32_t offset = slice->offset + slice->size * iview->base_layer; + const uint32_t stride = + slice->pitch * vk_format_get_blocksize(iview->vk_format); + const enum a6xx_tile_mode tile_mode = TILE6_LINEAR; + const enum a3xx_msaa_samples samples = tu6_msaa_samples(1); + + tu_cs_emit_pkt4(cs, REG_A6XX_RB_BLIT_INFO, 1); + tu_cs_emit(cs, blit_info); + + /* tile mode? */ + const struct tu_native_format *format = + tu6_get_native_format(iview->vk_format); + assert(format && format->rb >= 0); + + tu_cs_emit_pkt4(cs, REG_A6XX_RB_BLIT_DST_INFO, 5); + tu_cs_emit(cs, A6XX_RB_BLIT_DST_INFO_TILE_MODE(tile_mode) | + A6XX_RB_BLIT_DST_INFO_SAMPLES(samples) | + A6XX_RB_BLIT_DST_INFO_COLOR_FORMAT(format->rb) | + A6XX_RB_BLIT_DST_INFO_COLOR_SWAP(format->swap)); + tu_cs_emit_qw(cs, + iview->image->bo->iova + iview->image->bo_offset + offset); + tu_cs_emit(cs, A6XX_RB_BLIT_DST_PITCH(stride)); + tu_cs_emit(cs, A6XX_RB_BLIT_DST_ARRAY_PITCH(slice->size)); + + tu_cs_emit_pkt4(cs, REG_A6XX_RB_BLIT_BASE_GMEM, 1); + tu_cs_emit(cs, gmem_offset); +} + +static void +tu6_emit_blit_clear(struct tu_cmd_buffer *cmd, + struct tu_cs *cs, + const struct tu_image_view *iview, + uint32_t gmem_offset, + const VkClearValue *clear_value) +{ + const enum a6xx_tile_mode tile_mode = TILE6_LINEAR; + const enum a3xx_msaa_samples samples = tu6_msaa_samples(1); + + const struct tu_native_format *format = + tu6_get_native_format(iview->vk_format); + assert(format && format->rb >= 0); + /* must be WZYX; other values are ignored */ + const enum a3xx_color_swap swap = WZYX; + + tu_cs_emit_pkt4(cs, REG_A6XX_RB_BLIT_DST_INFO, 1); + tu_cs_emit(cs, A6XX_RB_BLIT_DST_INFO_TILE_MODE(tile_mode) | + A6XX_RB_BLIT_DST_INFO_SAMPLES(samples) | + A6XX_RB_BLIT_DST_INFO_COLOR_FORMAT(format->rb) | + A6XX_RB_BLIT_DST_INFO_COLOR_SWAP(swap)); + + tu_cs_emit_pkt4(cs, REG_A6XX_RB_BLIT_INFO, 1); + tu_cs_emit(cs, A6XX_RB_BLIT_INFO_GMEM | A6XX_RB_BLIT_INFO_CLEAR_MASK(0xf)); + + tu_cs_emit_pkt4(cs, REG_A6XX_RB_BLIT_BASE_GMEM, 1); + tu_cs_emit(cs, gmem_offset); + + tu_cs_emit_pkt4(cs, REG_A6XX_RB_UNKNOWN_88D0, 1); + tu_cs_emit(cs, 0); + + /* pack clear_value into WZYX order */ + uint32_t clear_vals[4] = { 0 }; + tu_pack_clear_value(clear_value, iview->vk_format, clear_vals); + + tu_cs_emit_pkt4(cs, REG_A6XX_RB_BLIT_CLEAR_COLOR_DW0, 4); + tu_cs_emit(cs, clear_vals[0]); + tu_cs_emit(cs, clear_vals[1]); + tu_cs_emit(cs, clear_vals[2]); + tu_cs_emit(cs, clear_vals[3]); +} + +static void +tu6_emit_blit(struct tu_cmd_buffer *cmd, struct tu_cs *cs) +{ + tu6_emit_marker(cmd, cs); + tu6_emit_event_write(cmd, cs, BLIT, false); + tu6_emit_marker(cmd, cs); +} + +static void +tu6_emit_window_scissor(struct tu_cmd_buffer *cmd, + struct tu_cs *cs, + uint32_t x1, + uint32_t y1, + uint32_t x2, + uint32_t y2) +{ + tu_cs_emit_pkt4(cs, REG_A6XX_GRAS_SC_WINDOW_SCISSOR_TL, 2); + tu_cs_emit(cs, A6XX_GRAS_SC_WINDOW_SCISSOR_TL_X(x1) | + A6XX_GRAS_SC_WINDOW_SCISSOR_TL_Y(y1)); + tu_cs_emit(cs, A6XX_GRAS_SC_WINDOW_SCISSOR_BR_X(x2) | + A6XX_GRAS_SC_WINDOW_SCISSOR_BR_Y(y2)); + + tu_cs_emit_pkt4(cs, REG_A6XX_GRAS_RESOLVE_CNTL_1, 2); + tu_cs_emit( + cs, A6XX_GRAS_RESOLVE_CNTL_1_X(x1) | A6XX_GRAS_RESOLVE_CNTL_1_Y(y1)); + tu_cs_emit( + cs, A6XX_GRAS_RESOLVE_CNTL_2_X(x2) | A6XX_GRAS_RESOLVE_CNTL_2_Y(y2)); +} + +static void +tu6_emit_window_offset(struct tu_cmd_buffer *cmd, + struct tu_cs *cs, + uint32_t x1, + uint32_t y1) +{ + tu_cs_emit_pkt4(cs, REG_A6XX_RB_WINDOW_OFFSET, 1); + tu_cs_emit(cs, A6XX_RB_WINDOW_OFFSET_X(x1) | A6XX_RB_WINDOW_OFFSET_Y(y1)); + + tu_cs_emit_pkt4(cs, REG_A6XX_RB_WINDOW_OFFSET2, 1); + tu_cs_emit(cs, + A6XX_RB_WINDOW_OFFSET2_X(x1) | A6XX_RB_WINDOW_OFFSET2_Y(y1)); + + tu_cs_emit_pkt4(cs, REG_A6XX_SP_WINDOW_OFFSET, 1); + tu_cs_emit(cs, A6XX_SP_WINDOW_OFFSET_X(x1) | A6XX_SP_WINDOW_OFFSET_Y(y1)); + + tu_cs_emit_pkt4(cs, REG_A6XX_SP_TP_WINDOW_OFFSET, 1); + tu_cs_emit( + cs, A6XX_SP_TP_WINDOW_OFFSET_X(x1) | A6XX_SP_TP_WINDOW_OFFSET_Y(y1)); +} + +static void +tu6_emit_tile_select(struct tu_cmd_buffer *cmd, + struct tu_cs *cs, + const struct tu_tile *tile) +{ + tu_cs_emit_pkt7(cs, CP_SET_MARKER, 1); + tu_cs_emit(cs, A2XX_CP_SET_MARKER_0_MODE(0x7)); + + tu6_emit_marker(cmd, cs); + tu_cs_emit_pkt7(cs, CP_SET_MARKER, 1); + tu_cs_emit(cs, A2XX_CP_SET_MARKER_0_MODE(RM6_GMEM) | 0x10); + tu6_emit_marker(cmd, cs); + + const uint32_t x1 = tile->begin.x; + const uint32_t y1 = tile->begin.y; + const uint32_t x2 = tile->end.x - 1; + const uint32_t y2 = tile->end.y - 1; + tu6_emit_window_scissor(cmd, cs, x1, y1, x2, y2); + tu6_emit_window_offset(cmd, cs, x1, y1); + + tu_cs_emit_pkt4(cs, REG_A6XX_VPC_SO_OVERRIDE, 1); + tu_cs_emit(cs, A6XX_VPC_SO_OVERRIDE_SO_DISABLE); + + if (false) { + /* hw binning? */ + } else { + tu_cs_emit_pkt7(cs, CP_SET_VISIBILITY_OVERRIDE, 1); + tu_cs_emit(cs, 0x1); + + tu_cs_emit_pkt7(cs, CP_SET_MODE, 1); + tu_cs_emit(cs, 0x0); + } +} + +static void +tu6_emit_tile_load(struct tu_cmd_buffer *cmd, struct tu_cs *cs) +{ + const struct tu_framebuffer *fb = cmd->state.framebuffer; + const struct tu_subpass *subpass = cmd->state.subpass; + const struct tu_tiling_config *tiling = &cmd->state.tiling_config; + const struct tu_attachment_state *attachments = cmd->state.attachments; + + tu6_emit_blit_scissor(cmd, cs); + + uint32_t gmem_index = 0; + for (uint32_t i = 0; i < subpass->color_count; ++i) { + const uint32_t a = subpass->color_attachments[i].attachment; + if (a == VK_ATTACHMENT_UNUSED) + continue; + + const struct tu_image_view *iview = fb->attachments[a].attachment; + const struct tu_attachment_state *att = attachments + a; + if (att->pending_clear_aspects) { + assert(att->pending_clear_aspects == VK_IMAGE_ASPECT_COLOR_BIT); + tu6_emit_blit_clear(cmd, cs, iview, + tiling->gmem_offsets[gmem_index++], + &att->clear_value); + } else { + tu6_emit_blit_info(cmd, cs, iview, + tiling->gmem_offsets[gmem_index++], + A6XX_RB_BLIT_INFO_UNK0 | A6XX_RB_BLIT_INFO_GMEM); + } + + tu6_emit_blit(cmd, cs); + } + + /* load/clear zs? */ +} + +static void +tu6_emit_tile_store(struct tu_cmd_buffer *cmd, struct tu_cs *cs) +{ + const struct tu_framebuffer *fb = cmd->state.framebuffer; + const struct tu_tiling_config *tiling = &cmd->state.tiling_config; + + if (false) { + /* hw binning? */ + } + + tu_cs_emit_pkt7(cs, CP_SET_DRAW_STATE, 3); + tu_cs_emit(cs, CP_SET_DRAW_STATE__0_COUNT(0) | + CP_SET_DRAW_STATE__0_DISABLE_ALL_GROUPS | + CP_SET_DRAW_STATE__0_GROUP_ID(0)); + tu_cs_emit(cs, CP_SET_DRAW_STATE__1_ADDR_LO(0)); + tu_cs_emit(cs, CP_SET_DRAW_STATE__2_ADDR_HI(0)); + + tu_cs_emit_pkt7(cs, CP_SKIP_IB2_ENABLE_GLOBAL, 1); + tu_cs_emit(cs, 0x0); + + tu6_emit_marker(cmd, cs); + tu_cs_emit_pkt7(cs, CP_SET_MARKER, 1); + tu_cs_emit(cs, A2XX_CP_SET_MARKER_0_MODE(RM6_RESOLVE) | 0x10); + tu6_emit_marker(cmd, cs); + + tu6_emit_blit_scissor(cmd, cs); + + uint32_t gmem_index = 0; + for (uint32_t i = 0; i < cmd->state.subpass->color_count; ++i) { + uint32_t a = cmd->state.subpass->color_attachments[i].attachment; + if (a == VK_ATTACHMENT_UNUSED) + continue; + + const struct tu_image_view *iview = fb->attachments[a].attachment; + tu6_emit_blit_info(cmd, cs, iview, tiling->gmem_offsets[gmem_index++], + 0); + tu6_emit_blit(cmd, cs); + } +} + +static void +tu6_init_hw(struct tu_cmd_buffer *cmd, struct tu_cs *cs) +{ + VkResult result = tu_cs_reserve_space(cmd->device, cs, 256); + if (result != VK_SUCCESS) { + cmd->record_result = result; + return; + } + + tu6_emit_cache_flush(cmd, cs); + + tu_cs_emit_write_reg(cs, REG_A6XX_HLSQ_UPDATE_CNTL, 0xfffff); + + tu_cs_emit_write_reg(cs, REG_A6XX_RB_CCU_CNTL, 0x7c400004); + tu_cs_emit_write_reg(cs, REG_A6XX_RB_UNKNOWN_8E04, 0x00100000); + tu_cs_emit_write_reg(cs, REG_A6XX_SP_UNKNOWN_AE04, 0x8); + tu_cs_emit_write_reg(cs, REG_A6XX_SP_UNKNOWN_AE00, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_SP_UNKNOWN_AE0F, 0x3f); + tu_cs_emit_write_reg(cs, REG_A6XX_SP_UNKNOWN_B605, 0x44); + tu_cs_emit_write_reg(cs, REG_A6XX_SP_UNKNOWN_B600, 0x100000); + tu_cs_emit_write_reg(cs, REG_A6XX_HLSQ_UNKNOWN_BE00, 0x80); + tu_cs_emit_write_reg(cs, REG_A6XX_HLSQ_UNKNOWN_BE01, 0); + + tu_cs_emit_write_reg(cs, REG_A6XX_VPC_UNKNOWN_9600, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_GRAS_UNKNOWN_8600, 0x880); + tu_cs_emit_write_reg(cs, REG_A6XX_HLSQ_UNKNOWN_BE04, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_SP_UNKNOWN_AE03, 0x00000410); + tu_cs_emit_write_reg(cs, REG_A6XX_SP_IBO_COUNT, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_SP_UNKNOWN_B182, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_HLSQ_UNKNOWN_BB11, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_UCHE_UNKNOWN_0E12, 0x3200000); + tu_cs_emit_write_reg(cs, REG_A6XX_UCHE_CLIENT_PF, 4); + tu_cs_emit_write_reg(cs, REG_A6XX_RB_UNKNOWN_8E01, 0x0); + tu_cs_emit_write_reg(cs, REG_A6XX_SP_UNKNOWN_AB00, 0x5); + tu_cs_emit_write_reg(cs, REG_A6XX_VFD_UNKNOWN_A009, 0x00000001); + tu_cs_emit_write_reg(cs, REG_A6XX_RB_UNKNOWN_8811, 0x00000010); + tu_cs_emit_write_reg(cs, REG_A6XX_PC_MODE_CNTL, 0x1f); + + tu_cs_emit_write_reg(cs, REG_A6XX_RB_SRGB_CNTL, 0); + + tu_cs_emit_write_reg(cs, REG_A6XX_GRAS_UNKNOWN_8101, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_GRAS_UNKNOWN_8109, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_GRAS_UNKNOWN_8110, 0); + + tu_cs_emit_write_reg(cs, REG_A6XX_RB_RENDER_CONTROL0, 0x401); + tu_cs_emit_write_reg(cs, REG_A6XX_RB_RENDER_CONTROL1, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_RB_FS_OUTPUT_CNTL0, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_RB_UNKNOWN_8810, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_RB_UNKNOWN_8818, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_RB_UNKNOWN_8819, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_RB_UNKNOWN_881A, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_RB_UNKNOWN_881B, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_RB_UNKNOWN_881C, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_RB_UNKNOWN_881D, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_RB_UNKNOWN_881E, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_RB_UNKNOWN_88F0, 0); + + tu_cs_emit_write_reg(cs, REG_A6XX_VPC_UNKNOWN_9101, 0xffff00); + tu_cs_emit_write_reg(cs, REG_A6XX_VPC_UNKNOWN_9107, 0); + + tu_cs_emit_write_reg(cs, REG_A6XX_VPC_UNKNOWN_9236, 1); + tu_cs_emit_write_reg(cs, REG_A6XX_VPC_UNKNOWN_9300, 0); + + tu_cs_emit_write_reg(cs, REG_A6XX_VPC_SO_OVERRIDE, + A6XX_VPC_SO_OVERRIDE_SO_DISABLE); + + tu_cs_emit_write_reg(cs, REG_A6XX_PC_UNKNOWN_9801, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_PC_UNKNOWN_9806, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_PC_UNKNOWN_9980, 0); + + tu_cs_emit_write_reg(cs, REG_A6XX_PC_UNKNOWN_9B06, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_PC_UNKNOWN_9B06, 0); + + tu_cs_emit_write_reg(cs, REG_A6XX_SP_UNKNOWN_A81B, 0); + + tu_cs_emit_write_reg(cs, REG_A6XX_SP_UNKNOWN_B183, 0); + + tu_cs_emit_write_reg(cs, REG_A6XX_GRAS_UNKNOWN_8099, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_GRAS_UNKNOWN_809B, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_GRAS_UNKNOWN_80A0, 2); + tu_cs_emit_write_reg(cs, REG_A6XX_GRAS_UNKNOWN_80AF, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_VPC_UNKNOWN_9210, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_VPC_UNKNOWN_9211, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_VPC_UNKNOWN_9602, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_PC_UNKNOWN_9981, 0x3); + tu_cs_emit_write_reg(cs, REG_A6XX_PC_UNKNOWN_9E72, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_VPC_UNKNOWN_9108, 0x3); + tu_cs_emit_write_reg(cs, REG_A6XX_SP_TP_UNKNOWN_B304, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_SP_TP_UNKNOWN_B309, 0x000000a2); + tu_cs_emit_write_reg(cs, REG_A6XX_RB_UNKNOWN_8804, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_GRAS_UNKNOWN_80A4, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_GRAS_UNKNOWN_80A5, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_GRAS_UNKNOWN_80A6, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_RB_UNKNOWN_8805, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_RB_UNKNOWN_8806, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_RB_UNKNOWN_8878, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_RB_UNKNOWN_8879, 0); + tu_cs_emit_write_reg(cs, REG_A6XX_HLSQ_CONTROL_5_REG, 0xfc); + + tu6_emit_marker(cmd, cs); + + tu_cs_emit_write_reg(cs, REG_A6XX_VFD_MODE_CNTL, 0x00000000); + + tu_cs_emit_write_reg(cs, REG_A6XX_VFD_UNKNOWN_A008, 0); + + tu_cs_emit_write_reg(cs, REG_A6XX_PC_MODE_CNTL, 0x0000001f); + + /* we don't use this yet.. probably best to disable.. */ + tu_cs_emit_pkt7(cs, CP_SET_DRAW_STATE, 3); + tu_cs_emit(cs, CP_SET_DRAW_STATE__0_COUNT(0) | + CP_SET_DRAW_STATE__0_DISABLE_ALL_GROUPS | + CP_SET_DRAW_STATE__0_GROUP_ID(0)); + tu_cs_emit(cs, CP_SET_DRAW_STATE__1_ADDR_LO(0)); + tu_cs_emit(cs, CP_SET_DRAW_STATE__2_ADDR_HI(0)); + + tu_cs_emit_pkt4(cs, REG_A6XX_VPC_SO_BUFFER_BASE_LO(0), 3); + tu_cs_emit(cs, 0x00000000); /* VPC_SO_BUFFER_BASE_LO_0 */ + tu_cs_emit(cs, 0x00000000); /* VPC_SO_BUFFER_BASE_HI_0 */ + tu_cs_emit(cs, 0x00000000); /* VPC_SO_BUFFER_SIZE_0 */ + + tu_cs_emit_pkt4(cs, REG_A6XX_VPC_SO_FLUSH_BASE_LO(0), 2); + tu_cs_emit(cs, 0x00000000); /* VPC_SO_FLUSH_BASE_LO_0 */ + tu_cs_emit(cs, 0x00000000); /* VPC_SO_FLUSH_BASE_HI_0 */ + + tu_cs_emit_pkt4(cs, REG_A6XX_VPC_SO_BUF_CNTL, 1); + tu_cs_emit(cs, 0x00000000); /* VPC_SO_BUF_CNTL */ + + tu_cs_emit_pkt4(cs, REG_A6XX_VPC_SO_BUFFER_OFFSET(0), 1); + tu_cs_emit(cs, 0x00000000); /* UNKNOWN_E2AB */ + + tu_cs_emit_pkt4(cs, REG_A6XX_VPC_SO_BUFFER_BASE_LO(1), 3); + tu_cs_emit(cs, 0x00000000); + tu_cs_emit(cs, 0x00000000); + tu_cs_emit(cs, 0x00000000); + + tu_cs_emit_pkt4(cs, REG_A6XX_VPC_SO_BUFFER_OFFSET(1), 6); + tu_cs_emit(cs, 0x00000000); + tu_cs_emit(cs, 0x00000000); + tu_cs_emit(cs, 0x00000000); + tu_cs_emit(cs, 0x00000000); + tu_cs_emit(cs, 0x00000000); + tu_cs_emit(cs, 0x00000000); + + tu_cs_emit_pkt4(cs, REG_A6XX_VPC_SO_BUFFER_OFFSET(2), 6); + tu_cs_emit(cs, 0x00000000); + tu_cs_emit(cs, 0x00000000); + tu_cs_emit(cs, 0x00000000); + tu_cs_emit(cs, 0x00000000); + tu_cs_emit(cs, 0x00000000); + tu_cs_emit(cs, 0x00000000); + + tu_cs_emit_pkt4(cs, REG_A6XX_VPC_SO_BUFFER_OFFSET(3), 3); + tu_cs_emit(cs, 0x00000000); + tu_cs_emit(cs, 0x00000000); + tu_cs_emit(cs, 0x00000000); + + tu_cs_emit_pkt4(cs, REG_A6XX_SP_HS_CTRL_REG0, 1); + tu_cs_emit(cs, 0x00000000); + + tu_cs_emit_pkt4(cs, REG_A6XX_SP_GS_CTRL_REG0, 1); + tu_cs_emit(cs, 0x00000000); + + tu_cs_emit_pkt4(cs, REG_A6XX_GRAS_LRZ_CNTL, 1); + tu_cs_emit(cs, 0x00000000); + + tu_cs_emit_pkt4(cs, REG_A6XX_RB_LRZ_CNTL, 1); + tu_cs_emit(cs, 0x00000000); + + tu_cs_sanity_check(cs); +} + +static void +tu6_render_begin(struct tu_cmd_buffer *cmd, struct tu_cs *cs) +{ + VkResult result = tu_cs_reserve_space(cmd->device, cs, 256); + if (result != VK_SUCCESS) { + cmd->record_result = result; + return; + } + + tu6_emit_lrz_flush(cmd, cs); + + /* lrz clear? */ + + tu6_emit_cache_flush(cmd, cs); + + tu_cs_emit_pkt7(cs, CP_SKIP_IB2_ENABLE_GLOBAL, 1); + tu_cs_emit(cs, 0x0); + + /* 0x10000000 for BYPASS.. 0x7c13c080 for GMEM: */ + tu6_emit_wfi(cmd, cs); + tu_cs_emit_pkt4(cs, REG_A6XX_RB_CCU_CNTL, 1); + tu_cs_emit(cs, 0x7c400004); /* RB_CCU_CNTL */ + + tu6_emit_zs(cmd, cs); + tu6_emit_mrt(cmd, cs); + tu6_emit_msaa(cmd, cs); + + if (false) { + /* hw binning? */ + } else { + tu6_emit_bin_size(cmd, cs, 0x6000000); + /* no draws */ + } + + tu6_emit_render_cntl(cmd, cs, false); + + tu_cs_sanity_check(cs); +} + +static void +tu6_render_tile(struct tu_cmd_buffer *cmd, + struct tu_cs *cs, + const struct tu_tile *tile) +{ + const uint32_t render_tile_space = 64 + tu_cs_get_call_size(&cmd->draw_cs); + VkResult result = tu_cs_reserve_space(cmd->device, cs, render_tile_space); + if (result != VK_SUCCESS) { + cmd->record_result = result; + return; + } + + tu6_emit_tile_select(cmd, cs, tile); + tu_cs_emit_ib(cs, &cmd->state.tile_load_ib); + + tu_cs_emit_call(cs, &cmd->draw_cs); + cmd->wait_for_idle = true; + + tu_cs_emit_ib(cs, &cmd->state.tile_store_ib); + + tu_cs_sanity_check(cs); +} + +static void +tu6_render_end(struct tu_cmd_buffer *cmd, struct tu_cs *cs) +{ + VkResult result = tu_cs_reserve_space(cmd->device, cs, 16); + if (result != VK_SUCCESS) { + cmd->record_result = result; + return; + } + + tu_cs_emit_pkt4(cs, REG_A6XX_GRAS_LRZ_CNTL, 1); + tu_cs_emit(cs, A6XX_GRAS_LRZ_CNTL_ENABLE | A6XX_GRAS_LRZ_CNTL_UNK3); + + tu6_emit_lrz_flush(cmd, cs); + + tu6_emit_event_write(cmd, cs, CACHE_FLUSH_TS, true); + + tu_cs_sanity_check(cs); +} + +static void +tu_cmd_render_tiles(struct tu_cmd_buffer *cmd) +{ + const struct tu_tiling_config *tiling = &cmd->state.tiling_config; + + tu6_render_begin(cmd, &cmd->cs); + + for (uint32_t y = 0; y < tiling->tile_count.height; y++) { + for (uint32_t x = 0; x < tiling->tile_count.width; x++) { + struct tu_tile tile; + tu_tiling_config_get_tile(tiling, cmd->device, x, y, &tile); + tu6_render_tile(cmd, &cmd->cs, &tile); + } + } + + tu6_render_end(cmd, &cmd->cs); +} + +static void +tu_cmd_prepare_tile_load_ib(struct tu_cmd_buffer *cmd) +{ + const uint32_t tile_load_space = 16 + 32 * MAX_RTS; + const struct tu_subpass *subpass = cmd->state.subpass; + struct tu_attachment_state *attachments = cmd->state.attachments; + struct tu_cs sub_cs; + + VkResult result = tu_cs_begin_sub_stream(cmd->device, &cmd->tile_cs, + tile_load_space, &sub_cs); + if (result != VK_SUCCESS) { + cmd->record_result = result; + return; + } + + /* emit to tile-load sub_cs */ + tu6_emit_tile_load(cmd, &sub_cs); + + cmd->state.tile_load_ib = tu_cs_end_sub_stream(&cmd->tile_cs, &sub_cs); + + for (uint32_t i = 0; i < subpass->color_count; ++i) { + const uint32_t a = subpass->color_attachments[i].attachment; + if (a != VK_ATTACHMENT_UNUSED) + attachments[a].pending_clear_aspects = 0; + } +} + +static void +tu_cmd_prepare_tile_store_ib(struct tu_cmd_buffer *cmd) +{ + const uint32_t tile_store_space = 32 + 32 * MAX_RTS; + struct tu_cs sub_cs; + + VkResult result = tu_cs_begin_sub_stream(cmd->device, &cmd->tile_cs, + tile_store_space, &sub_cs); + if (result != VK_SUCCESS) { + cmd->record_result = result; + return; + } + + /* emit to tile-store sub_cs */ + tu6_emit_tile_store(cmd, &sub_cs); + + cmd->state.tile_store_ib = tu_cs_end_sub_stream(&cmd->tile_cs, &sub_cs); +} + +static void +tu_cmd_update_tiling_config(struct tu_cmd_buffer *cmd, + const VkRect2D *render_area) +{ + const struct tu_device *dev = cmd->device; + const struct tu_render_pass *pass = cmd->state.pass; + const struct tu_subpass *subpass = cmd->state.subpass; + struct tu_tiling_config *tiling = &cmd->state.tiling_config; + + uint32_t buffer_cpp[MAX_RTS + 2]; + uint32_t buffer_count = 0; + + for (uint32_t i = 0; i < subpass->color_count; ++i) { + const uint32_t a = subpass->color_attachments[i].attachment; + if (a == VK_ATTACHMENT_UNUSED) + continue; + + const struct tu_render_pass_attachment *att = &pass->attachments[a]; + buffer_cpp[buffer_count++] = + vk_format_get_blocksize(att->format) * att->samples; + } + + if (subpass->depth_stencil_attachment.attachment != VK_ATTACHMENT_UNUSED) { + const uint32_t a = subpass->depth_stencil_attachment.attachment; + const struct tu_render_pass_attachment *att = &pass->attachments[a]; + + /* TODO */ + assert(att->format != VK_FORMAT_D32_SFLOAT_S8_UINT); + + buffer_cpp[buffer_count++] = + vk_format_get_blocksize(att->format) * att->samples; + } + + tu_tiling_config_update(tiling, dev, buffer_cpp, buffer_count, + render_area); +} + const struct tu_dynamic_state default_dynamic_state = { .viewport = { @@ -274,24 +1342,38 @@ tu_create_cmd_buffer(struct tu_device *device, } tu_bo_list_init(&cmd_buffer->bo_list); - tu_cs_init(&cmd_buffer->cs); + tu_cs_init(&cmd_buffer->cs, TU_CS_MODE_GROW, 4096); + tu_cs_init(&cmd_buffer->draw_cs, TU_CS_MODE_GROW, 4096); + tu_cs_init(&cmd_buffer->tile_cs, TU_CS_MODE_SUB_STREAM, 1024); *pCommandBuffer = tu_cmd_buffer_to_handle(cmd_buffer); list_inithead(&cmd_buffer->upload.list); + cmd_buffer->marker_reg = REG_A6XX_CP_SCRATCH_REG( + cmd_buffer->level == VK_COMMAND_BUFFER_LEVEL_PRIMARY ? 7 : 6); + + VkResult result = tu_bo_init_new(device, &cmd_buffer->scratch_bo, 0x1000); + if (result != VK_SUCCESS) + return result; + return VK_SUCCESS; } static void tu_cmd_buffer_destroy(struct tu_cmd_buffer *cmd_buffer) { + tu_bo_finish(cmd_buffer->device, &cmd_buffer->scratch_bo); + list_del(&cmd_buffer->pool_link); for (unsigned i = 0; i < VK_PIPELINE_BIND_POINT_RANGE_SIZE; i++) free(cmd_buffer->descriptors[i].push_set.set.mapped_ptr); tu_cs_finish(cmd_buffer->device, &cmd_buffer->cs); + tu_cs_finish(cmd_buffer->device, &cmd_buffer->draw_cs); + tu_cs_finish(cmd_buffer->device, &cmd_buffer->tile_cs); + tu_bo_list_destroy(&cmd_buffer->bo_list); vk_free(&cmd_buffer->pool->alloc, cmd_buffer); } @@ -299,10 +1381,14 @@ tu_cmd_buffer_destroy(struct tu_cmd_buffer *cmd_buffer) static VkResult tu_reset_cmd_buffer(struct tu_cmd_buffer *cmd_buffer) { + cmd_buffer->wait_for_idle = true; + cmd_buffer->record_result = VK_SUCCESS; tu_bo_list_reset(&cmd_buffer->bo_list); tu_cs_reset(cmd_buffer->device, &cmd_buffer->cs); + tu_cs_reset(cmd_buffer->device, &cmd_buffer->draw_cs); + tu_cs_reset(cmd_buffer->device, &cmd_buffer->tile_cs); for (unsigned i = 0; i < VK_PIPELINE_BIND_POINT_RANGE_SIZE; i++) { cmd_buffer->descriptors[i].dirty = 0; @@ -317,10 +1403,17 @@ tu_reset_cmd_buffer(struct tu_cmd_buffer *cmd_buffer) static VkResult tu_cmd_state_setup_attachments(struct tu_cmd_buffer *cmd_buffer, - struct tu_render_pass *pass, const VkRenderPassBeginInfo *info) { struct tu_cmd_state *state = &cmd_buffer->state; + const struct tu_framebuffer *fb = state->framebuffer; + const struct tu_render_pass *pass = state->pass; + + for (uint32_t i = 0; i < fb->attachment_count; ++i) { + const struct tu_image_view *iview = fb->attachments[i].attachment; + tu_bo_list_add(&cmd_buffer->bo_list, iview->image->bo, + MSM_SUBMIT_BO_READ | MSM_SUBMIT_BO_WRITE); + } if (pass->attachment_count == 0) { state->attachments = NULL; @@ -474,30 +1567,24 @@ tu_BeginCommandBuffer(VkCommandBuffer commandBuffer, memset(&cmd_buffer->state, 0, sizeof(cmd_buffer->state)); cmd_buffer->usage_flags = pBeginInfo->flags; + tu_cs_begin(&cmd_buffer->cs); + + cmd_buffer->marker_seqno = 0; + cmd_buffer->scratch_seqno = 0; + /* setup initial configuration into command buffer */ if (cmd_buffer->level == VK_COMMAND_BUFFER_LEVEL_PRIMARY) { switch (cmd_buffer->queue_family_index) { case TU_QUEUE_GENERAL: - /* init */ + tu6_init_hw(cmd_buffer, &cmd_buffer->cs); break; default: break; } } - result = tu_cs_begin(cmd_buffer->device, &cmd_buffer->cs, 4096); - if (result != VK_SUCCESS) - return result; - cmd_buffer->status = TU_CMD_BUFFER_STATUS_RECORDING; - /* Put some stuff in so we do not have empty command buffers. */ - tu_cs_emit_pkt7(&cmd_buffer->cs, CP_NOP, 4); - tu_cs_emit(&cmd_buffer->cs, 0); - tu_cs_emit(&cmd_buffer->cs, 0); - tu_cs_emit(&cmd_buffer->cs, 0); - tu_cs_emit(&cmd_buffer->cs, 0); - return VK_SUCCESS; } @@ -545,9 +1632,22 @@ tu_EndCommandBuffer(VkCommandBuffer commandBuffer) { TU_FROM_HANDLE(tu_cmd_buffer, cmd_buffer, commandBuffer); - VkResult result = tu_cs_end(&cmd_buffer->cs); - if (result != VK_SUCCESS) - cmd_buffer->record_result = result; + if (cmd_buffer->scratch_seqno) { + tu_bo_list_add(&cmd_buffer->bo_list, &cmd_buffer->scratch_bo, + MSM_SUBMIT_BO_WRITE); + } + + for (uint32_t i = 0; i < cmd_buffer->draw_cs.bo_count; i++) { + tu_bo_list_add(&cmd_buffer->bo_list, cmd_buffer->draw_cs.bos[i], + MSM_SUBMIT_BO_READ | MSM_SUBMIT_BO_DUMP); + } + + for (uint32_t i = 0; i < cmd_buffer->tile_cs.bo_count; i++) { + tu_bo_list_add(&cmd_buffer->bo_list, cmd_buffer->tile_cs.bos[i], + MSM_SUBMIT_BO_READ | MSM_SUBMIT_BO_DUMP); + } + + tu_cs_end(&cmd_buffer->cs); assert(!cmd_buffer->state.attachments); @@ -738,10 +1838,17 @@ tu_CmdBeginRenderPass(VkCommandBuffer commandBuffer, cmd_buffer->state.subpass = pass->subpasses; cmd_buffer->state.framebuffer = framebuffer; - result = - tu_cmd_state_setup_attachments(cmd_buffer, pass, pRenderPassBegin); + result = tu_cmd_state_setup_attachments(cmd_buffer, pRenderPassBegin); if (result != VK_SUCCESS) return; + + tu_cmd_update_tiling_config(cmd_buffer, &pRenderPassBegin->renderArea); + tu_cmd_prepare_tile_load_ib(cmd_buffer); + tu_cmd_prepare_tile_store_ib(cmd_buffer); + + /* draw_cs should contain entries only for this render pass */ + assert(!cmd_buffer->draw_cs.entry_count); + tu_cs_begin(&cmd_buffer->draw_cs); } void @@ -756,6 +1863,15 @@ tu_CmdBeginRenderPass2KHR(VkCommandBuffer commandBuffer, void tu_CmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents) { + TU_FROM_HANDLE(tu_cmd_buffer, cmd, commandBuffer); + + tu_cmd_render_tiles(cmd); + + cmd->state.subpass++; + + tu_cmd_update_tiling_config(cmd, NULL); + tu_cmd_prepare_tile_load_ib(cmd); + tu_cmd_prepare_tile_store_ib(cmd); } void @@ -976,6 +2092,13 @@ tu_CmdEndRenderPass(VkCommandBuffer commandBuffer) { TU_FROM_HANDLE(tu_cmd_buffer, cmd_buffer, commandBuffer); + tu_cs_end(&cmd_buffer->draw_cs); + + tu_cmd_render_tiles(cmd_buffer); + + /* discard draw_cs entries now that the tiles are rendered */ + tu_cs_discard_entries(&cmd_buffer->draw_cs); + vk_free(&cmd_buffer->pool->alloc, cmd_buffer->state.attachments); cmd_buffer->state.attachments = NULL;