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