1b8e80941Smrg/* 2b8e80941Smrg * Copyright © 2014-2015 Broadcom 3b8e80941Smrg * 4b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a 5b8e80941Smrg * copy of this software and associated documentation files (the "Software"), 6b8e80941Smrg * to deal in the Software without restriction, including without limitation 7b8e80941Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8b8e80941Smrg * and/or sell copies of the Software, and to permit persons to whom the 9b8e80941Smrg * Software is furnished to do so, subject to the following conditions: 10b8e80941Smrg * 11b8e80941Smrg * The above copyright notice and this permission notice (including the next 12b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the 13b8e80941Smrg * Software. 14b8e80941Smrg * 15b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18b8e80941Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19b8e80941Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20b8e80941Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21b8e80941Smrg * IN THE SOFTWARE. 22b8e80941Smrg */ 23b8e80941Smrg 24b8e80941Smrg/** @file vc4_job.c 25b8e80941Smrg * 26b8e80941Smrg * Functions for submitting VC4 render jobs to the kernel. 27b8e80941Smrg */ 28b8e80941Smrg 29b8e80941Smrg#include <xf86drm.h> 30b8e80941Smrg#include "vc4_cl_dump.h" 31b8e80941Smrg#include "vc4_context.h" 32b8e80941Smrg#include "util/hash_table.h" 33b8e80941Smrg 34b8e80941Smrgstatic void 35b8e80941Smrgvc4_job_free(struct vc4_context *vc4, struct vc4_job *job) 36b8e80941Smrg{ 37b8e80941Smrg struct vc4_bo **referenced_bos = job->bo_pointers.base; 38b8e80941Smrg for (int i = 0; i < cl_offset(&job->bo_handles) / 4; i++) { 39b8e80941Smrg vc4_bo_unreference(&referenced_bos[i]); 40b8e80941Smrg } 41b8e80941Smrg 42b8e80941Smrg _mesa_hash_table_remove_key(vc4->jobs, &job->key); 43b8e80941Smrg 44b8e80941Smrg if (job->color_write) { 45b8e80941Smrg _mesa_hash_table_remove_key(vc4->write_jobs, 46b8e80941Smrg job->color_write->texture); 47b8e80941Smrg pipe_surface_reference(&job->color_write, NULL); 48b8e80941Smrg } 49b8e80941Smrg if (job->msaa_color_write) { 50b8e80941Smrg _mesa_hash_table_remove_key(vc4->write_jobs, 51b8e80941Smrg job->msaa_color_write->texture); 52b8e80941Smrg pipe_surface_reference(&job->msaa_color_write, NULL); 53b8e80941Smrg } 54b8e80941Smrg if (job->zs_write) { 55b8e80941Smrg _mesa_hash_table_remove_key(vc4->write_jobs, 56b8e80941Smrg job->zs_write->texture); 57b8e80941Smrg pipe_surface_reference(&job->zs_write, NULL); 58b8e80941Smrg } 59b8e80941Smrg if (job->msaa_zs_write) { 60b8e80941Smrg _mesa_hash_table_remove_key(vc4->write_jobs, 61b8e80941Smrg job->msaa_zs_write->texture); 62b8e80941Smrg pipe_surface_reference(&job->msaa_zs_write, NULL); 63b8e80941Smrg } 64b8e80941Smrg 65b8e80941Smrg pipe_surface_reference(&job->color_read, NULL); 66b8e80941Smrg pipe_surface_reference(&job->zs_read, NULL); 67b8e80941Smrg 68b8e80941Smrg if (vc4->job == job) 69b8e80941Smrg vc4->job = NULL; 70b8e80941Smrg 71b8e80941Smrg ralloc_free(job); 72b8e80941Smrg} 73b8e80941Smrg 74b8e80941Smrgstatic struct vc4_job * 75b8e80941Smrgvc4_job_create(struct vc4_context *vc4) 76b8e80941Smrg{ 77b8e80941Smrg struct vc4_job *job = rzalloc(vc4, struct vc4_job); 78b8e80941Smrg 79b8e80941Smrg vc4_init_cl(job, &job->bcl); 80b8e80941Smrg vc4_init_cl(job, &job->shader_rec); 81b8e80941Smrg vc4_init_cl(job, &job->uniforms); 82b8e80941Smrg vc4_init_cl(job, &job->bo_handles); 83b8e80941Smrg vc4_init_cl(job, &job->bo_pointers); 84b8e80941Smrg 85b8e80941Smrg job->draw_min_x = ~0; 86b8e80941Smrg job->draw_min_y = ~0; 87b8e80941Smrg job->draw_max_x = 0; 88b8e80941Smrg job->draw_max_y = 0; 89b8e80941Smrg 90b8e80941Smrg job->last_gem_handle_hindex = ~0; 91b8e80941Smrg 92b8e80941Smrg if (vc4->perfmon) 93b8e80941Smrg job->perfmon = vc4->perfmon; 94b8e80941Smrg 95b8e80941Smrg return job; 96b8e80941Smrg} 97b8e80941Smrg 98b8e80941Smrgvoid 99b8e80941Smrgvc4_flush_jobs_writing_resource(struct vc4_context *vc4, 100b8e80941Smrg struct pipe_resource *prsc) 101b8e80941Smrg{ 102b8e80941Smrg struct hash_entry *entry = _mesa_hash_table_search(vc4->write_jobs, 103b8e80941Smrg prsc); 104b8e80941Smrg if (entry) { 105b8e80941Smrg struct vc4_job *job = entry->data; 106b8e80941Smrg vc4_job_submit(vc4, job); 107b8e80941Smrg } 108b8e80941Smrg} 109b8e80941Smrg 110b8e80941Smrgvoid 111b8e80941Smrgvc4_flush_jobs_reading_resource(struct vc4_context *vc4, 112b8e80941Smrg struct pipe_resource *prsc) 113b8e80941Smrg{ 114b8e80941Smrg struct vc4_resource *rsc = vc4_resource(prsc); 115b8e80941Smrg 116b8e80941Smrg vc4_flush_jobs_writing_resource(vc4, prsc); 117b8e80941Smrg 118b8e80941Smrg hash_table_foreach(vc4->jobs, entry) { 119b8e80941Smrg struct vc4_job *job = entry->data; 120b8e80941Smrg 121b8e80941Smrg struct vc4_bo **referenced_bos = job->bo_pointers.base; 122b8e80941Smrg bool found = false; 123b8e80941Smrg for (int i = 0; i < cl_offset(&job->bo_handles) / 4; i++) { 124b8e80941Smrg if (referenced_bos[i] == rsc->bo) { 125b8e80941Smrg found = true; 126b8e80941Smrg break; 127b8e80941Smrg } 128b8e80941Smrg } 129b8e80941Smrg if (found) { 130b8e80941Smrg vc4_job_submit(vc4, job); 131b8e80941Smrg continue; 132b8e80941Smrg } 133b8e80941Smrg 134b8e80941Smrg /* Also check for the Z/color buffers, since the references to 135b8e80941Smrg * those are only added immediately before submit. 136b8e80941Smrg */ 137b8e80941Smrg if (job->color_read && !(job->cleared & PIPE_CLEAR_COLOR)) { 138b8e80941Smrg struct vc4_resource *ctex = 139b8e80941Smrg vc4_resource(job->color_read->texture); 140b8e80941Smrg if (ctex->bo == rsc->bo) { 141b8e80941Smrg vc4_job_submit(vc4, job); 142b8e80941Smrg continue; 143b8e80941Smrg } 144b8e80941Smrg } 145b8e80941Smrg 146b8e80941Smrg if (job->zs_read && !(job->cleared & 147b8e80941Smrg (PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL))) { 148b8e80941Smrg struct vc4_resource *ztex = 149b8e80941Smrg vc4_resource(job->zs_read->texture); 150b8e80941Smrg if (ztex->bo == rsc->bo) { 151b8e80941Smrg vc4_job_submit(vc4, job); 152b8e80941Smrg continue; 153b8e80941Smrg } 154b8e80941Smrg } 155b8e80941Smrg } 156b8e80941Smrg} 157b8e80941Smrg 158b8e80941Smrg/** 159b8e80941Smrg * Returns a vc4_job struture for tracking V3D rendering to a particular FBO. 160b8e80941Smrg * 161b8e80941Smrg * If we've already started rendering to this FBO, then return old same job, 162b8e80941Smrg * otherwise make a new one. If we're beginning rendering to an FBO, make 163b8e80941Smrg * sure that any previous reads of the FBO (or writes to its color/Z surfaces) 164b8e80941Smrg * have been flushed. 165b8e80941Smrg */ 166b8e80941Smrgstruct vc4_job * 167b8e80941Smrgvc4_get_job(struct vc4_context *vc4, 168b8e80941Smrg struct pipe_surface *cbuf, struct pipe_surface *zsbuf) 169b8e80941Smrg{ 170b8e80941Smrg /* Return the existing job for this FBO if we have one */ 171b8e80941Smrg struct vc4_job_key local_key = {.cbuf = cbuf, .zsbuf = zsbuf}; 172b8e80941Smrg struct hash_entry *entry = _mesa_hash_table_search(vc4->jobs, 173b8e80941Smrg &local_key); 174b8e80941Smrg if (entry) 175b8e80941Smrg return entry->data; 176b8e80941Smrg 177b8e80941Smrg /* Creating a new job. Make sure that any previous jobs reading or 178b8e80941Smrg * writing these buffers are flushed. 179b8e80941Smrg */ 180b8e80941Smrg if (cbuf) 181b8e80941Smrg vc4_flush_jobs_reading_resource(vc4, cbuf->texture); 182b8e80941Smrg if (zsbuf) 183b8e80941Smrg vc4_flush_jobs_reading_resource(vc4, zsbuf->texture); 184b8e80941Smrg 185b8e80941Smrg struct vc4_job *job = vc4_job_create(vc4); 186b8e80941Smrg 187b8e80941Smrg if (cbuf) { 188b8e80941Smrg if (cbuf->texture->nr_samples > 1) { 189b8e80941Smrg job->msaa = true; 190b8e80941Smrg pipe_surface_reference(&job->msaa_color_write, cbuf); 191b8e80941Smrg } else { 192b8e80941Smrg pipe_surface_reference(&job->color_write, cbuf); 193b8e80941Smrg } 194b8e80941Smrg } 195b8e80941Smrg 196b8e80941Smrg if (zsbuf) { 197b8e80941Smrg if (zsbuf->texture->nr_samples > 1) { 198b8e80941Smrg job->msaa = true; 199b8e80941Smrg pipe_surface_reference(&job->msaa_zs_write, zsbuf); 200b8e80941Smrg } else { 201b8e80941Smrg pipe_surface_reference(&job->zs_write, zsbuf); 202b8e80941Smrg } 203b8e80941Smrg } 204b8e80941Smrg 205b8e80941Smrg if (job->msaa) { 206b8e80941Smrg job->tile_width = 32; 207b8e80941Smrg job->tile_height = 32; 208b8e80941Smrg } else { 209b8e80941Smrg job->tile_width = 64; 210b8e80941Smrg job->tile_height = 64; 211b8e80941Smrg } 212b8e80941Smrg 213b8e80941Smrg if (cbuf) 214b8e80941Smrg _mesa_hash_table_insert(vc4->write_jobs, cbuf->texture, job); 215b8e80941Smrg if (zsbuf) 216b8e80941Smrg _mesa_hash_table_insert(vc4->write_jobs, zsbuf->texture, job); 217b8e80941Smrg 218b8e80941Smrg job->key.cbuf = cbuf; 219b8e80941Smrg job->key.zsbuf = zsbuf; 220b8e80941Smrg _mesa_hash_table_insert(vc4->jobs, &job->key, job); 221b8e80941Smrg 222b8e80941Smrg return job; 223b8e80941Smrg} 224b8e80941Smrg 225b8e80941Smrgstruct vc4_job * 226b8e80941Smrgvc4_get_job_for_fbo(struct vc4_context *vc4) 227b8e80941Smrg{ 228b8e80941Smrg if (vc4->job) 229b8e80941Smrg return vc4->job; 230b8e80941Smrg 231b8e80941Smrg struct pipe_surface *cbuf = vc4->framebuffer.cbufs[0]; 232b8e80941Smrg struct pipe_surface *zsbuf = vc4->framebuffer.zsbuf; 233b8e80941Smrg struct vc4_job *job = vc4_get_job(vc4, cbuf, zsbuf); 234b8e80941Smrg 235b8e80941Smrg /* The dirty flags are tracking what's been updated while vc4->job has 236b8e80941Smrg * been bound, so set them all to ~0 when switching between jobs. We 237b8e80941Smrg * also need to reset all state at the start of rendering. 238b8e80941Smrg */ 239b8e80941Smrg vc4->dirty = ~0; 240b8e80941Smrg 241b8e80941Smrg /* Set up the read surfaces in the job. If they aren't actually 242b8e80941Smrg * getting read (due to a clear starting the frame), job->cleared will 243b8e80941Smrg * mask out the read. 244b8e80941Smrg */ 245b8e80941Smrg pipe_surface_reference(&job->color_read, cbuf); 246b8e80941Smrg pipe_surface_reference(&job->zs_read, zsbuf); 247b8e80941Smrg 248b8e80941Smrg /* If we're binding to uninitialized buffers, no need to load their 249b8e80941Smrg * contents before drawing. 250b8e80941Smrg */ 251b8e80941Smrg if (cbuf) { 252b8e80941Smrg struct vc4_resource *rsc = vc4_resource(cbuf->texture); 253b8e80941Smrg if (!rsc->writes) 254b8e80941Smrg job->cleared |= PIPE_CLEAR_COLOR0; 255b8e80941Smrg } 256b8e80941Smrg 257b8e80941Smrg if (zsbuf) { 258b8e80941Smrg struct vc4_resource *rsc = vc4_resource(zsbuf->texture); 259b8e80941Smrg if (!rsc->writes) 260b8e80941Smrg job->cleared |= PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL; 261b8e80941Smrg } 262b8e80941Smrg 263b8e80941Smrg job->draw_tiles_x = DIV_ROUND_UP(vc4->framebuffer.width, 264b8e80941Smrg job->tile_width); 265b8e80941Smrg job->draw_tiles_y = DIV_ROUND_UP(vc4->framebuffer.height, 266b8e80941Smrg job->tile_height); 267b8e80941Smrg 268b8e80941Smrg /* Initialize the job with the raster order flags -- each draw will 269b8e80941Smrg * check that we haven't changed the flags, since that requires a 270b8e80941Smrg * flush. 271b8e80941Smrg */ 272b8e80941Smrg if (vc4->rasterizer) 273b8e80941Smrg job->flags = vc4->rasterizer->tile_raster_order_flags; 274b8e80941Smrg 275b8e80941Smrg vc4->job = job; 276b8e80941Smrg 277b8e80941Smrg return job; 278b8e80941Smrg} 279b8e80941Smrg 280b8e80941Smrgstatic void 281b8e80941Smrgvc4_submit_setup_rcl_surface(struct vc4_job *job, 282b8e80941Smrg struct drm_vc4_submit_rcl_surface *submit_surf, 283b8e80941Smrg struct pipe_surface *psurf, 284b8e80941Smrg bool is_depth, bool is_write) 285b8e80941Smrg{ 286b8e80941Smrg struct vc4_surface *surf = vc4_surface(psurf); 287b8e80941Smrg 288b8e80941Smrg if (!surf) 289b8e80941Smrg return; 290b8e80941Smrg 291b8e80941Smrg struct vc4_resource *rsc = vc4_resource(psurf->texture); 292b8e80941Smrg submit_surf->hindex = vc4_gem_hindex(job, rsc->bo); 293b8e80941Smrg submit_surf->offset = surf->offset; 294b8e80941Smrg 295b8e80941Smrg if (psurf->texture->nr_samples <= 1) { 296b8e80941Smrg if (is_depth) { 297b8e80941Smrg submit_surf->bits = 298b8e80941Smrg VC4_SET_FIELD(VC4_LOADSTORE_TILE_BUFFER_ZS, 299b8e80941Smrg VC4_LOADSTORE_TILE_BUFFER_BUFFER); 300b8e80941Smrg 301b8e80941Smrg } else { 302b8e80941Smrg submit_surf->bits = 303b8e80941Smrg VC4_SET_FIELD(VC4_LOADSTORE_TILE_BUFFER_COLOR, 304b8e80941Smrg VC4_LOADSTORE_TILE_BUFFER_BUFFER) | 305b8e80941Smrg VC4_SET_FIELD(vc4_rt_format_is_565(psurf->format) ? 306b8e80941Smrg VC4_LOADSTORE_TILE_BUFFER_BGR565 : 307b8e80941Smrg VC4_LOADSTORE_TILE_BUFFER_RGBA8888, 308b8e80941Smrg VC4_LOADSTORE_TILE_BUFFER_FORMAT); 309b8e80941Smrg } 310b8e80941Smrg submit_surf->bits |= 311b8e80941Smrg VC4_SET_FIELD(surf->tiling, 312b8e80941Smrg VC4_LOADSTORE_TILE_BUFFER_TILING); 313b8e80941Smrg } else { 314b8e80941Smrg assert(!is_write); 315b8e80941Smrg submit_surf->flags |= VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES; 316b8e80941Smrg } 317b8e80941Smrg 318b8e80941Smrg if (is_write) 319b8e80941Smrg rsc->writes++; 320b8e80941Smrg} 321b8e80941Smrg 322b8e80941Smrgstatic void 323b8e80941Smrgvc4_submit_setup_rcl_render_config_surface(struct vc4_job *job, 324b8e80941Smrg struct drm_vc4_submit_rcl_surface *submit_surf, 325b8e80941Smrg struct pipe_surface *psurf) 326b8e80941Smrg{ 327b8e80941Smrg struct vc4_surface *surf = vc4_surface(psurf); 328b8e80941Smrg 329b8e80941Smrg if (!surf) 330b8e80941Smrg return; 331b8e80941Smrg 332b8e80941Smrg struct vc4_resource *rsc = vc4_resource(psurf->texture); 333b8e80941Smrg submit_surf->hindex = vc4_gem_hindex(job, rsc->bo); 334b8e80941Smrg submit_surf->offset = surf->offset; 335b8e80941Smrg 336b8e80941Smrg if (psurf->texture->nr_samples <= 1) { 337b8e80941Smrg submit_surf->bits = 338b8e80941Smrg VC4_SET_FIELD(vc4_rt_format_is_565(surf->base.format) ? 339b8e80941Smrg VC4_RENDER_CONFIG_FORMAT_BGR565 : 340b8e80941Smrg VC4_RENDER_CONFIG_FORMAT_RGBA8888, 341b8e80941Smrg VC4_RENDER_CONFIG_FORMAT) | 342b8e80941Smrg VC4_SET_FIELD(surf->tiling, 343b8e80941Smrg VC4_RENDER_CONFIG_MEMORY_FORMAT); 344b8e80941Smrg } 345b8e80941Smrg 346b8e80941Smrg rsc->writes++; 347b8e80941Smrg} 348b8e80941Smrg 349b8e80941Smrgstatic void 350b8e80941Smrgvc4_submit_setup_rcl_msaa_surface(struct vc4_job *job, 351b8e80941Smrg struct drm_vc4_submit_rcl_surface *submit_surf, 352b8e80941Smrg struct pipe_surface *psurf) 353b8e80941Smrg{ 354b8e80941Smrg struct vc4_surface *surf = vc4_surface(psurf); 355b8e80941Smrg 356b8e80941Smrg if (!surf) 357b8e80941Smrg return; 358b8e80941Smrg 359b8e80941Smrg struct vc4_resource *rsc = vc4_resource(psurf->texture); 360b8e80941Smrg submit_surf->hindex = vc4_gem_hindex(job, rsc->bo); 361b8e80941Smrg submit_surf->offset = surf->offset; 362b8e80941Smrg submit_surf->bits = 0; 363b8e80941Smrg rsc->writes++; 364b8e80941Smrg} 365b8e80941Smrg 366b8e80941Smrg/** 367b8e80941Smrg * Submits the job to the kernel and then reinitializes it. 368b8e80941Smrg */ 369b8e80941Smrgvoid 370b8e80941Smrgvc4_job_submit(struct vc4_context *vc4, struct vc4_job *job) 371b8e80941Smrg{ 372b8e80941Smrg if (!job->needs_flush) 373b8e80941Smrg goto done; 374b8e80941Smrg 375b8e80941Smrg /* The RCL setup would choke if the draw bounds cause no drawing, so 376b8e80941Smrg * just drop the drawing if that's the case. 377b8e80941Smrg */ 378b8e80941Smrg if (job->draw_max_x <= job->draw_min_x || 379b8e80941Smrg job->draw_max_y <= job->draw_min_y) { 380b8e80941Smrg goto done; 381b8e80941Smrg } 382b8e80941Smrg 383b8e80941Smrg if (vc4_debug & VC4_DEBUG_CL) { 384b8e80941Smrg fprintf(stderr, "BCL:\n"); 385b8e80941Smrg vc4_dump_cl(job->bcl.base, cl_offset(&job->bcl), false); 386b8e80941Smrg } 387b8e80941Smrg 388b8e80941Smrg if (cl_offset(&job->bcl) > 0) { 389b8e80941Smrg /* Increment the semaphore indicating that binning is done and 390b8e80941Smrg * unblocking the render thread. Note that this doesn't act 391b8e80941Smrg * until the FLUSH completes. 392b8e80941Smrg */ 393b8e80941Smrg cl_ensure_space(&job->bcl, 8); 394b8e80941Smrg cl_emit(&job->bcl, INCREMENT_SEMAPHORE, incr); 395b8e80941Smrg /* The FLUSH caps all of our bin lists with a 396b8e80941Smrg * VC4_PACKET_RETURN. 397b8e80941Smrg */ 398b8e80941Smrg cl_emit(&job->bcl, FLUSH, flush); 399b8e80941Smrg } 400b8e80941Smrg struct drm_vc4_submit_cl submit = { 401b8e80941Smrg .color_read.hindex = ~0, 402b8e80941Smrg .zs_read.hindex = ~0, 403b8e80941Smrg .color_write.hindex = ~0, 404b8e80941Smrg .msaa_color_write.hindex = ~0, 405b8e80941Smrg .zs_write.hindex = ~0, 406b8e80941Smrg .msaa_zs_write.hindex = ~0, 407b8e80941Smrg }; 408b8e80941Smrg 409b8e80941Smrg cl_ensure_space(&job->bo_handles, 6 * sizeof(uint32_t)); 410b8e80941Smrg cl_ensure_space(&job->bo_pointers, 6 * sizeof(struct vc4_bo *)); 411b8e80941Smrg 412b8e80941Smrg if (job->resolve & PIPE_CLEAR_COLOR) { 413b8e80941Smrg if (!(job->cleared & PIPE_CLEAR_COLOR)) { 414b8e80941Smrg vc4_submit_setup_rcl_surface(job, &submit.color_read, 415b8e80941Smrg job->color_read, 416b8e80941Smrg false, false); 417b8e80941Smrg } 418b8e80941Smrg vc4_submit_setup_rcl_render_config_surface(job, 419b8e80941Smrg &submit.color_write, 420b8e80941Smrg job->color_write); 421b8e80941Smrg vc4_submit_setup_rcl_msaa_surface(job, 422b8e80941Smrg &submit.msaa_color_write, 423b8e80941Smrg job->msaa_color_write); 424b8e80941Smrg } 425b8e80941Smrg if (job->resolve & (PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL)) { 426b8e80941Smrg if (!(job->cleared & (PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL))) { 427b8e80941Smrg vc4_submit_setup_rcl_surface(job, &submit.zs_read, 428b8e80941Smrg job->zs_read, true, false); 429b8e80941Smrg } 430b8e80941Smrg vc4_submit_setup_rcl_surface(job, &submit.zs_write, 431b8e80941Smrg job->zs_write, true, true); 432b8e80941Smrg vc4_submit_setup_rcl_msaa_surface(job, &submit.msaa_zs_write, 433b8e80941Smrg job->msaa_zs_write); 434b8e80941Smrg } 435b8e80941Smrg 436b8e80941Smrg if (job->msaa) { 437b8e80941Smrg /* This bit controls how many pixels the general 438b8e80941Smrg * (i.e. subsampled) loads/stores are iterating over 439b8e80941Smrg * (multisample loads replicate out to the other samples). 440b8e80941Smrg */ 441b8e80941Smrg submit.color_write.bits |= VC4_RENDER_CONFIG_MS_MODE_4X; 442b8e80941Smrg /* Controls whether color_write's 443b8e80941Smrg * VC4_PACKET_STORE_MS_TILE_BUFFER does 4x decimation 444b8e80941Smrg */ 445b8e80941Smrg submit.color_write.bits |= VC4_RENDER_CONFIG_DECIMATE_MODE_4X; 446b8e80941Smrg } 447b8e80941Smrg 448b8e80941Smrg submit.bo_handles = (uintptr_t)job->bo_handles.base; 449b8e80941Smrg submit.bo_handle_count = cl_offset(&job->bo_handles) / 4; 450b8e80941Smrg submit.bin_cl = (uintptr_t)job->bcl.base; 451b8e80941Smrg submit.bin_cl_size = cl_offset(&job->bcl); 452b8e80941Smrg submit.shader_rec = (uintptr_t)job->shader_rec.base; 453b8e80941Smrg submit.shader_rec_size = cl_offset(&job->shader_rec); 454b8e80941Smrg submit.shader_rec_count = job->shader_rec_count; 455b8e80941Smrg submit.uniforms = (uintptr_t)job->uniforms.base; 456b8e80941Smrg submit.uniforms_size = cl_offset(&job->uniforms); 457b8e80941Smrg if (job->perfmon) 458b8e80941Smrg submit.perfmonid = job->perfmon->id; 459b8e80941Smrg 460b8e80941Smrg assert(job->draw_min_x != ~0 && job->draw_min_y != ~0); 461b8e80941Smrg submit.min_x_tile = job->draw_min_x / job->tile_width; 462b8e80941Smrg submit.min_y_tile = job->draw_min_y / job->tile_height; 463b8e80941Smrg submit.max_x_tile = (job->draw_max_x - 1) / job->tile_width; 464b8e80941Smrg submit.max_y_tile = (job->draw_max_y - 1) / job->tile_height; 465b8e80941Smrg submit.width = job->draw_width; 466b8e80941Smrg submit.height = job->draw_height; 467b8e80941Smrg if (job->cleared) { 468b8e80941Smrg submit.flags |= VC4_SUBMIT_CL_USE_CLEAR_COLOR; 469b8e80941Smrg submit.clear_color[0] = job->clear_color[0]; 470b8e80941Smrg submit.clear_color[1] = job->clear_color[1]; 471b8e80941Smrg submit.clear_z = job->clear_depth; 472b8e80941Smrg submit.clear_s = job->clear_stencil; 473b8e80941Smrg } 474b8e80941Smrg submit.flags |= job->flags; 475b8e80941Smrg 476b8e80941Smrg if (vc4->screen->has_syncobj) { 477b8e80941Smrg submit.out_sync = vc4->job_syncobj; 478b8e80941Smrg 479b8e80941Smrg if (vc4->in_fence_fd >= 0) { 480b8e80941Smrg /* This replaces the fence in the syncobj. */ 481b8e80941Smrg drmSyncobjImportSyncFile(vc4->fd, vc4->in_syncobj, 482b8e80941Smrg vc4->in_fence_fd); 483b8e80941Smrg submit.in_sync = vc4->in_syncobj; 484b8e80941Smrg close(vc4->in_fence_fd); 485b8e80941Smrg vc4->in_fence_fd = -1; 486b8e80941Smrg } 487b8e80941Smrg } 488b8e80941Smrg 489b8e80941Smrg if (!(vc4_debug & VC4_DEBUG_NORAST)) { 490b8e80941Smrg int ret; 491b8e80941Smrg 492b8e80941Smrg ret = vc4_ioctl(vc4->fd, DRM_IOCTL_VC4_SUBMIT_CL, &submit); 493b8e80941Smrg static bool warned = false; 494b8e80941Smrg if (ret && !warned) { 495b8e80941Smrg fprintf(stderr, "Draw call returned %s. " 496b8e80941Smrg "Expect corruption.\n", strerror(errno)); 497b8e80941Smrg warned = true; 498b8e80941Smrg } else if (!ret) { 499b8e80941Smrg vc4->last_emit_seqno = submit.seqno; 500b8e80941Smrg if (job->perfmon) 501b8e80941Smrg job->perfmon->last_seqno = submit.seqno; 502b8e80941Smrg } 503b8e80941Smrg } 504b8e80941Smrg 505b8e80941Smrg if (vc4->last_emit_seqno - vc4->screen->finished_seqno > 5) { 506b8e80941Smrg if (!vc4_wait_seqno(vc4->screen, 507b8e80941Smrg vc4->last_emit_seqno - 5, 508b8e80941Smrg PIPE_TIMEOUT_INFINITE, 509b8e80941Smrg "job throttling")) { 510b8e80941Smrg fprintf(stderr, "Job throttling failed\n"); 511b8e80941Smrg } 512b8e80941Smrg } 513b8e80941Smrg 514b8e80941Smrg if (vc4_debug & VC4_DEBUG_ALWAYS_SYNC) { 515b8e80941Smrg if (!vc4_wait_seqno(vc4->screen, vc4->last_emit_seqno, 516b8e80941Smrg PIPE_TIMEOUT_INFINITE, "sync")) { 517b8e80941Smrg fprintf(stderr, "Wait failed.\n"); 518b8e80941Smrg abort(); 519b8e80941Smrg } 520b8e80941Smrg } 521b8e80941Smrg 522b8e80941Smrgdone: 523b8e80941Smrg vc4_job_free(vc4, job); 524b8e80941Smrg} 525b8e80941Smrg 526b8e80941Smrgstatic bool 527b8e80941Smrgvc4_job_compare(const void *a, const void *b) 528b8e80941Smrg{ 529b8e80941Smrg return memcmp(a, b, sizeof(struct vc4_job_key)) == 0; 530b8e80941Smrg} 531b8e80941Smrg 532b8e80941Smrgstatic uint32_t 533b8e80941Smrgvc4_job_hash(const void *key) 534b8e80941Smrg{ 535b8e80941Smrg return _mesa_hash_data(key, sizeof(struct vc4_job_key)); 536b8e80941Smrg} 537b8e80941Smrg 538b8e80941Smrgint 539b8e80941Smrgvc4_job_init(struct vc4_context *vc4) 540b8e80941Smrg{ 541b8e80941Smrg vc4->jobs = _mesa_hash_table_create(vc4, 542b8e80941Smrg vc4_job_hash, 543b8e80941Smrg vc4_job_compare); 544b8e80941Smrg vc4->write_jobs = _mesa_hash_table_create(vc4, 545b8e80941Smrg _mesa_hash_pointer, 546b8e80941Smrg _mesa_key_pointer_equal); 547b8e80941Smrg 548b8e80941Smrg if (vc4->screen->has_syncobj) { 549b8e80941Smrg /* Create the syncobj as signaled since with no job executed 550b8e80941Smrg * there is nothing to wait on. 551b8e80941Smrg */ 552b8e80941Smrg int ret = drmSyncobjCreate(vc4->fd, 553b8e80941Smrg DRM_SYNCOBJ_CREATE_SIGNALED, 554b8e80941Smrg &vc4->job_syncobj); 555b8e80941Smrg if (ret) { 556b8e80941Smrg /* If the screen indicated syncobj support, we should 557b8e80941Smrg * be able to create a signaled syncobj. 558b8e80941Smrg * At this point it is too late to pretend the screen 559b8e80941Smrg * has no syncobj support. 560b8e80941Smrg */ 561b8e80941Smrg return ret; 562b8e80941Smrg } 563b8e80941Smrg } 564b8e80941Smrg 565b8e80941Smrg return 0; 566b8e80941Smrg} 567b8e80941Smrg 568