2 * Copyright © 2017 Timothy Arceri
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:
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
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.
26 #include "st_program.h"
27 #include "st_shader_cache.h"
28 #include "compiler/glsl/program.h"
29 #include "pipe/p_shader_tokens.h"
30 #include "program/ir_to_mesa.h"
31 #include "util/u_memory.h"
34 write_stream_out_to_cache(struct blob
*blob
,
35 struct pipe_shader_state
*tgsi
)
37 blob_write_bytes(blob
, &tgsi
->stream_output
,
38 sizeof(tgsi
->stream_output
));
42 write_tgsi_to_cache(struct blob
*blob
, const struct tgsi_token
*tokens
,
43 struct gl_program
*prog
, unsigned num_tokens
)
45 blob_write_uint32(blob
, num_tokens
);
46 blob_write_bytes(blob
, tokens
, num_tokens
* sizeof(struct tgsi_token
));
48 prog
->driver_cache_blob
= ralloc_size(NULL
, blob
->size
);
49 memcpy(prog
->driver_cache_blob
, blob
->data
, blob
->size
);
50 prog
->driver_cache_blob_size
= blob
->size
;
54 * Store tgsi and any other required state in on-disk shader cache.
57 st_store_tgsi_in_disk_cache(struct st_context
*st
, struct gl_program
*prog
)
62 /* Exit early when we are dealing with a ff shader with no source file to
63 * generate a source from.
65 static const char zero
[sizeof(prog
->sh
.data
->sha1
)] = {0};
66 if (memcmp(prog
->sh
.data
->sha1
, zero
, sizeof(prog
->sh
.data
->sha1
)) == 0)
72 switch (prog
->info
.stage
) {
73 case MESA_SHADER_VERTEX
: {
74 struct st_vertex_program
*stvp
= (struct st_vertex_program
*) prog
;
76 blob_write_uint32(&blob
, stvp
->num_inputs
);
77 blob_write_bytes(&blob
, stvp
->index_to_input
,
78 sizeof(stvp
->index_to_input
));
79 blob_write_bytes(&blob
, stvp
->result_to_output
,
80 sizeof(stvp
->result_to_output
));
82 write_stream_out_to_cache(&blob
, &stvp
->tgsi
);
83 write_tgsi_to_cache(&blob
, stvp
->tgsi
.tokens
, prog
,
84 stvp
->num_tgsi_tokens
);
87 case MESA_SHADER_TESS_CTRL
:
88 case MESA_SHADER_TESS_EVAL
:
89 case MESA_SHADER_GEOMETRY
: {
90 struct st_common_program
*stcp
= (struct st_common_program
*) prog
;
92 write_stream_out_to_cache(&blob
, &stcp
->tgsi
);
93 write_tgsi_to_cache(&blob
, stcp
->tgsi
.tokens
, prog
,
94 stcp
->num_tgsi_tokens
);
97 case MESA_SHADER_FRAGMENT
: {
98 struct st_fragment_program
*stfp
= (struct st_fragment_program
*) prog
;
100 write_tgsi_to_cache(&blob
, stfp
->tgsi
.tokens
, prog
,
101 stfp
->num_tgsi_tokens
);
104 case MESA_SHADER_COMPUTE
: {
105 struct st_compute_program
*stcp
= (struct st_compute_program
*) prog
;
107 write_tgsi_to_cache(&blob
, stcp
->tgsi
.prog
, prog
,
108 stcp
->num_tgsi_tokens
);
112 unreachable("Unsupported stage");
115 if (st
->ctx
->_Shader
->Flags
& GLSL_CACHE_INFO
) {
116 fprintf(stderr
, "putting %s tgsi_tokens in cache\n",
117 _mesa_shader_stage_to_string(prog
->info
.stage
));
124 read_stream_out_from_cache(struct blob_reader
*blob_reader
,
125 struct pipe_shader_state
*tgsi
)
127 blob_copy_bytes(blob_reader
, (uint8_t *) &tgsi
->stream_output
,
128 sizeof(tgsi
->stream_output
));
132 read_tgsi_from_cache(struct blob_reader
*blob_reader
,
133 const struct tgsi_token
**tokens
)
135 uint32_t num_tokens
= blob_read_uint32(blob_reader
);
136 unsigned tokens_size
= num_tokens
* sizeof(struct tgsi_token
);
137 *tokens
= (const struct tgsi_token
*) MALLOC(tokens_size
);
138 blob_copy_bytes(blob_reader
, (uint8_t *) *tokens
, tokens_size
);
142 st_load_tgsi_from_disk_cache(struct gl_context
*ctx
,
143 struct gl_shader_program
*prog
)
148 /* If we didn't load the GLSL metadata from cache then we could not have
149 * loaded the tgsi either.
151 if (prog
->data
->LinkStatus
!= linking_skipped
)
154 struct st_context
*st
= st_context(ctx
);
155 for (unsigned i
= 0; i
< MESA_SHADER_STAGES
; i
++) {
156 if (prog
->_LinkedShaders
[i
] == NULL
)
159 struct gl_program
*glprog
= prog
->_LinkedShaders
[i
]->Program
;
161 size_t size
= glprog
->driver_cache_blob_size
;
162 uint8_t *buffer
= (uint8_t *) glprog
->driver_cache_blob
;
164 struct blob_reader blob_reader
;
165 blob_reader_init(&blob_reader
, buffer
, size
);
167 switch (glprog
->info
.stage
) {
168 case MESA_SHADER_VERTEX
: {
169 struct st_vertex_program
*stvp
= (struct st_vertex_program
*) glprog
;
171 st_release_vp_variants(st
, stvp
);
173 stvp
->num_inputs
= blob_read_uint32(&blob_reader
);
174 blob_copy_bytes(&blob_reader
, (uint8_t *) stvp
->index_to_input
,
175 sizeof(stvp
->index_to_input
));
176 blob_copy_bytes(&blob_reader
, (uint8_t *) stvp
->result_to_output
,
177 sizeof(stvp
->result_to_output
));
179 read_stream_out_from_cache(&blob_reader
, &stvp
->tgsi
);
180 read_tgsi_from_cache(&blob_reader
, &stvp
->tgsi
.tokens
);
183 st
->dirty
|= ST_NEW_VERTEX_PROGRAM(st
, stvp
);
187 case MESA_SHADER_TESS_CTRL
: {
188 struct st_common_program
*sttcp
= st_common_program(glprog
);
190 st_release_basic_variants(st
, sttcp
->Base
.Target
,
191 &sttcp
->variants
, &sttcp
->tgsi
);
193 read_stream_out_from_cache(&blob_reader
, &sttcp
->tgsi
);
194 read_tgsi_from_cache(&blob_reader
, &sttcp
->tgsi
.tokens
);
196 if (st
->tcp
== sttcp
)
197 st
->dirty
|= sttcp
->affected_states
;
201 case MESA_SHADER_TESS_EVAL
: {
202 struct st_common_program
*sttep
= st_common_program(glprog
);
204 st_release_basic_variants(st
, sttep
->Base
.Target
,
205 &sttep
->variants
, &sttep
->tgsi
);
207 read_stream_out_from_cache(&blob_reader
, &sttep
->tgsi
);
208 read_tgsi_from_cache(&blob_reader
, &sttep
->tgsi
.tokens
);
210 if (st
->tep
== sttep
)
211 st
->dirty
|= sttep
->affected_states
;
215 case MESA_SHADER_GEOMETRY
: {
216 struct st_common_program
*stgp
= st_common_program(glprog
);
218 st_release_basic_variants(st
, stgp
->Base
.Target
, &stgp
->variants
,
221 read_stream_out_from_cache(&blob_reader
, &stgp
->tgsi
);
222 read_tgsi_from_cache(&blob_reader
, &stgp
->tgsi
.tokens
);
225 st
->dirty
|= stgp
->affected_states
;
229 case MESA_SHADER_FRAGMENT
: {
230 struct st_fragment_program
*stfp
=
231 (struct st_fragment_program
*) glprog
;
233 st_release_fp_variants(st
, stfp
);
235 read_tgsi_from_cache(&blob_reader
, &stfp
->tgsi
.tokens
);
238 st
->dirty
|= stfp
->affected_states
;
242 case MESA_SHADER_COMPUTE
: {
243 struct st_compute_program
*stcp
=
244 (struct st_compute_program
*) glprog
;
246 st_release_cp_variants(st
, stcp
);
248 read_tgsi_from_cache(&blob_reader
,
249 (const struct tgsi_token
**) &stcp
->tgsi
.prog
);
251 stcp
->tgsi
.req_local_mem
= stcp
->Base
.info
.cs
.shared_size
;
252 stcp
->tgsi
.req_private_mem
= 0;
253 stcp
->tgsi
.req_input_mem
= 0;
256 st
->dirty
|= stcp
->affected_states
;
261 unreachable("Unsupported stage");
264 /* Make sure we don't try to read more data than we wrote. This should
265 * never happen in release builds but its useful to have this check to
266 * catch development bugs.
268 if (blob_reader
.current
!= blob_reader
.end
|| blob_reader
.overrun
) {
269 assert(!"Invalid TGSI shader disk cache item!");
271 if (ctx
->_Shader
->Flags
& GLSL_CACHE_INFO
) {
272 fprintf(stderr
, "Error reading program from cache (invalid "
273 "TGSI cache item)\n");
277 if (ctx
->_Shader
->Flags
& GLSL_CACHE_INFO
) {
278 fprintf(stderr
, "%s tgsi_tokens retrieved from cache\n",
279 _mesa_shader_stage_to_string(i
));
282 st_set_prog_affected_state_flags(glprog
);
283 _mesa_associate_uniform_storage(ctx
, prog
, glprog
, false);
285 /* Create Gallium shaders now instead of on demand. */
286 if (ST_DEBUG
& DEBUG_PRECOMPILE
||
287 st
->shader_has_one_variant
[glprog
->info
.stage
])
288 st_precompile_shader_variant(st
, glprog
);
290 /* We don't need the cached blob anymore so free it */
291 ralloc_free(glprog
->driver_cache_blob
);
292 glprog
->driver_cache_blob
= NULL
;
293 glprog
->driver_cache_blob_size
= 0;