2 * Mesa 3-D graphics library
4 * Copyright (c) 2017 Intel Corporation
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
26 * \file program_binary.c
28 * Helper functions for serializing a binary program.
32 #include "compiler/blob.h"
33 #include "compiler/glsl/serialize.h"
34 #include "main/errors.h"
35 #include "main/mtypes.h"
36 #include "util/crc32.h"
37 #include "program_binary.h"
38 #include "program/prog_parameter.h"
41 * Mesa supports one binary format, but it must differentiate between formats
42 * produced by different drivers and different Mesa versions.
44 * Mesa uses a uint32_t value to specify an internal format. The only format
45 * defined has one uint32_t value of 0, followed by 20 bytes specifying a sha1
46 * that uniquely identifies the Mesa driver type and version.
49 struct program_binary_header
{
50 /* If internal_format is 0, it must be followed by the 20 byte sha1 that
51 * identifies the Mesa driver and version supported. If we want to support
52 * something besides a sha1, then a new internal_format value can be added.
54 uint32_t internal_format
;
56 /* Fields following sha1 can be changed since the sha1 will guarantee that
57 * the binary only works with the same Mesa version.
64 * Returns the header size needed for a binary
67 get_program_binary_header_size(void)
69 return sizeof(struct program_binary_header
);
73 write_program_binary(const void *payload
, unsigned payload_size
,
74 const void *sha1
, void *binary
, unsigned binary_size
,
75 GLenum
*binary_format
)
77 struct program_binary_header
*hdr
= binary
;
79 if (binary_size
< sizeof(*hdr
))
82 /* binary_size is the size of the buffer provided by the application.
83 * Make sure our program (payload) will fit in the buffer.
85 if (payload_size
> binary_size
- sizeof(*hdr
))
88 hdr
->internal_format
= 0;
89 memcpy(hdr
->sha1
, sha1
, sizeof(hdr
->sha1
));
90 memcpy(hdr
+ 1, payload
, payload_size
);
91 hdr
->size
= payload_size
;
93 hdr
->crc32
= util_hash_crc32(hdr
+ 1, payload_size
);
94 *binary_format
= GL_PROGRAM_BINARY_FORMAT_MESA
;
100 simple_header_checks(const struct program_binary_header
*hdr
, unsigned length
)
102 if (hdr
== NULL
|| length
< sizeof(*hdr
))
105 if (hdr
->internal_format
!= 0)
112 check_crc32(const struct program_binary_header
*hdr
, unsigned length
)
117 crc32_len
= hdr
->size
;
118 if (crc32_len
> length
- sizeof(*hdr
))
121 crc32
= util_hash_crc32(hdr
+ 1, crc32_len
);
122 if (hdr
->crc32
!= crc32
)
129 is_program_binary_valid(GLenum binary_format
, const void *sha1
,
130 const struct program_binary_header
*hdr
,
133 if (binary_format
!= GL_PROGRAM_BINARY_FORMAT_MESA
)
136 if (!simple_header_checks(hdr
, length
))
139 if (memcmp(hdr
->sha1
, sha1
, sizeof(hdr
->sha1
)) != 0)
142 if (!check_crc32(hdr
, length
))
149 * Returns the payload within the binary.
151 * If NULL is returned, then the binary not supported. If non-NULL is
152 * returned, it will be a pointer contained within the specified `binary`
155 * This can be used to access the payload of `binary` during the
156 * glProgramBinary call.
159 get_program_binary_payload(GLenum binary_format
, const void *sha1
,
160 const void *binary
, unsigned length
)
162 const struct program_binary_header
*hdr
= binary
;
163 if (!is_program_binary_valid(binary_format
, sha1
, hdr
, length
))
165 return (const uint8_t*)binary
+ sizeof(*hdr
);
169 write_program_payload(struct gl_context
*ctx
, struct blob
*blob
,
170 struct gl_shader_program
*sh_prog
)
172 bool serialize
[MESA_SHADER_STAGES
];
173 for (unsigned stage
= 0; stage
< MESA_SHADER_STAGES
; stage
++) {
174 struct gl_linked_shader
*shader
= sh_prog
->_LinkedShaders
[stage
];
175 serialize
[stage
] = shader
&& shader
->Program
->driver_cache_blob
== NULL
;
176 if (serialize
[stage
])
177 ctx
->Driver
.ProgramBinarySerializeDriverBlob(ctx
, shader
->Program
);
180 serialize_glsl_program(blob
, ctx
, sh_prog
);
182 for (unsigned stage
= 0; stage
< MESA_SHADER_STAGES
; stage
++) {
183 if (!serialize
[stage
])
186 struct gl_program
*prog
= sh_prog
->_LinkedShaders
[stage
]->Program
;
187 ralloc_free(prog
->driver_cache_blob
);
188 prog
->driver_cache_blob
= NULL
;
189 prog
->driver_cache_blob_size
= 0;
194 read_program_payload(struct gl_context
*ctx
, struct blob_reader
*blob
,
195 GLenum binary_format
, struct gl_shader_program
*sh_prog
)
197 if (!deserialize_glsl_program(blob
, ctx
, sh_prog
))
201 for (stage
= 0; stage
< ARRAY_SIZE(sh_prog
->_LinkedShaders
); stage
++) {
202 struct gl_linked_shader
*shader
= sh_prog
->_LinkedShaders
[stage
];
206 ctx
->Driver
.ProgramBinaryDeserializeDriverBlob(ctx
, sh_prog
,
214 _mesa_get_program_binary_length(struct gl_context
*ctx
,
215 struct gl_shader_program
*sh_prog
,
219 blob_init_fixed(&blob
, NULL
, SIZE_MAX
);
220 write_program_payload(ctx
, &blob
, sh_prog
);
221 *length
= get_program_binary_header_size() + blob
.size
;
226 _mesa_get_program_binary(struct gl_context
*ctx
,
227 struct gl_shader_program
*sh_prog
,
228 GLsizei buf_size
, GLsizei
*length
,
229 GLenum
*binary_format
, GLvoid
*binary
)
232 uint8_t driver_sha1
[20];
233 unsigned header_size
= get_program_binary_header_size();
235 ctx
->Driver
.GetProgramBinaryDriverSHA1(ctx
, driver_sha1
);
239 if (buf_size
< header_size
)
242 write_program_payload(ctx
, &blob
, sh_prog
);
243 if (blob
.size
+ header_size
> buf_size
||
247 bool written
= write_program_binary(blob
.data
, blob
.size
, driver_sha1
,
248 binary
, buf_size
, binary_format
);
249 if (!written
|| blob
.out_of_memory
)
252 *length
= header_size
+ blob
.size
;
258 _mesa_error(ctx
, GL_INVALID_OPERATION
,
259 "glGetProgramBinary(buffer too small)");
265 _mesa_program_binary(struct gl_context
*ctx
, struct gl_shader_program
*sh_prog
,
266 GLenum binary_format
, const GLvoid
*binary
,
269 uint8_t driver_sha1
[20];
270 unsigned header_size
= get_program_binary_header_size();
272 ctx
->Driver
.GetProgramBinaryDriverSHA1(ctx
, driver_sha1
);
274 const void *payload
= get_program_binary_payload(binary_format
, driver_sha1
,
277 if (payload
== NULL
) {
278 sh_prog
->data
->LinkStatus
= linking_failure
;
282 struct blob_reader blob
;
283 blob_reader_init(&blob
, payload
, length
- header_size
);
285 if (!read_program_payload(ctx
, &blob
, binary_format
, sh_prog
)) {
286 sh_prog
->data
->LinkStatus
= linking_failure
;
290 sh_prog
->data
->LinkStatus
= linking_success
;