1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2018 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 iris_binder.c 25bf215546Sopenharmony_ci * 26bf215546Sopenharmony_ci * Shader programs refer to most resources via integer handles. These are 27bf215546Sopenharmony_ci * indexes (BTIs) into a "Binding Table", which is simply a list of pointers 28bf215546Sopenharmony_ci * to SURFACE_STATE entries. Each shader stage has its own binding table, 29bf215546Sopenharmony_ci * set by the 3DSTATE_BINDING_TABLE_POINTERS_* commands. We stream out 30bf215546Sopenharmony_ci * binding tables dynamically, storing them in special BOs we call "binders." 31bf215546Sopenharmony_ci * 32bf215546Sopenharmony_ci * Unfortunately, the hardware designers made 3DSTATE_BINDING_TABLE_POINTERS 33bf215546Sopenharmony_ci * only accept a 16-bit pointer. This means that all binding tables have to 34bf215546Sopenharmony_ci * live within the 64kB range starting at Surface State Base Address. (The 35bf215546Sopenharmony_ci * actual SURFACE_STATE entries can live anywhere in the 4GB zone, as the 36bf215546Sopenharmony_ci * binding table entries are full 32-bit pointers.) 37bf215546Sopenharmony_ci * 38bf215546Sopenharmony_ci * To handle this, we split a 4GB region of VMA into two memory zones. 39bf215546Sopenharmony_ci * IRIS_MEMZONE_BINDER is a 1GB region at the bottom able to hold a few 40bf215546Sopenharmony_ci * binder BOs. IRIS_MEMZONE_SURFACE contains the rest of the 4GB, and is 41bf215546Sopenharmony_ci * always at a higher address than the binders. This allows us to program 42bf215546Sopenharmony_ci * Surface State Base Address to the binder BO's address, and offset the 43bf215546Sopenharmony_ci * values in the binding table to account for the base not starting at the 44bf215546Sopenharmony_ci * beginning of the 4GB region. 45bf215546Sopenharmony_ci * 46bf215546Sopenharmony_ci * This does mean that we have to emit STATE_BASE_ADDRESS and stall when 47bf215546Sopenharmony_ci * we run out of space in the binder, which hopefully won't happen too often. 48bf215546Sopenharmony_ci */ 49bf215546Sopenharmony_ci 50bf215546Sopenharmony_ci#include <stdlib.h> 51bf215546Sopenharmony_ci#include "util/u_math.h" 52bf215546Sopenharmony_ci#include "iris_binder.h" 53bf215546Sopenharmony_ci#include "iris_bufmgr.h" 54bf215546Sopenharmony_ci#include "iris_context.h" 55bf215546Sopenharmony_ci 56bf215546Sopenharmony_cistatic bool 57bf215546Sopenharmony_cibinder_has_space(struct iris_binder *binder, unsigned size) 58bf215546Sopenharmony_ci{ 59bf215546Sopenharmony_ci return binder->insert_point + size <= binder->size; 60bf215546Sopenharmony_ci} 61bf215546Sopenharmony_ci 62bf215546Sopenharmony_cistatic void 63bf215546Sopenharmony_cibinder_realloc(struct iris_context *ice) 64bf215546Sopenharmony_ci{ 65bf215546Sopenharmony_ci struct iris_screen *screen = (void *) ice->ctx.screen; 66bf215546Sopenharmony_ci struct iris_bufmgr *bufmgr = screen->bufmgr; 67bf215546Sopenharmony_ci struct iris_binder *binder = &ice->state.binder; 68bf215546Sopenharmony_ci 69bf215546Sopenharmony_ci if (binder->bo) 70bf215546Sopenharmony_ci iris_bo_unreference(binder->bo); 71bf215546Sopenharmony_ci 72bf215546Sopenharmony_ci binder->bo = iris_bo_alloc(bufmgr, "binder", binder->size, binder->alignment, 73bf215546Sopenharmony_ci IRIS_MEMZONE_BINDER, 4096); 74bf215546Sopenharmony_ci binder->map = iris_bo_map(NULL, binder->bo, MAP_WRITE); 75bf215546Sopenharmony_ci 76bf215546Sopenharmony_ci /* Avoid using offset 0 - tools consider it NULL. */ 77bf215546Sopenharmony_ci binder->insert_point = binder->alignment; 78bf215546Sopenharmony_ci 79bf215546Sopenharmony_ci /* Allocating a new binder requires changing Surface State Base Address, 80bf215546Sopenharmony_ci * which also invalidates all our previous binding tables - each entry 81bf215546Sopenharmony_ci * in those tables is an offset from the old base. 82bf215546Sopenharmony_ci * 83bf215546Sopenharmony_ci * We do this here so that iris_binder_reserve_3d correctly gets a new 84bf215546Sopenharmony_ci * larger total_size when making the updated reservation. 85bf215546Sopenharmony_ci * 86bf215546Sopenharmony_ci * Gfx11+ simply updates the binding table pool address instead, which 87bf215546Sopenharmony_ci * means the old binding table's contents are still valid. Nevertheless, 88bf215546Sopenharmony_ci * it still lives in the old BO, so we'd at least need to copy it to the 89bf215546Sopenharmony_ci * new one. Instead, we just flag it dirty and re-emit it anyway. 90bf215546Sopenharmony_ci */ 91bf215546Sopenharmony_ci ice->state.dirty |= IRIS_DIRTY_RENDER_BUFFER; 92bf215546Sopenharmony_ci ice->state.stage_dirty |= IRIS_ALL_STAGE_DIRTY_BINDINGS; 93bf215546Sopenharmony_ci} 94bf215546Sopenharmony_ci 95bf215546Sopenharmony_cistatic uint32_t 96bf215546Sopenharmony_cibinder_insert(struct iris_binder *binder, unsigned size) 97bf215546Sopenharmony_ci{ 98bf215546Sopenharmony_ci uint32_t offset = binder->insert_point; 99bf215546Sopenharmony_ci 100bf215546Sopenharmony_ci binder->insert_point = 101bf215546Sopenharmony_ci align(binder->insert_point + size, binder->alignment); 102bf215546Sopenharmony_ci 103bf215546Sopenharmony_ci return offset; 104bf215546Sopenharmony_ci} 105bf215546Sopenharmony_ci 106bf215546Sopenharmony_ci/** 107bf215546Sopenharmony_ci * Reserve a block of space in the binder, given the raw size in bytes. 108bf215546Sopenharmony_ci */ 109bf215546Sopenharmony_ciuint32_t 110bf215546Sopenharmony_ciiris_binder_reserve(struct iris_context *ice, 111bf215546Sopenharmony_ci unsigned size) 112bf215546Sopenharmony_ci{ 113bf215546Sopenharmony_ci struct iris_binder *binder = &ice->state.binder; 114bf215546Sopenharmony_ci 115bf215546Sopenharmony_ci if (!binder_has_space(binder, size)) 116bf215546Sopenharmony_ci binder_realloc(ice); 117bf215546Sopenharmony_ci 118bf215546Sopenharmony_ci assert(size > 0); 119bf215546Sopenharmony_ci return binder_insert(binder, size); 120bf215546Sopenharmony_ci} 121bf215546Sopenharmony_ci 122bf215546Sopenharmony_ci/** 123bf215546Sopenharmony_ci * Reserve and record binder space for 3D pipeline shader stages. 124bf215546Sopenharmony_ci * 125bf215546Sopenharmony_ci * Note that you must actually populate the new binding tables after 126bf215546Sopenharmony_ci * calling this command - the new area is uninitialized. 127bf215546Sopenharmony_ci */ 128bf215546Sopenharmony_civoid 129bf215546Sopenharmony_ciiris_binder_reserve_3d(struct iris_context *ice) 130bf215546Sopenharmony_ci{ 131bf215546Sopenharmony_ci struct iris_compiled_shader **shaders = ice->shaders.prog; 132bf215546Sopenharmony_ci struct iris_binder *binder = &ice->state.binder; 133bf215546Sopenharmony_ci unsigned sizes[MESA_SHADER_STAGES] = {}; 134bf215546Sopenharmony_ci unsigned total_size; 135bf215546Sopenharmony_ci 136bf215546Sopenharmony_ci /* If nothing is dirty, skip all this. */ 137bf215546Sopenharmony_ci if (!(ice->state.dirty & IRIS_DIRTY_RENDER_BUFFER) && 138bf215546Sopenharmony_ci !(ice->state.stage_dirty & IRIS_ALL_STAGE_DIRTY_BINDINGS_FOR_RENDER)) 139bf215546Sopenharmony_ci return; 140bf215546Sopenharmony_ci 141bf215546Sopenharmony_ci /* Get the binding table sizes for each stage */ 142bf215546Sopenharmony_ci for (int stage = 0; stage <= MESA_SHADER_FRAGMENT; stage++) { 143bf215546Sopenharmony_ci if (!shaders[stage]) 144bf215546Sopenharmony_ci continue; 145bf215546Sopenharmony_ci 146bf215546Sopenharmony_ci /* Round up the size so our next table has an aligned starting offset */ 147bf215546Sopenharmony_ci sizes[stage] = align(shaders[stage]->bt.size_bytes, binder->alignment); 148bf215546Sopenharmony_ci } 149bf215546Sopenharmony_ci 150bf215546Sopenharmony_ci /* Make space for the new binding tables...this may take two tries. */ 151bf215546Sopenharmony_ci while (true) { 152bf215546Sopenharmony_ci total_size = 0; 153bf215546Sopenharmony_ci for (int stage = 0; stage <= MESA_SHADER_FRAGMENT; stage++) { 154bf215546Sopenharmony_ci if (ice->state.stage_dirty & (IRIS_STAGE_DIRTY_BINDINGS_VS << stage)) 155bf215546Sopenharmony_ci total_size += sizes[stage]; 156bf215546Sopenharmony_ci } 157bf215546Sopenharmony_ci 158bf215546Sopenharmony_ci assert(total_size < binder->size); 159bf215546Sopenharmony_ci 160bf215546Sopenharmony_ci if (total_size == 0) 161bf215546Sopenharmony_ci return; 162bf215546Sopenharmony_ci 163bf215546Sopenharmony_ci if (binder_has_space(binder, total_size)) 164bf215546Sopenharmony_ci break; 165bf215546Sopenharmony_ci 166bf215546Sopenharmony_ci /* It didn't fit. Allocate a new buffer and try again. Note that 167bf215546Sopenharmony_ci * this will flag all bindings dirty, which may increase total_size 168bf215546Sopenharmony_ci * on the next iteration. 169bf215546Sopenharmony_ci */ 170bf215546Sopenharmony_ci binder_realloc(ice); 171bf215546Sopenharmony_ci } 172bf215546Sopenharmony_ci 173bf215546Sopenharmony_ci /* Assign space and record the new binding table offsets. */ 174bf215546Sopenharmony_ci uint32_t offset = binder_insert(binder, total_size); 175bf215546Sopenharmony_ci 176bf215546Sopenharmony_ci for (int stage = 0; stage <= MESA_SHADER_FRAGMENT; stage++) { 177bf215546Sopenharmony_ci if (ice->state.stage_dirty & (IRIS_STAGE_DIRTY_BINDINGS_VS << stage)) { 178bf215546Sopenharmony_ci binder->bt_offset[stage] = sizes[stage] > 0 ? offset : 0; 179bf215546Sopenharmony_ci iris_record_state_size(ice->state.sizes, 180bf215546Sopenharmony_ci binder->bo->address + offset, sizes[stage]); 181bf215546Sopenharmony_ci offset += sizes[stage]; 182bf215546Sopenharmony_ci } 183bf215546Sopenharmony_ci } 184bf215546Sopenharmony_ci} 185bf215546Sopenharmony_ci 186bf215546Sopenharmony_civoid 187bf215546Sopenharmony_ciiris_binder_reserve_compute(struct iris_context *ice) 188bf215546Sopenharmony_ci{ 189bf215546Sopenharmony_ci if (!(ice->state.stage_dirty & IRIS_STAGE_DIRTY_BINDINGS_CS)) 190bf215546Sopenharmony_ci return; 191bf215546Sopenharmony_ci 192bf215546Sopenharmony_ci struct iris_binder *binder = &ice->state.binder; 193bf215546Sopenharmony_ci struct iris_compiled_shader *shader = 194bf215546Sopenharmony_ci ice->shaders.prog[MESA_SHADER_COMPUTE]; 195bf215546Sopenharmony_ci 196bf215546Sopenharmony_ci unsigned size = shader->bt.size_bytes; 197bf215546Sopenharmony_ci 198bf215546Sopenharmony_ci if (size == 0) 199bf215546Sopenharmony_ci return; 200bf215546Sopenharmony_ci 201bf215546Sopenharmony_ci binder->bt_offset[MESA_SHADER_COMPUTE] = iris_binder_reserve(ice, size); 202bf215546Sopenharmony_ci} 203bf215546Sopenharmony_ci 204bf215546Sopenharmony_civoid 205bf215546Sopenharmony_ciiris_init_binder(struct iris_context *ice) 206bf215546Sopenharmony_ci{ 207bf215546Sopenharmony_ci struct iris_screen *screen = (void *) ice->ctx.screen; 208bf215546Sopenharmony_ci const struct intel_device_info *devinfo = &screen->devinfo; 209bf215546Sopenharmony_ci 210bf215546Sopenharmony_ci memset(&ice->state.binder, 0, sizeof(struct iris_binder)); 211bf215546Sopenharmony_ci 212bf215546Sopenharmony_ci /* We use different binding table pointer formats on various generations. 213bf215546Sopenharmony_ci * 214bf215546Sopenharmony_ci * - The 20:5 format gives us an alignment of 32B and max size of 1024kB. 215bf215546Sopenharmony_ci * - The 18:8 format gives us an alignment of 256B and max size of 512kB. 216bf215546Sopenharmony_ci * - The 15:5 format gives us an alignment of 32B and max size of 64kB. 217bf215546Sopenharmony_ci * 218bf215546Sopenharmony_ci * XeHP and later use the 20:5 format. Icelake and Tigerlake use 18:8 219bf215546Sopenharmony_ci * in iris, but can use 15:5 if desired, Older platforms require 15:5. 220bf215546Sopenharmony_ci */ 221bf215546Sopenharmony_ci if (devinfo->verx10 >= 125) { 222bf215546Sopenharmony_ci ice->state.binder.alignment = 32; 223bf215546Sopenharmony_ci ice->state.binder.size = 1024 * 1024; 224bf215546Sopenharmony_ci } else if (devinfo->ver >= 11) { 225bf215546Sopenharmony_ci ice->state.binder.alignment = 256; 226bf215546Sopenharmony_ci ice->state.binder.size = 512 * 1024; 227bf215546Sopenharmony_ci } else { 228bf215546Sopenharmony_ci ice->state.binder.alignment = 32; 229bf215546Sopenharmony_ci ice->state.binder.size = 64 * 1024; 230bf215546Sopenharmony_ci } 231bf215546Sopenharmony_ci 232bf215546Sopenharmony_ci binder_realloc(ice); 233bf215546Sopenharmony_ci} 234bf215546Sopenharmony_ci 235bf215546Sopenharmony_civoid 236bf215546Sopenharmony_ciiris_destroy_binder(struct iris_binder *binder) 237bf215546Sopenharmony_ci{ 238bf215546Sopenharmony_ci iris_bo_unreference(binder->bo); 239bf215546Sopenharmony_ci} 240