1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2014-2017 Broadcom 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21bf215546Sopenharmony_ci * IN THE SOFTWARE. 22bf215546Sopenharmony_ci */ 23bf215546Sopenharmony_ci 24bf215546Sopenharmony_ci/** @file v3d_job.c 25bf215546Sopenharmony_ci * 26bf215546Sopenharmony_ci * Functions for submitting V3D render jobs to the kernel. 27bf215546Sopenharmony_ci */ 28bf215546Sopenharmony_ci 29bf215546Sopenharmony_ci#include <xf86drm.h> 30bf215546Sopenharmony_ci#include "v3d_context.h" 31bf215546Sopenharmony_ci/* The OQ/semaphore packets are the same across V3D versions. */ 32bf215546Sopenharmony_ci#define V3D_VERSION 33 33bf215546Sopenharmony_ci#include "broadcom/cle/v3dx_pack.h" 34bf215546Sopenharmony_ci#include "broadcom/common/v3d_macros.h" 35bf215546Sopenharmony_ci#include "util/hash_table.h" 36bf215546Sopenharmony_ci#include "util/ralloc.h" 37bf215546Sopenharmony_ci#include "util/set.h" 38bf215546Sopenharmony_ci#include "broadcom/clif/clif_dump.h" 39bf215546Sopenharmony_ci 40bf215546Sopenharmony_civoid 41bf215546Sopenharmony_civ3d_job_free(struct v3d_context *v3d, struct v3d_job *job) 42bf215546Sopenharmony_ci{ 43bf215546Sopenharmony_ci set_foreach(job->bos, entry) { 44bf215546Sopenharmony_ci struct v3d_bo *bo = (struct v3d_bo *)entry->key; 45bf215546Sopenharmony_ci v3d_bo_unreference(&bo); 46bf215546Sopenharmony_ci } 47bf215546Sopenharmony_ci 48bf215546Sopenharmony_ci _mesa_hash_table_remove_key(v3d->jobs, &job->key); 49bf215546Sopenharmony_ci 50bf215546Sopenharmony_ci if (job->write_prscs) { 51bf215546Sopenharmony_ci set_foreach(job->write_prscs, entry) { 52bf215546Sopenharmony_ci const struct pipe_resource *prsc = entry->key; 53bf215546Sopenharmony_ci 54bf215546Sopenharmony_ci _mesa_hash_table_remove_key(v3d->write_jobs, prsc); 55bf215546Sopenharmony_ci } 56bf215546Sopenharmony_ci } 57bf215546Sopenharmony_ci 58bf215546Sopenharmony_ci for (int i = 0; i < job->nr_cbufs; i++) { 59bf215546Sopenharmony_ci if (job->cbufs[i]) { 60bf215546Sopenharmony_ci _mesa_hash_table_remove_key(v3d->write_jobs, 61bf215546Sopenharmony_ci job->cbufs[i]->texture); 62bf215546Sopenharmony_ci pipe_surface_reference(&job->cbufs[i], NULL); 63bf215546Sopenharmony_ci } 64bf215546Sopenharmony_ci } 65bf215546Sopenharmony_ci if (job->zsbuf) { 66bf215546Sopenharmony_ci struct v3d_resource *rsc = v3d_resource(job->zsbuf->texture); 67bf215546Sopenharmony_ci if (rsc->separate_stencil) 68bf215546Sopenharmony_ci _mesa_hash_table_remove_key(v3d->write_jobs, 69bf215546Sopenharmony_ci &rsc->separate_stencil->base); 70bf215546Sopenharmony_ci 71bf215546Sopenharmony_ci _mesa_hash_table_remove_key(v3d->write_jobs, 72bf215546Sopenharmony_ci job->zsbuf->texture); 73bf215546Sopenharmony_ci pipe_surface_reference(&job->zsbuf, NULL); 74bf215546Sopenharmony_ci } 75bf215546Sopenharmony_ci if (job->bbuf) 76bf215546Sopenharmony_ci pipe_surface_reference(&job->bbuf, NULL); 77bf215546Sopenharmony_ci 78bf215546Sopenharmony_ci if (v3d->job == job) 79bf215546Sopenharmony_ci v3d->job = NULL; 80bf215546Sopenharmony_ci 81bf215546Sopenharmony_ci v3d_destroy_cl(&job->bcl); 82bf215546Sopenharmony_ci v3d_destroy_cl(&job->rcl); 83bf215546Sopenharmony_ci v3d_destroy_cl(&job->indirect); 84bf215546Sopenharmony_ci v3d_bo_unreference(&job->tile_alloc); 85bf215546Sopenharmony_ci v3d_bo_unreference(&job->tile_state); 86bf215546Sopenharmony_ci 87bf215546Sopenharmony_ci ralloc_free(job); 88bf215546Sopenharmony_ci} 89bf215546Sopenharmony_ci 90bf215546Sopenharmony_cistruct v3d_job * 91bf215546Sopenharmony_civ3d_job_create(struct v3d_context *v3d) 92bf215546Sopenharmony_ci{ 93bf215546Sopenharmony_ci struct v3d_job *job = rzalloc(v3d, struct v3d_job); 94bf215546Sopenharmony_ci 95bf215546Sopenharmony_ci job->v3d = v3d; 96bf215546Sopenharmony_ci 97bf215546Sopenharmony_ci v3d_init_cl(job, &job->bcl); 98bf215546Sopenharmony_ci v3d_init_cl(job, &job->rcl); 99bf215546Sopenharmony_ci v3d_init_cl(job, &job->indirect); 100bf215546Sopenharmony_ci 101bf215546Sopenharmony_ci job->draw_min_x = ~0; 102bf215546Sopenharmony_ci job->draw_min_y = ~0; 103bf215546Sopenharmony_ci job->draw_max_x = 0; 104bf215546Sopenharmony_ci job->draw_max_y = 0; 105bf215546Sopenharmony_ci 106bf215546Sopenharmony_ci job->bos = _mesa_set_create(job, 107bf215546Sopenharmony_ci _mesa_hash_pointer, 108bf215546Sopenharmony_ci _mesa_key_pointer_equal); 109bf215546Sopenharmony_ci return job; 110bf215546Sopenharmony_ci} 111bf215546Sopenharmony_ci 112bf215546Sopenharmony_civoid 113bf215546Sopenharmony_civ3d_job_add_bo(struct v3d_job *job, struct v3d_bo *bo) 114bf215546Sopenharmony_ci{ 115bf215546Sopenharmony_ci if (!bo) 116bf215546Sopenharmony_ci return; 117bf215546Sopenharmony_ci 118bf215546Sopenharmony_ci if (_mesa_set_search(job->bos, bo)) 119bf215546Sopenharmony_ci return; 120bf215546Sopenharmony_ci 121bf215546Sopenharmony_ci v3d_bo_reference(bo); 122bf215546Sopenharmony_ci _mesa_set_add(job->bos, bo); 123bf215546Sopenharmony_ci job->referenced_size += bo->size; 124bf215546Sopenharmony_ci 125bf215546Sopenharmony_ci uint32_t *bo_handles = (void *)(uintptr_t)job->submit.bo_handles; 126bf215546Sopenharmony_ci 127bf215546Sopenharmony_ci if (job->submit.bo_handle_count >= job->bo_handles_size) { 128bf215546Sopenharmony_ci job->bo_handles_size = MAX2(4, job->bo_handles_size * 2); 129bf215546Sopenharmony_ci bo_handles = reralloc(job, bo_handles, 130bf215546Sopenharmony_ci uint32_t, job->bo_handles_size); 131bf215546Sopenharmony_ci job->submit.bo_handles = (uintptr_t)(void *)bo_handles; 132bf215546Sopenharmony_ci } 133bf215546Sopenharmony_ci bo_handles[job->submit.bo_handle_count++] = bo->handle; 134bf215546Sopenharmony_ci} 135bf215546Sopenharmony_ci 136bf215546Sopenharmony_civoid 137bf215546Sopenharmony_civ3d_job_add_write_resource(struct v3d_job *job, struct pipe_resource *prsc) 138bf215546Sopenharmony_ci{ 139bf215546Sopenharmony_ci struct v3d_context *v3d = job->v3d; 140bf215546Sopenharmony_ci 141bf215546Sopenharmony_ci if (!job->write_prscs) { 142bf215546Sopenharmony_ci job->write_prscs = _mesa_set_create(job, 143bf215546Sopenharmony_ci _mesa_hash_pointer, 144bf215546Sopenharmony_ci _mesa_key_pointer_equal); 145bf215546Sopenharmony_ci } 146bf215546Sopenharmony_ci 147bf215546Sopenharmony_ci _mesa_set_add(job->write_prscs, prsc); 148bf215546Sopenharmony_ci _mesa_hash_table_insert(v3d->write_jobs, prsc, job); 149bf215546Sopenharmony_ci} 150bf215546Sopenharmony_ci 151bf215546Sopenharmony_civoid 152bf215546Sopenharmony_civ3d_flush_jobs_using_bo(struct v3d_context *v3d, struct v3d_bo *bo) 153bf215546Sopenharmony_ci{ 154bf215546Sopenharmony_ci hash_table_foreach(v3d->jobs, entry) { 155bf215546Sopenharmony_ci struct v3d_job *job = entry->data; 156bf215546Sopenharmony_ci 157bf215546Sopenharmony_ci if (_mesa_set_search(job->bos, bo)) 158bf215546Sopenharmony_ci v3d_job_submit(v3d, job); 159bf215546Sopenharmony_ci } 160bf215546Sopenharmony_ci} 161bf215546Sopenharmony_ci 162bf215546Sopenharmony_civoid 163bf215546Sopenharmony_civ3d_job_add_tf_write_resource(struct v3d_job *job, struct pipe_resource *prsc) 164bf215546Sopenharmony_ci{ 165bf215546Sopenharmony_ci v3d_job_add_write_resource(job, prsc); 166bf215546Sopenharmony_ci 167bf215546Sopenharmony_ci if (!job->tf_write_prscs) 168bf215546Sopenharmony_ci job->tf_write_prscs = _mesa_pointer_set_create(job); 169bf215546Sopenharmony_ci 170bf215546Sopenharmony_ci _mesa_set_add(job->tf_write_prscs, prsc); 171bf215546Sopenharmony_ci} 172bf215546Sopenharmony_ci 173bf215546Sopenharmony_cistatic bool 174bf215546Sopenharmony_civ3d_job_writes_resource_from_tf(struct v3d_job *job, 175bf215546Sopenharmony_ci struct pipe_resource *prsc) 176bf215546Sopenharmony_ci{ 177bf215546Sopenharmony_ci if (!job->tf_enabled) 178bf215546Sopenharmony_ci return false; 179bf215546Sopenharmony_ci 180bf215546Sopenharmony_ci if (!job->tf_write_prscs) 181bf215546Sopenharmony_ci return false; 182bf215546Sopenharmony_ci 183bf215546Sopenharmony_ci return _mesa_set_search(job->tf_write_prscs, prsc) != NULL; 184bf215546Sopenharmony_ci} 185bf215546Sopenharmony_ci 186bf215546Sopenharmony_civoid 187bf215546Sopenharmony_civ3d_flush_jobs_writing_resource(struct v3d_context *v3d, 188bf215546Sopenharmony_ci struct pipe_resource *prsc, 189bf215546Sopenharmony_ci enum v3d_flush_cond flush_cond, 190bf215546Sopenharmony_ci bool is_compute_pipeline) 191bf215546Sopenharmony_ci{ 192bf215546Sopenharmony_ci struct hash_entry *entry = _mesa_hash_table_search(v3d->write_jobs, 193bf215546Sopenharmony_ci prsc); 194bf215546Sopenharmony_ci struct v3d_resource *rsc = v3d_resource(prsc); 195bf215546Sopenharmony_ci 196bf215546Sopenharmony_ci /* We need to sync if graphics pipeline reads a resource written 197bf215546Sopenharmony_ci * by the compute pipeline. The same would be needed for the case of 198bf215546Sopenharmony_ci * graphics-compute dependency but nowadays all compute jobs 199bf215546Sopenharmony_ci * are serialized with the previous submitted job. 200bf215546Sopenharmony_ci */ 201bf215546Sopenharmony_ci if (!is_compute_pipeline && rsc->bo != NULL && rsc->compute_written) { 202bf215546Sopenharmony_ci v3d->sync_on_last_compute_job = true; 203bf215546Sopenharmony_ci rsc->compute_written = false; 204bf215546Sopenharmony_ci } 205bf215546Sopenharmony_ci 206bf215546Sopenharmony_ci if (!entry) 207bf215546Sopenharmony_ci return; 208bf215546Sopenharmony_ci 209bf215546Sopenharmony_ci struct v3d_job *job = entry->data; 210bf215546Sopenharmony_ci 211bf215546Sopenharmony_ci bool needs_flush; 212bf215546Sopenharmony_ci switch (flush_cond) { 213bf215546Sopenharmony_ci case V3D_FLUSH_ALWAYS: 214bf215546Sopenharmony_ci needs_flush = true; 215bf215546Sopenharmony_ci break; 216bf215546Sopenharmony_ci case V3D_FLUSH_NOT_CURRENT_JOB: 217bf215546Sopenharmony_ci needs_flush = !v3d->job || v3d->job != job; 218bf215546Sopenharmony_ci break; 219bf215546Sopenharmony_ci case V3D_FLUSH_DEFAULT: 220bf215546Sopenharmony_ci default: 221bf215546Sopenharmony_ci /* For writes from TF in the same job we use the "Wait for TF" 222bf215546Sopenharmony_ci * feature provided by the hardware so we don't want to flush. 223bf215546Sopenharmony_ci * The exception to this is when the caller is about to map the 224bf215546Sopenharmony_ci * resource since in that case we don't have a 'Wait for TF' 225bf215546Sopenharmony_ci * command the in command stream. In this scenario the caller 226bf215546Sopenharmony_ci * is expected to set 'always_flush' to True. 227bf215546Sopenharmony_ci */ 228bf215546Sopenharmony_ci needs_flush = !v3d_job_writes_resource_from_tf(job, prsc); 229bf215546Sopenharmony_ci } 230bf215546Sopenharmony_ci 231bf215546Sopenharmony_ci if (needs_flush) 232bf215546Sopenharmony_ci v3d_job_submit(v3d, job); 233bf215546Sopenharmony_ci} 234bf215546Sopenharmony_ci 235bf215546Sopenharmony_civoid 236bf215546Sopenharmony_civ3d_flush_jobs_reading_resource(struct v3d_context *v3d, 237bf215546Sopenharmony_ci struct pipe_resource *prsc, 238bf215546Sopenharmony_ci enum v3d_flush_cond flush_cond, 239bf215546Sopenharmony_ci bool is_compute_pipeline) 240bf215546Sopenharmony_ci{ 241bf215546Sopenharmony_ci struct v3d_resource *rsc = v3d_resource(prsc); 242bf215546Sopenharmony_ci 243bf215546Sopenharmony_ci /* We only need to force the flush on TF writes, which is the only 244bf215546Sopenharmony_ci * case where we might skip the flush to use the 'Wait for TF' 245bf215546Sopenharmony_ci * command. Here we are flushing for a read, which means that the 246bf215546Sopenharmony_ci * caller intends to write to the resource, so we don't care if 247bf215546Sopenharmony_ci * there was a previous TF write to it. 248bf215546Sopenharmony_ci */ 249bf215546Sopenharmony_ci v3d_flush_jobs_writing_resource(v3d, prsc, flush_cond, 250bf215546Sopenharmony_ci is_compute_pipeline); 251bf215546Sopenharmony_ci 252bf215546Sopenharmony_ci hash_table_foreach(v3d->jobs, entry) { 253bf215546Sopenharmony_ci struct v3d_job *job = entry->data; 254bf215546Sopenharmony_ci 255bf215546Sopenharmony_ci if (!_mesa_set_search(job->bos, rsc->bo)) 256bf215546Sopenharmony_ci continue; 257bf215546Sopenharmony_ci 258bf215546Sopenharmony_ci bool needs_flush; 259bf215546Sopenharmony_ci switch (flush_cond) { 260bf215546Sopenharmony_ci case V3D_FLUSH_NOT_CURRENT_JOB: 261bf215546Sopenharmony_ci needs_flush = !v3d->job || v3d->job != job; 262bf215546Sopenharmony_ci break; 263bf215546Sopenharmony_ci case V3D_FLUSH_ALWAYS: 264bf215546Sopenharmony_ci case V3D_FLUSH_DEFAULT: 265bf215546Sopenharmony_ci default: 266bf215546Sopenharmony_ci needs_flush = true; 267bf215546Sopenharmony_ci } 268bf215546Sopenharmony_ci 269bf215546Sopenharmony_ci if (needs_flush) 270bf215546Sopenharmony_ci v3d_job_submit(v3d, job); 271bf215546Sopenharmony_ci 272bf215546Sopenharmony_ci /* Reminder: v3d->jobs is safe to keep iterating even 273bf215546Sopenharmony_ci * after deletion of an entry. 274bf215546Sopenharmony_ci */ 275bf215546Sopenharmony_ci continue; 276bf215546Sopenharmony_ci } 277bf215546Sopenharmony_ci} 278bf215546Sopenharmony_ci 279bf215546Sopenharmony_ci/** 280bf215546Sopenharmony_ci * Returns a v3d_job struture for tracking V3D rendering to a particular FBO. 281bf215546Sopenharmony_ci * 282bf215546Sopenharmony_ci * If we've already started rendering to this FBO, then return the same job, 283bf215546Sopenharmony_ci * otherwise make a new one. If we're beginning rendering to an FBO, make 284bf215546Sopenharmony_ci * sure that any previous reads of the FBO (or writes to its color/Z surfaces) 285bf215546Sopenharmony_ci * have been flushed. 286bf215546Sopenharmony_ci */ 287bf215546Sopenharmony_cistruct v3d_job * 288bf215546Sopenharmony_civ3d_get_job(struct v3d_context *v3d, 289bf215546Sopenharmony_ci uint32_t nr_cbufs, 290bf215546Sopenharmony_ci struct pipe_surface **cbufs, 291bf215546Sopenharmony_ci struct pipe_surface *zsbuf, 292bf215546Sopenharmony_ci struct pipe_surface *bbuf) 293bf215546Sopenharmony_ci{ 294bf215546Sopenharmony_ci /* Return the existing job for this FBO if we have one */ 295bf215546Sopenharmony_ci struct v3d_job_key local_key = { 296bf215546Sopenharmony_ci .cbufs = { 297bf215546Sopenharmony_ci cbufs[0], 298bf215546Sopenharmony_ci cbufs[1], 299bf215546Sopenharmony_ci cbufs[2], 300bf215546Sopenharmony_ci cbufs[3], 301bf215546Sopenharmony_ci }, 302bf215546Sopenharmony_ci .zsbuf = zsbuf, 303bf215546Sopenharmony_ci .bbuf = bbuf, 304bf215546Sopenharmony_ci }; 305bf215546Sopenharmony_ci struct hash_entry *entry = _mesa_hash_table_search(v3d->jobs, 306bf215546Sopenharmony_ci &local_key); 307bf215546Sopenharmony_ci if (entry) 308bf215546Sopenharmony_ci return entry->data; 309bf215546Sopenharmony_ci 310bf215546Sopenharmony_ci /* Creating a new job. Make sure that any previous jobs reading or 311bf215546Sopenharmony_ci * writing these buffers are flushed. 312bf215546Sopenharmony_ci */ 313bf215546Sopenharmony_ci struct v3d_job *job = v3d_job_create(v3d); 314bf215546Sopenharmony_ci job->nr_cbufs = nr_cbufs; 315bf215546Sopenharmony_ci 316bf215546Sopenharmony_ci for (int i = 0; i < job->nr_cbufs; i++) { 317bf215546Sopenharmony_ci if (cbufs[i]) { 318bf215546Sopenharmony_ci v3d_flush_jobs_reading_resource(v3d, cbufs[i]->texture, 319bf215546Sopenharmony_ci V3D_FLUSH_DEFAULT, 320bf215546Sopenharmony_ci false); 321bf215546Sopenharmony_ci pipe_surface_reference(&job->cbufs[i], cbufs[i]); 322bf215546Sopenharmony_ci 323bf215546Sopenharmony_ci if (cbufs[i]->texture->nr_samples > 1) 324bf215546Sopenharmony_ci job->msaa = true; 325bf215546Sopenharmony_ci } 326bf215546Sopenharmony_ci } 327bf215546Sopenharmony_ci if (zsbuf) { 328bf215546Sopenharmony_ci v3d_flush_jobs_reading_resource(v3d, zsbuf->texture, 329bf215546Sopenharmony_ci V3D_FLUSH_DEFAULT, 330bf215546Sopenharmony_ci false); 331bf215546Sopenharmony_ci pipe_surface_reference(&job->zsbuf, zsbuf); 332bf215546Sopenharmony_ci if (zsbuf->texture->nr_samples > 1) 333bf215546Sopenharmony_ci job->msaa = true; 334bf215546Sopenharmony_ci } 335bf215546Sopenharmony_ci if (bbuf) { 336bf215546Sopenharmony_ci pipe_surface_reference(&job->bbuf, bbuf); 337bf215546Sopenharmony_ci if (bbuf->texture->nr_samples > 1) 338bf215546Sopenharmony_ci job->msaa = true; 339bf215546Sopenharmony_ci } 340bf215546Sopenharmony_ci 341bf215546Sopenharmony_ci for (int i = 0; i < job->nr_cbufs; i++) { 342bf215546Sopenharmony_ci if (cbufs[i]) 343bf215546Sopenharmony_ci _mesa_hash_table_insert(v3d->write_jobs, 344bf215546Sopenharmony_ci cbufs[i]->texture, job); 345bf215546Sopenharmony_ci } 346bf215546Sopenharmony_ci if (zsbuf) { 347bf215546Sopenharmony_ci _mesa_hash_table_insert(v3d->write_jobs, zsbuf->texture, job); 348bf215546Sopenharmony_ci 349bf215546Sopenharmony_ci struct v3d_resource *rsc = v3d_resource(zsbuf->texture); 350bf215546Sopenharmony_ci if (rsc->separate_stencil) { 351bf215546Sopenharmony_ci v3d_flush_jobs_reading_resource(v3d, 352bf215546Sopenharmony_ci &rsc->separate_stencil->base, 353bf215546Sopenharmony_ci V3D_FLUSH_DEFAULT, 354bf215546Sopenharmony_ci false); 355bf215546Sopenharmony_ci _mesa_hash_table_insert(v3d->write_jobs, 356bf215546Sopenharmony_ci &rsc->separate_stencil->base, 357bf215546Sopenharmony_ci job); 358bf215546Sopenharmony_ci } 359bf215546Sopenharmony_ci } 360bf215546Sopenharmony_ci 361bf215546Sopenharmony_ci job->double_buffer = 362bf215546Sopenharmony_ci unlikely(V3D_DEBUG & V3D_DEBUG_DOUBLE_BUFFER) && !job->msaa; 363bf215546Sopenharmony_ci 364bf215546Sopenharmony_ci memcpy(&job->key, &local_key, sizeof(local_key)); 365bf215546Sopenharmony_ci _mesa_hash_table_insert(v3d->jobs, &job->key, job); 366bf215546Sopenharmony_ci 367bf215546Sopenharmony_ci return job; 368bf215546Sopenharmony_ci} 369bf215546Sopenharmony_ci 370bf215546Sopenharmony_cistruct v3d_job * 371bf215546Sopenharmony_civ3d_get_job_for_fbo(struct v3d_context *v3d) 372bf215546Sopenharmony_ci{ 373bf215546Sopenharmony_ci if (v3d->job) 374bf215546Sopenharmony_ci return v3d->job; 375bf215546Sopenharmony_ci 376bf215546Sopenharmony_ci uint32_t nr_cbufs = v3d->framebuffer.nr_cbufs; 377bf215546Sopenharmony_ci struct pipe_surface **cbufs = v3d->framebuffer.cbufs; 378bf215546Sopenharmony_ci struct pipe_surface *zsbuf = v3d->framebuffer.zsbuf; 379bf215546Sopenharmony_ci struct v3d_job *job = v3d_get_job(v3d, nr_cbufs, cbufs, zsbuf, NULL); 380bf215546Sopenharmony_ci 381bf215546Sopenharmony_ci if (v3d->framebuffer.samples >= 1) { 382bf215546Sopenharmony_ci job->msaa = true; 383bf215546Sopenharmony_ci job->double_buffer = false; 384bf215546Sopenharmony_ci } 385bf215546Sopenharmony_ci 386bf215546Sopenharmony_ci v3d_get_tile_buffer_size(job->msaa, job->double_buffer, 387bf215546Sopenharmony_ci job->nr_cbufs, job->cbufs, job->bbuf, 388bf215546Sopenharmony_ci &job->tile_width, &job->tile_height, 389bf215546Sopenharmony_ci &job->internal_bpp); 390bf215546Sopenharmony_ci 391bf215546Sopenharmony_ci /* The dirty flags are tracking what's been updated while v3d->job has 392bf215546Sopenharmony_ci * been bound, so set them all to ~0 when switching between jobs. We 393bf215546Sopenharmony_ci * also need to reset all state at the start of rendering. 394bf215546Sopenharmony_ci */ 395bf215546Sopenharmony_ci v3d->dirty = ~0; 396bf215546Sopenharmony_ci 397bf215546Sopenharmony_ci /* If we're binding to uninitialized buffers, no need to load their 398bf215546Sopenharmony_ci * contents before drawing. 399bf215546Sopenharmony_ci */ 400bf215546Sopenharmony_ci for (int i = 0; i < nr_cbufs; i++) { 401bf215546Sopenharmony_ci if (cbufs[i]) { 402bf215546Sopenharmony_ci struct v3d_resource *rsc = v3d_resource(cbufs[i]->texture); 403bf215546Sopenharmony_ci if (!rsc->writes) 404bf215546Sopenharmony_ci job->clear |= PIPE_CLEAR_COLOR0 << i; 405bf215546Sopenharmony_ci } 406bf215546Sopenharmony_ci } 407bf215546Sopenharmony_ci 408bf215546Sopenharmony_ci if (zsbuf) { 409bf215546Sopenharmony_ci struct v3d_resource *rsc = v3d_resource(zsbuf->texture); 410bf215546Sopenharmony_ci if (!rsc->writes) 411bf215546Sopenharmony_ci job->clear |= PIPE_CLEAR_DEPTH; 412bf215546Sopenharmony_ci 413bf215546Sopenharmony_ci if (rsc->separate_stencil) 414bf215546Sopenharmony_ci rsc = rsc->separate_stencil; 415bf215546Sopenharmony_ci 416bf215546Sopenharmony_ci if (!rsc->writes) 417bf215546Sopenharmony_ci job->clear |= PIPE_CLEAR_STENCIL; 418bf215546Sopenharmony_ci } 419bf215546Sopenharmony_ci 420bf215546Sopenharmony_ci job->draw_tiles_x = DIV_ROUND_UP(v3d->framebuffer.width, 421bf215546Sopenharmony_ci job->tile_width); 422bf215546Sopenharmony_ci job->draw_tiles_y = DIV_ROUND_UP(v3d->framebuffer.height, 423bf215546Sopenharmony_ci job->tile_height); 424bf215546Sopenharmony_ci 425bf215546Sopenharmony_ci v3d->job = job; 426bf215546Sopenharmony_ci 427bf215546Sopenharmony_ci return job; 428bf215546Sopenharmony_ci} 429bf215546Sopenharmony_ci 430bf215546Sopenharmony_cistatic void 431bf215546Sopenharmony_civ3d_clif_dump(struct v3d_context *v3d, struct v3d_job *job) 432bf215546Sopenharmony_ci{ 433bf215546Sopenharmony_ci if (!(unlikely(V3D_DEBUG & (V3D_DEBUG_CL | 434bf215546Sopenharmony_ci V3D_DEBUG_CL_NO_BIN | 435bf215546Sopenharmony_ci V3D_DEBUG_CLIF)))) 436bf215546Sopenharmony_ci return; 437bf215546Sopenharmony_ci 438bf215546Sopenharmony_ci struct clif_dump *clif = clif_dump_init(&v3d->screen->devinfo, 439bf215546Sopenharmony_ci stderr, 440bf215546Sopenharmony_ci V3D_DEBUG & (V3D_DEBUG_CL | 441bf215546Sopenharmony_ci V3D_DEBUG_CL_NO_BIN), 442bf215546Sopenharmony_ci V3D_DEBUG & V3D_DEBUG_CL_NO_BIN); 443bf215546Sopenharmony_ci 444bf215546Sopenharmony_ci set_foreach(job->bos, entry) { 445bf215546Sopenharmony_ci struct v3d_bo *bo = (void *)entry->key; 446bf215546Sopenharmony_ci char *name = ralloc_asprintf(NULL, "%s_0x%x", 447bf215546Sopenharmony_ci bo->name, bo->offset); 448bf215546Sopenharmony_ci 449bf215546Sopenharmony_ci v3d_bo_map(bo); 450bf215546Sopenharmony_ci clif_dump_add_bo(clif, name, bo->offset, bo->size, bo->map); 451bf215546Sopenharmony_ci 452bf215546Sopenharmony_ci ralloc_free(name); 453bf215546Sopenharmony_ci } 454bf215546Sopenharmony_ci 455bf215546Sopenharmony_ci clif_dump(clif, &job->submit); 456bf215546Sopenharmony_ci 457bf215546Sopenharmony_ci clif_dump_destroy(clif); 458bf215546Sopenharmony_ci} 459bf215546Sopenharmony_ci 460bf215546Sopenharmony_cistatic void 461bf215546Sopenharmony_civ3d_read_and_accumulate_primitive_counters(struct v3d_context *v3d) 462bf215546Sopenharmony_ci{ 463bf215546Sopenharmony_ci assert(v3d->prim_counts); 464bf215546Sopenharmony_ci 465bf215546Sopenharmony_ci perf_debug("stalling on TF counts readback\n"); 466bf215546Sopenharmony_ci struct v3d_resource *rsc = v3d_resource(v3d->prim_counts); 467bf215546Sopenharmony_ci if (v3d_bo_wait(rsc->bo, PIPE_TIMEOUT_INFINITE, "prim-counts")) { 468bf215546Sopenharmony_ci uint32_t *map = v3d_bo_map(rsc->bo) + v3d->prim_counts_offset; 469bf215546Sopenharmony_ci v3d->tf_prims_generated += map[V3D_PRIM_COUNTS_TF_WRITTEN]; 470bf215546Sopenharmony_ci /* When we only have a vertex shader we determine the primitive 471bf215546Sopenharmony_ci * count in the CPU so don't update it here again. 472bf215546Sopenharmony_ci */ 473bf215546Sopenharmony_ci if (v3d->prog.gs) 474bf215546Sopenharmony_ci v3d->prims_generated += map[V3D_PRIM_COUNTS_WRITTEN]; 475bf215546Sopenharmony_ci } 476bf215546Sopenharmony_ci} 477bf215546Sopenharmony_ci 478bf215546Sopenharmony_ci/** 479bf215546Sopenharmony_ci * Submits the job to the kernel and then reinitializes it. 480bf215546Sopenharmony_ci */ 481bf215546Sopenharmony_civoid 482bf215546Sopenharmony_civ3d_job_submit(struct v3d_context *v3d, struct v3d_job *job) 483bf215546Sopenharmony_ci{ 484bf215546Sopenharmony_ci struct v3d_screen *screen = v3d->screen; 485bf215546Sopenharmony_ci 486bf215546Sopenharmony_ci if (!job->needs_flush) 487bf215546Sopenharmony_ci goto done; 488bf215546Sopenharmony_ci 489bf215546Sopenharmony_ci /* The GL_PRIMITIVES_GENERATED query is included with 490bf215546Sopenharmony_ci * OES_geometry_shader. 491bf215546Sopenharmony_ci */ 492bf215546Sopenharmony_ci job->needs_primitives_generated = 493bf215546Sopenharmony_ci v3d->n_primitives_generated_queries_in_flight > 0 && 494bf215546Sopenharmony_ci v3d->prog.gs; 495bf215546Sopenharmony_ci 496bf215546Sopenharmony_ci if (job->needs_primitives_generated) 497bf215546Sopenharmony_ci v3d_ensure_prim_counts_allocated(v3d); 498bf215546Sopenharmony_ci 499bf215546Sopenharmony_ci if (screen->devinfo.ver >= 41) 500bf215546Sopenharmony_ci v3d41_emit_rcl(job); 501bf215546Sopenharmony_ci else 502bf215546Sopenharmony_ci v3d33_emit_rcl(job); 503bf215546Sopenharmony_ci 504bf215546Sopenharmony_ci if (cl_offset(&job->bcl) > 0) { 505bf215546Sopenharmony_ci if (screen->devinfo.ver >= 41) 506bf215546Sopenharmony_ci v3d41_bcl_epilogue(v3d, job); 507bf215546Sopenharmony_ci else 508bf215546Sopenharmony_ci v3d33_bcl_epilogue(v3d, job); 509bf215546Sopenharmony_ci } 510bf215546Sopenharmony_ci 511bf215546Sopenharmony_ci /* While the RCL will implicitly depend on the last RCL to have 512bf215546Sopenharmony_ci * finished, we also need to block on any previous TFU job we may have 513bf215546Sopenharmony_ci * dispatched. 514bf215546Sopenharmony_ci */ 515bf215546Sopenharmony_ci job->submit.in_sync_rcl = v3d->out_sync; 516bf215546Sopenharmony_ci 517bf215546Sopenharmony_ci /* Update the sync object for the last rendering by our context. */ 518bf215546Sopenharmony_ci job->submit.out_sync = v3d->out_sync; 519bf215546Sopenharmony_ci 520bf215546Sopenharmony_ci job->submit.bcl_end = job->bcl.bo->offset + cl_offset(&job->bcl); 521bf215546Sopenharmony_ci job->submit.rcl_end = job->rcl.bo->offset + cl_offset(&job->rcl); 522bf215546Sopenharmony_ci 523bf215546Sopenharmony_ci if (v3d->active_perfmon) { 524bf215546Sopenharmony_ci assert(screen->has_perfmon); 525bf215546Sopenharmony_ci job->submit.perfmon_id = v3d->active_perfmon->kperfmon_id; 526bf215546Sopenharmony_ci } 527bf215546Sopenharmony_ci 528bf215546Sopenharmony_ci /* If we are submitting a job with a different perfmon, we need to 529bf215546Sopenharmony_ci * ensure the previous one fully finishes before starting this; 530bf215546Sopenharmony_ci * otherwise it would wrongly mix counter results. 531bf215546Sopenharmony_ci */ 532bf215546Sopenharmony_ci if (v3d->active_perfmon != v3d->last_perfmon) { 533bf215546Sopenharmony_ci v3d->last_perfmon = v3d->active_perfmon; 534bf215546Sopenharmony_ci job->submit.in_sync_bcl = v3d->out_sync; 535bf215546Sopenharmony_ci } 536bf215546Sopenharmony_ci 537bf215546Sopenharmony_ci job->submit.flags = 0; 538bf215546Sopenharmony_ci if (job->tmu_dirty_rcl && screen->has_cache_flush) 539bf215546Sopenharmony_ci job->submit.flags |= DRM_V3D_SUBMIT_CL_FLUSH_CACHE; 540bf215546Sopenharmony_ci 541bf215546Sopenharmony_ci /* On V3D 4.1, the tile alloc/state setup moved to register writes 542bf215546Sopenharmony_ci * instead of binner packets. 543bf215546Sopenharmony_ci */ 544bf215546Sopenharmony_ci if (screen->devinfo.ver >= 41) { 545bf215546Sopenharmony_ci v3d_job_add_bo(job, job->tile_alloc); 546bf215546Sopenharmony_ci job->submit.qma = job->tile_alloc->offset; 547bf215546Sopenharmony_ci job->submit.qms = job->tile_alloc->size; 548bf215546Sopenharmony_ci 549bf215546Sopenharmony_ci v3d_job_add_bo(job, job->tile_state); 550bf215546Sopenharmony_ci job->submit.qts = job->tile_state->offset; 551bf215546Sopenharmony_ci } 552bf215546Sopenharmony_ci 553bf215546Sopenharmony_ci v3d_clif_dump(v3d, job); 554bf215546Sopenharmony_ci 555bf215546Sopenharmony_ci if (!(unlikely(V3D_DEBUG & V3D_DEBUG_NORAST))) { 556bf215546Sopenharmony_ci int ret; 557bf215546Sopenharmony_ci 558bf215546Sopenharmony_ci ret = v3d_ioctl(v3d->fd, DRM_IOCTL_V3D_SUBMIT_CL, &job->submit); 559bf215546Sopenharmony_ci static bool warned = false; 560bf215546Sopenharmony_ci if (ret && !warned) { 561bf215546Sopenharmony_ci fprintf(stderr, "Draw call returned %s. " 562bf215546Sopenharmony_ci "Expect corruption.\n", strerror(errno)); 563bf215546Sopenharmony_ci warned = true; 564bf215546Sopenharmony_ci } else if (!ret) { 565bf215546Sopenharmony_ci if (v3d->active_perfmon) 566bf215546Sopenharmony_ci v3d->active_perfmon->job_submitted = true; 567bf215546Sopenharmony_ci } 568bf215546Sopenharmony_ci 569bf215546Sopenharmony_ci /* If we are submitting a job in the middle of transform 570bf215546Sopenharmony_ci * feedback or there is a primitives generated query with a 571bf215546Sopenharmony_ci * geometry shader then we need to read the primitive counts 572bf215546Sopenharmony_ci * and accumulate them, otherwise they will be reset at the 573bf215546Sopenharmony_ci * start of the next draw when we emit the Tile Binning Mode 574bf215546Sopenharmony_ci * Configuration packet. 575bf215546Sopenharmony_ci * 576bf215546Sopenharmony_ci * If the job doesn't have any TF draw calls, then we know 577bf215546Sopenharmony_ci * the primitive count must be zero and we can skip stalling 578bf215546Sopenharmony_ci * for this. This also fixes a problem because it seems that 579bf215546Sopenharmony_ci * in this scenario the counters are not reset with the Tile 580bf215546Sopenharmony_ci * Binning Mode Configuration packet, which would translate 581bf215546Sopenharmony_ci * to us reading an obsolete (possibly non-zero) value from 582bf215546Sopenharmony_ci * the GPU counters. 583bf215546Sopenharmony_ci */ 584bf215546Sopenharmony_ci if (job->needs_primitives_generated || 585bf215546Sopenharmony_ci (v3d->streamout.num_targets && 586bf215546Sopenharmony_ci job->tf_draw_calls_queued > 0)) 587bf215546Sopenharmony_ci v3d_read_and_accumulate_primitive_counters(v3d); 588bf215546Sopenharmony_ci } 589bf215546Sopenharmony_ci 590bf215546Sopenharmony_cidone: 591bf215546Sopenharmony_ci v3d_job_free(v3d, job); 592bf215546Sopenharmony_ci} 593bf215546Sopenharmony_ci 594bf215546Sopenharmony_cistatic bool 595bf215546Sopenharmony_civ3d_job_compare(const void *a, const void *b) 596bf215546Sopenharmony_ci{ 597bf215546Sopenharmony_ci return memcmp(a, b, sizeof(struct v3d_job_key)) == 0; 598bf215546Sopenharmony_ci} 599bf215546Sopenharmony_ci 600bf215546Sopenharmony_cistatic uint32_t 601bf215546Sopenharmony_civ3d_job_hash(const void *key) 602bf215546Sopenharmony_ci{ 603bf215546Sopenharmony_ci return _mesa_hash_data(key, sizeof(struct v3d_job_key)); 604bf215546Sopenharmony_ci} 605bf215546Sopenharmony_ci 606bf215546Sopenharmony_civoid 607bf215546Sopenharmony_civ3d_job_init(struct v3d_context *v3d) 608bf215546Sopenharmony_ci{ 609bf215546Sopenharmony_ci v3d->jobs = _mesa_hash_table_create(v3d, 610bf215546Sopenharmony_ci v3d_job_hash, 611bf215546Sopenharmony_ci v3d_job_compare); 612bf215546Sopenharmony_ci v3d->write_jobs = _mesa_hash_table_create(v3d, 613bf215546Sopenharmony_ci _mesa_hash_pointer, 614bf215546Sopenharmony_ci _mesa_key_pointer_equal); 615bf215546Sopenharmony_ci} 616bf215546Sopenharmony_ci 617