1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2017 Intel Corporation 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 shall be included 12bf215546Sopenharmony_ci * in all copies or substantial portions of the Software. 13bf215546Sopenharmony_ci * 14bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20bf215546Sopenharmony_ci * DEALINGS IN THE SOFTWARE. 21bf215546Sopenharmony_ci */ 22bf215546Sopenharmony_ci 23bf215546Sopenharmony_ci/** 24bf215546Sopenharmony_ci * @file crocus_batch.c 25bf215546Sopenharmony_ci * 26bf215546Sopenharmony_ci * Batchbuffer and command submission module. 27bf215546Sopenharmony_ci * 28bf215546Sopenharmony_ci * Every API draw call results in a number of GPU commands, which we 29bf215546Sopenharmony_ci * collect into a "batch buffer". Typically, many draw calls are grouped 30bf215546Sopenharmony_ci * into a single batch to amortize command submission overhead. 31bf215546Sopenharmony_ci * 32bf215546Sopenharmony_ci * We submit batches to the kernel using the I915_GEM_EXECBUFFER2 ioctl. 33bf215546Sopenharmony_ci * One critical piece of data is the "validation list", which contains a 34bf215546Sopenharmony_ci * list of the buffer objects (BOs) which the commands in the GPU need. 35bf215546Sopenharmony_ci * The kernel will make sure these are resident and pinned at the correct 36bf215546Sopenharmony_ci * virtual memory address before executing our batch. If a BO is not in 37bf215546Sopenharmony_ci * the validation list, it effectively does not exist, so take care. 38bf215546Sopenharmony_ci */ 39bf215546Sopenharmony_ci 40bf215546Sopenharmony_ci#include "crocus_batch.h" 41bf215546Sopenharmony_ci#include "crocus_bufmgr.h" 42bf215546Sopenharmony_ci#include "crocus_context.h" 43bf215546Sopenharmony_ci#include "crocus_fence.h" 44bf215546Sopenharmony_ci 45bf215546Sopenharmony_ci#include "drm-uapi/i915_drm.h" 46bf215546Sopenharmony_ci 47bf215546Sopenharmony_ci#include "intel/common/intel_gem.h" 48bf215546Sopenharmony_ci#include "util/hash_table.h" 49bf215546Sopenharmony_ci#include "util/set.h" 50bf215546Sopenharmony_ci#include "util/u_upload_mgr.h" 51bf215546Sopenharmony_ci 52bf215546Sopenharmony_ci#include <errno.h> 53bf215546Sopenharmony_ci#include <xf86drm.h> 54bf215546Sopenharmony_ci 55bf215546Sopenharmony_ci#if HAVE_VALGRIND 56bf215546Sopenharmony_ci#include <memcheck.h> 57bf215546Sopenharmony_ci#include <valgrind.h> 58bf215546Sopenharmony_ci#define VG(x) x 59bf215546Sopenharmony_ci#else 60bf215546Sopenharmony_ci#define VG(x) 61bf215546Sopenharmony_ci#endif 62bf215546Sopenharmony_ci 63bf215546Sopenharmony_ci#define FILE_DEBUG_FLAG DEBUG_BUFMGR 64bf215546Sopenharmony_ci 65bf215546Sopenharmony_ci/* Terminating the batch takes either 4 bytes for MI_BATCH_BUFFER_END 66bf215546Sopenharmony_ci * or 12 bytes for MI_BATCH_BUFFER_START (when chaining). Plus, we may 67bf215546Sopenharmony_ci * need an extra 4 bytes to pad out to the nearest QWord. So reserve 16. 68bf215546Sopenharmony_ci */ 69bf215546Sopenharmony_ci#define BATCH_RESERVED(devinfo) ((devinfo)->platform == INTEL_PLATFORM_HSW ? 32 : 16) 70bf215546Sopenharmony_ci 71bf215546Sopenharmony_cistatic void crocus_batch_reset(struct crocus_batch *batch); 72bf215546Sopenharmony_ci 73bf215546Sopenharmony_cistatic unsigned 74bf215546Sopenharmony_cinum_fences(struct crocus_batch *batch) 75bf215546Sopenharmony_ci{ 76bf215546Sopenharmony_ci return util_dynarray_num_elements(&batch->exec_fences, 77bf215546Sopenharmony_ci struct drm_i915_gem_exec_fence); 78bf215546Sopenharmony_ci} 79bf215546Sopenharmony_ci 80bf215546Sopenharmony_ci/** 81bf215546Sopenharmony_ci * Debugging code to dump the fence list, used by INTEL_DEBUG=submit. 82bf215546Sopenharmony_ci */ 83bf215546Sopenharmony_cistatic void 84bf215546Sopenharmony_cidump_fence_list(struct crocus_batch *batch) 85bf215546Sopenharmony_ci{ 86bf215546Sopenharmony_ci fprintf(stderr, "Fence list (length %u): ", num_fences(batch)); 87bf215546Sopenharmony_ci 88bf215546Sopenharmony_ci util_dynarray_foreach(&batch->exec_fences, 89bf215546Sopenharmony_ci struct drm_i915_gem_exec_fence, f) { 90bf215546Sopenharmony_ci fprintf(stderr, "%s%u%s ", 91bf215546Sopenharmony_ci (f->flags & I915_EXEC_FENCE_WAIT) ? "..." : "", 92bf215546Sopenharmony_ci f->handle, 93bf215546Sopenharmony_ci (f->flags & I915_EXEC_FENCE_SIGNAL) ? "!" : ""); 94bf215546Sopenharmony_ci } 95bf215546Sopenharmony_ci 96bf215546Sopenharmony_ci fprintf(stderr, "\n"); 97bf215546Sopenharmony_ci} 98bf215546Sopenharmony_ci 99bf215546Sopenharmony_ci/** 100bf215546Sopenharmony_ci * Debugging code to dump the validation list, used by INTEL_DEBUG=submit. 101bf215546Sopenharmony_ci */ 102bf215546Sopenharmony_cistatic void 103bf215546Sopenharmony_cidump_validation_list(struct crocus_batch *batch) 104bf215546Sopenharmony_ci{ 105bf215546Sopenharmony_ci fprintf(stderr, "Validation list (length %d):\n", batch->exec_count); 106bf215546Sopenharmony_ci 107bf215546Sopenharmony_ci for (int i = 0; i < batch->exec_count; i++) { 108bf215546Sopenharmony_ci uint64_t flags = batch->validation_list[i].flags; 109bf215546Sopenharmony_ci assert(batch->validation_list[i].handle == 110bf215546Sopenharmony_ci batch->exec_bos[i]->gem_handle); 111bf215546Sopenharmony_ci fprintf(stderr, 112bf215546Sopenharmony_ci "[%2d]: %2d %-14s @ 0x%"PRIx64" (%" PRIu64 "B)\t %2d refs %s\n", i, 113bf215546Sopenharmony_ci batch->validation_list[i].handle, batch->exec_bos[i]->name, 114bf215546Sopenharmony_ci (uint64_t)batch->validation_list[i].offset, batch->exec_bos[i]->size, 115bf215546Sopenharmony_ci batch->exec_bos[i]->refcount, 116bf215546Sopenharmony_ci (flags & EXEC_OBJECT_WRITE) ? " (write)" : ""); 117bf215546Sopenharmony_ci } 118bf215546Sopenharmony_ci} 119bf215546Sopenharmony_ci 120bf215546Sopenharmony_ci/** 121bf215546Sopenharmony_ci * Return BO information to the batch decoder (for debugging). 122bf215546Sopenharmony_ci */ 123bf215546Sopenharmony_cistatic struct intel_batch_decode_bo 124bf215546Sopenharmony_cidecode_get_bo(void *v_batch, bool ppgtt, uint64_t address) 125bf215546Sopenharmony_ci{ 126bf215546Sopenharmony_ci struct crocus_batch *batch = v_batch; 127bf215546Sopenharmony_ci 128bf215546Sopenharmony_ci for (int i = 0; i < batch->exec_count; i++) { 129bf215546Sopenharmony_ci struct crocus_bo *bo = batch->exec_bos[i]; 130bf215546Sopenharmony_ci /* The decoder zeroes out the top 16 bits, so we need to as well */ 131bf215546Sopenharmony_ci uint64_t bo_address = bo->gtt_offset & (~0ull >> 16); 132bf215546Sopenharmony_ci 133bf215546Sopenharmony_ci if (address >= bo_address && address < bo_address + bo->size) { 134bf215546Sopenharmony_ci return (struct intel_batch_decode_bo){ 135bf215546Sopenharmony_ci .addr = address, 136bf215546Sopenharmony_ci .size = bo->size, 137bf215546Sopenharmony_ci .map = crocus_bo_map(batch->dbg, bo, MAP_READ) + 138bf215546Sopenharmony_ci (address - bo_address), 139bf215546Sopenharmony_ci }; 140bf215546Sopenharmony_ci } 141bf215546Sopenharmony_ci } 142bf215546Sopenharmony_ci 143bf215546Sopenharmony_ci return (struct intel_batch_decode_bo) { }; 144bf215546Sopenharmony_ci} 145bf215546Sopenharmony_ci 146bf215546Sopenharmony_cistatic unsigned 147bf215546Sopenharmony_cidecode_get_state_size(void *v_batch, uint64_t address, 148bf215546Sopenharmony_ci uint64_t base_address) 149bf215546Sopenharmony_ci{ 150bf215546Sopenharmony_ci struct crocus_batch *batch = v_batch; 151bf215546Sopenharmony_ci 152bf215546Sopenharmony_ci /* The decoder gives us offsets from a base address, which is not great. 153bf215546Sopenharmony_ci * Binding tables are relative to surface state base address, and other 154bf215546Sopenharmony_ci * state is relative to dynamic state base address. These could alias, 155bf215546Sopenharmony_ci * but in practice it's unlikely because surface offsets are always in 156bf215546Sopenharmony_ci * the [0, 64K) range, and we assign dynamic state addresses starting at 157bf215546Sopenharmony_ci * the top of the 4GB range. We should fix this but it's likely good 158bf215546Sopenharmony_ci * enough for now. 159bf215546Sopenharmony_ci */ 160bf215546Sopenharmony_ci unsigned size = (uintptr_t) 161bf215546Sopenharmony_ci _mesa_hash_table_u64_search(batch->state_sizes, address - base_address); 162bf215546Sopenharmony_ci 163bf215546Sopenharmony_ci return size; 164bf215546Sopenharmony_ci} 165bf215546Sopenharmony_ci 166bf215546Sopenharmony_ci/** 167bf215546Sopenharmony_ci * Decode the current batch. 168bf215546Sopenharmony_ci */ 169bf215546Sopenharmony_cistatic void 170bf215546Sopenharmony_cidecode_batch(struct crocus_batch *batch) 171bf215546Sopenharmony_ci{ 172bf215546Sopenharmony_ci void *map = crocus_bo_map(batch->dbg, batch->exec_bos[0], MAP_READ); 173bf215546Sopenharmony_ci intel_print_batch(&batch->decoder, map, batch->primary_batch_size, 174bf215546Sopenharmony_ci batch->exec_bos[0]->gtt_offset, false); 175bf215546Sopenharmony_ci} 176bf215546Sopenharmony_ci 177bf215546Sopenharmony_cistatic void 178bf215546Sopenharmony_ciinit_reloc_list(struct crocus_reloc_list *rlist, int count) 179bf215546Sopenharmony_ci{ 180bf215546Sopenharmony_ci rlist->reloc_count = 0; 181bf215546Sopenharmony_ci rlist->reloc_array_size = count; 182bf215546Sopenharmony_ci rlist->relocs = malloc(rlist->reloc_array_size * 183bf215546Sopenharmony_ci sizeof(struct drm_i915_gem_relocation_entry)); 184bf215546Sopenharmony_ci} 185bf215546Sopenharmony_ci 186bf215546Sopenharmony_civoid 187bf215546Sopenharmony_cicrocus_init_batch(struct crocus_context *ice, 188bf215546Sopenharmony_ci enum crocus_batch_name name, 189bf215546Sopenharmony_ci int priority) 190bf215546Sopenharmony_ci{ 191bf215546Sopenharmony_ci struct crocus_batch *batch = &ice->batches[name]; 192bf215546Sopenharmony_ci struct crocus_screen *screen = (struct crocus_screen *)ice->ctx.screen; 193bf215546Sopenharmony_ci struct intel_device_info *devinfo = &screen->devinfo; 194bf215546Sopenharmony_ci 195bf215546Sopenharmony_ci batch->ice = ice; 196bf215546Sopenharmony_ci batch->screen = screen; 197bf215546Sopenharmony_ci batch->dbg = &ice->dbg; 198bf215546Sopenharmony_ci batch->reset = &ice->reset; 199bf215546Sopenharmony_ci batch->name = name; 200bf215546Sopenharmony_ci batch->contains_fence_signal = false; 201bf215546Sopenharmony_ci 202bf215546Sopenharmony_ci if (devinfo->ver >= 7) { 203bf215546Sopenharmony_ci batch->fine_fences.uploader = 204bf215546Sopenharmony_ci u_upload_create(&ice->ctx, 4096, PIPE_BIND_CUSTOM, 205bf215546Sopenharmony_ci PIPE_USAGE_STAGING, 0); 206bf215546Sopenharmony_ci } 207bf215546Sopenharmony_ci crocus_fine_fence_init(batch); 208bf215546Sopenharmony_ci 209bf215546Sopenharmony_ci batch->hw_ctx_id = crocus_create_hw_context(screen->bufmgr); 210bf215546Sopenharmony_ci assert(batch->hw_ctx_id); 211bf215546Sopenharmony_ci 212bf215546Sopenharmony_ci crocus_hw_context_set_priority(screen->bufmgr, batch->hw_ctx_id, priority); 213bf215546Sopenharmony_ci 214bf215546Sopenharmony_ci batch->valid_reloc_flags = EXEC_OBJECT_WRITE; 215bf215546Sopenharmony_ci if (devinfo->ver == 6) 216bf215546Sopenharmony_ci batch->valid_reloc_flags |= EXEC_OBJECT_NEEDS_GTT; 217bf215546Sopenharmony_ci 218bf215546Sopenharmony_ci if (INTEL_DEBUG(DEBUG_BATCH)) { 219bf215546Sopenharmony_ci /* The shadow doesn't get relocs written so state decode fails. */ 220bf215546Sopenharmony_ci batch->use_shadow_copy = false; 221bf215546Sopenharmony_ci } else 222bf215546Sopenharmony_ci batch->use_shadow_copy = !devinfo->has_llc; 223bf215546Sopenharmony_ci 224bf215546Sopenharmony_ci util_dynarray_init(&batch->exec_fences, ralloc_context(NULL)); 225bf215546Sopenharmony_ci util_dynarray_init(&batch->syncobjs, ralloc_context(NULL)); 226bf215546Sopenharmony_ci 227bf215546Sopenharmony_ci init_reloc_list(&batch->command.relocs, 250); 228bf215546Sopenharmony_ci init_reloc_list(&batch->state.relocs, 250); 229bf215546Sopenharmony_ci 230bf215546Sopenharmony_ci batch->exec_count = 0; 231bf215546Sopenharmony_ci batch->exec_array_size = 100; 232bf215546Sopenharmony_ci batch->exec_bos = 233bf215546Sopenharmony_ci malloc(batch->exec_array_size * sizeof(batch->exec_bos[0])); 234bf215546Sopenharmony_ci batch->validation_list = 235bf215546Sopenharmony_ci malloc(batch->exec_array_size * sizeof(batch->validation_list[0])); 236bf215546Sopenharmony_ci 237bf215546Sopenharmony_ci batch->cache.render = _mesa_hash_table_create(NULL, NULL, 238bf215546Sopenharmony_ci _mesa_key_pointer_equal); 239bf215546Sopenharmony_ci batch->cache.depth = _mesa_set_create(NULL, NULL, 240bf215546Sopenharmony_ci _mesa_key_pointer_equal); 241bf215546Sopenharmony_ci 242bf215546Sopenharmony_ci memset(batch->other_batches, 0, sizeof(batch->other_batches)); 243bf215546Sopenharmony_ci 244bf215546Sopenharmony_ci for (int i = 0, j = 0; i < ice->batch_count; i++) { 245bf215546Sopenharmony_ci if (i != name) 246bf215546Sopenharmony_ci batch->other_batches[j++] = &ice->batches[i]; 247bf215546Sopenharmony_ci } 248bf215546Sopenharmony_ci 249bf215546Sopenharmony_ci if (INTEL_DEBUG(DEBUG_BATCH)) { 250bf215546Sopenharmony_ci 251bf215546Sopenharmony_ci batch->state_sizes = _mesa_hash_table_u64_create(NULL); 252bf215546Sopenharmony_ci const unsigned decode_flags = 253bf215546Sopenharmony_ci INTEL_BATCH_DECODE_FULL | 254bf215546Sopenharmony_ci (INTEL_DEBUG(DEBUG_COLOR) ? INTEL_BATCH_DECODE_IN_COLOR : 0) | 255bf215546Sopenharmony_ci INTEL_BATCH_DECODE_OFFSETS | INTEL_BATCH_DECODE_FLOATS; 256bf215546Sopenharmony_ci 257bf215546Sopenharmony_ci intel_batch_decode_ctx_init(&batch->decoder, &screen->compiler->isa, 258bf215546Sopenharmony_ci &screen->devinfo, stderr, 259bf215546Sopenharmony_ci decode_flags, NULL, decode_get_bo, 260bf215546Sopenharmony_ci decode_get_state_size, batch); 261bf215546Sopenharmony_ci batch->decoder.max_vbo_decoded_lines = 32; 262bf215546Sopenharmony_ci } 263bf215546Sopenharmony_ci 264bf215546Sopenharmony_ci crocus_batch_reset(batch); 265bf215546Sopenharmony_ci} 266bf215546Sopenharmony_ci 267bf215546Sopenharmony_cistatic int 268bf215546Sopenharmony_cifind_exec_index(struct crocus_batch *batch, struct crocus_bo *bo) 269bf215546Sopenharmony_ci{ 270bf215546Sopenharmony_ci unsigned index = READ_ONCE(bo->index); 271bf215546Sopenharmony_ci 272bf215546Sopenharmony_ci if (index < batch->exec_count && batch->exec_bos[index] == bo) 273bf215546Sopenharmony_ci return index; 274bf215546Sopenharmony_ci 275bf215546Sopenharmony_ci /* May have been shared between multiple active batches */ 276bf215546Sopenharmony_ci for (index = 0; index < batch->exec_count; index++) { 277bf215546Sopenharmony_ci if (batch->exec_bos[index] == bo) 278bf215546Sopenharmony_ci return index; 279bf215546Sopenharmony_ci } 280bf215546Sopenharmony_ci return -1; 281bf215546Sopenharmony_ci} 282bf215546Sopenharmony_ci 283bf215546Sopenharmony_cistatic struct drm_i915_gem_exec_object2 * 284bf215546Sopenharmony_cifind_validation_entry(struct crocus_batch *batch, struct crocus_bo *bo) 285bf215546Sopenharmony_ci{ 286bf215546Sopenharmony_ci int index = find_exec_index(batch, bo); 287bf215546Sopenharmony_ci 288bf215546Sopenharmony_ci if (index == -1) 289bf215546Sopenharmony_ci return NULL; 290bf215546Sopenharmony_ci return &batch->validation_list[index]; 291bf215546Sopenharmony_ci} 292bf215546Sopenharmony_ci 293bf215546Sopenharmony_cistatic void 294bf215546Sopenharmony_ciensure_exec_obj_space(struct crocus_batch *batch, uint32_t count) 295bf215546Sopenharmony_ci{ 296bf215546Sopenharmony_ci while (batch->exec_count + count > batch->exec_array_size) { 297bf215546Sopenharmony_ci batch->exec_array_size *= 2; 298bf215546Sopenharmony_ci batch->exec_bos = realloc( 299bf215546Sopenharmony_ci batch->exec_bos, batch->exec_array_size * sizeof(batch->exec_bos[0])); 300bf215546Sopenharmony_ci batch->validation_list = 301bf215546Sopenharmony_ci realloc(batch->validation_list, 302bf215546Sopenharmony_ci batch->exec_array_size * sizeof(batch->validation_list[0])); 303bf215546Sopenharmony_ci } 304bf215546Sopenharmony_ci} 305bf215546Sopenharmony_ci 306bf215546Sopenharmony_cistatic struct drm_i915_gem_exec_object2 * 307bf215546Sopenharmony_cicrocus_use_bo(struct crocus_batch *batch, struct crocus_bo *bo, bool writable) 308bf215546Sopenharmony_ci{ 309bf215546Sopenharmony_ci assert(bo->bufmgr == batch->command.bo->bufmgr); 310bf215546Sopenharmony_ci 311bf215546Sopenharmony_ci struct drm_i915_gem_exec_object2 *existing_entry = 312bf215546Sopenharmony_ci find_validation_entry(batch, bo); 313bf215546Sopenharmony_ci 314bf215546Sopenharmony_ci if (existing_entry) { 315bf215546Sopenharmony_ci /* The BO is already in the validation list; mark it writable */ 316bf215546Sopenharmony_ci if (writable) 317bf215546Sopenharmony_ci existing_entry->flags |= EXEC_OBJECT_WRITE; 318bf215546Sopenharmony_ci return existing_entry; 319bf215546Sopenharmony_ci } 320bf215546Sopenharmony_ci 321bf215546Sopenharmony_ci if (bo != batch->command.bo && bo != batch->state.bo) { 322bf215546Sopenharmony_ci /* This is the first time our batch has seen this BO. Before we use it, 323bf215546Sopenharmony_ci * we may need to flush and synchronize with other batches. 324bf215546Sopenharmony_ci */ 325bf215546Sopenharmony_ci for (int b = 0; b < ARRAY_SIZE(batch->other_batches); b++) { 326bf215546Sopenharmony_ci 327bf215546Sopenharmony_ci if (!batch->other_batches[b]) 328bf215546Sopenharmony_ci continue; 329bf215546Sopenharmony_ci struct drm_i915_gem_exec_object2 *other_entry = 330bf215546Sopenharmony_ci find_validation_entry(batch->other_batches[b], bo); 331bf215546Sopenharmony_ci 332bf215546Sopenharmony_ci /* If the buffer is referenced by another batch, and either batch 333bf215546Sopenharmony_ci * intends to write it, then flush the other batch and synchronize. 334bf215546Sopenharmony_ci * 335bf215546Sopenharmony_ci * Consider these cases: 336bf215546Sopenharmony_ci * 337bf215546Sopenharmony_ci * 1. They read, we read => No synchronization required. 338bf215546Sopenharmony_ci * 2. They read, we write => Synchronize (they need the old value) 339bf215546Sopenharmony_ci * 3. They write, we read => Synchronize (we need their new value) 340bf215546Sopenharmony_ci * 4. They write, we write => Synchronize (order writes) 341bf215546Sopenharmony_ci * 342bf215546Sopenharmony_ci * The read/read case is very common, as multiple batches usually 343bf215546Sopenharmony_ci * share a streaming state buffer or shader assembly buffer, and 344bf215546Sopenharmony_ci * we want to avoid synchronizing in this case. 345bf215546Sopenharmony_ci */ 346bf215546Sopenharmony_ci if (other_entry && 347bf215546Sopenharmony_ci ((other_entry->flags & EXEC_OBJECT_WRITE) || writable)) { 348bf215546Sopenharmony_ci crocus_batch_flush(batch->other_batches[b]); 349bf215546Sopenharmony_ci crocus_batch_add_syncobj(batch, 350bf215546Sopenharmony_ci batch->other_batches[b]->last_fence->syncobj, 351bf215546Sopenharmony_ci I915_EXEC_FENCE_WAIT); 352bf215546Sopenharmony_ci } 353bf215546Sopenharmony_ci } 354bf215546Sopenharmony_ci } 355bf215546Sopenharmony_ci 356bf215546Sopenharmony_ci /* Bump the ref count since the batch is now using this bo. */ 357bf215546Sopenharmony_ci crocus_bo_reference(bo); 358bf215546Sopenharmony_ci 359bf215546Sopenharmony_ci ensure_exec_obj_space(batch, 1); 360bf215546Sopenharmony_ci 361bf215546Sopenharmony_ci batch->validation_list[batch->exec_count] = 362bf215546Sopenharmony_ci (struct drm_i915_gem_exec_object2) { 363bf215546Sopenharmony_ci .handle = bo->gem_handle, 364bf215546Sopenharmony_ci .offset = bo->gtt_offset, 365bf215546Sopenharmony_ci .flags = bo->kflags | (writable ? EXEC_OBJECT_WRITE : 0), 366bf215546Sopenharmony_ci }; 367bf215546Sopenharmony_ci 368bf215546Sopenharmony_ci bo->index = batch->exec_count; 369bf215546Sopenharmony_ci batch->exec_bos[batch->exec_count] = bo; 370bf215546Sopenharmony_ci batch->aperture_space += bo->size; 371bf215546Sopenharmony_ci 372bf215546Sopenharmony_ci batch->exec_count++; 373bf215546Sopenharmony_ci 374bf215546Sopenharmony_ci return &batch->validation_list[batch->exec_count - 1]; 375bf215546Sopenharmony_ci} 376bf215546Sopenharmony_ci 377bf215546Sopenharmony_cistatic uint64_t 378bf215546Sopenharmony_ciemit_reloc(struct crocus_batch *batch, 379bf215546Sopenharmony_ci struct crocus_reloc_list *rlist, uint32_t offset, 380bf215546Sopenharmony_ci struct crocus_bo *target, int32_t target_offset, 381bf215546Sopenharmony_ci unsigned int reloc_flags) 382bf215546Sopenharmony_ci{ 383bf215546Sopenharmony_ci assert(target != NULL); 384bf215546Sopenharmony_ci 385bf215546Sopenharmony_ci if (target == batch->ice->workaround_bo) 386bf215546Sopenharmony_ci reloc_flags &= ~RELOC_WRITE; 387bf215546Sopenharmony_ci 388bf215546Sopenharmony_ci bool writable = reloc_flags & RELOC_WRITE; 389bf215546Sopenharmony_ci 390bf215546Sopenharmony_ci struct drm_i915_gem_exec_object2 *entry = 391bf215546Sopenharmony_ci crocus_use_bo(batch, target, writable); 392bf215546Sopenharmony_ci 393bf215546Sopenharmony_ci if (rlist->reloc_count == rlist->reloc_array_size) { 394bf215546Sopenharmony_ci rlist->reloc_array_size *= 2; 395bf215546Sopenharmony_ci rlist->relocs = realloc(rlist->relocs, 396bf215546Sopenharmony_ci rlist->reloc_array_size * 397bf215546Sopenharmony_ci sizeof(struct drm_i915_gem_relocation_entry)); 398bf215546Sopenharmony_ci } 399bf215546Sopenharmony_ci 400bf215546Sopenharmony_ci if (reloc_flags & RELOC_32BIT) { 401bf215546Sopenharmony_ci /* Restrict this buffer to the low 32 bits of the address space. 402bf215546Sopenharmony_ci * 403bf215546Sopenharmony_ci * Altering the validation list flags restricts it for this batch, 404bf215546Sopenharmony_ci * but we also alter the BO's kflags to restrict it permanently 405bf215546Sopenharmony_ci * (until the BO is destroyed and put back in the cache). Buffers 406bf215546Sopenharmony_ci * may stay bound across batches, and we want keep it constrained. 407bf215546Sopenharmony_ci */ 408bf215546Sopenharmony_ci target->kflags &= ~EXEC_OBJECT_SUPPORTS_48B_ADDRESS; 409bf215546Sopenharmony_ci entry->flags &= ~EXEC_OBJECT_SUPPORTS_48B_ADDRESS; 410bf215546Sopenharmony_ci 411bf215546Sopenharmony_ci /* RELOC_32BIT is not an EXEC_OBJECT_* flag, so get rid of it. */ 412bf215546Sopenharmony_ci reloc_flags &= ~RELOC_32BIT; 413bf215546Sopenharmony_ci } 414bf215546Sopenharmony_ci 415bf215546Sopenharmony_ci if (reloc_flags) 416bf215546Sopenharmony_ci entry->flags |= reloc_flags & batch->valid_reloc_flags; 417bf215546Sopenharmony_ci 418bf215546Sopenharmony_ci rlist->relocs[rlist->reloc_count++] = 419bf215546Sopenharmony_ci (struct drm_i915_gem_relocation_entry) { 420bf215546Sopenharmony_ci .offset = offset, 421bf215546Sopenharmony_ci .delta = target_offset, 422bf215546Sopenharmony_ci .target_handle = find_exec_index(batch, target), 423bf215546Sopenharmony_ci .presumed_offset = entry->offset, 424bf215546Sopenharmony_ci }; 425bf215546Sopenharmony_ci 426bf215546Sopenharmony_ci /* Using the old buffer offset, write in what the right data would be, in 427bf215546Sopenharmony_ci * case the buffer doesn't move and we can short-circuit the relocation 428bf215546Sopenharmony_ci * processing in the kernel 429bf215546Sopenharmony_ci */ 430bf215546Sopenharmony_ci return entry->offset + target_offset; 431bf215546Sopenharmony_ci} 432bf215546Sopenharmony_ci 433bf215546Sopenharmony_ciuint64_t 434bf215546Sopenharmony_cicrocus_command_reloc(struct crocus_batch *batch, uint32_t batch_offset, 435bf215546Sopenharmony_ci struct crocus_bo *target, uint32_t target_offset, 436bf215546Sopenharmony_ci unsigned int reloc_flags) 437bf215546Sopenharmony_ci{ 438bf215546Sopenharmony_ci assert(batch_offset <= batch->command.bo->size - sizeof(uint32_t)); 439bf215546Sopenharmony_ci 440bf215546Sopenharmony_ci return emit_reloc(batch, &batch->command.relocs, batch_offset, 441bf215546Sopenharmony_ci target, target_offset, reloc_flags); 442bf215546Sopenharmony_ci} 443bf215546Sopenharmony_ci 444bf215546Sopenharmony_ciuint64_t 445bf215546Sopenharmony_cicrocus_state_reloc(struct crocus_batch *batch, uint32_t state_offset, 446bf215546Sopenharmony_ci struct crocus_bo *target, uint32_t target_offset, 447bf215546Sopenharmony_ci unsigned int reloc_flags) 448bf215546Sopenharmony_ci{ 449bf215546Sopenharmony_ci assert(state_offset <= batch->state.bo->size - sizeof(uint32_t)); 450bf215546Sopenharmony_ci 451bf215546Sopenharmony_ci return emit_reloc(batch, &batch->state.relocs, state_offset, 452bf215546Sopenharmony_ci target, target_offset, reloc_flags); 453bf215546Sopenharmony_ci} 454bf215546Sopenharmony_ci 455bf215546Sopenharmony_cistatic void 456bf215546Sopenharmony_cirecreate_growing_buffer(struct crocus_batch *batch, 457bf215546Sopenharmony_ci struct crocus_growing_bo *grow, 458bf215546Sopenharmony_ci const char *name, unsigned size) 459bf215546Sopenharmony_ci{ 460bf215546Sopenharmony_ci struct crocus_screen *screen = batch->screen; 461bf215546Sopenharmony_ci struct crocus_bufmgr *bufmgr = screen->bufmgr; 462bf215546Sopenharmony_ci grow->bo = crocus_bo_alloc(bufmgr, name, size); 463bf215546Sopenharmony_ci grow->bo->kflags |= EXEC_OBJECT_CAPTURE; 464bf215546Sopenharmony_ci grow->partial_bo = NULL; 465bf215546Sopenharmony_ci grow->partial_bo_map = NULL; 466bf215546Sopenharmony_ci grow->partial_bytes = 0; 467bf215546Sopenharmony_ci if (batch->use_shadow_copy) 468bf215546Sopenharmony_ci grow->map = realloc(grow->map, grow->bo->size); 469bf215546Sopenharmony_ci else 470bf215546Sopenharmony_ci grow->map = crocus_bo_map(NULL, grow->bo, MAP_READ | MAP_WRITE); 471bf215546Sopenharmony_ci grow->map_next = grow->map; 472bf215546Sopenharmony_ci} 473bf215546Sopenharmony_ci 474bf215546Sopenharmony_cistatic void 475bf215546Sopenharmony_cicreate_batch(struct crocus_batch *batch) 476bf215546Sopenharmony_ci{ 477bf215546Sopenharmony_ci struct crocus_screen *screen = batch->screen; 478bf215546Sopenharmony_ci 479bf215546Sopenharmony_ci recreate_growing_buffer(batch, &batch->command, 480bf215546Sopenharmony_ci "command buffer", 481bf215546Sopenharmony_ci BATCH_SZ + BATCH_RESERVED(&screen->devinfo)); 482bf215546Sopenharmony_ci 483bf215546Sopenharmony_ci crocus_use_bo(batch, batch->command.bo, false); 484bf215546Sopenharmony_ci 485bf215546Sopenharmony_ci /* Always add workaround_bo which contains a driver identifier to be 486bf215546Sopenharmony_ci * recorded in error states. 487bf215546Sopenharmony_ci */ 488bf215546Sopenharmony_ci crocus_use_bo(batch, batch->ice->workaround_bo, false); 489bf215546Sopenharmony_ci 490bf215546Sopenharmony_ci recreate_growing_buffer(batch, &batch->state, 491bf215546Sopenharmony_ci "state buffer", 492bf215546Sopenharmony_ci STATE_SZ); 493bf215546Sopenharmony_ci 494bf215546Sopenharmony_ci batch->state.used = 1; 495bf215546Sopenharmony_ci crocus_use_bo(batch, batch->state.bo, false); 496bf215546Sopenharmony_ci} 497bf215546Sopenharmony_ci 498bf215546Sopenharmony_cistatic void 499bf215546Sopenharmony_cicrocus_batch_maybe_noop(struct crocus_batch *batch) 500bf215546Sopenharmony_ci{ 501bf215546Sopenharmony_ci /* We only insert the NOOP at the beginning of the batch. */ 502bf215546Sopenharmony_ci assert(crocus_batch_bytes_used(batch) == 0); 503bf215546Sopenharmony_ci 504bf215546Sopenharmony_ci if (batch->noop_enabled) { 505bf215546Sopenharmony_ci /* Emit MI_BATCH_BUFFER_END to prevent any further command to be 506bf215546Sopenharmony_ci * executed. 507bf215546Sopenharmony_ci */ 508bf215546Sopenharmony_ci uint32_t *map = batch->command.map_next; 509bf215546Sopenharmony_ci 510bf215546Sopenharmony_ci map[0] = (0xA << 23); 511bf215546Sopenharmony_ci 512bf215546Sopenharmony_ci batch->command.map_next += 4; 513bf215546Sopenharmony_ci } 514bf215546Sopenharmony_ci} 515bf215546Sopenharmony_ci 516bf215546Sopenharmony_cistatic void 517bf215546Sopenharmony_cicrocus_batch_reset(struct crocus_batch *batch) 518bf215546Sopenharmony_ci{ 519bf215546Sopenharmony_ci struct crocus_screen *screen = batch->screen; 520bf215546Sopenharmony_ci 521bf215546Sopenharmony_ci crocus_bo_unreference(batch->command.bo); 522bf215546Sopenharmony_ci crocus_bo_unreference(batch->state.bo); 523bf215546Sopenharmony_ci batch->primary_batch_size = 0; 524bf215546Sopenharmony_ci batch->contains_draw = false; 525bf215546Sopenharmony_ci batch->contains_fence_signal = false; 526bf215546Sopenharmony_ci batch->state_base_address_emitted = false; 527bf215546Sopenharmony_ci batch->screen->vtbl.batch_reset_dirty(batch); 528bf215546Sopenharmony_ci 529bf215546Sopenharmony_ci create_batch(batch); 530bf215546Sopenharmony_ci assert(batch->command.bo->index == 0); 531bf215546Sopenharmony_ci 532bf215546Sopenharmony_ci if (batch->state_sizes) 533bf215546Sopenharmony_ci _mesa_hash_table_u64_clear(batch->state_sizes); 534bf215546Sopenharmony_ci struct crocus_syncobj *syncobj = crocus_create_syncobj(screen); 535bf215546Sopenharmony_ci crocus_batch_add_syncobj(batch, syncobj, I915_EXEC_FENCE_SIGNAL); 536bf215546Sopenharmony_ci crocus_syncobj_reference(screen, &syncobj, NULL); 537bf215546Sopenharmony_ci 538bf215546Sopenharmony_ci crocus_cache_sets_clear(batch); 539bf215546Sopenharmony_ci} 540bf215546Sopenharmony_ci 541bf215546Sopenharmony_civoid 542bf215546Sopenharmony_cicrocus_batch_free(struct crocus_batch *batch) 543bf215546Sopenharmony_ci{ 544bf215546Sopenharmony_ci struct crocus_screen *screen = batch->screen; 545bf215546Sopenharmony_ci struct crocus_bufmgr *bufmgr = screen->bufmgr; 546bf215546Sopenharmony_ci 547bf215546Sopenharmony_ci if (batch->use_shadow_copy) { 548bf215546Sopenharmony_ci free(batch->command.map); 549bf215546Sopenharmony_ci free(batch->state.map); 550bf215546Sopenharmony_ci } 551bf215546Sopenharmony_ci 552bf215546Sopenharmony_ci for (int i = 0; i < batch->exec_count; i++) { 553bf215546Sopenharmony_ci crocus_bo_unreference(batch->exec_bos[i]); 554bf215546Sopenharmony_ci } 555bf215546Sopenharmony_ci 556bf215546Sopenharmony_ci pipe_resource_reference(&batch->fine_fences.ref.res, NULL); 557bf215546Sopenharmony_ci 558bf215546Sopenharmony_ci free(batch->command.relocs.relocs); 559bf215546Sopenharmony_ci free(batch->state.relocs.relocs); 560bf215546Sopenharmony_ci free(batch->exec_bos); 561bf215546Sopenharmony_ci free(batch->validation_list); 562bf215546Sopenharmony_ci 563bf215546Sopenharmony_ci ralloc_free(batch->exec_fences.mem_ctx); 564bf215546Sopenharmony_ci 565bf215546Sopenharmony_ci util_dynarray_foreach(&batch->syncobjs, struct crocus_syncobj *, s) 566bf215546Sopenharmony_ci crocus_syncobj_reference(screen, s, NULL); 567bf215546Sopenharmony_ci ralloc_free(batch->syncobjs.mem_ctx); 568bf215546Sopenharmony_ci 569bf215546Sopenharmony_ci crocus_fine_fence_reference(batch->screen, &batch->last_fence, NULL); 570bf215546Sopenharmony_ci if (batch_has_fine_fence(batch)) 571bf215546Sopenharmony_ci u_upload_destroy(batch->fine_fences.uploader); 572bf215546Sopenharmony_ci 573bf215546Sopenharmony_ci crocus_bo_unreference(batch->command.bo); 574bf215546Sopenharmony_ci crocus_bo_unreference(batch->state.bo); 575bf215546Sopenharmony_ci batch->command.bo = NULL; 576bf215546Sopenharmony_ci batch->command.map = NULL; 577bf215546Sopenharmony_ci batch->command.map_next = NULL; 578bf215546Sopenharmony_ci 579bf215546Sopenharmony_ci crocus_destroy_hw_context(bufmgr, batch->hw_ctx_id); 580bf215546Sopenharmony_ci 581bf215546Sopenharmony_ci _mesa_hash_table_destroy(batch->cache.render, NULL); 582bf215546Sopenharmony_ci _mesa_set_destroy(batch->cache.depth, NULL); 583bf215546Sopenharmony_ci 584bf215546Sopenharmony_ci if (batch->state_sizes) { 585bf215546Sopenharmony_ci _mesa_hash_table_u64_destroy(batch->state_sizes); 586bf215546Sopenharmony_ci intel_batch_decode_ctx_finish(&batch->decoder); 587bf215546Sopenharmony_ci } 588bf215546Sopenharmony_ci} 589bf215546Sopenharmony_ci 590bf215546Sopenharmony_ci/** 591bf215546Sopenharmony_ci * If we've chained to a secondary batch, or are getting near to the end, 592bf215546Sopenharmony_ci * then flush. This should only be called between draws. 593bf215546Sopenharmony_ci */ 594bf215546Sopenharmony_civoid 595bf215546Sopenharmony_cicrocus_batch_maybe_flush(struct crocus_batch *batch, unsigned estimate) 596bf215546Sopenharmony_ci{ 597bf215546Sopenharmony_ci if (batch->command.bo != batch->exec_bos[0] || 598bf215546Sopenharmony_ci crocus_batch_bytes_used(batch) + estimate >= BATCH_SZ) { 599bf215546Sopenharmony_ci crocus_batch_flush(batch); 600bf215546Sopenharmony_ci } 601bf215546Sopenharmony_ci} 602bf215546Sopenharmony_ci 603bf215546Sopenharmony_ci/** 604bf215546Sopenharmony_ci * Finish copying the old batch/state buffer's contents to the new one 605bf215546Sopenharmony_ci * after we tried to "grow" the buffer in an earlier operation. 606bf215546Sopenharmony_ci */ 607bf215546Sopenharmony_cistatic void 608bf215546Sopenharmony_cifinish_growing_bos(struct crocus_growing_bo *grow) 609bf215546Sopenharmony_ci{ 610bf215546Sopenharmony_ci struct crocus_bo *old_bo = grow->partial_bo; 611bf215546Sopenharmony_ci if (!old_bo) 612bf215546Sopenharmony_ci return; 613bf215546Sopenharmony_ci 614bf215546Sopenharmony_ci memcpy(grow->map, grow->partial_bo_map, grow->partial_bytes); 615bf215546Sopenharmony_ci 616bf215546Sopenharmony_ci grow->partial_bo = NULL; 617bf215546Sopenharmony_ci grow->partial_bo_map = NULL; 618bf215546Sopenharmony_ci grow->partial_bytes = 0; 619bf215546Sopenharmony_ci 620bf215546Sopenharmony_ci crocus_bo_unreference(old_bo); 621bf215546Sopenharmony_ci} 622bf215546Sopenharmony_ci 623bf215546Sopenharmony_civoid 624bf215546Sopenharmony_cicrocus_grow_buffer(struct crocus_batch *batch, bool grow_state, 625bf215546Sopenharmony_ci unsigned used, 626bf215546Sopenharmony_ci unsigned new_size) 627bf215546Sopenharmony_ci{ 628bf215546Sopenharmony_ci struct crocus_screen *screen = batch->screen; 629bf215546Sopenharmony_ci struct crocus_bufmgr *bufmgr = screen->bufmgr; 630bf215546Sopenharmony_ci struct crocus_growing_bo *grow = grow_state ? &batch->state : &batch->command; 631bf215546Sopenharmony_ci struct crocus_bo *bo = grow->bo; 632bf215546Sopenharmony_ci 633bf215546Sopenharmony_ci if (grow->partial_bo) { 634bf215546Sopenharmony_ci /* We've already grown once, and now we need to do it again. 635bf215546Sopenharmony_ci * Finish our last grow operation so we can start a new one. 636bf215546Sopenharmony_ci * This should basically never happen. 637bf215546Sopenharmony_ci */ 638bf215546Sopenharmony_ci finish_growing_bos(grow); 639bf215546Sopenharmony_ci } 640bf215546Sopenharmony_ci 641bf215546Sopenharmony_ci struct crocus_bo *new_bo = crocus_bo_alloc(bufmgr, bo->name, new_size); 642bf215546Sopenharmony_ci 643bf215546Sopenharmony_ci /* Copy existing data to the new larger buffer */ 644bf215546Sopenharmony_ci grow->partial_bo_map = grow->map; 645bf215546Sopenharmony_ci 646bf215546Sopenharmony_ci if (batch->use_shadow_copy) { 647bf215546Sopenharmony_ci /* We can't safely use realloc, as it may move the existing buffer, 648bf215546Sopenharmony_ci * breaking existing pointers the caller may still be using. Just 649bf215546Sopenharmony_ci * malloc a new copy and memcpy it like the normal BO path. 650bf215546Sopenharmony_ci * 651bf215546Sopenharmony_ci * Use bo->size rather than new_size because the bufmgr may have 652bf215546Sopenharmony_ci * rounded up the size, and we want the shadow size to match. 653bf215546Sopenharmony_ci */ 654bf215546Sopenharmony_ci grow->map = malloc(new_bo->size); 655bf215546Sopenharmony_ci } else { 656bf215546Sopenharmony_ci grow->map = crocus_bo_map(NULL, new_bo, MAP_READ | MAP_WRITE); 657bf215546Sopenharmony_ci } 658bf215546Sopenharmony_ci /* Try to put the new BO at the same GTT offset as the old BO (which 659bf215546Sopenharmony_ci * we're throwing away, so it doesn't need to be there). 660bf215546Sopenharmony_ci * 661bf215546Sopenharmony_ci * This guarantees that our relocations continue to work: values we've 662bf215546Sopenharmony_ci * already written into the buffer, values we're going to write into the 663bf215546Sopenharmony_ci * buffer, and the validation/relocation lists all will match. 664bf215546Sopenharmony_ci * 665bf215546Sopenharmony_ci * Also preserve kflags for EXEC_OBJECT_CAPTURE. 666bf215546Sopenharmony_ci */ 667bf215546Sopenharmony_ci new_bo->gtt_offset = bo->gtt_offset; 668bf215546Sopenharmony_ci new_bo->index = bo->index; 669bf215546Sopenharmony_ci new_bo->kflags = bo->kflags; 670bf215546Sopenharmony_ci 671bf215546Sopenharmony_ci /* Batch/state buffers are per-context, and if we've run out of space, 672bf215546Sopenharmony_ci * we must have actually used them before, so...they will be in the list. 673bf215546Sopenharmony_ci */ 674bf215546Sopenharmony_ci assert(bo->index < batch->exec_count); 675bf215546Sopenharmony_ci assert(batch->exec_bos[bo->index] == bo); 676bf215546Sopenharmony_ci 677bf215546Sopenharmony_ci /* Update the validation list to use the new BO. */ 678bf215546Sopenharmony_ci batch->validation_list[bo->index].handle = new_bo->gem_handle; 679bf215546Sopenharmony_ci /* Exchange the two BOs...without breaking pointers to the old BO. 680bf215546Sopenharmony_ci * 681bf215546Sopenharmony_ci * Consider this scenario: 682bf215546Sopenharmony_ci * 683bf215546Sopenharmony_ci * 1. Somebody calls brw_state_batch() to get a region of memory, and 684bf215546Sopenharmony_ci * and then creates a brw_address pointing to brw->batch.state.bo. 685bf215546Sopenharmony_ci * 2. They then call brw_state_batch() a second time, which happens to 686bf215546Sopenharmony_ci * grow and replace the state buffer. They then try to emit a 687bf215546Sopenharmony_ci * relocation to their first section of memory. 688bf215546Sopenharmony_ci * 689bf215546Sopenharmony_ci * If we replace the brw->batch.state.bo pointer at step 2, we would 690bf215546Sopenharmony_ci * break the address created in step 1. They'd have a pointer to the 691bf215546Sopenharmony_ci * old destroyed BO. Emitting a relocation would add this dead BO to 692bf215546Sopenharmony_ci * the validation list...causing /both/ statebuffers to be in the list, 693bf215546Sopenharmony_ci * and all kinds of disasters. 694bf215546Sopenharmony_ci * 695bf215546Sopenharmony_ci * This is not a contrived case - BLORP vertex data upload hits this. 696bf215546Sopenharmony_ci * 697bf215546Sopenharmony_ci * There are worse scenarios too. Fences for GL sync objects reference 698bf215546Sopenharmony_ci * brw->batch.batch.bo. If we replaced the batch pointer when growing, 699bf215546Sopenharmony_ci * we'd need to chase down every fence and update it to point to the 700bf215546Sopenharmony_ci * new BO. Otherwise, it would refer to a "batch" that never actually 701bf215546Sopenharmony_ci * gets submitted, and would fail to trigger. 702bf215546Sopenharmony_ci * 703bf215546Sopenharmony_ci * To work around both of these issues, we transmutate the buffers in 704bf215546Sopenharmony_ci * place, making the existing struct brw_bo represent the new buffer, 705bf215546Sopenharmony_ci * and "new_bo" represent the old BO. This is highly unusual, but it 706bf215546Sopenharmony_ci * seems like a necessary evil. 707bf215546Sopenharmony_ci * 708bf215546Sopenharmony_ci * We also defer the memcpy of the existing batch's contents. Callers 709bf215546Sopenharmony_ci * may make multiple brw_state_batch calls, and retain pointers to the 710bf215546Sopenharmony_ci * old BO's map. We'll perform the memcpy in finish_growing_bo() when 711bf215546Sopenharmony_ci * we finally submit the batch, at which point we've finished uploading 712bf215546Sopenharmony_ci * state, and nobody should have any old references anymore. 713bf215546Sopenharmony_ci * 714bf215546Sopenharmony_ci * To do that, we keep a reference to the old BO in grow->partial_bo, 715bf215546Sopenharmony_ci * and store the number of bytes to copy in grow->partial_bytes. We 716bf215546Sopenharmony_ci * can monkey with the refcounts directly without atomics because these 717bf215546Sopenharmony_ci * are per-context BOs and they can only be touched by this thread. 718bf215546Sopenharmony_ci */ 719bf215546Sopenharmony_ci assert(new_bo->refcount == 1); 720bf215546Sopenharmony_ci new_bo->refcount = bo->refcount; 721bf215546Sopenharmony_ci bo->refcount = 1; 722bf215546Sopenharmony_ci 723bf215546Sopenharmony_ci struct crocus_bo tmp; 724bf215546Sopenharmony_ci memcpy(&tmp, bo, sizeof(struct crocus_bo)); 725bf215546Sopenharmony_ci memcpy(bo, new_bo, sizeof(struct crocus_bo)); 726bf215546Sopenharmony_ci memcpy(new_bo, &tmp, sizeof(struct crocus_bo)); 727bf215546Sopenharmony_ci 728bf215546Sopenharmony_ci grow->partial_bo = new_bo; /* the one reference of the OLD bo */ 729bf215546Sopenharmony_ci grow->partial_bytes = used; 730bf215546Sopenharmony_ci} 731bf215546Sopenharmony_ci 732bf215546Sopenharmony_cistatic void 733bf215546Sopenharmony_cifinish_seqno(struct crocus_batch *batch) 734bf215546Sopenharmony_ci{ 735bf215546Sopenharmony_ci struct crocus_fine_fence *sq = crocus_fine_fence_new(batch, CROCUS_FENCE_END); 736bf215546Sopenharmony_ci if (!sq) 737bf215546Sopenharmony_ci return; 738bf215546Sopenharmony_ci 739bf215546Sopenharmony_ci crocus_fine_fence_reference(batch->screen, &batch->last_fence, sq); 740bf215546Sopenharmony_ci crocus_fine_fence_reference(batch->screen, &sq, NULL); 741bf215546Sopenharmony_ci} 742bf215546Sopenharmony_ci 743bf215546Sopenharmony_ci/** 744bf215546Sopenharmony_ci * Terminate a batch with MI_BATCH_BUFFER_END. 745bf215546Sopenharmony_ci */ 746bf215546Sopenharmony_cistatic void 747bf215546Sopenharmony_cicrocus_finish_batch(struct crocus_batch *batch) 748bf215546Sopenharmony_ci{ 749bf215546Sopenharmony_ci 750bf215546Sopenharmony_ci batch->no_wrap = true; 751bf215546Sopenharmony_ci if (batch->screen->vtbl.finish_batch) 752bf215546Sopenharmony_ci batch->screen->vtbl.finish_batch(batch); 753bf215546Sopenharmony_ci 754bf215546Sopenharmony_ci finish_seqno(batch); 755bf215546Sopenharmony_ci 756bf215546Sopenharmony_ci /* Emit MI_BATCH_BUFFER_END to finish our batch. */ 757bf215546Sopenharmony_ci uint32_t *map = batch->command.map_next; 758bf215546Sopenharmony_ci 759bf215546Sopenharmony_ci map[0] = (0xA << 23); 760bf215546Sopenharmony_ci 761bf215546Sopenharmony_ci batch->command.map_next += 4; 762bf215546Sopenharmony_ci VG(VALGRIND_CHECK_MEM_IS_DEFINED(batch->command.map, crocus_batch_bytes_used(batch))); 763bf215546Sopenharmony_ci 764bf215546Sopenharmony_ci if (batch->command.bo == batch->exec_bos[0]) 765bf215546Sopenharmony_ci batch->primary_batch_size = crocus_batch_bytes_used(batch); 766bf215546Sopenharmony_ci batch->no_wrap = false; 767bf215546Sopenharmony_ci} 768bf215546Sopenharmony_ci 769bf215546Sopenharmony_ci/** 770bf215546Sopenharmony_ci * Replace our current GEM context with a new one (in case it got banned). 771bf215546Sopenharmony_ci */ 772bf215546Sopenharmony_cistatic bool 773bf215546Sopenharmony_cireplace_hw_ctx(struct crocus_batch *batch) 774bf215546Sopenharmony_ci{ 775bf215546Sopenharmony_ci struct crocus_screen *screen = batch->screen; 776bf215546Sopenharmony_ci struct crocus_bufmgr *bufmgr = screen->bufmgr; 777bf215546Sopenharmony_ci 778bf215546Sopenharmony_ci uint32_t new_ctx = crocus_clone_hw_context(bufmgr, batch->hw_ctx_id); 779bf215546Sopenharmony_ci if (!new_ctx) 780bf215546Sopenharmony_ci return false; 781bf215546Sopenharmony_ci 782bf215546Sopenharmony_ci crocus_destroy_hw_context(bufmgr, batch->hw_ctx_id); 783bf215546Sopenharmony_ci batch->hw_ctx_id = new_ctx; 784bf215546Sopenharmony_ci 785bf215546Sopenharmony_ci /* Notify the context that state must be re-initialized. */ 786bf215546Sopenharmony_ci crocus_lost_context_state(batch); 787bf215546Sopenharmony_ci 788bf215546Sopenharmony_ci return true; 789bf215546Sopenharmony_ci} 790bf215546Sopenharmony_ci 791bf215546Sopenharmony_cienum pipe_reset_status 792bf215546Sopenharmony_cicrocus_batch_check_for_reset(struct crocus_batch *batch) 793bf215546Sopenharmony_ci{ 794bf215546Sopenharmony_ci struct crocus_screen *screen = batch->screen; 795bf215546Sopenharmony_ci enum pipe_reset_status status = PIPE_NO_RESET; 796bf215546Sopenharmony_ci struct drm_i915_reset_stats stats = { .ctx_id = batch->hw_ctx_id }; 797bf215546Sopenharmony_ci 798bf215546Sopenharmony_ci if (drmIoctl(screen->fd, DRM_IOCTL_I915_GET_RESET_STATS, &stats)) 799bf215546Sopenharmony_ci DBG("DRM_IOCTL_I915_GET_RESET_STATS failed: %s\n", strerror(errno)); 800bf215546Sopenharmony_ci 801bf215546Sopenharmony_ci if (stats.batch_active != 0) { 802bf215546Sopenharmony_ci /* A reset was observed while a batch from this hardware context was 803bf215546Sopenharmony_ci * executing. Assume that this context was at fault. 804bf215546Sopenharmony_ci */ 805bf215546Sopenharmony_ci status = PIPE_GUILTY_CONTEXT_RESET; 806bf215546Sopenharmony_ci } else if (stats.batch_pending != 0) { 807bf215546Sopenharmony_ci /* A reset was observed while a batch from this context was in progress, 808bf215546Sopenharmony_ci * but the batch was not executing. In this case, assume that the 809bf215546Sopenharmony_ci * context was not at fault. 810bf215546Sopenharmony_ci */ 811bf215546Sopenharmony_ci status = PIPE_INNOCENT_CONTEXT_RESET; 812bf215546Sopenharmony_ci } 813bf215546Sopenharmony_ci 814bf215546Sopenharmony_ci if (status != PIPE_NO_RESET) { 815bf215546Sopenharmony_ci /* Our context is likely banned, or at least in an unknown state. 816bf215546Sopenharmony_ci * Throw it away and start with a fresh context. Ideally this may 817bf215546Sopenharmony_ci * catch the problem before our next execbuf fails with -EIO. 818bf215546Sopenharmony_ci */ 819bf215546Sopenharmony_ci replace_hw_ctx(batch); 820bf215546Sopenharmony_ci } 821bf215546Sopenharmony_ci 822bf215546Sopenharmony_ci return status; 823bf215546Sopenharmony_ci} 824bf215546Sopenharmony_ci 825bf215546Sopenharmony_ci/** 826bf215546Sopenharmony_ci * Submit the batch to the GPU via execbuffer2. 827bf215546Sopenharmony_ci */ 828bf215546Sopenharmony_cistatic int 829bf215546Sopenharmony_cisubmit_batch(struct crocus_batch *batch) 830bf215546Sopenharmony_ci{ 831bf215546Sopenharmony_ci 832bf215546Sopenharmony_ci if (batch->use_shadow_copy) { 833bf215546Sopenharmony_ci void *bo_map = crocus_bo_map(batch->dbg, batch->command.bo, MAP_WRITE); 834bf215546Sopenharmony_ci memcpy(bo_map, batch->command.map, crocus_batch_bytes_used(batch)); 835bf215546Sopenharmony_ci 836bf215546Sopenharmony_ci bo_map = crocus_bo_map(batch->dbg, batch->state.bo, MAP_WRITE); 837bf215546Sopenharmony_ci memcpy(bo_map, batch->state.map, batch->state.used); 838bf215546Sopenharmony_ci } 839bf215546Sopenharmony_ci 840bf215546Sopenharmony_ci crocus_bo_unmap(batch->command.bo); 841bf215546Sopenharmony_ci crocus_bo_unmap(batch->state.bo); 842bf215546Sopenharmony_ci 843bf215546Sopenharmony_ci /* The requirement for using I915_EXEC_NO_RELOC are: 844bf215546Sopenharmony_ci * 845bf215546Sopenharmony_ci * The addresses written in the objects must match the corresponding 846bf215546Sopenharmony_ci * reloc.gtt_offset which in turn must match the corresponding 847bf215546Sopenharmony_ci * execobject.offset. 848bf215546Sopenharmony_ci * 849bf215546Sopenharmony_ci * Any render targets written to in the batch must be flagged with 850bf215546Sopenharmony_ci * EXEC_OBJECT_WRITE. 851bf215546Sopenharmony_ci * 852bf215546Sopenharmony_ci * To avoid stalling, execobject.offset should match the current 853bf215546Sopenharmony_ci * address of that object within the active context. 854bf215546Sopenharmony_ci */ 855bf215546Sopenharmony_ci /* Set statebuffer relocations */ 856bf215546Sopenharmony_ci const unsigned state_index = batch->state.bo->index; 857bf215546Sopenharmony_ci if (state_index < batch->exec_count && 858bf215546Sopenharmony_ci batch->exec_bos[state_index] == batch->state.bo) { 859bf215546Sopenharmony_ci struct drm_i915_gem_exec_object2 *entry = 860bf215546Sopenharmony_ci &batch->validation_list[state_index]; 861bf215546Sopenharmony_ci assert(entry->handle == batch->state.bo->gem_handle); 862bf215546Sopenharmony_ci entry->relocation_count = batch->state.relocs.reloc_count; 863bf215546Sopenharmony_ci entry->relocs_ptr = (uintptr_t)batch->state.relocs.relocs; 864bf215546Sopenharmony_ci } 865bf215546Sopenharmony_ci 866bf215546Sopenharmony_ci /* Set batchbuffer relocations */ 867bf215546Sopenharmony_ci struct drm_i915_gem_exec_object2 *entry = &batch->validation_list[0]; 868bf215546Sopenharmony_ci assert(entry->handle == batch->command.bo->gem_handle); 869bf215546Sopenharmony_ci entry->relocation_count = batch->command.relocs.reloc_count; 870bf215546Sopenharmony_ci entry->relocs_ptr = (uintptr_t)batch->command.relocs.relocs; 871bf215546Sopenharmony_ci 872bf215546Sopenharmony_ci struct drm_i915_gem_execbuffer2 execbuf = { 873bf215546Sopenharmony_ci .buffers_ptr = (uintptr_t)batch->validation_list, 874bf215546Sopenharmony_ci .buffer_count = batch->exec_count, 875bf215546Sopenharmony_ci .batch_start_offset = 0, 876bf215546Sopenharmony_ci /* This must be QWord aligned. */ 877bf215546Sopenharmony_ci .batch_len = ALIGN(batch->primary_batch_size, 8), 878bf215546Sopenharmony_ci .flags = I915_EXEC_RENDER | 879bf215546Sopenharmony_ci I915_EXEC_NO_RELOC | 880bf215546Sopenharmony_ci I915_EXEC_BATCH_FIRST | 881bf215546Sopenharmony_ci I915_EXEC_HANDLE_LUT, 882bf215546Sopenharmony_ci .rsvd1 = batch->hw_ctx_id, /* rsvd1 is actually the context ID */ 883bf215546Sopenharmony_ci }; 884bf215546Sopenharmony_ci 885bf215546Sopenharmony_ci if (num_fences(batch)) { 886bf215546Sopenharmony_ci execbuf.flags |= I915_EXEC_FENCE_ARRAY; 887bf215546Sopenharmony_ci execbuf.num_cliprects = num_fences(batch); 888bf215546Sopenharmony_ci execbuf.cliprects_ptr = 889bf215546Sopenharmony_ci (uintptr_t)util_dynarray_begin(&batch->exec_fences); 890bf215546Sopenharmony_ci } 891bf215546Sopenharmony_ci 892bf215546Sopenharmony_ci int ret = 0; 893bf215546Sopenharmony_ci if (!batch->screen->devinfo.no_hw && 894bf215546Sopenharmony_ci intel_ioctl(batch->screen->fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf)) 895bf215546Sopenharmony_ci ret = -errno; 896bf215546Sopenharmony_ci 897bf215546Sopenharmony_ci for (int i = 0; i < batch->exec_count; i++) { 898bf215546Sopenharmony_ci struct crocus_bo *bo = batch->exec_bos[i]; 899bf215546Sopenharmony_ci 900bf215546Sopenharmony_ci bo->idle = false; 901bf215546Sopenharmony_ci bo->index = -1; 902bf215546Sopenharmony_ci 903bf215546Sopenharmony_ci /* Update brw_bo::gtt_offset */ 904bf215546Sopenharmony_ci if (batch->validation_list[i].offset != bo->gtt_offset) { 905bf215546Sopenharmony_ci DBG("BO %d migrated: 0x%" PRIx64 " -> 0x%" PRIx64 "\n", 906bf215546Sopenharmony_ci bo->gem_handle, bo->gtt_offset, 907bf215546Sopenharmony_ci (uint64_t)batch->validation_list[i].offset); 908bf215546Sopenharmony_ci assert(!(bo->kflags & EXEC_OBJECT_PINNED)); 909bf215546Sopenharmony_ci bo->gtt_offset = batch->validation_list[i].offset; 910bf215546Sopenharmony_ci } 911bf215546Sopenharmony_ci } 912bf215546Sopenharmony_ci 913bf215546Sopenharmony_ci return ret; 914bf215546Sopenharmony_ci} 915bf215546Sopenharmony_ci 916bf215546Sopenharmony_cistatic const char * 917bf215546Sopenharmony_cibatch_name_to_string(enum crocus_batch_name name) 918bf215546Sopenharmony_ci{ 919bf215546Sopenharmony_ci const char *names[CROCUS_BATCH_COUNT] = { 920bf215546Sopenharmony_ci [CROCUS_BATCH_RENDER] = "render", 921bf215546Sopenharmony_ci [CROCUS_BATCH_COMPUTE] = "compute", 922bf215546Sopenharmony_ci }; 923bf215546Sopenharmony_ci return names[name]; 924bf215546Sopenharmony_ci} 925bf215546Sopenharmony_ci 926bf215546Sopenharmony_ci/** 927bf215546Sopenharmony_ci * Flush the batch buffer, submitting it to the GPU and resetting it so 928bf215546Sopenharmony_ci * we're ready to emit the next batch. 929bf215546Sopenharmony_ci * 930bf215546Sopenharmony_ci * \param in_fence_fd is ignored if -1. Otherwise, this function takes 931bf215546Sopenharmony_ci * ownership of the fd. 932bf215546Sopenharmony_ci * 933bf215546Sopenharmony_ci * \param out_fence_fd is ignored if NULL. Otherwise, the caller must 934bf215546Sopenharmony_ci * take ownership of the returned fd. 935bf215546Sopenharmony_ci */ 936bf215546Sopenharmony_civoid 937bf215546Sopenharmony_ci_crocus_batch_flush(struct crocus_batch *batch, const char *file, int line) 938bf215546Sopenharmony_ci{ 939bf215546Sopenharmony_ci struct crocus_screen *screen = batch->screen; 940bf215546Sopenharmony_ci 941bf215546Sopenharmony_ci /* If a fence signals we need to flush it. */ 942bf215546Sopenharmony_ci if (crocus_batch_bytes_used(batch) == 0 && !batch->contains_fence_signal) 943bf215546Sopenharmony_ci return; 944bf215546Sopenharmony_ci 945bf215546Sopenharmony_ci assert(!batch->no_wrap); 946bf215546Sopenharmony_ci crocus_finish_batch(batch); 947bf215546Sopenharmony_ci 948bf215546Sopenharmony_ci finish_growing_bos(&batch->command); 949bf215546Sopenharmony_ci finish_growing_bos(&batch->state); 950bf215546Sopenharmony_ci int ret = submit_batch(batch); 951bf215546Sopenharmony_ci 952bf215546Sopenharmony_ci if (INTEL_DEBUG(DEBUG_BATCH | DEBUG_SUBMIT | DEBUG_PIPE_CONTROL)) { 953bf215546Sopenharmony_ci int bytes_for_commands = crocus_batch_bytes_used(batch); 954bf215546Sopenharmony_ci int second_bytes = 0; 955bf215546Sopenharmony_ci if (batch->command.bo != batch->exec_bos[0]) { 956bf215546Sopenharmony_ci second_bytes = bytes_for_commands; 957bf215546Sopenharmony_ci bytes_for_commands += batch->primary_batch_size; 958bf215546Sopenharmony_ci } 959bf215546Sopenharmony_ci fprintf(stderr, "%19s:%-3d: %s batch [%u] flush with %5d+%5db (%0.1f%%) " 960bf215546Sopenharmony_ci "(cmds), %4d BOs (%0.1fMb aperture)," 961bf215546Sopenharmony_ci " %4d command relocs, %4d state relocs\n", 962bf215546Sopenharmony_ci file, line, batch_name_to_string(batch->name), batch->hw_ctx_id, 963bf215546Sopenharmony_ci batch->primary_batch_size, second_bytes, 964bf215546Sopenharmony_ci 100.0f * bytes_for_commands / BATCH_SZ, 965bf215546Sopenharmony_ci batch->exec_count, 966bf215546Sopenharmony_ci (float) batch->aperture_space / (1024 * 1024), 967bf215546Sopenharmony_ci batch->command.relocs.reloc_count, 968bf215546Sopenharmony_ci batch->state.relocs.reloc_count); 969bf215546Sopenharmony_ci 970bf215546Sopenharmony_ci if (INTEL_DEBUG(DEBUG_BATCH | DEBUG_SUBMIT)) { 971bf215546Sopenharmony_ci dump_fence_list(batch); 972bf215546Sopenharmony_ci dump_validation_list(batch); 973bf215546Sopenharmony_ci } 974bf215546Sopenharmony_ci 975bf215546Sopenharmony_ci if (INTEL_DEBUG(DEBUG_BATCH)) { 976bf215546Sopenharmony_ci decode_batch(batch); 977bf215546Sopenharmony_ci } 978bf215546Sopenharmony_ci } 979bf215546Sopenharmony_ci 980bf215546Sopenharmony_ci for (int i = 0; i < batch->exec_count; i++) { 981bf215546Sopenharmony_ci struct crocus_bo *bo = batch->exec_bos[i]; 982bf215546Sopenharmony_ci crocus_bo_unreference(bo); 983bf215546Sopenharmony_ci } 984bf215546Sopenharmony_ci 985bf215546Sopenharmony_ci batch->command.relocs.reloc_count = 0; 986bf215546Sopenharmony_ci batch->state.relocs.reloc_count = 0; 987bf215546Sopenharmony_ci batch->exec_count = 0; 988bf215546Sopenharmony_ci batch->aperture_space = 0; 989bf215546Sopenharmony_ci 990bf215546Sopenharmony_ci util_dynarray_foreach(&batch->syncobjs, struct crocus_syncobj *, s) 991bf215546Sopenharmony_ci crocus_syncobj_reference(screen, s, NULL); 992bf215546Sopenharmony_ci util_dynarray_clear(&batch->syncobjs); 993bf215546Sopenharmony_ci 994bf215546Sopenharmony_ci util_dynarray_clear(&batch->exec_fences); 995bf215546Sopenharmony_ci 996bf215546Sopenharmony_ci if (INTEL_DEBUG(DEBUG_SYNC)) { 997bf215546Sopenharmony_ci dbg_printf("waiting for idle\n"); 998bf215546Sopenharmony_ci crocus_bo_wait_rendering(batch->command.bo); /* if execbuf failed; this is a nop */ 999bf215546Sopenharmony_ci } 1000bf215546Sopenharmony_ci 1001bf215546Sopenharmony_ci /* Start a new batch buffer. */ 1002bf215546Sopenharmony_ci crocus_batch_reset(batch); 1003bf215546Sopenharmony_ci 1004bf215546Sopenharmony_ci /* EIO means our context is banned. In this case, try and replace it 1005bf215546Sopenharmony_ci * with a new logical context, and inform crocus_context that all state 1006bf215546Sopenharmony_ci * has been lost and needs to be re-initialized. If this succeeds, 1007bf215546Sopenharmony_ci * dubiously claim success... 1008bf215546Sopenharmony_ci */ 1009bf215546Sopenharmony_ci if (ret == -EIO && replace_hw_ctx(batch)) { 1010bf215546Sopenharmony_ci if (batch->reset->reset) { 1011bf215546Sopenharmony_ci /* Tell the state tracker the device is lost and it was our fault. */ 1012bf215546Sopenharmony_ci batch->reset->reset(batch->reset->data, PIPE_GUILTY_CONTEXT_RESET); 1013bf215546Sopenharmony_ci } 1014bf215546Sopenharmony_ci 1015bf215546Sopenharmony_ci ret = 0; 1016bf215546Sopenharmony_ci } 1017bf215546Sopenharmony_ci 1018bf215546Sopenharmony_ci if (ret < 0) { 1019bf215546Sopenharmony_ci#ifdef DEBUG 1020bf215546Sopenharmony_ci const bool color = INTEL_DEBUG(DEBUG_COLOR); 1021bf215546Sopenharmony_ci fprintf(stderr, "%scrocus: Failed to submit batchbuffer: %-80s%s\n", 1022bf215546Sopenharmony_ci color ? "\e[1;41m" : "", strerror(-ret), color ? "\e[0m" : ""); 1023bf215546Sopenharmony_ci#endif 1024bf215546Sopenharmony_ci abort(); 1025bf215546Sopenharmony_ci } 1026bf215546Sopenharmony_ci} 1027bf215546Sopenharmony_ci 1028bf215546Sopenharmony_ci/** 1029bf215546Sopenharmony_ci * Does the current batch refer to the given BO? 1030bf215546Sopenharmony_ci * 1031bf215546Sopenharmony_ci * (In other words, is the BO in the current batch's validation list?) 1032bf215546Sopenharmony_ci */ 1033bf215546Sopenharmony_cibool 1034bf215546Sopenharmony_cicrocus_batch_references(struct crocus_batch *batch, struct crocus_bo *bo) 1035bf215546Sopenharmony_ci{ 1036bf215546Sopenharmony_ci return find_validation_entry(batch, bo) != NULL; 1037bf215546Sopenharmony_ci} 1038bf215546Sopenharmony_ci 1039bf215546Sopenharmony_ci/** 1040bf215546Sopenharmony_ci * Updates the state of the noop feature. Returns true if there was a noop 1041bf215546Sopenharmony_ci * transition that led to state invalidation. 1042bf215546Sopenharmony_ci */ 1043bf215546Sopenharmony_cibool 1044bf215546Sopenharmony_cicrocus_batch_prepare_noop(struct crocus_batch *batch, bool noop_enable) 1045bf215546Sopenharmony_ci{ 1046bf215546Sopenharmony_ci if (batch->noop_enabled == noop_enable) 1047bf215546Sopenharmony_ci return 0; 1048bf215546Sopenharmony_ci 1049bf215546Sopenharmony_ci batch->noop_enabled = noop_enable; 1050bf215546Sopenharmony_ci 1051bf215546Sopenharmony_ci crocus_batch_flush(batch); 1052bf215546Sopenharmony_ci 1053bf215546Sopenharmony_ci /* If the batch was empty, flush had no effect, so insert our noop. */ 1054bf215546Sopenharmony_ci if (crocus_batch_bytes_used(batch) == 0) 1055bf215546Sopenharmony_ci crocus_batch_maybe_noop(batch); 1056bf215546Sopenharmony_ci 1057bf215546Sopenharmony_ci /* We only need to update the entire state if we transition from noop -> 1058bf215546Sopenharmony_ci * not-noop. 1059bf215546Sopenharmony_ci */ 1060bf215546Sopenharmony_ci return !batch->noop_enabled; 1061bf215546Sopenharmony_ci} 1062