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 iris_program_cache.c 25bf215546Sopenharmony_ci * 26bf215546Sopenharmony_ci * The in-memory program cache. This is basically a hash table mapping 27bf215546Sopenharmony_ci * API-specified shaders and a state key to a compiled variant. It also 28bf215546Sopenharmony_ci * takes care of uploading shader assembly into a BO for use on the GPU. 29bf215546Sopenharmony_ci */ 30bf215546Sopenharmony_ci 31bf215546Sopenharmony_ci#include <stdio.h> 32bf215546Sopenharmony_ci#include <errno.h> 33bf215546Sopenharmony_ci#include "pipe/p_defines.h" 34bf215546Sopenharmony_ci#include "pipe/p_state.h" 35bf215546Sopenharmony_ci#include "pipe/p_context.h" 36bf215546Sopenharmony_ci#include "pipe/p_screen.h" 37bf215546Sopenharmony_ci#include "util/u_atomic.h" 38bf215546Sopenharmony_ci#include "util/u_upload_mgr.h" 39bf215546Sopenharmony_ci#include "compiler/nir/nir.h" 40bf215546Sopenharmony_ci#include "compiler/nir/nir_builder.h" 41bf215546Sopenharmony_ci#include "intel/common/intel_disasm.h" 42bf215546Sopenharmony_ci#include "intel/compiler/brw_compiler.h" 43bf215546Sopenharmony_ci#include "intel/compiler/brw_eu.h" 44bf215546Sopenharmony_ci#include "intel/compiler/brw_nir.h" 45bf215546Sopenharmony_ci#include "iris_context.h" 46bf215546Sopenharmony_ci#include "iris_resource.h" 47bf215546Sopenharmony_ci 48bf215546Sopenharmony_cistruct keybox { 49bf215546Sopenharmony_ci uint16_t size; 50bf215546Sopenharmony_ci enum iris_program_cache_id cache_id; 51bf215546Sopenharmony_ci uint8_t data[0]; 52bf215546Sopenharmony_ci}; 53bf215546Sopenharmony_ci 54bf215546Sopenharmony_cistatic struct keybox * 55bf215546Sopenharmony_cimake_keybox(void *mem_ctx, 56bf215546Sopenharmony_ci enum iris_program_cache_id cache_id, 57bf215546Sopenharmony_ci const void *key, 58bf215546Sopenharmony_ci uint32_t key_size) 59bf215546Sopenharmony_ci{ 60bf215546Sopenharmony_ci struct keybox *keybox = 61bf215546Sopenharmony_ci ralloc_size(mem_ctx, sizeof(struct keybox) + key_size); 62bf215546Sopenharmony_ci 63bf215546Sopenharmony_ci keybox->cache_id = cache_id; 64bf215546Sopenharmony_ci keybox->size = key_size; 65bf215546Sopenharmony_ci memcpy(keybox->data, key, key_size); 66bf215546Sopenharmony_ci 67bf215546Sopenharmony_ci return keybox; 68bf215546Sopenharmony_ci} 69bf215546Sopenharmony_ci 70bf215546Sopenharmony_cistatic uint32_t 71bf215546Sopenharmony_cikeybox_hash(const void *void_key) 72bf215546Sopenharmony_ci{ 73bf215546Sopenharmony_ci const struct keybox *key = void_key; 74bf215546Sopenharmony_ci return _mesa_hash_data(&key->cache_id, key->size + sizeof(key->cache_id)); 75bf215546Sopenharmony_ci} 76bf215546Sopenharmony_ci 77bf215546Sopenharmony_cistatic bool 78bf215546Sopenharmony_cikeybox_equals(const void *void_a, const void *void_b) 79bf215546Sopenharmony_ci{ 80bf215546Sopenharmony_ci const struct keybox *a = void_a, *b = void_b; 81bf215546Sopenharmony_ci if (a->size != b->size) 82bf215546Sopenharmony_ci return false; 83bf215546Sopenharmony_ci 84bf215546Sopenharmony_ci return memcmp(a->data, b->data, a->size) == 0; 85bf215546Sopenharmony_ci} 86bf215546Sopenharmony_ci 87bf215546Sopenharmony_cistruct iris_compiled_shader * 88bf215546Sopenharmony_ciiris_find_cached_shader(struct iris_context *ice, 89bf215546Sopenharmony_ci enum iris_program_cache_id cache_id, 90bf215546Sopenharmony_ci uint32_t key_size, 91bf215546Sopenharmony_ci const void *key) 92bf215546Sopenharmony_ci{ 93bf215546Sopenharmony_ci struct keybox *keybox = make_keybox(NULL, cache_id, key, key_size); 94bf215546Sopenharmony_ci struct hash_entry *entry = 95bf215546Sopenharmony_ci _mesa_hash_table_search(ice->shaders.cache, keybox); 96bf215546Sopenharmony_ci 97bf215546Sopenharmony_ci ralloc_free(keybox); 98bf215546Sopenharmony_ci 99bf215546Sopenharmony_ci return entry ? entry->data : NULL; 100bf215546Sopenharmony_ci} 101bf215546Sopenharmony_ci 102bf215546Sopenharmony_civoid 103bf215546Sopenharmony_ciiris_delete_shader_variant(struct iris_compiled_shader *shader) 104bf215546Sopenharmony_ci{ 105bf215546Sopenharmony_ci pipe_resource_reference(&shader->assembly.res, NULL); 106bf215546Sopenharmony_ci util_queue_fence_destroy(&shader->ready); 107bf215546Sopenharmony_ci ralloc_free(shader); 108bf215546Sopenharmony_ci} 109bf215546Sopenharmony_ci 110bf215546Sopenharmony_cistruct iris_compiled_shader * 111bf215546Sopenharmony_ciiris_create_shader_variant(const struct iris_screen *screen, 112bf215546Sopenharmony_ci void *mem_ctx, 113bf215546Sopenharmony_ci enum iris_program_cache_id cache_id, 114bf215546Sopenharmony_ci uint32_t key_size, 115bf215546Sopenharmony_ci const void *key) 116bf215546Sopenharmony_ci{ 117bf215546Sopenharmony_ci#ifndef NDEBUG 118bf215546Sopenharmony_ci if (cache_id == IRIS_CACHE_BLORP) { 119bf215546Sopenharmony_ci /* Blorp shader must have a mem_ctx. */ 120bf215546Sopenharmony_ci assert(mem_ctx != NULL); 121bf215546Sopenharmony_ci } else if (cache_id == IRIS_CACHE_TCS) { 122bf215546Sopenharmony_ci /* Pass-through tessellation control shaders (generated by the driver) 123bf215546Sopenharmony_ci * will have a mem_ctx, and other tessellation control shaders will not. 124bf215546Sopenharmony_ci */ 125bf215546Sopenharmony_ci } else { 126bf215546Sopenharmony_ci /* Shaders that are neither blorp nor tessellation control must not have 127bf215546Sopenharmony_ci * a mem_ctx. 128bf215546Sopenharmony_ci */ 129bf215546Sopenharmony_ci assert(mem_ctx == NULL); 130bf215546Sopenharmony_ci } 131bf215546Sopenharmony_ci#endif 132bf215546Sopenharmony_ci 133bf215546Sopenharmony_ci struct iris_compiled_shader *shader = 134bf215546Sopenharmony_ci rzalloc_size(mem_ctx, sizeof(struct iris_compiled_shader) + 135bf215546Sopenharmony_ci screen->vtbl.derived_program_state_size(cache_id)); 136bf215546Sopenharmony_ci 137bf215546Sopenharmony_ci pipe_reference_init(&shader->ref, 1); 138bf215546Sopenharmony_ci util_queue_fence_init(&shader->ready); 139bf215546Sopenharmony_ci util_queue_fence_reset(&shader->ready); 140bf215546Sopenharmony_ci 141bf215546Sopenharmony_ci if (cache_id != IRIS_CACHE_BLORP) { 142bf215546Sopenharmony_ci assert(key_size <= sizeof(union iris_any_prog_key)); 143bf215546Sopenharmony_ci memcpy(&shader->key, key, key_size); 144bf215546Sopenharmony_ci } 145bf215546Sopenharmony_ci 146bf215546Sopenharmony_ci return shader; 147bf215546Sopenharmony_ci} 148bf215546Sopenharmony_ci 149bf215546Sopenharmony_civoid 150bf215546Sopenharmony_ciiris_upload_shader(struct iris_screen *screen, 151bf215546Sopenharmony_ci struct iris_uncompiled_shader *ish, 152bf215546Sopenharmony_ci struct iris_compiled_shader *shader, 153bf215546Sopenharmony_ci struct hash_table *driver_shaders, 154bf215546Sopenharmony_ci struct u_upload_mgr *uploader, 155bf215546Sopenharmony_ci enum iris_program_cache_id cache_id, 156bf215546Sopenharmony_ci uint32_t key_size, 157bf215546Sopenharmony_ci const void *key, 158bf215546Sopenharmony_ci const void *assembly) 159bf215546Sopenharmony_ci{ 160bf215546Sopenharmony_ci const struct intel_device_info *devinfo = &screen->devinfo; 161bf215546Sopenharmony_ci 162bf215546Sopenharmony_ci u_upload_alloc(uploader, 0, shader->prog_data->program_size, 64, 163bf215546Sopenharmony_ci &shader->assembly.offset, &shader->assembly.res, 164bf215546Sopenharmony_ci &shader->map); 165bf215546Sopenharmony_ci memcpy(shader->map, assembly, shader->prog_data->program_size); 166bf215546Sopenharmony_ci 167bf215546Sopenharmony_ci struct iris_resource *res = (void *) shader->assembly.res; 168bf215546Sopenharmony_ci uint64_t shader_data_addr = res->bo->address + 169bf215546Sopenharmony_ci shader->assembly.offset + 170bf215546Sopenharmony_ci shader->prog_data->const_data_offset; 171bf215546Sopenharmony_ci 172bf215546Sopenharmony_ci struct brw_shader_reloc_value reloc_values[] = { 173bf215546Sopenharmony_ci { 174bf215546Sopenharmony_ci .id = BRW_SHADER_RELOC_CONST_DATA_ADDR_LOW, 175bf215546Sopenharmony_ci .value = shader_data_addr, 176bf215546Sopenharmony_ci }, 177bf215546Sopenharmony_ci { 178bf215546Sopenharmony_ci .id = BRW_SHADER_RELOC_CONST_DATA_ADDR_HIGH, 179bf215546Sopenharmony_ci .value = shader_data_addr >> 32, 180bf215546Sopenharmony_ci }, 181bf215546Sopenharmony_ci }; 182bf215546Sopenharmony_ci brw_write_shader_relocs(&screen->compiler->isa, shader->map, 183bf215546Sopenharmony_ci shader->prog_data, reloc_values, 184bf215546Sopenharmony_ci ARRAY_SIZE(reloc_values)); 185bf215546Sopenharmony_ci 186bf215546Sopenharmony_ci /* Store the 3DSTATE shader packets and other derived state. */ 187bf215546Sopenharmony_ci screen->vtbl.store_derived_program_state(devinfo, cache_id, shader); 188bf215546Sopenharmony_ci 189bf215546Sopenharmony_ci util_queue_fence_signal(&shader->ready); 190bf215546Sopenharmony_ci 191bf215546Sopenharmony_ci if (!ish) { 192bf215546Sopenharmony_ci struct keybox *keybox = make_keybox(shader, cache_id, key, key_size); 193bf215546Sopenharmony_ci _mesa_hash_table_insert(driver_shaders, keybox, shader); 194bf215546Sopenharmony_ci } 195bf215546Sopenharmony_ci} 196bf215546Sopenharmony_ci 197bf215546Sopenharmony_cibool 198bf215546Sopenharmony_ciiris_blorp_lookup_shader(struct blorp_batch *blorp_batch, 199bf215546Sopenharmony_ci const void *key, uint32_t key_size, 200bf215546Sopenharmony_ci uint32_t *kernel_out, void *prog_data_out) 201bf215546Sopenharmony_ci{ 202bf215546Sopenharmony_ci struct blorp_context *blorp = blorp_batch->blorp; 203bf215546Sopenharmony_ci struct iris_context *ice = blorp->driver_ctx; 204bf215546Sopenharmony_ci struct iris_batch *batch = blorp_batch->driver_batch; 205bf215546Sopenharmony_ci struct iris_compiled_shader *shader = 206bf215546Sopenharmony_ci iris_find_cached_shader(ice, IRIS_CACHE_BLORP, key_size, key); 207bf215546Sopenharmony_ci 208bf215546Sopenharmony_ci if (!shader) 209bf215546Sopenharmony_ci return false; 210bf215546Sopenharmony_ci 211bf215546Sopenharmony_ci struct iris_bo *bo = iris_resource_bo(shader->assembly.res); 212bf215546Sopenharmony_ci *kernel_out = 213bf215546Sopenharmony_ci iris_bo_offset_from_base_address(bo) + shader->assembly.offset; 214bf215546Sopenharmony_ci *((void **) prog_data_out) = shader->prog_data; 215bf215546Sopenharmony_ci 216bf215546Sopenharmony_ci iris_use_pinned_bo(batch, bo, false, IRIS_DOMAIN_NONE); 217bf215546Sopenharmony_ci 218bf215546Sopenharmony_ci return true; 219bf215546Sopenharmony_ci} 220bf215546Sopenharmony_ci 221bf215546Sopenharmony_cibool 222bf215546Sopenharmony_ciiris_blorp_upload_shader(struct blorp_batch *blorp_batch, uint32_t stage, 223bf215546Sopenharmony_ci const void *key, uint32_t key_size, 224bf215546Sopenharmony_ci const void *kernel, UNUSED uint32_t kernel_size, 225bf215546Sopenharmony_ci const struct brw_stage_prog_data *prog_data_templ, 226bf215546Sopenharmony_ci UNUSED uint32_t prog_data_size, 227bf215546Sopenharmony_ci uint32_t *kernel_out, void *prog_data_out) 228bf215546Sopenharmony_ci{ 229bf215546Sopenharmony_ci struct blorp_context *blorp = blorp_batch->blorp; 230bf215546Sopenharmony_ci struct iris_context *ice = blorp->driver_ctx; 231bf215546Sopenharmony_ci struct iris_batch *batch = blorp_batch->driver_batch; 232bf215546Sopenharmony_ci struct iris_screen *screen = batch->screen; 233bf215546Sopenharmony_ci 234bf215546Sopenharmony_ci void *prog_data = ralloc_size(NULL, prog_data_size); 235bf215546Sopenharmony_ci memcpy(prog_data, prog_data_templ, prog_data_size); 236bf215546Sopenharmony_ci 237bf215546Sopenharmony_ci struct iris_binding_table bt; 238bf215546Sopenharmony_ci memset(&bt, 0, sizeof(bt)); 239bf215546Sopenharmony_ci 240bf215546Sopenharmony_ci struct iris_compiled_shader *shader = 241bf215546Sopenharmony_ci iris_create_shader_variant(screen, ice->shaders.cache, IRIS_CACHE_BLORP, 242bf215546Sopenharmony_ci key_size, key); 243bf215546Sopenharmony_ci 244bf215546Sopenharmony_ci iris_finalize_program(shader, prog_data, NULL, NULL, 0, 0, 0, &bt); 245bf215546Sopenharmony_ci 246bf215546Sopenharmony_ci iris_upload_shader(screen, NULL, shader, ice->shaders.cache, 247bf215546Sopenharmony_ci ice->shaders.uploader_driver, 248bf215546Sopenharmony_ci IRIS_CACHE_BLORP, key_size, key, kernel); 249bf215546Sopenharmony_ci 250bf215546Sopenharmony_ci struct iris_bo *bo = iris_resource_bo(shader->assembly.res); 251bf215546Sopenharmony_ci *kernel_out = 252bf215546Sopenharmony_ci iris_bo_offset_from_base_address(bo) + shader->assembly.offset; 253bf215546Sopenharmony_ci *((void **) prog_data_out) = shader->prog_data; 254bf215546Sopenharmony_ci 255bf215546Sopenharmony_ci iris_use_pinned_bo(batch, bo, false, IRIS_DOMAIN_NONE); 256bf215546Sopenharmony_ci 257bf215546Sopenharmony_ci return true; 258bf215546Sopenharmony_ci} 259bf215546Sopenharmony_ci 260bf215546Sopenharmony_civoid 261bf215546Sopenharmony_ciiris_init_program_cache(struct iris_context *ice) 262bf215546Sopenharmony_ci{ 263bf215546Sopenharmony_ci ice->shaders.cache = 264bf215546Sopenharmony_ci _mesa_hash_table_create(ice, keybox_hash, keybox_equals); 265bf215546Sopenharmony_ci 266bf215546Sopenharmony_ci ice->shaders.uploader_driver = 267bf215546Sopenharmony_ci u_upload_create(&ice->ctx, 16384, PIPE_BIND_CUSTOM, PIPE_USAGE_IMMUTABLE, 268bf215546Sopenharmony_ci IRIS_RESOURCE_FLAG_SHADER_MEMZONE | 269bf215546Sopenharmony_ci IRIS_RESOURCE_FLAG_DEVICE_MEM); 270bf215546Sopenharmony_ci ice->shaders.uploader_unsync = 271bf215546Sopenharmony_ci u_upload_create(&ice->ctx, 16384, PIPE_BIND_CUSTOM, PIPE_USAGE_IMMUTABLE, 272bf215546Sopenharmony_ci IRIS_RESOURCE_FLAG_SHADER_MEMZONE | 273bf215546Sopenharmony_ci IRIS_RESOURCE_FLAG_DEVICE_MEM); 274bf215546Sopenharmony_ci} 275bf215546Sopenharmony_ci 276bf215546Sopenharmony_civoid 277bf215546Sopenharmony_ciiris_destroy_program_cache(struct iris_context *ice) 278bf215546Sopenharmony_ci{ 279bf215546Sopenharmony_ci for (int i = 0; i < MESA_SHADER_STAGES; i++) { 280bf215546Sopenharmony_ci iris_shader_variant_reference(&ice->shaders.prog[i], NULL); 281bf215546Sopenharmony_ci } 282bf215546Sopenharmony_ci iris_shader_variant_reference(&ice->shaders.last_vue_shader, NULL); 283bf215546Sopenharmony_ci 284bf215546Sopenharmony_ci hash_table_foreach(ice->shaders.cache, entry) { 285bf215546Sopenharmony_ci struct iris_compiled_shader *shader = entry->data; 286bf215546Sopenharmony_ci iris_delete_shader_variant(shader); 287bf215546Sopenharmony_ci } 288bf215546Sopenharmony_ci 289bf215546Sopenharmony_ci u_upload_destroy(ice->shaders.uploader_driver); 290bf215546Sopenharmony_ci u_upload_destroy(ice->shaders.uploader_unsync); 291bf215546Sopenharmony_ci 292bf215546Sopenharmony_ci ralloc_free(ice->shaders.cache); 293bf215546Sopenharmony_ci} 294