1d5b1a78aSEric Anholt /* 2d5b1a78aSEric Anholt * Copyright © 2014-2015 Broadcom 3d5b1a78aSEric Anholt * 4d5b1a78aSEric Anholt * Permission is hereby granted, free of charge, to any person obtaining a 5d5b1a78aSEric Anholt * copy of this software and associated documentation files (the "Software"), 6d5b1a78aSEric Anholt * to deal in the Software without restriction, including without limitation 7d5b1a78aSEric Anholt * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8d5b1a78aSEric Anholt * and/or sell copies of the Software, and to permit persons to whom the 9d5b1a78aSEric Anholt * Software is furnished to do so, subject to the following conditions: 10d5b1a78aSEric Anholt * 11d5b1a78aSEric Anholt * The above copyright notice and this permission notice (including the next 12d5b1a78aSEric Anholt * paragraph) shall be included in all copies or substantial portions of the 13d5b1a78aSEric Anholt * Software. 14d5b1a78aSEric Anholt * 15d5b1a78aSEric Anholt * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16d5b1a78aSEric Anholt * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17d5b1a78aSEric Anholt * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18d5b1a78aSEric Anholt * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19d5b1a78aSEric Anholt * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20d5b1a78aSEric Anholt * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21d5b1a78aSEric Anholt * IN THE SOFTWARE. 22d5b1a78aSEric Anholt */ 23d5b1a78aSEric Anholt 24d5b1a78aSEric Anholt /** 25d5b1a78aSEric Anholt * DOC: Render command list generation 26d5b1a78aSEric Anholt * 27f6c01530SEric Anholt * In the V3D hardware, render command lists are what load and store 28f6c01530SEric Anholt * tiles of a framebuffer and optionally call out to binner-generated 29f6c01530SEric Anholt * command lists to do the 3D drawing for that tile. 30f6c01530SEric Anholt * 31d5b1a78aSEric Anholt * In the VC4 driver, render command list generation is performed by the 32d5b1a78aSEric Anholt * kernel instead of userspace. We do this because validating a 33d5b1a78aSEric Anholt * user-submitted command list is hard to get right and has high CPU overhead, 34d5b1a78aSEric Anholt * while the number of valid configurations for render command lists is 35d5b1a78aSEric Anholt * actually fairly low. 36d5b1a78aSEric Anholt */ 37d5b1a78aSEric Anholt 38d5b1a78aSEric Anholt #include "uapi/drm/vc4_drm.h" 39d5b1a78aSEric Anholt #include "vc4_drv.h" 40d5b1a78aSEric Anholt #include "vc4_packet.h" 41d5b1a78aSEric Anholt 42d5b1a78aSEric Anholt struct vc4_rcl_setup { 43d5b1a78aSEric Anholt struct drm_gem_cma_object *color_read; 44d5b1a78aSEric Anholt struct drm_gem_cma_object *color_write; 45d5b1a78aSEric Anholt struct drm_gem_cma_object *zs_read; 46d5b1a78aSEric Anholt struct drm_gem_cma_object *zs_write; 47d5b1a78aSEric Anholt struct drm_gem_cma_object *msaa_color_write; 48d5b1a78aSEric Anholt struct drm_gem_cma_object *msaa_zs_write; 49d5b1a78aSEric Anholt 50d5b1a78aSEric Anholt struct drm_gem_cma_object *rcl; 51d5b1a78aSEric Anholt u32 next_offset; 527edabee0SEric Anholt 537edabee0SEric Anholt u32 next_write_bo_index; 54d5b1a78aSEric Anholt }; 55d5b1a78aSEric Anholt 56d5b1a78aSEric Anholt static inline void rcl_u8(struct vc4_rcl_setup *setup, u8 val) 57d5b1a78aSEric Anholt { 58d5b1a78aSEric Anholt *(u8 *)(setup->rcl->vaddr + setup->next_offset) = val; 59d5b1a78aSEric Anholt setup->next_offset += 1; 60d5b1a78aSEric Anholt } 61d5b1a78aSEric Anholt 62d5b1a78aSEric Anholt static inline void rcl_u16(struct vc4_rcl_setup *setup, u16 val) 63d5b1a78aSEric Anholt { 64d5b1a78aSEric Anholt *(u16 *)(setup->rcl->vaddr + setup->next_offset) = val; 65d5b1a78aSEric Anholt setup->next_offset += 2; 66d5b1a78aSEric Anholt } 67d5b1a78aSEric Anholt 68d5b1a78aSEric Anholt static inline void rcl_u32(struct vc4_rcl_setup *setup, u32 val) 69d5b1a78aSEric Anholt { 70d5b1a78aSEric Anholt *(u32 *)(setup->rcl->vaddr + setup->next_offset) = val; 71d5b1a78aSEric Anholt setup->next_offset += 4; 72d5b1a78aSEric Anholt } 73d5b1a78aSEric Anholt 74d5b1a78aSEric Anholt /* 75d5b1a78aSEric Anholt * Emits a no-op STORE_TILE_BUFFER_GENERAL. 76d5b1a78aSEric Anholt * 77d5b1a78aSEric Anholt * If we emit a PACKET_TILE_COORDINATES, it must be followed by a store of 78d5b1a78aSEric Anholt * some sort before another load is triggered. 79d5b1a78aSEric Anholt */ 80d5b1a78aSEric Anholt static void vc4_store_before_load(struct vc4_rcl_setup *setup) 81d5b1a78aSEric Anholt { 82d5b1a78aSEric Anholt rcl_u8(setup, VC4_PACKET_STORE_TILE_BUFFER_GENERAL); 83d5b1a78aSEric Anholt rcl_u16(setup, 84d5b1a78aSEric Anholt VC4_SET_FIELD(VC4_LOADSTORE_TILE_BUFFER_NONE, 85d5b1a78aSEric Anholt VC4_LOADSTORE_TILE_BUFFER_BUFFER) | 86d5b1a78aSEric Anholt VC4_STORE_TILE_BUFFER_DISABLE_COLOR_CLEAR | 87d5b1a78aSEric Anholt VC4_STORE_TILE_BUFFER_DISABLE_ZS_CLEAR | 88d5b1a78aSEric Anholt VC4_STORE_TILE_BUFFER_DISABLE_VG_MASK_CLEAR); 89d5b1a78aSEric Anholt rcl_u32(setup, 0); /* no address, since we're in None mode */ 90d5b1a78aSEric Anholt } 91d5b1a78aSEric Anholt 92d5b1a78aSEric Anholt /* 93d5b1a78aSEric Anholt * Calculates the physical address of the start of a tile in a RCL surface. 94d5b1a78aSEric Anholt * 95d5b1a78aSEric Anholt * Unlike the other load/store packets, 96d5b1a78aSEric Anholt * VC4_PACKET_LOAD/STORE_FULL_RES_TILE_BUFFER don't look at the tile 97d5b1a78aSEric Anholt * coordinates packet, and instead just store to the address given. 98d5b1a78aSEric Anholt */ 99d5b1a78aSEric Anholt static uint32_t vc4_full_res_offset(struct vc4_exec_info *exec, 100d5b1a78aSEric Anholt struct drm_gem_cma_object *bo, 101d5b1a78aSEric Anholt struct drm_vc4_submit_rcl_surface *surf, 102d5b1a78aSEric Anholt uint8_t x, uint8_t y) 103d5b1a78aSEric Anholt { 104d5b1a78aSEric Anholt return bo->paddr + surf->offset + VC4_TILE_BUFFER_SIZE * 105d5b1a78aSEric Anholt (DIV_ROUND_UP(exec->args->width, 32) * y + x); 106d5b1a78aSEric Anholt } 107d5b1a78aSEric Anholt 108d5b1a78aSEric Anholt /* 109d5b1a78aSEric Anholt * Emits a PACKET_TILE_COORDINATES if one isn't already pending. 110d5b1a78aSEric Anholt * 111d5b1a78aSEric Anholt * The tile coordinates packet triggers a pending load if there is one, are 112d5b1a78aSEric Anholt * used for clipping during rendering, and determine where loads/stores happen 113d5b1a78aSEric Anholt * relative to their base address. 114d5b1a78aSEric Anholt */ 115d5b1a78aSEric Anholt static void vc4_tile_coordinates(struct vc4_rcl_setup *setup, 116d5b1a78aSEric Anholt uint32_t x, uint32_t y) 117d5b1a78aSEric Anholt { 118d5b1a78aSEric Anholt rcl_u8(setup, VC4_PACKET_TILE_COORDINATES); 119d5b1a78aSEric Anholt rcl_u8(setup, x); 120d5b1a78aSEric Anholt rcl_u8(setup, y); 121d5b1a78aSEric Anholt } 122d5b1a78aSEric Anholt 123d5b1a78aSEric Anholt static void emit_tile(struct vc4_exec_info *exec, 124d5b1a78aSEric Anholt struct vc4_rcl_setup *setup, 125d5b1a78aSEric Anholt uint8_t x, uint8_t y, bool first, bool last) 126d5b1a78aSEric Anholt { 127d5b1a78aSEric Anholt struct drm_vc4_submit_cl *args = exec->args; 128d5b1a78aSEric Anholt bool has_bin = args->bin_cl_size != 0; 129d5b1a78aSEric Anholt 130d5b1a78aSEric Anholt /* Note that the load doesn't actually occur until the 131d5b1a78aSEric Anholt * tile coords packet is processed, and only one load 132d5b1a78aSEric Anholt * may be outstanding at a time. 133d5b1a78aSEric Anholt */ 134d5b1a78aSEric Anholt if (setup->color_read) { 135d5b1a78aSEric Anholt if (args->color_read.flags & 136d5b1a78aSEric Anholt VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) { 137d5b1a78aSEric Anholt rcl_u8(setup, VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER); 138d5b1a78aSEric Anholt rcl_u32(setup, 139d5b1a78aSEric Anholt vc4_full_res_offset(exec, setup->color_read, 140d5b1a78aSEric Anholt &args->color_read, x, y) | 141d5b1a78aSEric Anholt VC4_LOADSTORE_FULL_RES_DISABLE_ZS); 142d5b1a78aSEric Anholt } else { 143d5b1a78aSEric Anholt rcl_u8(setup, VC4_PACKET_LOAD_TILE_BUFFER_GENERAL); 144d5b1a78aSEric Anholt rcl_u16(setup, args->color_read.bits); 145d5b1a78aSEric Anholt rcl_u32(setup, setup->color_read->paddr + 146d5b1a78aSEric Anholt args->color_read.offset); 147d5b1a78aSEric Anholt } 148d5b1a78aSEric Anholt } 149d5b1a78aSEric Anholt 150d5b1a78aSEric Anholt if (setup->zs_read) { 151d5b1a78aSEric Anholt if (args->zs_read.flags & 152d5b1a78aSEric Anholt VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) { 153d5b1a78aSEric Anholt rcl_u8(setup, VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER); 154d5b1a78aSEric Anholt rcl_u32(setup, 155d5b1a78aSEric Anholt vc4_full_res_offset(exec, setup->zs_read, 156d5b1a78aSEric Anholt &args->zs_read, x, y) | 157d5b1a78aSEric Anholt VC4_LOADSTORE_FULL_RES_DISABLE_COLOR); 158d5b1a78aSEric Anholt } else { 159d5b1a78aSEric Anholt if (setup->color_read) { 160d5b1a78aSEric Anholt /* Exec previous load. */ 161d5b1a78aSEric Anholt vc4_tile_coordinates(setup, x, y); 162d5b1a78aSEric Anholt vc4_store_before_load(setup); 163d5b1a78aSEric Anholt } 164d5b1a78aSEric Anholt 165d5b1a78aSEric Anholt rcl_u8(setup, VC4_PACKET_LOAD_TILE_BUFFER_GENERAL); 166d5b1a78aSEric Anholt rcl_u16(setup, args->zs_read.bits); 167d5b1a78aSEric Anholt rcl_u32(setup, setup->zs_read->paddr + 168d5b1a78aSEric Anholt args->zs_read.offset); 169d5b1a78aSEric Anholt } 170d5b1a78aSEric Anholt } 171d5b1a78aSEric Anholt 172d5b1a78aSEric Anholt /* Clipping depends on tile coordinates having been 173d5b1a78aSEric Anholt * emitted, so we always need one here. 174d5b1a78aSEric Anholt */ 175d5b1a78aSEric Anholt vc4_tile_coordinates(setup, x, y); 176d5b1a78aSEric Anholt 177d5b1a78aSEric Anholt /* Wait for the binner before jumping to the first 178d5b1a78aSEric Anholt * tile's lists. 179d5b1a78aSEric Anholt */ 180d5b1a78aSEric Anholt if (first && has_bin) 181d5b1a78aSEric Anholt rcl_u8(setup, VC4_PACKET_WAIT_ON_SEMAPHORE); 182d5b1a78aSEric Anholt 183d5b1a78aSEric Anholt if (has_bin) { 184d5b1a78aSEric Anholt rcl_u8(setup, VC4_PACKET_BRANCH_TO_SUB_LIST); 185553c942fSEric Anholt rcl_u32(setup, (exec->tile_alloc_offset + 186d5b1a78aSEric Anholt (y * exec->bin_tiles_x + x) * 32)); 187d5b1a78aSEric Anholt } 188d5b1a78aSEric Anholt 189d5b1a78aSEric Anholt if (setup->msaa_color_write) { 190d5b1a78aSEric Anholt bool last_tile_write = (!setup->msaa_zs_write && 191d5b1a78aSEric Anholt !setup->zs_write && 192d5b1a78aSEric Anholt !setup->color_write); 193d5b1a78aSEric Anholt uint32_t bits = VC4_LOADSTORE_FULL_RES_DISABLE_ZS; 194d5b1a78aSEric Anholt 195d5b1a78aSEric Anholt if (!last_tile_write) 196d5b1a78aSEric Anholt bits |= VC4_LOADSTORE_FULL_RES_DISABLE_CLEAR_ALL; 197d5b1a78aSEric Anholt else if (last) 198d5b1a78aSEric Anholt bits |= VC4_LOADSTORE_FULL_RES_EOF; 199d5b1a78aSEric Anholt rcl_u8(setup, VC4_PACKET_STORE_FULL_RES_TILE_BUFFER); 200d5b1a78aSEric Anholt rcl_u32(setup, 201d5b1a78aSEric Anholt vc4_full_res_offset(exec, setup->msaa_color_write, 202d5b1a78aSEric Anholt &args->msaa_color_write, x, y) | 203d5b1a78aSEric Anholt bits); 204d5b1a78aSEric Anholt } 205d5b1a78aSEric Anholt 206d5b1a78aSEric Anholt if (setup->msaa_zs_write) { 207d5b1a78aSEric Anholt bool last_tile_write = (!setup->zs_write && 208d5b1a78aSEric Anholt !setup->color_write); 209d5b1a78aSEric Anholt uint32_t bits = VC4_LOADSTORE_FULL_RES_DISABLE_COLOR; 210d5b1a78aSEric Anholt 211d5b1a78aSEric Anholt if (setup->msaa_color_write) 212d5b1a78aSEric Anholt vc4_tile_coordinates(setup, x, y); 213d5b1a78aSEric Anholt if (!last_tile_write) 214d5b1a78aSEric Anholt bits |= VC4_LOADSTORE_FULL_RES_DISABLE_CLEAR_ALL; 215d5b1a78aSEric Anholt else if (last) 216d5b1a78aSEric Anholt bits |= VC4_LOADSTORE_FULL_RES_EOF; 217d5b1a78aSEric Anholt rcl_u8(setup, VC4_PACKET_STORE_FULL_RES_TILE_BUFFER); 218d5b1a78aSEric Anholt rcl_u32(setup, 219d5b1a78aSEric Anholt vc4_full_res_offset(exec, setup->msaa_zs_write, 220d5b1a78aSEric Anholt &args->msaa_zs_write, x, y) | 221d5b1a78aSEric Anholt bits); 222d5b1a78aSEric Anholt } 223d5b1a78aSEric Anholt 224d5b1a78aSEric Anholt if (setup->zs_write) { 225d5b1a78aSEric Anholt bool last_tile_write = !setup->color_write; 226d5b1a78aSEric Anholt 227d5b1a78aSEric Anholt if (setup->msaa_color_write || setup->msaa_zs_write) 228d5b1a78aSEric Anholt vc4_tile_coordinates(setup, x, y); 229d5b1a78aSEric Anholt 230d5b1a78aSEric Anholt rcl_u8(setup, VC4_PACKET_STORE_TILE_BUFFER_GENERAL); 231d5b1a78aSEric Anholt rcl_u16(setup, args->zs_write.bits | 232d5b1a78aSEric Anholt (last_tile_write ? 233d5b1a78aSEric Anholt 0 : VC4_STORE_TILE_BUFFER_DISABLE_COLOR_CLEAR)); 234d5b1a78aSEric Anholt rcl_u32(setup, 235d5b1a78aSEric Anholt (setup->zs_write->paddr + args->zs_write.offset) | 236d5b1a78aSEric Anholt ((last && last_tile_write) ? 237d5b1a78aSEric Anholt VC4_LOADSTORE_TILE_BUFFER_EOF : 0)); 238d5b1a78aSEric Anholt } 239d5b1a78aSEric Anholt 240d5b1a78aSEric Anholt if (setup->color_write) { 241d5b1a78aSEric Anholt if (setup->msaa_color_write || setup->msaa_zs_write || 242d5b1a78aSEric Anholt setup->zs_write) { 243d5b1a78aSEric Anholt vc4_tile_coordinates(setup, x, y); 244d5b1a78aSEric Anholt } 245d5b1a78aSEric Anholt 246d5b1a78aSEric Anholt if (last) 247d5b1a78aSEric Anholt rcl_u8(setup, VC4_PACKET_STORE_MS_TILE_BUFFER_AND_EOF); 248d5b1a78aSEric Anholt else 249d5b1a78aSEric Anholt rcl_u8(setup, VC4_PACKET_STORE_MS_TILE_BUFFER); 250d5b1a78aSEric Anholt } 251d5b1a78aSEric Anholt } 252d5b1a78aSEric Anholt 253d5b1a78aSEric Anholt static int vc4_create_rcl_bo(struct drm_device *dev, struct vc4_exec_info *exec, 254d5b1a78aSEric Anholt struct vc4_rcl_setup *setup) 255d5b1a78aSEric Anholt { 256d5b1a78aSEric Anholt struct drm_vc4_submit_cl *args = exec->args; 257d5b1a78aSEric Anholt bool has_bin = args->bin_cl_size != 0; 258d5b1a78aSEric Anholt uint8_t min_x_tile = args->min_x_tile; 259d5b1a78aSEric Anholt uint8_t min_y_tile = args->min_y_tile; 260d5b1a78aSEric Anholt uint8_t max_x_tile = args->max_x_tile; 261d5b1a78aSEric Anholt uint8_t max_y_tile = args->max_y_tile; 262d5b1a78aSEric Anholt uint8_t xtiles = max_x_tile - min_x_tile + 1; 263d5b1a78aSEric Anholt uint8_t ytiles = max_y_tile - min_y_tile + 1; 264d5b1a78aSEric Anholt uint8_t x, y; 265d5b1a78aSEric Anholt uint32_t size, loop_body_size; 266d5b1a78aSEric Anholt 267d5b1a78aSEric Anholt size = VC4_PACKET_TILE_RENDERING_MODE_CONFIG_SIZE; 268d5b1a78aSEric Anholt loop_body_size = VC4_PACKET_TILE_COORDINATES_SIZE; 269d5b1a78aSEric Anholt 270d5b1a78aSEric Anholt if (args->flags & VC4_SUBMIT_CL_USE_CLEAR_COLOR) { 271d5b1a78aSEric Anholt size += VC4_PACKET_CLEAR_COLORS_SIZE + 272d5b1a78aSEric Anholt VC4_PACKET_TILE_COORDINATES_SIZE + 273d5b1a78aSEric Anholt VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE; 274d5b1a78aSEric Anholt } 275d5b1a78aSEric Anholt 276d5b1a78aSEric Anholt if (setup->color_read) { 277d5b1a78aSEric Anholt if (args->color_read.flags & 278d5b1a78aSEric Anholt VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) { 279d5b1a78aSEric Anholt loop_body_size += VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER_SIZE; 280d5b1a78aSEric Anholt } else { 281d5b1a78aSEric Anholt loop_body_size += VC4_PACKET_LOAD_TILE_BUFFER_GENERAL_SIZE; 282d5b1a78aSEric Anholt } 283d5b1a78aSEric Anholt } 284d5b1a78aSEric Anholt if (setup->zs_read) { 285d5b1a78aSEric Anholt if (args->zs_read.flags & 286d5b1a78aSEric Anholt VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) { 287d5b1a78aSEric Anholt loop_body_size += VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER_SIZE; 288d5b1a78aSEric Anholt } else { 289d5b1a78aSEric Anholt if (setup->color_read && 290d5b1a78aSEric Anholt !(args->color_read.flags & 291d5b1a78aSEric Anholt VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES)) { 292d5b1a78aSEric Anholt loop_body_size += VC4_PACKET_TILE_COORDINATES_SIZE; 293d5b1a78aSEric Anholt loop_body_size += VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE; 294d5b1a78aSEric Anholt } 295d5b1a78aSEric Anholt loop_body_size += VC4_PACKET_LOAD_TILE_BUFFER_GENERAL_SIZE; 296d5b1a78aSEric Anholt } 297d5b1a78aSEric Anholt } 298d5b1a78aSEric Anholt 299d5b1a78aSEric Anholt if (has_bin) { 300d5b1a78aSEric Anholt size += VC4_PACKET_WAIT_ON_SEMAPHORE_SIZE; 301d5b1a78aSEric Anholt loop_body_size += VC4_PACKET_BRANCH_TO_SUB_LIST_SIZE; 302d5b1a78aSEric Anholt } 303d5b1a78aSEric Anholt 304d5b1a78aSEric Anholt if (setup->msaa_color_write) 305d5b1a78aSEric Anholt loop_body_size += VC4_PACKET_STORE_FULL_RES_TILE_BUFFER_SIZE; 306d5b1a78aSEric Anholt if (setup->msaa_zs_write) 307d5b1a78aSEric Anholt loop_body_size += VC4_PACKET_STORE_FULL_RES_TILE_BUFFER_SIZE; 308d5b1a78aSEric Anholt 309d5b1a78aSEric Anholt if (setup->zs_write) 310d5b1a78aSEric Anholt loop_body_size += VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE; 311d5b1a78aSEric Anholt if (setup->color_write) 312d5b1a78aSEric Anholt loop_body_size += VC4_PACKET_STORE_MS_TILE_BUFFER_SIZE; 313d5b1a78aSEric Anholt 314d5b1a78aSEric Anholt /* We need a VC4_PACKET_TILE_COORDINATES in between each store. */ 315d5b1a78aSEric Anholt loop_body_size += VC4_PACKET_TILE_COORDINATES_SIZE * 316d5b1a78aSEric Anholt ((setup->msaa_color_write != NULL) + 317d5b1a78aSEric Anholt (setup->msaa_zs_write != NULL) + 318d5b1a78aSEric Anholt (setup->color_write != NULL) + 319d5b1a78aSEric Anholt (setup->zs_write != NULL) - 1); 320d5b1a78aSEric Anholt 321d5b1a78aSEric Anholt size += xtiles * ytiles * loop_body_size; 322d5b1a78aSEric Anholt 323*f3099462SEric Anholt setup->rcl = &vc4_bo_create(dev, size, true, VC4_BO_TYPE_RCL)->base; 3242c68f1fcSEric Anholt if (IS_ERR(setup->rcl)) 3252c68f1fcSEric Anholt return PTR_ERR(setup->rcl); 326d5b1a78aSEric Anholt list_add_tail(&to_vc4_bo(&setup->rcl->base)->unref_head, 327d5b1a78aSEric Anholt &exec->unref_list); 328d5b1a78aSEric Anholt 329d5b1a78aSEric Anholt /* The tile buffer gets cleared when the previous tile is stored. If 330d5b1a78aSEric Anholt * the clear values changed between frames, then the tile buffer has 331d5b1a78aSEric Anholt * stale clear values in it, so we have to do a store in None mode (no 332d5b1a78aSEric Anholt * writes) so that we trigger the tile buffer clear. 333d5b1a78aSEric Anholt */ 334d5b1a78aSEric Anholt if (args->flags & VC4_SUBMIT_CL_USE_CLEAR_COLOR) { 335d5b1a78aSEric Anholt rcl_u8(setup, VC4_PACKET_CLEAR_COLORS); 336d5b1a78aSEric Anholt rcl_u32(setup, args->clear_color[0]); 337d5b1a78aSEric Anholt rcl_u32(setup, args->clear_color[1]); 338d5b1a78aSEric Anholt rcl_u32(setup, args->clear_z); 339d5b1a78aSEric Anholt rcl_u8(setup, args->clear_s); 340d5b1a78aSEric Anholt 341d5b1a78aSEric Anholt vc4_tile_coordinates(setup, 0, 0); 342d5b1a78aSEric Anholt 343d5b1a78aSEric Anholt rcl_u8(setup, VC4_PACKET_STORE_TILE_BUFFER_GENERAL); 344d5b1a78aSEric Anholt rcl_u16(setup, VC4_LOADSTORE_TILE_BUFFER_NONE); 345d5b1a78aSEric Anholt rcl_u32(setup, 0); /* no address, since we're in None mode */ 346d5b1a78aSEric Anholt } 347d5b1a78aSEric Anholt 34854aec44aSEric Anholt rcl_u8(setup, VC4_PACKET_TILE_RENDERING_MODE_CONFIG); 34954aec44aSEric Anholt rcl_u32(setup, 35054aec44aSEric Anholt (setup->color_write ? (setup->color_write->paddr + 35154aec44aSEric Anholt args->color_write.offset) : 35254aec44aSEric Anholt 0)); 35354aec44aSEric Anholt rcl_u16(setup, args->width); 35454aec44aSEric Anholt rcl_u16(setup, args->height); 35554aec44aSEric Anholt rcl_u16(setup, args->color_write.bits); 35654aec44aSEric Anholt 357d5b1a78aSEric Anholt for (y = min_y_tile; y <= max_y_tile; y++) { 358d5b1a78aSEric Anholt for (x = min_x_tile; x <= max_x_tile; x++) { 359d5b1a78aSEric Anholt bool first = (x == min_x_tile && y == min_y_tile); 360d5b1a78aSEric Anholt bool last = (x == max_x_tile && y == max_y_tile); 361d5b1a78aSEric Anholt 362d5b1a78aSEric Anholt emit_tile(exec, setup, x, y, first, last); 363d5b1a78aSEric Anholt } 364d5b1a78aSEric Anholt } 365d5b1a78aSEric Anholt 366d5b1a78aSEric Anholt BUG_ON(setup->next_offset != size); 367d5b1a78aSEric Anholt exec->ct1ca = setup->rcl->paddr; 368d5b1a78aSEric Anholt exec->ct1ea = setup->rcl->paddr + setup->next_offset; 369d5b1a78aSEric Anholt 370d5b1a78aSEric Anholt return 0; 371d5b1a78aSEric Anholt } 372d5b1a78aSEric Anholt 373d5b1a78aSEric Anholt static int vc4_full_res_bounds_check(struct vc4_exec_info *exec, 374d5b1a78aSEric Anholt struct drm_gem_cma_object *obj, 375d5b1a78aSEric Anholt struct drm_vc4_submit_rcl_surface *surf) 376d5b1a78aSEric Anholt { 377d5b1a78aSEric Anholt struct drm_vc4_submit_cl *args = exec->args; 378d5b1a78aSEric Anholt u32 render_tiles_stride = DIV_ROUND_UP(exec->args->width, 32); 379d5b1a78aSEric Anholt 380d5b1a78aSEric Anholt if (surf->offset > obj->base.size) { 381d5b1a78aSEric Anholt DRM_ERROR("surface offset %d > BO size %zd\n", 382d5b1a78aSEric Anholt surf->offset, obj->base.size); 383d5b1a78aSEric Anholt return -EINVAL; 384d5b1a78aSEric Anholt } 385d5b1a78aSEric Anholt 386d5b1a78aSEric Anholt if ((obj->base.size - surf->offset) / VC4_TILE_BUFFER_SIZE < 387d5b1a78aSEric Anholt render_tiles_stride * args->max_y_tile + args->max_x_tile) { 388d5b1a78aSEric Anholt DRM_ERROR("MSAA tile %d, %d out of bounds " 389d5b1a78aSEric Anholt "(bo size %zd, offset %d).\n", 390d5b1a78aSEric Anholt args->max_x_tile, args->max_y_tile, 391d5b1a78aSEric Anholt obj->base.size, 392d5b1a78aSEric Anholt surf->offset); 393d5b1a78aSEric Anholt return -EINVAL; 394d5b1a78aSEric Anholt } 395d5b1a78aSEric Anholt 396d5b1a78aSEric Anholt return 0; 397d5b1a78aSEric Anholt } 398d5b1a78aSEric Anholt 399d5b1a78aSEric Anholt static int vc4_rcl_msaa_surface_setup(struct vc4_exec_info *exec, 400d5b1a78aSEric Anholt struct drm_gem_cma_object **obj, 401d5b1a78aSEric Anholt struct drm_vc4_submit_rcl_surface *surf) 402d5b1a78aSEric Anholt { 403d5b1a78aSEric Anholt if (surf->flags != 0 || surf->bits != 0) { 404d5b1a78aSEric Anholt DRM_ERROR("MSAA surface had nonzero flags/bits\n"); 405d5b1a78aSEric Anholt return -EINVAL; 406d5b1a78aSEric Anholt } 407d5b1a78aSEric Anholt 408d5b1a78aSEric Anholt if (surf->hindex == ~0) 409d5b1a78aSEric Anholt return 0; 410d5b1a78aSEric Anholt 411d5b1a78aSEric Anholt *obj = vc4_use_bo(exec, surf->hindex); 412d5b1a78aSEric Anholt if (!*obj) 413d5b1a78aSEric Anholt return -EINVAL; 414d5b1a78aSEric Anholt 4157edabee0SEric Anholt exec->rcl_write_bo[exec->rcl_write_bo_count++] = *obj; 4167edabee0SEric Anholt 417d5b1a78aSEric Anholt if (surf->offset & 0xf) { 418d5b1a78aSEric Anholt DRM_ERROR("MSAA write must be 16b aligned.\n"); 419d5b1a78aSEric Anholt return -EINVAL; 420d5b1a78aSEric Anholt } 421d5b1a78aSEric Anholt 422d5b1a78aSEric Anholt return vc4_full_res_bounds_check(exec, *obj, surf); 423d5b1a78aSEric Anholt } 424d5b1a78aSEric Anholt 425d5b1a78aSEric Anholt static int vc4_rcl_surface_setup(struct vc4_exec_info *exec, 426d5b1a78aSEric Anholt struct drm_gem_cma_object **obj, 4277edabee0SEric Anholt struct drm_vc4_submit_rcl_surface *surf, 4287edabee0SEric Anholt bool is_write) 429d5b1a78aSEric Anholt { 430d5b1a78aSEric Anholt uint8_t tiling = VC4_GET_FIELD(surf->bits, 431d5b1a78aSEric Anholt VC4_LOADSTORE_TILE_BUFFER_TILING); 432d5b1a78aSEric Anholt uint8_t buffer = VC4_GET_FIELD(surf->bits, 433d5b1a78aSEric Anholt VC4_LOADSTORE_TILE_BUFFER_BUFFER); 434d5b1a78aSEric Anholt uint8_t format = VC4_GET_FIELD(surf->bits, 435d5b1a78aSEric Anholt VC4_LOADSTORE_TILE_BUFFER_FORMAT); 436d5b1a78aSEric Anholt int cpp; 437d5b1a78aSEric Anholt int ret; 438d5b1a78aSEric Anholt 439d5b1a78aSEric Anholt if (surf->flags & ~VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) { 440d5b1a78aSEric Anholt DRM_ERROR("Extra flags set\n"); 441d5b1a78aSEric Anholt return -EINVAL; 442d5b1a78aSEric Anholt } 443d5b1a78aSEric Anholt 444d5b1a78aSEric Anholt if (surf->hindex == ~0) 445d5b1a78aSEric Anholt return 0; 446d5b1a78aSEric Anholt 447d5b1a78aSEric Anholt *obj = vc4_use_bo(exec, surf->hindex); 448d5b1a78aSEric Anholt if (!*obj) 449d5b1a78aSEric Anholt return -EINVAL; 450d5b1a78aSEric Anholt 4517edabee0SEric Anholt if (is_write) 4527edabee0SEric Anholt exec->rcl_write_bo[exec->rcl_write_bo_count++] = *obj; 4537edabee0SEric Anholt 454d5b1a78aSEric Anholt if (surf->flags & VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) { 455d5b1a78aSEric Anholt if (surf == &exec->args->zs_write) { 456d5b1a78aSEric Anholt DRM_ERROR("general zs write may not be a full-res.\n"); 457d5b1a78aSEric Anholt return -EINVAL; 458d5b1a78aSEric Anholt } 459d5b1a78aSEric Anholt 460d5b1a78aSEric Anholt if (surf->bits != 0) { 461d5b1a78aSEric Anholt DRM_ERROR("load/store general bits set with " 462d5b1a78aSEric Anholt "full res load/store.\n"); 463d5b1a78aSEric Anholt return -EINVAL; 464d5b1a78aSEric Anholt } 465d5b1a78aSEric Anholt 466d5b1a78aSEric Anholt ret = vc4_full_res_bounds_check(exec, *obj, surf); 46721ccc324SDan Carpenter if (ret) 468d5b1a78aSEric Anholt return ret; 469d5b1a78aSEric Anholt 470d5b1a78aSEric Anholt return 0; 471d5b1a78aSEric Anholt } 472d5b1a78aSEric Anholt 473d5b1a78aSEric Anholt if (surf->bits & ~(VC4_LOADSTORE_TILE_BUFFER_TILING_MASK | 474d5b1a78aSEric Anholt VC4_LOADSTORE_TILE_BUFFER_BUFFER_MASK | 475d5b1a78aSEric Anholt VC4_LOADSTORE_TILE_BUFFER_FORMAT_MASK)) { 476d5b1a78aSEric Anholt DRM_ERROR("Unknown bits in load/store: 0x%04x\n", 477d5b1a78aSEric Anholt surf->bits); 478d5b1a78aSEric Anholt return -EINVAL; 479d5b1a78aSEric Anholt } 480d5b1a78aSEric Anholt 481d5b1a78aSEric Anholt if (tiling > VC4_TILING_FORMAT_LT) { 482d5b1a78aSEric Anholt DRM_ERROR("Bad tiling format\n"); 483d5b1a78aSEric Anholt return -EINVAL; 484d5b1a78aSEric Anholt } 485d5b1a78aSEric Anholt 486d5b1a78aSEric Anholt if (buffer == VC4_LOADSTORE_TILE_BUFFER_ZS) { 487d5b1a78aSEric Anholt if (format != 0) { 488d5b1a78aSEric Anholt DRM_ERROR("No color format should be set for ZS\n"); 489d5b1a78aSEric Anholt return -EINVAL; 490d5b1a78aSEric Anholt } 491d5b1a78aSEric Anholt cpp = 4; 492d5b1a78aSEric Anholt } else if (buffer == VC4_LOADSTORE_TILE_BUFFER_COLOR) { 493d5b1a78aSEric Anholt switch (format) { 494d5b1a78aSEric Anholt case VC4_LOADSTORE_TILE_BUFFER_BGR565: 495d5b1a78aSEric Anholt case VC4_LOADSTORE_TILE_BUFFER_BGR565_DITHER: 496d5b1a78aSEric Anholt cpp = 2; 497d5b1a78aSEric Anholt break; 498d5b1a78aSEric Anholt case VC4_LOADSTORE_TILE_BUFFER_RGBA8888: 499d5b1a78aSEric Anholt cpp = 4; 500d5b1a78aSEric Anholt break; 501d5b1a78aSEric Anholt default: 502d5b1a78aSEric Anholt DRM_ERROR("Bad tile buffer format\n"); 503d5b1a78aSEric Anholt return -EINVAL; 504d5b1a78aSEric Anholt } 505d5b1a78aSEric Anholt } else { 506d5b1a78aSEric Anholt DRM_ERROR("Bad load/store buffer %d.\n", buffer); 507d5b1a78aSEric Anholt return -EINVAL; 508d5b1a78aSEric Anholt } 509d5b1a78aSEric Anholt 510d5b1a78aSEric Anholt if (surf->offset & 0xf) { 511d5b1a78aSEric Anholt DRM_ERROR("load/store buffer must be 16b aligned.\n"); 512d5b1a78aSEric Anholt return -EINVAL; 513d5b1a78aSEric Anholt } 514d5b1a78aSEric Anholt 515d5b1a78aSEric Anholt if (!vc4_check_tex_size(exec, *obj, surf->offset, tiling, 516d5b1a78aSEric Anholt exec->args->width, exec->args->height, cpp)) { 517d5b1a78aSEric Anholt return -EINVAL; 518d5b1a78aSEric Anholt } 519d5b1a78aSEric Anholt 520d5b1a78aSEric Anholt return 0; 521d5b1a78aSEric Anholt } 522d5b1a78aSEric Anholt 523d5b1a78aSEric Anholt static int 524d5b1a78aSEric Anholt vc4_rcl_render_config_surface_setup(struct vc4_exec_info *exec, 525d5b1a78aSEric Anholt struct vc4_rcl_setup *setup, 526d5b1a78aSEric Anholt struct drm_gem_cma_object **obj, 527d5b1a78aSEric Anholt struct drm_vc4_submit_rcl_surface *surf) 528d5b1a78aSEric Anholt { 529d5b1a78aSEric Anholt uint8_t tiling = VC4_GET_FIELD(surf->bits, 530d5b1a78aSEric Anholt VC4_RENDER_CONFIG_MEMORY_FORMAT); 531d5b1a78aSEric Anholt uint8_t format = VC4_GET_FIELD(surf->bits, 532d5b1a78aSEric Anholt VC4_RENDER_CONFIG_FORMAT); 533d5b1a78aSEric Anholt int cpp; 534d5b1a78aSEric Anholt 535d5b1a78aSEric Anholt if (surf->flags != 0) { 536d5b1a78aSEric Anholt DRM_ERROR("No flags supported on render config.\n"); 537d5b1a78aSEric Anholt return -EINVAL; 538d5b1a78aSEric Anholt } 539d5b1a78aSEric Anholt 540d5b1a78aSEric Anholt if (surf->bits & ~(VC4_RENDER_CONFIG_MEMORY_FORMAT_MASK | 541d5b1a78aSEric Anholt VC4_RENDER_CONFIG_FORMAT_MASK | 542d5b1a78aSEric Anholt VC4_RENDER_CONFIG_MS_MODE_4X | 543d5b1a78aSEric Anholt VC4_RENDER_CONFIG_DECIMATE_MODE_4X)) { 544d5b1a78aSEric Anholt DRM_ERROR("Unknown bits in render config: 0x%04x\n", 545d5b1a78aSEric Anholt surf->bits); 546d5b1a78aSEric Anholt return -EINVAL; 547d5b1a78aSEric Anholt } 548d5b1a78aSEric Anholt 549d5b1a78aSEric Anholt if (surf->hindex == ~0) 550d5b1a78aSEric Anholt return 0; 551d5b1a78aSEric Anholt 552d5b1a78aSEric Anholt *obj = vc4_use_bo(exec, surf->hindex); 553d5b1a78aSEric Anholt if (!*obj) 554d5b1a78aSEric Anholt return -EINVAL; 555d5b1a78aSEric Anholt 5567edabee0SEric Anholt exec->rcl_write_bo[exec->rcl_write_bo_count++] = *obj; 5577edabee0SEric Anholt 558d5b1a78aSEric Anholt if (tiling > VC4_TILING_FORMAT_LT) { 559d5b1a78aSEric Anholt DRM_ERROR("Bad tiling format\n"); 560d5b1a78aSEric Anholt return -EINVAL; 561d5b1a78aSEric Anholt } 562d5b1a78aSEric Anholt 563d5b1a78aSEric Anholt switch (format) { 564d5b1a78aSEric Anholt case VC4_RENDER_CONFIG_FORMAT_BGR565_DITHERED: 565d5b1a78aSEric Anholt case VC4_RENDER_CONFIG_FORMAT_BGR565: 566d5b1a78aSEric Anholt cpp = 2; 567d5b1a78aSEric Anholt break; 568d5b1a78aSEric Anholt case VC4_RENDER_CONFIG_FORMAT_RGBA8888: 569d5b1a78aSEric Anholt cpp = 4; 570d5b1a78aSEric Anholt break; 571d5b1a78aSEric Anholt default: 572d5b1a78aSEric Anholt DRM_ERROR("Bad tile buffer format\n"); 573d5b1a78aSEric Anholt return -EINVAL; 574d5b1a78aSEric Anholt } 575d5b1a78aSEric Anholt 576d5b1a78aSEric Anholt if (!vc4_check_tex_size(exec, *obj, surf->offset, tiling, 577d5b1a78aSEric Anholt exec->args->width, exec->args->height, cpp)) { 578d5b1a78aSEric Anholt return -EINVAL; 579d5b1a78aSEric Anholt } 580d5b1a78aSEric Anholt 581d5b1a78aSEric Anholt return 0; 582d5b1a78aSEric Anholt } 583d5b1a78aSEric Anholt 584d5b1a78aSEric Anholt int vc4_get_rcl(struct drm_device *dev, struct vc4_exec_info *exec) 585d5b1a78aSEric Anholt { 586d5b1a78aSEric Anholt struct vc4_rcl_setup setup = {0}; 587d5b1a78aSEric Anholt struct drm_vc4_submit_cl *args = exec->args; 588d5b1a78aSEric Anholt bool has_bin = args->bin_cl_size != 0; 589d5b1a78aSEric Anholt int ret; 590d5b1a78aSEric Anholt 591d5b1a78aSEric Anholt if (args->min_x_tile > args->max_x_tile || 592d5b1a78aSEric Anholt args->min_y_tile > args->max_y_tile) { 593d5b1a78aSEric Anholt DRM_ERROR("Bad render tile set (%d,%d)-(%d,%d)\n", 594d5b1a78aSEric Anholt args->min_x_tile, args->min_y_tile, 595d5b1a78aSEric Anholt args->max_x_tile, args->max_y_tile); 596d5b1a78aSEric Anholt return -EINVAL; 597d5b1a78aSEric Anholt } 598d5b1a78aSEric Anholt 599d5b1a78aSEric Anholt if (has_bin && 600d5b1a78aSEric Anholt (args->max_x_tile > exec->bin_tiles_x || 601d5b1a78aSEric Anholt args->max_y_tile > exec->bin_tiles_y)) { 602d5b1a78aSEric Anholt DRM_ERROR("Render tiles (%d,%d) outside of bin config " 603d5b1a78aSEric Anholt "(%d,%d)\n", 604d5b1a78aSEric Anholt args->max_x_tile, args->max_y_tile, 605d5b1a78aSEric Anholt exec->bin_tiles_x, exec->bin_tiles_y); 606d5b1a78aSEric Anholt return -EINVAL; 607d5b1a78aSEric Anholt } 608d5b1a78aSEric Anholt 609d5b1a78aSEric Anholt ret = vc4_rcl_render_config_surface_setup(exec, &setup, 610d5b1a78aSEric Anholt &setup.color_write, 611d5b1a78aSEric Anholt &args->color_write); 612d5b1a78aSEric Anholt if (ret) 613d5b1a78aSEric Anholt return ret; 614d5b1a78aSEric Anholt 6157edabee0SEric Anholt ret = vc4_rcl_surface_setup(exec, &setup.color_read, &args->color_read, 6167edabee0SEric Anholt false); 617d5b1a78aSEric Anholt if (ret) 618d5b1a78aSEric Anholt return ret; 619d5b1a78aSEric Anholt 6207edabee0SEric Anholt ret = vc4_rcl_surface_setup(exec, &setup.zs_read, &args->zs_read, 6217edabee0SEric Anholt false); 622d5b1a78aSEric Anholt if (ret) 623d5b1a78aSEric Anholt return ret; 624d5b1a78aSEric Anholt 6257edabee0SEric Anholt ret = vc4_rcl_surface_setup(exec, &setup.zs_write, &args->zs_write, 6267edabee0SEric Anholt true); 627d5b1a78aSEric Anholt if (ret) 628d5b1a78aSEric Anholt return ret; 629d5b1a78aSEric Anholt 630d5b1a78aSEric Anholt ret = vc4_rcl_msaa_surface_setup(exec, &setup.msaa_color_write, 631d5b1a78aSEric Anholt &args->msaa_color_write); 632d5b1a78aSEric Anholt if (ret) 633d5b1a78aSEric Anholt return ret; 634d5b1a78aSEric Anholt 635d5b1a78aSEric Anholt ret = vc4_rcl_msaa_surface_setup(exec, &setup.msaa_zs_write, 636d5b1a78aSEric Anholt &args->msaa_zs_write); 637d5b1a78aSEric Anholt if (ret) 638d5b1a78aSEric Anholt return ret; 639d5b1a78aSEric Anholt 640d5b1a78aSEric Anholt /* We shouldn't even have the job submitted to us if there's no 641d5b1a78aSEric Anholt * surface to write out. 642d5b1a78aSEric Anholt */ 643d5b1a78aSEric Anholt if (!setup.color_write && !setup.zs_write && 644d5b1a78aSEric Anholt !setup.msaa_color_write && !setup.msaa_zs_write) { 645d5b1a78aSEric Anholt DRM_ERROR("RCL requires color or Z/S write\n"); 646d5b1a78aSEric Anholt return -EINVAL; 647d5b1a78aSEric Anholt } 648d5b1a78aSEric Anholt 649d5b1a78aSEric Anholt return vc4_create_rcl_bo(dev, exec, &setup); 650d5b1a78aSEric Anholt } 651