101e04c3fSmrg/* 201e04c3fSmrg * Copyright © 2014-2015 Broadcom 301e04c3fSmrg * 401e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a 501e04c3fSmrg * copy of this software and associated documentation files (the "Software"), 601e04c3fSmrg * to deal in the Software without restriction, including without limitation 701e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 801e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the 901e04c3fSmrg * Software is furnished to do so, subject to the following conditions: 1001e04c3fSmrg * 1101e04c3fSmrg * The above copyright notice and this permission notice (including the next 1201e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the 1301e04c3fSmrg * Software. 1401e04c3fSmrg * 1501e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1601e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1701e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1801e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1901e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2001e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 2101e04c3fSmrg * IN THE SOFTWARE. 2201e04c3fSmrg */ 2301e04c3fSmrg 2401e04c3fSmrg/** @file vc4_job.c 2501e04c3fSmrg * 2601e04c3fSmrg * Functions for submitting VC4 render jobs to the kernel. 2701e04c3fSmrg */ 2801e04c3fSmrg 2901e04c3fSmrg#include <xf86drm.h> 3001e04c3fSmrg#include "vc4_cl_dump.h" 3101e04c3fSmrg#include "vc4_context.h" 3201e04c3fSmrg#include "util/hash_table.h" 3301e04c3fSmrg 3401e04c3fSmrgstatic void 3501e04c3fSmrgvc4_job_free(struct vc4_context *vc4, struct vc4_job *job) 3601e04c3fSmrg{ 3701e04c3fSmrg struct vc4_bo **referenced_bos = job->bo_pointers.base; 3801e04c3fSmrg for (int i = 0; i < cl_offset(&job->bo_handles) / 4; i++) { 3901e04c3fSmrg vc4_bo_unreference(&referenced_bos[i]); 4001e04c3fSmrg } 4101e04c3fSmrg 429f464c52Smaya _mesa_hash_table_remove_key(vc4->jobs, &job->key); 4301e04c3fSmrg 4401e04c3fSmrg if (job->color_write) { 459f464c52Smaya _mesa_hash_table_remove_key(vc4->write_jobs, 469f464c52Smaya job->color_write->texture); 4701e04c3fSmrg pipe_surface_reference(&job->color_write, NULL); 4801e04c3fSmrg } 4901e04c3fSmrg if (job->msaa_color_write) { 509f464c52Smaya _mesa_hash_table_remove_key(vc4->write_jobs, 519f464c52Smaya job->msaa_color_write->texture); 5201e04c3fSmrg pipe_surface_reference(&job->msaa_color_write, NULL); 5301e04c3fSmrg } 5401e04c3fSmrg if (job->zs_write) { 559f464c52Smaya _mesa_hash_table_remove_key(vc4->write_jobs, 569f464c52Smaya job->zs_write->texture); 5701e04c3fSmrg pipe_surface_reference(&job->zs_write, NULL); 5801e04c3fSmrg } 5901e04c3fSmrg if (job->msaa_zs_write) { 609f464c52Smaya _mesa_hash_table_remove_key(vc4->write_jobs, 619f464c52Smaya job->msaa_zs_write->texture); 6201e04c3fSmrg pipe_surface_reference(&job->msaa_zs_write, NULL); 6301e04c3fSmrg } 6401e04c3fSmrg 6501e04c3fSmrg pipe_surface_reference(&job->color_read, NULL); 6601e04c3fSmrg pipe_surface_reference(&job->zs_read, NULL); 6701e04c3fSmrg 6801e04c3fSmrg if (vc4->job == job) 6901e04c3fSmrg vc4->job = NULL; 7001e04c3fSmrg 7101e04c3fSmrg ralloc_free(job); 7201e04c3fSmrg} 7301e04c3fSmrg 7401e04c3fSmrgstatic struct vc4_job * 7501e04c3fSmrgvc4_job_create(struct vc4_context *vc4) 7601e04c3fSmrg{ 7701e04c3fSmrg struct vc4_job *job = rzalloc(vc4, struct vc4_job); 7801e04c3fSmrg 7901e04c3fSmrg vc4_init_cl(job, &job->bcl); 8001e04c3fSmrg vc4_init_cl(job, &job->shader_rec); 8101e04c3fSmrg vc4_init_cl(job, &job->uniforms); 8201e04c3fSmrg vc4_init_cl(job, &job->bo_handles); 8301e04c3fSmrg vc4_init_cl(job, &job->bo_pointers); 8401e04c3fSmrg 8501e04c3fSmrg job->draw_min_x = ~0; 8601e04c3fSmrg job->draw_min_y = ~0; 8701e04c3fSmrg job->draw_max_x = 0; 8801e04c3fSmrg job->draw_max_y = 0; 8901e04c3fSmrg 9001e04c3fSmrg job->last_gem_handle_hindex = ~0; 9101e04c3fSmrg 9201e04c3fSmrg if (vc4->perfmon) 9301e04c3fSmrg job->perfmon = vc4->perfmon; 9401e04c3fSmrg 9501e04c3fSmrg return job; 9601e04c3fSmrg} 9701e04c3fSmrg 9801e04c3fSmrgvoid 9901e04c3fSmrgvc4_flush_jobs_writing_resource(struct vc4_context *vc4, 10001e04c3fSmrg struct pipe_resource *prsc) 10101e04c3fSmrg{ 10201e04c3fSmrg struct hash_entry *entry = _mesa_hash_table_search(vc4->write_jobs, 10301e04c3fSmrg prsc); 10401e04c3fSmrg if (entry) { 10501e04c3fSmrg struct vc4_job *job = entry->data; 10601e04c3fSmrg vc4_job_submit(vc4, job); 10701e04c3fSmrg } 10801e04c3fSmrg} 10901e04c3fSmrg 11001e04c3fSmrgvoid 11101e04c3fSmrgvc4_flush_jobs_reading_resource(struct vc4_context *vc4, 11201e04c3fSmrg struct pipe_resource *prsc) 11301e04c3fSmrg{ 11401e04c3fSmrg struct vc4_resource *rsc = vc4_resource(prsc); 11501e04c3fSmrg 11601e04c3fSmrg vc4_flush_jobs_writing_resource(vc4, prsc); 11701e04c3fSmrg 11801e04c3fSmrg hash_table_foreach(vc4->jobs, entry) { 11901e04c3fSmrg struct vc4_job *job = entry->data; 12001e04c3fSmrg 12101e04c3fSmrg struct vc4_bo **referenced_bos = job->bo_pointers.base; 12201e04c3fSmrg bool found = false; 12301e04c3fSmrg for (int i = 0; i < cl_offset(&job->bo_handles) / 4; i++) { 12401e04c3fSmrg if (referenced_bos[i] == rsc->bo) { 12501e04c3fSmrg found = true; 12601e04c3fSmrg break; 12701e04c3fSmrg } 12801e04c3fSmrg } 12901e04c3fSmrg if (found) { 13001e04c3fSmrg vc4_job_submit(vc4, job); 13101e04c3fSmrg continue; 13201e04c3fSmrg } 13301e04c3fSmrg 13401e04c3fSmrg /* Also check for the Z/color buffers, since the references to 13501e04c3fSmrg * those are only added immediately before submit. 13601e04c3fSmrg */ 13701e04c3fSmrg if (job->color_read && !(job->cleared & PIPE_CLEAR_COLOR)) { 13801e04c3fSmrg struct vc4_resource *ctex = 13901e04c3fSmrg vc4_resource(job->color_read->texture); 14001e04c3fSmrg if (ctex->bo == rsc->bo) { 14101e04c3fSmrg vc4_job_submit(vc4, job); 14201e04c3fSmrg continue; 14301e04c3fSmrg } 14401e04c3fSmrg } 14501e04c3fSmrg 14601e04c3fSmrg if (job->zs_read && !(job->cleared & 14701e04c3fSmrg (PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL))) { 14801e04c3fSmrg struct vc4_resource *ztex = 14901e04c3fSmrg vc4_resource(job->zs_read->texture); 15001e04c3fSmrg if (ztex->bo == rsc->bo) { 15101e04c3fSmrg vc4_job_submit(vc4, job); 15201e04c3fSmrg continue; 15301e04c3fSmrg } 15401e04c3fSmrg } 15501e04c3fSmrg } 15601e04c3fSmrg} 15701e04c3fSmrg 15801e04c3fSmrg/** 15901e04c3fSmrg * Returns a vc4_job struture for tracking V3D rendering to a particular FBO. 16001e04c3fSmrg * 16101e04c3fSmrg * If we've already started rendering to this FBO, then return old same job, 16201e04c3fSmrg * otherwise make a new one. If we're beginning rendering to an FBO, make 16301e04c3fSmrg * sure that any previous reads of the FBO (or writes to its color/Z surfaces) 16401e04c3fSmrg * have been flushed. 16501e04c3fSmrg */ 16601e04c3fSmrgstruct vc4_job * 16701e04c3fSmrgvc4_get_job(struct vc4_context *vc4, 16801e04c3fSmrg struct pipe_surface *cbuf, struct pipe_surface *zsbuf) 16901e04c3fSmrg{ 17001e04c3fSmrg /* Return the existing job for this FBO if we have one */ 17101e04c3fSmrg struct vc4_job_key local_key = {.cbuf = cbuf, .zsbuf = zsbuf}; 17201e04c3fSmrg struct hash_entry *entry = _mesa_hash_table_search(vc4->jobs, 17301e04c3fSmrg &local_key); 17401e04c3fSmrg if (entry) 17501e04c3fSmrg return entry->data; 17601e04c3fSmrg 17701e04c3fSmrg /* Creating a new job. Make sure that any previous jobs reading or 17801e04c3fSmrg * writing these buffers are flushed. 17901e04c3fSmrg */ 18001e04c3fSmrg if (cbuf) 18101e04c3fSmrg vc4_flush_jobs_reading_resource(vc4, cbuf->texture); 18201e04c3fSmrg if (zsbuf) 18301e04c3fSmrg vc4_flush_jobs_reading_resource(vc4, zsbuf->texture); 18401e04c3fSmrg 18501e04c3fSmrg struct vc4_job *job = vc4_job_create(vc4); 18601e04c3fSmrg 18701e04c3fSmrg if (cbuf) { 18801e04c3fSmrg if (cbuf->texture->nr_samples > 1) { 18901e04c3fSmrg job->msaa = true; 19001e04c3fSmrg pipe_surface_reference(&job->msaa_color_write, cbuf); 19101e04c3fSmrg } else { 19201e04c3fSmrg pipe_surface_reference(&job->color_write, cbuf); 19301e04c3fSmrg } 19401e04c3fSmrg } 19501e04c3fSmrg 19601e04c3fSmrg if (zsbuf) { 19701e04c3fSmrg if (zsbuf->texture->nr_samples > 1) { 19801e04c3fSmrg job->msaa = true; 19901e04c3fSmrg pipe_surface_reference(&job->msaa_zs_write, zsbuf); 20001e04c3fSmrg } else { 20101e04c3fSmrg pipe_surface_reference(&job->zs_write, zsbuf); 20201e04c3fSmrg } 20301e04c3fSmrg } 20401e04c3fSmrg 20501e04c3fSmrg if (job->msaa) { 20601e04c3fSmrg job->tile_width = 32; 20701e04c3fSmrg job->tile_height = 32; 20801e04c3fSmrg } else { 20901e04c3fSmrg job->tile_width = 64; 21001e04c3fSmrg job->tile_height = 64; 21101e04c3fSmrg } 21201e04c3fSmrg 21301e04c3fSmrg if (cbuf) 21401e04c3fSmrg _mesa_hash_table_insert(vc4->write_jobs, cbuf->texture, job); 21501e04c3fSmrg if (zsbuf) 21601e04c3fSmrg _mesa_hash_table_insert(vc4->write_jobs, zsbuf->texture, job); 21701e04c3fSmrg 21801e04c3fSmrg job->key.cbuf = cbuf; 21901e04c3fSmrg job->key.zsbuf = zsbuf; 22001e04c3fSmrg _mesa_hash_table_insert(vc4->jobs, &job->key, job); 22101e04c3fSmrg 22201e04c3fSmrg return job; 22301e04c3fSmrg} 22401e04c3fSmrg 22501e04c3fSmrgstruct vc4_job * 22601e04c3fSmrgvc4_get_job_for_fbo(struct vc4_context *vc4) 22701e04c3fSmrg{ 22801e04c3fSmrg if (vc4->job) 22901e04c3fSmrg return vc4->job; 23001e04c3fSmrg 23101e04c3fSmrg struct pipe_surface *cbuf = vc4->framebuffer.cbufs[0]; 23201e04c3fSmrg struct pipe_surface *zsbuf = vc4->framebuffer.zsbuf; 23301e04c3fSmrg struct vc4_job *job = vc4_get_job(vc4, cbuf, zsbuf); 23401e04c3fSmrg 23501e04c3fSmrg /* The dirty flags are tracking what's been updated while vc4->job has 23601e04c3fSmrg * been bound, so set them all to ~0 when switching between jobs. We 23701e04c3fSmrg * also need to reset all state at the start of rendering. 23801e04c3fSmrg */ 23901e04c3fSmrg vc4->dirty = ~0; 24001e04c3fSmrg 24101e04c3fSmrg /* Set up the read surfaces in the job. If they aren't actually 24201e04c3fSmrg * getting read (due to a clear starting the frame), job->cleared will 24301e04c3fSmrg * mask out the read. 24401e04c3fSmrg */ 24501e04c3fSmrg pipe_surface_reference(&job->color_read, cbuf); 24601e04c3fSmrg pipe_surface_reference(&job->zs_read, zsbuf); 24701e04c3fSmrg 24801e04c3fSmrg /* If we're binding to uninitialized buffers, no need to load their 24901e04c3fSmrg * contents before drawing. 25001e04c3fSmrg */ 25101e04c3fSmrg if (cbuf) { 25201e04c3fSmrg struct vc4_resource *rsc = vc4_resource(cbuf->texture); 25301e04c3fSmrg if (!rsc->writes) 25401e04c3fSmrg job->cleared |= PIPE_CLEAR_COLOR0; 25501e04c3fSmrg } 25601e04c3fSmrg 25701e04c3fSmrg if (zsbuf) { 25801e04c3fSmrg struct vc4_resource *rsc = vc4_resource(zsbuf->texture); 25901e04c3fSmrg if (!rsc->writes) 26001e04c3fSmrg job->cleared |= PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL; 26101e04c3fSmrg } 26201e04c3fSmrg 26301e04c3fSmrg job->draw_tiles_x = DIV_ROUND_UP(vc4->framebuffer.width, 26401e04c3fSmrg job->tile_width); 26501e04c3fSmrg job->draw_tiles_y = DIV_ROUND_UP(vc4->framebuffer.height, 26601e04c3fSmrg job->tile_height); 26701e04c3fSmrg 26801e04c3fSmrg /* Initialize the job with the raster order flags -- each draw will 26901e04c3fSmrg * check that we haven't changed the flags, since that requires a 27001e04c3fSmrg * flush. 27101e04c3fSmrg */ 27201e04c3fSmrg if (vc4->rasterizer) 27301e04c3fSmrg job->flags = vc4->rasterizer->tile_raster_order_flags; 27401e04c3fSmrg 27501e04c3fSmrg vc4->job = job; 27601e04c3fSmrg 27701e04c3fSmrg return job; 27801e04c3fSmrg} 27901e04c3fSmrg 28001e04c3fSmrgstatic void 28101e04c3fSmrgvc4_submit_setup_rcl_surface(struct vc4_job *job, 28201e04c3fSmrg struct drm_vc4_submit_rcl_surface *submit_surf, 28301e04c3fSmrg struct pipe_surface *psurf, 28401e04c3fSmrg bool is_depth, bool is_write) 28501e04c3fSmrg{ 28601e04c3fSmrg struct vc4_surface *surf = vc4_surface(psurf); 28701e04c3fSmrg 28801e04c3fSmrg if (!surf) 28901e04c3fSmrg return; 29001e04c3fSmrg 29101e04c3fSmrg struct vc4_resource *rsc = vc4_resource(psurf->texture); 29201e04c3fSmrg submit_surf->hindex = vc4_gem_hindex(job, rsc->bo); 29301e04c3fSmrg submit_surf->offset = surf->offset; 29401e04c3fSmrg 29501e04c3fSmrg if (psurf->texture->nr_samples <= 1) { 29601e04c3fSmrg if (is_depth) { 29701e04c3fSmrg submit_surf->bits = 29801e04c3fSmrg VC4_SET_FIELD(VC4_LOADSTORE_TILE_BUFFER_ZS, 29901e04c3fSmrg VC4_LOADSTORE_TILE_BUFFER_BUFFER); 30001e04c3fSmrg 30101e04c3fSmrg } else { 30201e04c3fSmrg submit_surf->bits = 30301e04c3fSmrg VC4_SET_FIELD(VC4_LOADSTORE_TILE_BUFFER_COLOR, 30401e04c3fSmrg VC4_LOADSTORE_TILE_BUFFER_BUFFER) | 30501e04c3fSmrg VC4_SET_FIELD(vc4_rt_format_is_565(psurf->format) ? 30601e04c3fSmrg VC4_LOADSTORE_TILE_BUFFER_BGR565 : 30701e04c3fSmrg VC4_LOADSTORE_TILE_BUFFER_RGBA8888, 30801e04c3fSmrg VC4_LOADSTORE_TILE_BUFFER_FORMAT); 30901e04c3fSmrg } 31001e04c3fSmrg submit_surf->bits |= 31101e04c3fSmrg VC4_SET_FIELD(surf->tiling, 31201e04c3fSmrg VC4_LOADSTORE_TILE_BUFFER_TILING); 31301e04c3fSmrg } else { 31401e04c3fSmrg assert(!is_write); 31501e04c3fSmrg submit_surf->flags |= VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES; 31601e04c3fSmrg } 31701e04c3fSmrg 31801e04c3fSmrg if (is_write) 31901e04c3fSmrg rsc->writes++; 32001e04c3fSmrg} 32101e04c3fSmrg 32201e04c3fSmrgstatic void 32301e04c3fSmrgvc4_submit_setup_rcl_render_config_surface(struct vc4_job *job, 32401e04c3fSmrg struct drm_vc4_submit_rcl_surface *submit_surf, 32501e04c3fSmrg struct pipe_surface *psurf) 32601e04c3fSmrg{ 32701e04c3fSmrg struct vc4_surface *surf = vc4_surface(psurf); 32801e04c3fSmrg 32901e04c3fSmrg if (!surf) 33001e04c3fSmrg return; 33101e04c3fSmrg 33201e04c3fSmrg struct vc4_resource *rsc = vc4_resource(psurf->texture); 33301e04c3fSmrg submit_surf->hindex = vc4_gem_hindex(job, rsc->bo); 33401e04c3fSmrg submit_surf->offset = surf->offset; 33501e04c3fSmrg 33601e04c3fSmrg if (psurf->texture->nr_samples <= 1) { 33701e04c3fSmrg submit_surf->bits = 33801e04c3fSmrg VC4_SET_FIELD(vc4_rt_format_is_565(surf->base.format) ? 33901e04c3fSmrg VC4_RENDER_CONFIG_FORMAT_BGR565 : 34001e04c3fSmrg VC4_RENDER_CONFIG_FORMAT_RGBA8888, 34101e04c3fSmrg VC4_RENDER_CONFIG_FORMAT) | 34201e04c3fSmrg VC4_SET_FIELD(surf->tiling, 34301e04c3fSmrg VC4_RENDER_CONFIG_MEMORY_FORMAT); 34401e04c3fSmrg } 34501e04c3fSmrg 34601e04c3fSmrg rsc->writes++; 34701e04c3fSmrg} 34801e04c3fSmrg 34901e04c3fSmrgstatic void 35001e04c3fSmrgvc4_submit_setup_rcl_msaa_surface(struct vc4_job *job, 35101e04c3fSmrg struct drm_vc4_submit_rcl_surface *submit_surf, 35201e04c3fSmrg struct pipe_surface *psurf) 35301e04c3fSmrg{ 35401e04c3fSmrg struct vc4_surface *surf = vc4_surface(psurf); 35501e04c3fSmrg 35601e04c3fSmrg if (!surf) 35701e04c3fSmrg return; 35801e04c3fSmrg 35901e04c3fSmrg struct vc4_resource *rsc = vc4_resource(psurf->texture); 36001e04c3fSmrg submit_surf->hindex = vc4_gem_hindex(job, rsc->bo); 36101e04c3fSmrg submit_surf->offset = surf->offset; 36201e04c3fSmrg submit_surf->bits = 0; 36301e04c3fSmrg rsc->writes++; 36401e04c3fSmrg} 36501e04c3fSmrg 36601e04c3fSmrg/** 36701e04c3fSmrg * Submits the job to the kernel and then reinitializes it. 36801e04c3fSmrg */ 36901e04c3fSmrgvoid 37001e04c3fSmrgvc4_job_submit(struct vc4_context *vc4, struct vc4_job *job) 37101e04c3fSmrg{ 37201e04c3fSmrg if (!job->needs_flush) 37301e04c3fSmrg goto done; 37401e04c3fSmrg 37501e04c3fSmrg /* The RCL setup would choke if the draw bounds cause no drawing, so 37601e04c3fSmrg * just drop the drawing if that's the case. 37701e04c3fSmrg */ 37801e04c3fSmrg if (job->draw_max_x <= job->draw_min_x || 37901e04c3fSmrg job->draw_max_y <= job->draw_min_y) { 38001e04c3fSmrg goto done; 38101e04c3fSmrg } 38201e04c3fSmrg 38301e04c3fSmrg if (vc4_debug & VC4_DEBUG_CL) { 38401e04c3fSmrg fprintf(stderr, "BCL:\n"); 38501e04c3fSmrg vc4_dump_cl(job->bcl.base, cl_offset(&job->bcl), false); 38601e04c3fSmrg } 38701e04c3fSmrg 38801e04c3fSmrg if (cl_offset(&job->bcl) > 0) { 38901e04c3fSmrg /* Increment the semaphore indicating that binning is done and 39001e04c3fSmrg * unblocking the render thread. Note that this doesn't act 39101e04c3fSmrg * until the FLUSH completes. 39201e04c3fSmrg */ 39301e04c3fSmrg cl_ensure_space(&job->bcl, 8); 39401e04c3fSmrg cl_emit(&job->bcl, INCREMENT_SEMAPHORE, incr); 39501e04c3fSmrg /* The FLUSH caps all of our bin lists with a 39601e04c3fSmrg * VC4_PACKET_RETURN. 39701e04c3fSmrg */ 39801e04c3fSmrg cl_emit(&job->bcl, FLUSH, flush); 39901e04c3fSmrg } 40001e04c3fSmrg struct drm_vc4_submit_cl submit = { 40101e04c3fSmrg .color_read.hindex = ~0, 40201e04c3fSmrg .zs_read.hindex = ~0, 40301e04c3fSmrg .color_write.hindex = ~0, 40401e04c3fSmrg .msaa_color_write.hindex = ~0, 40501e04c3fSmrg .zs_write.hindex = ~0, 40601e04c3fSmrg .msaa_zs_write.hindex = ~0, 40701e04c3fSmrg }; 40801e04c3fSmrg 40901e04c3fSmrg cl_ensure_space(&job->bo_handles, 6 * sizeof(uint32_t)); 41001e04c3fSmrg cl_ensure_space(&job->bo_pointers, 6 * sizeof(struct vc4_bo *)); 41101e04c3fSmrg 41201e04c3fSmrg if (job->resolve & PIPE_CLEAR_COLOR) { 41301e04c3fSmrg if (!(job->cleared & PIPE_CLEAR_COLOR)) { 41401e04c3fSmrg vc4_submit_setup_rcl_surface(job, &submit.color_read, 41501e04c3fSmrg job->color_read, 41601e04c3fSmrg false, false); 41701e04c3fSmrg } 41801e04c3fSmrg vc4_submit_setup_rcl_render_config_surface(job, 41901e04c3fSmrg &submit.color_write, 42001e04c3fSmrg job->color_write); 42101e04c3fSmrg vc4_submit_setup_rcl_msaa_surface(job, 42201e04c3fSmrg &submit.msaa_color_write, 42301e04c3fSmrg job->msaa_color_write); 42401e04c3fSmrg } 42501e04c3fSmrg if (job->resolve & (PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL)) { 42601e04c3fSmrg if (!(job->cleared & (PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL))) { 42701e04c3fSmrg vc4_submit_setup_rcl_surface(job, &submit.zs_read, 42801e04c3fSmrg job->zs_read, true, false); 42901e04c3fSmrg } 43001e04c3fSmrg vc4_submit_setup_rcl_surface(job, &submit.zs_write, 43101e04c3fSmrg job->zs_write, true, true); 43201e04c3fSmrg vc4_submit_setup_rcl_msaa_surface(job, &submit.msaa_zs_write, 43301e04c3fSmrg job->msaa_zs_write); 43401e04c3fSmrg } 43501e04c3fSmrg 43601e04c3fSmrg if (job->msaa) { 43701e04c3fSmrg /* This bit controls how many pixels the general 43801e04c3fSmrg * (i.e. subsampled) loads/stores are iterating over 43901e04c3fSmrg * (multisample loads replicate out to the other samples). 44001e04c3fSmrg */ 44101e04c3fSmrg submit.color_write.bits |= VC4_RENDER_CONFIG_MS_MODE_4X; 44201e04c3fSmrg /* Controls whether color_write's 44301e04c3fSmrg * VC4_PACKET_STORE_MS_TILE_BUFFER does 4x decimation 44401e04c3fSmrg */ 44501e04c3fSmrg submit.color_write.bits |= VC4_RENDER_CONFIG_DECIMATE_MODE_4X; 44601e04c3fSmrg } 44701e04c3fSmrg 44801e04c3fSmrg submit.bo_handles = (uintptr_t)job->bo_handles.base; 44901e04c3fSmrg submit.bo_handle_count = cl_offset(&job->bo_handles) / 4; 45001e04c3fSmrg submit.bin_cl = (uintptr_t)job->bcl.base; 45101e04c3fSmrg submit.bin_cl_size = cl_offset(&job->bcl); 45201e04c3fSmrg submit.shader_rec = (uintptr_t)job->shader_rec.base; 45301e04c3fSmrg submit.shader_rec_size = cl_offset(&job->shader_rec); 45401e04c3fSmrg submit.shader_rec_count = job->shader_rec_count; 45501e04c3fSmrg submit.uniforms = (uintptr_t)job->uniforms.base; 45601e04c3fSmrg submit.uniforms_size = cl_offset(&job->uniforms); 45701e04c3fSmrg if (job->perfmon) 45801e04c3fSmrg submit.perfmonid = job->perfmon->id; 45901e04c3fSmrg 46001e04c3fSmrg assert(job->draw_min_x != ~0 && job->draw_min_y != ~0); 46101e04c3fSmrg submit.min_x_tile = job->draw_min_x / job->tile_width; 46201e04c3fSmrg submit.min_y_tile = job->draw_min_y / job->tile_height; 46301e04c3fSmrg submit.max_x_tile = (job->draw_max_x - 1) / job->tile_width; 46401e04c3fSmrg submit.max_y_tile = (job->draw_max_y - 1) / job->tile_height; 46501e04c3fSmrg submit.width = job->draw_width; 46601e04c3fSmrg submit.height = job->draw_height; 46701e04c3fSmrg if (job->cleared) { 46801e04c3fSmrg submit.flags |= VC4_SUBMIT_CL_USE_CLEAR_COLOR; 46901e04c3fSmrg submit.clear_color[0] = job->clear_color[0]; 47001e04c3fSmrg submit.clear_color[1] = job->clear_color[1]; 47101e04c3fSmrg submit.clear_z = job->clear_depth; 47201e04c3fSmrg submit.clear_s = job->clear_stencil; 47301e04c3fSmrg } 47401e04c3fSmrg submit.flags |= job->flags; 47501e04c3fSmrg 47601e04c3fSmrg if (vc4->screen->has_syncobj) { 47701e04c3fSmrg submit.out_sync = vc4->job_syncobj; 47801e04c3fSmrg 47901e04c3fSmrg if (vc4->in_fence_fd >= 0) { 48001e04c3fSmrg /* This replaces the fence in the syncobj. */ 48101e04c3fSmrg drmSyncobjImportSyncFile(vc4->fd, vc4->in_syncobj, 48201e04c3fSmrg vc4->in_fence_fd); 48301e04c3fSmrg submit.in_sync = vc4->in_syncobj; 48401e04c3fSmrg close(vc4->in_fence_fd); 48501e04c3fSmrg vc4->in_fence_fd = -1; 48601e04c3fSmrg } 48701e04c3fSmrg } 48801e04c3fSmrg 48901e04c3fSmrg if (!(vc4_debug & VC4_DEBUG_NORAST)) { 49001e04c3fSmrg int ret; 49101e04c3fSmrg 4929f464c52Smaya ret = vc4_ioctl(vc4->fd, DRM_IOCTL_VC4_SUBMIT_CL, &submit); 49301e04c3fSmrg static bool warned = false; 49401e04c3fSmrg if (ret && !warned) { 49501e04c3fSmrg fprintf(stderr, "Draw call returned %s. " 49601e04c3fSmrg "Expect corruption.\n", strerror(errno)); 49701e04c3fSmrg warned = true; 49801e04c3fSmrg } else if (!ret) { 49901e04c3fSmrg vc4->last_emit_seqno = submit.seqno; 50001e04c3fSmrg if (job->perfmon) 50101e04c3fSmrg job->perfmon->last_seqno = submit.seqno; 50201e04c3fSmrg } 50301e04c3fSmrg } 50401e04c3fSmrg 50501e04c3fSmrg if (vc4->last_emit_seqno - vc4->screen->finished_seqno > 5) { 50601e04c3fSmrg if (!vc4_wait_seqno(vc4->screen, 50701e04c3fSmrg vc4->last_emit_seqno - 5, 50801e04c3fSmrg PIPE_TIMEOUT_INFINITE, 50901e04c3fSmrg "job throttling")) { 51001e04c3fSmrg fprintf(stderr, "Job throttling failed\n"); 51101e04c3fSmrg } 51201e04c3fSmrg } 51301e04c3fSmrg 51401e04c3fSmrg if (vc4_debug & VC4_DEBUG_ALWAYS_SYNC) { 51501e04c3fSmrg if (!vc4_wait_seqno(vc4->screen, vc4->last_emit_seqno, 51601e04c3fSmrg PIPE_TIMEOUT_INFINITE, "sync")) { 51701e04c3fSmrg fprintf(stderr, "Wait failed.\n"); 51801e04c3fSmrg abort(); 51901e04c3fSmrg } 52001e04c3fSmrg } 52101e04c3fSmrg 52201e04c3fSmrgdone: 52301e04c3fSmrg vc4_job_free(vc4, job); 52401e04c3fSmrg} 52501e04c3fSmrg 52601e04c3fSmrgstatic bool 52701e04c3fSmrgvc4_job_compare(const void *a, const void *b) 52801e04c3fSmrg{ 52901e04c3fSmrg return memcmp(a, b, sizeof(struct vc4_job_key)) == 0; 53001e04c3fSmrg} 53101e04c3fSmrg 53201e04c3fSmrgstatic uint32_t 53301e04c3fSmrgvc4_job_hash(const void *key) 53401e04c3fSmrg{ 53501e04c3fSmrg return _mesa_hash_data(key, sizeof(struct vc4_job_key)); 53601e04c3fSmrg} 53701e04c3fSmrg 53801e04c3fSmrgint 53901e04c3fSmrgvc4_job_init(struct vc4_context *vc4) 54001e04c3fSmrg{ 54101e04c3fSmrg vc4->jobs = _mesa_hash_table_create(vc4, 54201e04c3fSmrg vc4_job_hash, 54301e04c3fSmrg vc4_job_compare); 54401e04c3fSmrg vc4->write_jobs = _mesa_hash_table_create(vc4, 54501e04c3fSmrg _mesa_hash_pointer, 54601e04c3fSmrg _mesa_key_pointer_equal); 54701e04c3fSmrg 54801e04c3fSmrg if (vc4->screen->has_syncobj) { 54901e04c3fSmrg /* Create the syncobj as signaled since with no job executed 55001e04c3fSmrg * there is nothing to wait on. 55101e04c3fSmrg */ 55201e04c3fSmrg int ret = drmSyncobjCreate(vc4->fd, 55301e04c3fSmrg DRM_SYNCOBJ_CREATE_SIGNALED, 55401e04c3fSmrg &vc4->job_syncobj); 55501e04c3fSmrg if (ret) { 55601e04c3fSmrg /* If the screen indicated syncobj support, we should 55701e04c3fSmrg * be able to create a signaled syncobj. 55801e04c3fSmrg * At this point it is too late to pretend the screen 55901e04c3fSmrg * has no syncobj support. 56001e04c3fSmrg */ 56101e04c3fSmrg return ret; 56201e04c3fSmrg } 56301e04c3fSmrg } 56401e04c3fSmrg 56501e04c3fSmrg return 0; 56601e04c3fSmrg} 56701e04c3fSmrg 568