1/* 2 * Copyright © 2017 Timothy Arceri 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 */ 23 24#include <stdio.h> 25#include "st_debug.h" 26#include "st_program.h" 27#include "st_shader_cache.h" 28#include "st_util.h" 29#include "compiler/glsl/program.h" 30#include "compiler/nir/nir.h" 31#include "compiler/nir/nir_serialize.h" 32#include "main/uniforms.h" 33#include "pipe/p_shader_tokens.h" 34#include "util/u_memory.h" 35 36void 37st_get_program_binary_driver_sha1(struct gl_context *ctx, uint8_t *sha1) 38{ 39 disk_cache_compute_key(ctx->Cache, NULL, 0, sha1); 40} 41 42static void 43write_stream_out_to_cache(struct blob *blob, 44 struct pipe_shader_state *state) 45{ 46 blob_write_uint32(blob, state->stream_output.num_outputs); 47 if (state->stream_output.num_outputs) { 48 blob_write_bytes(blob, &state->stream_output.stride, 49 sizeof(state->stream_output.stride)); 50 blob_write_bytes(blob, &state->stream_output.output, 51 sizeof(state->stream_output.output)); 52 } 53} 54 55static void 56copy_blob_to_driver_cache_blob(struct blob *blob, struct gl_program *prog) 57{ 58 prog->driver_cache_blob = ralloc_size(NULL, blob->size); 59 memcpy(prog->driver_cache_blob, blob->data, blob->size); 60 prog->driver_cache_blob_size = blob->size; 61} 62 63static void 64write_nir_to_cache(struct blob *blob, struct gl_program *prog) 65{ 66 st_serialize_nir(prog); 67 68 blob_write_intptr(blob, prog->serialized_nir_size); 69 blob_write_bytes(blob, prog->serialized_nir, prog->serialized_nir_size); 70 71 copy_blob_to_driver_cache_blob(blob, prog); 72} 73 74void 75st_serialise_nir_program(struct gl_context *ctx, struct gl_program *prog) 76{ 77 if (prog->driver_cache_blob) 78 return; 79 80 struct blob blob; 81 blob_init(&blob); 82 83 if (prog->info.stage == MESA_SHADER_VERTEX) { 84 struct gl_vertex_program *vp = (struct gl_vertex_program *)prog; 85 86 blob_write_uint32(&blob, vp->num_inputs); 87 blob_write_uint32(&blob, vp->vert_attrib_mask); 88 blob_write_bytes(&blob, vp->result_to_output, 89 sizeof(vp->result_to_output)); 90 } 91 92 if (prog->info.stage == MESA_SHADER_VERTEX || 93 prog->info.stage == MESA_SHADER_TESS_EVAL || 94 prog->info.stage == MESA_SHADER_GEOMETRY) 95 write_stream_out_to_cache(&blob, &prog->state); 96 97 write_nir_to_cache(&blob, prog); 98 99 blob_finish(&blob); 100} 101 102/** 103 * Store NIR and any other required state in on-disk shader cache. 104 */ 105void 106st_store_nir_in_disk_cache(struct st_context *st, struct gl_program *prog) 107{ 108 if (!st->ctx->Cache) 109 return; 110 111 /* Exit early when we are dealing with a ff shader with no source file to 112 * generate a source from. 113 */ 114 static const char zero[sizeof(prog->sh.data->sha1)] = {0}; 115 if (memcmp(prog->sh.data->sha1, zero, sizeof(prog->sh.data->sha1)) == 0) 116 return; 117 118 st_serialise_nir_program(st->ctx, prog); 119 120 if (st->ctx->_Shader->Flags & GLSL_CACHE_INFO) { 121 fprintf(stderr, "putting %s state tracker IR in cache\n", 122 _mesa_shader_stage_to_string(prog->info.stage)); 123 } 124} 125 126static void 127read_stream_out_from_cache(struct blob_reader *blob_reader, 128 struct pipe_shader_state *state) 129{ 130 memset(&state->stream_output, 0, sizeof(state->stream_output)); 131 state->stream_output.num_outputs = blob_read_uint32(blob_reader); 132 if (state->stream_output.num_outputs) { 133 blob_copy_bytes(blob_reader, &state->stream_output.stride, 134 sizeof(state->stream_output.stride)); 135 blob_copy_bytes(blob_reader, &state->stream_output.output, 136 sizeof(state->stream_output.output)); 137 } 138} 139 140void 141st_deserialise_nir_program(struct gl_context *ctx, 142 struct gl_shader_program *shProg, 143 struct gl_program *prog) 144{ 145 struct st_context *st = st_context(ctx); 146 size_t size = prog->driver_cache_blob_size; 147 uint8_t *buffer = (uint8_t *) prog->driver_cache_blob; 148 149 st_set_prog_affected_state_flags(prog); 150 151 /* Avoid reallocation of the program parameter list, because the uniform 152 * storage is only associated with the original parameter list. 153 * This should be enough for Bitmap and DrawPixels constants. 154 */ 155 _mesa_ensure_and_associate_uniform_storage(ctx, shProg, prog, 16); 156 157 assert(prog->driver_cache_blob && prog->driver_cache_blob_size > 0); 158 159 struct blob_reader blob_reader; 160 blob_reader_init(&blob_reader, buffer, size); 161 162 st_release_variants(st, prog); 163 164 if (prog->info.stage == MESA_SHADER_VERTEX) { 165 struct gl_vertex_program *vp = (struct gl_vertex_program *)prog; 166 vp->num_inputs = blob_read_uint32(&blob_reader); 167 vp->vert_attrib_mask = blob_read_uint32(&blob_reader); 168 blob_copy_bytes(&blob_reader, (uint8_t *) vp->result_to_output, 169 sizeof(vp->result_to_output)); 170 } 171 172 if (prog->info.stage == MESA_SHADER_VERTEX || 173 prog->info.stage == MESA_SHADER_TESS_EVAL || 174 prog->info.stage == MESA_SHADER_GEOMETRY) 175 read_stream_out_from_cache(&blob_reader, &prog->state); 176 177 assert(prog->nir == NULL); 178 assert(prog->serialized_nir == NULL); 179 180 prog->state.type = PIPE_SHADER_IR_NIR; 181 prog->serialized_nir_size = blob_read_intptr(&blob_reader); 182 prog->serialized_nir = malloc(prog->serialized_nir_size); 183 blob_copy_bytes(&blob_reader, prog->serialized_nir, prog->serialized_nir_size); 184 prog->shader_program = shProg; 185 186 /* Make sure we don't try to read more data than we wrote. This should 187 * never happen in release builds but its useful to have this check to 188 * catch development bugs. 189 */ 190 if (blob_reader.current != blob_reader.end || blob_reader.overrun) { 191 assert(!"Invalid shader disk cache item!"); 192 193 if (ctx->_Shader->Flags & GLSL_CACHE_INFO) { 194 fprintf(stderr, "Error reading program from cache (invalid " 195 "cache item)\n"); 196 } 197 } 198 199 st_finalize_program(st, prog); 200} 201 202bool 203st_load_nir_from_disk_cache(struct gl_context *ctx, 204 struct gl_shader_program *prog) 205{ 206 if (!ctx->Cache) 207 return false; 208 209 /* If we didn't load the GLSL metadata from cache then we could not have 210 * loaded the NIR either. 211 */ 212 if (prog->data->LinkStatus != LINKING_SKIPPED) 213 return false; 214 215 for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { 216 if (prog->_LinkedShaders[i] == NULL) 217 continue; 218 219 struct gl_program *glprog = prog->_LinkedShaders[i]->Program; 220 st_deserialise_nir_program(ctx, prog, glprog); 221 222 /* We don't need the cached blob anymore so free it */ 223 ralloc_free(glprog->driver_cache_blob); 224 glprog->driver_cache_blob = NULL; 225 glprog->driver_cache_blob_size = 0; 226 227 if (ctx->_Shader->Flags & GLSL_CACHE_INFO) { 228 fprintf(stderr, "%s state tracker IR retrieved from cache\n", 229 _mesa_shader_stage_to_string(i)); 230 } 231 } 232 233 return true; 234} 235 236void 237st_serialise_nir_program_binary(struct gl_context *ctx, 238 struct gl_shader_program *shProg, 239 struct gl_program *prog) 240{ 241 st_serialise_nir_program(ctx, prog); 242} 243