<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Wed, Jan 17, 2018 at 3:31 AM, Alejandro Piñeiro <span dir="ltr"><<a href="mailto:apinheiro@igalia.com" target="_blank">apinheiro@igalia.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">ARB_gl_spirv adds the ability to use SPIR-V binaries, and a new<br>
method, glSpecializeShader. From OpenGL 4.6 spec, section 7.2.1<br>
"Shader Specialization", error table:<br>
<br>
INVALID_VALUE is generated if <pEntryPoint> does not name a valid<br>
entry point for <shader>.<br>
<br>
INVALID_VALUE is generated if any element of <pConstantIndex><br>
refers to a specialization constant that does not exist in the<br>
shader module contained in <shader>.""<br>
<br>
But we are not really interested on creating the nir shader at that<br>
point, and adding nir structures on the gl_program, so at that point<br>
we are just interested on the error checking.<br>
<br>
So we add a new method focused on just checking those errors. It still<br>
needs to parse the binary, but skips what it is not needed, and<br>
doesn't create the nir shader.<br>
<br>
v2: rebase update (spirv_to_nir options added, changes on the warning<br>
logging, and others)<br>
<br>
v3: include passing options on common initialization, doesn't call<br>
setjmp on common_initialization<br>
<br>
</span>v4: (after Jason comments):<br>
* Rename common_initialization to vtn_builder_create<br>
* Move validation method and their helpers to own source file.<br>
* Create own handle_constant_decoration_cb instead of reuse existing one<br>
---<br>
<br>
<br>
I think that I handle all Jason concerns, although I have some minor<br>
doubts:<br>
<br>
* Source file: I moved the validation method and his helpers to a new<br>
source file. The name (compiler/spirv/gl_spirv.c) is debatable.<br>
<br>
* Headers: I didn't add a equivalent header, and I kept the<br>
definition of the method at nir_spirv.h. I also put all the now<br>
shared methods (like handle_decoration) to vtn_private. I hope<br>
that's ok.<br>
<br>
* nir_spirv_specialization: I added the boolean "defined_on_module"<br>
here, but this is only filled on gl_spirv_validation. And at the<br>
same way, data32/data64 is only filled at spirv_to_nir. That sounds<br>
somewhat strange. But at the same time adding a new struct<br>
(something like gl_spirv_validation) with just the id and<br>
"defined_on_module" seemed an overkill. I felt that reuse the<br>
struct was the lesser evil. It is also debatable though.<br>
<br>
<br>
src/compiler/Makefile.sources | 1 +<br>
src/compiler/nir/meson.build | 1 +<br>
src/compiler/spirv/gl_spirv.c | 268 ++++++++++++++++++++++++++++++<wbr>++++++++<br>
src/compiler/spirv/nir_spirv.h | 5 +<br>
src/compiler/spirv/spirv_to_<wbr>nir.c | 83 +++++++-----<br>
src/compiler/spirv/vtn_<wbr>private.h | 10 ++<br>
6 files changed, 338 insertions(+), 30 deletions(-)<br>
create mode 100644 src/compiler/spirv/gl_spirv.c<br>
<br>
diff --git a/src/compiler/Makefile.<wbr>sources b/src/compiler/Makefile.<wbr>sources<br>
index d3f746f5f94..89c632112a2 100644<br>
--- a/src/compiler/Makefile.<wbr>sources<br>
+++ b/src/compiler/Makefile.<wbr>sources<br>
@@ -294,6 +294,7 @@ SPIRV_GENERATED_FILES = \<br>
spirv/vtn_gather_types.c<br>
<br>
SPIRV_FILES = \<br>
+ spirv/gl_spirv.c \<br>
spirv/GLSL.std.450.h \<br>
spirv/nir_spirv.h \<br>
spirv/spirv.h \<br>
diff --git a/src/compiler/nir/meson.build b/src/compiler/nir/meson.build<br>
index 5dd21e6652f..dd8cae59cc4 100644<br>
--- a/src/compiler/nir/meson.build<br>
+++ b/src/compiler/nir/meson.build<br>
@@ -182,6 +182,7 @@ files_libnir = files(<br>
'nir_vla.h',<br>
'nir_worklist.c',<br>
'nir_worklist.h',<br>
+ '../spirv/gl_spirv.c',<br>
'../spirv/GLSL.std.450.h',<br>
'../spirv/nir_spirv.h',<br>
'../spirv/spirv.h',<br>
diff --git a/src/compiler/spirv/gl_spirv.<wbr>c b/src/compiler/spirv/gl_spirv.<wbr>c<br>
new file mode 100644<br>
index 00000000000..e82686bfe0d<br>
--- /dev/null<br>
+++ b/src/compiler/spirv/gl_spirv.<wbr>c<br>
@@ -0,0 +1,268 @@<br>
+/*<br>
+ * Copyright © 2017 Intel Corporation<br>
+ *<br>
+ * Permission is hereby granted, free of charge, to any person obtaining a<br>
+ * copy of this software and associated documentation files (the "Software"),<br>
+ * to deal in the Software without restriction, including without limitation<br>
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,<br>
+ * and/or sell copies of the Software, and to permit persons to whom the<br>
+ * Software is furnished to do so, subject to the following conditions:<br>
+ *<br>
+ * The above copyright notice and this permission notice (including the next<br>
+ * paragraph) shall be included in all copies or substantial portions of the<br>
+ * Software.<br>
+ *<br>
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR<br>
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,<br>
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL<br>
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER<br>
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING<br>
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS<br>
+ * IN THE SOFTWARE.<br>
+ *<br>
+ *<br>
+ */<br>
+<br>
+#include "nir_spirv.h"<br>
+<br>
+#include "vtn_private.h"<br>
+#include "spirv_info.h"<br>
+<br>
<span class="">+static bool<br>
+vtn_validate_preamble_<wbr>instruction(struct vtn_builder *b, SpvOp opcode,<br>
+ const uint32_t *w, unsigned count)<br></span></blockquote><div><br></div><div>I think you could probably re-use all of vtn_handle_preamble_instruction. It would do a bit more than strictly needed (like handle capabilities) but I don't see any harm in it.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">
+{<br>
+ switch (opcode) {<br>
</span>+ case SpvOpSource:<br>
<span class="">+ case SpvOpSourceExtension:<br>
+ case SpvOpSourceContinued:<br>
+ case SpvOpExtension:<br>
+ case SpvOpCapability:<br>
+ case SpvOpExtInstImport:<br>
+ case SpvOpMemoryModel:<br>
+ case SpvOpString:<br>
+ case SpvOpName:<br>
+ case SpvOpMemberName:<br>
+ case SpvOpExecutionMode:<br>
+ case SpvOpDecorationGroup:<br>
+ case SpvOpMemberDecorate:<br>
+ case SpvOpGroupDecorate:<br>
+ case SpvOpGroupMemberDecorate:<br>
+ break;<br>
+<br>
+ case SpvOpEntryPoint:<br>
</span>+ vtn_handle_entry_point(b, w, count);<br>
<span class="">+ break;<br>
+<br>
+ case SpvOpDecorate:<br>
+ vtn_handle_decoration(b, opcode, w, count);<br>
+ break;<br>
+<br>
+ default:<br>
+ return false; /* End of preamble */<br>
+ }<br>
+<br>
+ return true;<br>
+}<br>
+<br>
</span>+static void<br>
+spec_constant_decoration_cb(<wbr>struct vtn_builder *b, struct vtn_value *v,<br>
+ int member, const struct vtn_decoration *dec,<br>
+ void *data)<br>
+{<br>
+ vtn_assert(member == -1);<br>
+ if (dec->decoration != SpvDecorationSpecId)<br>
+ return;<br>
+<br>
+ for (unsigned i = 0; i < b->num_specializations; i++) {<br>
+ if (b->specializations[i].id == dec->literals[0]) {<br>
<span class="">+ b->specializations[i].defined_<wbr>on_module = true;<br></span></blockquote><div><br></div><div>I see you setting this but I don't seeing it getting checked anywhere. Perhaps something got lost in the refactor?<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">
</span>+ return;<br>
+ }<br>
+ }<br>
+}<br>
+<br>
+static void<br>
+vtn_validate_handle_constant(<wbr>struct vtn_builder *b, SpvOp opcode,<br>
<span class="">+ const uint32_t *w, unsigned count)<br>
+{<br>
</span>+ struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_constant);<br>
+<br>
+ switch (opcode) {<br>
+ case SpvOpConstant:<br>
+ case SpvOpConstantNull:<br>
+ case SpvOpSpecConstantComposite:<br>
+ case SpvOpConstantComposite:<br>
+ /* Nothing to do here for gl_spirv needs */<br>
+ break;<br>
+<br>
+ case SpvOpConstantTrue:<br>
+ case SpvOpConstantFalse:<br>
+ case SpvOpSpecConstantTrue:<br>
+ case SpvOpSpecConstantFalse:<br>
+ case SpvOpSpecConstant:<br>
+ case SpvOpSpecConstantOp:<br>
+ vtn_foreach_decoration(b, val, spec_constant_decoration_cb, NULL);<br>
+ break;<br>
+<br>
+ case SpvOpConstantSampler:<br>
+ vtn_fail("OpConstantSampler requires Kernel Capability");<br>
<span class="">+ break;<br>
+<br>
+ default:<br>
</span>+ vtn_fail("Unhandled opcode");<br>
+ }<br>
+}<br>
+<br>
+static bool<br>
+vtn_validate_handle_constant_<wbr>instruction(struct vtn_builder *b, SpvOp opcode,<br>
<span class="">+ const uint32_t *w, unsigned count)<br>
+{<br>
+ switch (opcode) {<br>
</span>+ case SpvOpSource:<br>
+ case SpvOpSourceContinued:<br>
+ case SpvOpSourceExtension:<br>
<span class="">+ case SpvOpExtension:<br>
+ case SpvOpCapability:<br>
+ case SpvOpExtInstImport:<br>
+ case SpvOpMemoryModel:<br>
</span>+ case SpvOpEntryPoint:<br>
+ case SpvOpExecutionMode:<br>
+ case SpvOpString:<br>
<span class="">+ case SpvOpName:<br>
+ case SpvOpMemberName:<br>
</span>+ case SpvOpDecorationGroup:<br>
+ case SpvOpDecorate:<br>
<span class="">+ case SpvOpMemberDecorate:<br>
+ case SpvOpGroupDecorate:<br>
+ case SpvOpGroupMemberDecorate:<br>
</span>+ vtn_fail("Invalid opcode types and variables section");<br>
+ break;<br>
+<br>
+ case SpvOpTypeVoid:<br>
+ case SpvOpTypeBool:<br>
+ case SpvOpTypeInt:<br>
+ case SpvOpTypeFloat:<br>
+ case SpvOpTypeVector:<br>
+ case SpvOpTypeMatrix:<br>
+ case SpvOpTypeImage:<br>
+ case SpvOpTypeSampler:<br>
+ case SpvOpTypeSampledImage:<br>
+ case SpvOpTypeArray:<br>
+ case SpvOpTypeRuntimeArray:<br>
+ case SpvOpTypeStruct:<br>
+ case SpvOpTypeOpaque:<br>
+ case SpvOpTypePointer:<br>
+ case SpvOpTypeFunction:<br>
+ case SpvOpTypeEvent:<br>
+ case SpvOpTypeDeviceEvent:<br>
+ case SpvOpTypeReserveId:<br>
+ case SpvOpTypeQueue:<br>
+ case SpvOpTypePipe:<br>
+ /* We don't need to handle types */<br>
+ break;<br>
+<br>
+ case SpvOpConstantTrue:<br>
+ case SpvOpConstantFalse:<br>
+ case SpvOpConstant:<br>
+ case SpvOpConstantComposite:<br>
+ case SpvOpConstantSampler:<br>
+ case SpvOpConstantNull:<br>
+ case SpvOpSpecConstantTrue:<br>
+ case SpvOpSpecConstantFalse:<br>
+ case SpvOpSpecConstant:<br>
+ case SpvOpSpecConstantComposite:<br>
+ case SpvOpSpecConstantOp:<br>
+ vtn_validate_handle_constant(<wbr>b, opcode, w, count);<br>
+ break;<br>
+<br>
+ case SpvOpUndef:<br>
+ case SpvOpVariable:<br>
+ /* We don't need to handle them */<br>
<span class="">+ break;<br>
+<br>
+ default:<br>
+ return false; /* End of preamble */<br>
+ }<br>
+<br>
+ return true;<br>
+}<br>
+<br>
</span><span class="">+/*<br>
+ * Since OpenGL 4.6 you can use SPIR-V modules directly on OpenGL. One of the<br>
+ * new methods, glSpecializeShader include some possible errors when trying to<br>
+ * use it. From OpenGL 4.6, Section 7.2.1, "Shader Specialization":<br>
+ *<br>
+ * "void SpecializeShaderARB(uint shader,<br>
+ * const char* pEntryPoint,<br>
+ * uint numSpecializationConstants,<br>
+ * const uint* pConstantIndex,<br>
</span>+ * const uint* pConstantValue);<br>
<span class="">+ * <skip><br>
+ *<br>
+ * INVALID_VALUE is generated if <pEntryPoint> does not name a valid<br>
+ * entry point for <shader>.<br>
+ *<br>
+ * An INVALID_VALUE error is generated if any element of pConstantIndex refers<br>
+ * to a specialization constant that does not exist in the shader module<br>
+ * contained in shader."<br>
+ *<br>
+ * We could do those checks on spirv_to_nir, but we are only interested on the<br>
+ * full translation later, during linking. This method is a simplified version<br>
+ * of spirv_to_nir, looking for only the checks needed by SpecializeShader.<br>
+ *<br>
+ * This method returns NULL if no entry point was found, and fill the<br>
+ * nir_spirv_specialization field "defined_on_module" accordingly. Caller<br>
+ * would need to trigger the specific errors.<br>
+ *<br>
+ */<br>
+bool<br>
+gl_spirv_validation(const uint32_t *words, size_t word_count,<br>
+ struct nir_spirv_specialization *spec, unsigned num_spec,<br>
+ gl_shader_stage stage, const char *entry_point_name)<br>
</span><span class="">+{<br>
+ /* vtn_warn/vtn_log uses debug.func. Setting a null to prevent crash. Not<br>
+ * need to print the warnings now, would be done later, on the real<br>
+ * spirv_to_nir<br>
+ */<br>
+ const struct spirv_to_nir_options options = { .debug.func = NULL};<br>
+ const uint32_t *word_end = words + word_count;<br>
+<br>
</span>+ struct vtn_builder *b = vtn_builder_create(words, word_count,<br>
<span class="">+ stage, entry_point_name,<br>
+ &options);<br>
+<br>
</span>+ if (b == NULL)<br>
<span class="">+ return false;<br>
+<br>
+ /* See also _vtn_fail() */<br>
+ if (setjmp(b->fail_jump)) {<br>
+ ralloc_free(b);<br>
+ return false;<br>
+ }<br>
+<br>
</span>+ words+= 5;<br>
<span class="">+<br>
+ /* Search entry point from preamble */<br>
+ words = vtn_foreach_instruction(b, words, word_end,<br>
+ vtn_validate_preamble_<wbr>instruction);<br>
+<br>
+ if (b->entry_point == NULL) {<br>
+ ralloc_free(b);<br>
+ return false;<br>
+ }<br>
+<br>
+ b->specializations = spec;<br>
+ b->num_specializations = num_spec;<br>
+<br>
</span>+ /* Handle constant instructions (we don't need to handle<br>
+ * variables or types for gl_spirv)<br>
<span class="">+ */<br>
+ words = vtn_foreach_instruction(b, words, word_end,<br>
</span>+ vtn_validate_handle_constant_<wbr>instruction);<br>
<span class="">+<br>
+ ralloc_free(b);<br>
+<br>
+ return true;<br>
+}<br>
+<br>
</span><span class="">diff --git a/src/compiler/spirv/nir_<wbr>spirv.h b/src/compiler/spirv/nir_<wbr>spirv.h<br>
index a2c40e57d18..d2766abb7f9 100644<br>
--- a/src/compiler/spirv/nir_<wbr>spirv.h<br>
+++ b/src/compiler/spirv/nir_<wbr>spirv.h<br>
@@ -41,6 +41,7 @@ struct nir_spirv_specialization {<br>
uint32_t data32;<br>
uint64_t data64;<br>
};<br>
+ bool defined_on_module;<br>
};<br>
<br>
enum nir_spirv_debug_level {<br>
@@ -69,6 +70,10 @@ struct spirv_to_nir_options {<br>
} debug;<br>
};<br>
<br>
+bool gl_spirv_validation(const uint32_t *words, size_t word_count,<br>
+ struct nir_spirv_specialization *spec, unsigned num_spec,<br>
+ gl_shader_stage stage, const char *entry_point_name);<br>
+<br>
nir_function *spirv_to_nir(const uint32_t *words, size_t word_count,<br>
struct nir_spirv_specialization *specializations,<br>
unsigned num_specializations,<br>
diff --git a/src/compiler/spirv/spirv_to_<wbr>nir.c b/src/compiler/spirv/spirv_to_<wbr>nir.c<br>
</span>index c6df764682e..67b98fcb08d 100644<br>
--- a/src/compiler/spirv/spirv_to_<wbr>nir.c<br>
+++ b/src/compiler/spirv/spirv_to_<wbr>nir.c<br>
@@ -458,7 +458,7 @@ vtn_foreach_execution_mode(<wbr>struct vtn_builder *b, struct vtn_value *value,<br>
}<br>
}<br>
<br>
-static void<br>
+void<br>
vtn_handle_decoration(struct vtn_builder *b, SpvOp opcode,<br>
<span class=""> const uint32_t *w, unsigned count)<br>
{<br>
</span>@@ -3065,6 +3065,24 @@ stage_for_execution_model(<wbr>struct vtn_builder *b, SpvExecutionModel model)<br>
spirv_capability_to_string(<wbr>cap)); \<br>
} while(0)<br>
<br>
+<br>
+void<br>
+vtn_handle_entry_point(struct vtn_builder *b, const uint32_t *w,<br>
+ unsigned count)<br>
+{<br>
+ struct vtn_value *entry_point = &b->values[w[2]];<br>
+ /* Let this be a name label regardless */<br>
+ unsigned name_words;<br>
+ entry_point->name = vtn_string_literal(b, &w[3], count - 3, &name_words);<br>
+<br>
+ if (strcmp(entry_point->name, b->entry_point_name) != 0 ||<br>
+ stage_for_execution_model(b, w[1]) != b->entry_point_stage)<br>
+ return;<br>
+<br>
+ vtn_assert(b->entry_point == NULL);<br>
+ b->entry_point = entry_point;<br>
+}<br>
+<br>
static bool<br>
<span class=""> vtn_handle_preamble_<wbr>instruction(struct vtn_builder *b, SpvOp opcode,<br>
</span><span class=""> const uint32_t *w, unsigned count)<br>
</span>@@ -3219,20 +3237,9 @@ vtn_handle_preamble_<wbr>instruction(struct vtn_builder *b, SpvOp opcode,<br>
w[2] == SpvMemoryModelGLSL450);<br>
break;<br>
<br>
- case SpvOpEntryPoint: {<br>
- struct vtn_value *entry_point = &b->values[w[2]];<br>
- /* Let this be a name label regardless */<br>
- unsigned name_words;<br>
- entry_point->name = vtn_string_literal(b, &w[3], count - 3, &name_words);<br>
-<br>
- if (strcmp(entry_point->name, b->entry_point_name) != 0 ||<br>
- stage_for_execution_model(b, w[1]) != b->entry_point_stage)<br>
- break;<br>
-<br>
- vtn_assert(b->entry_point == NULL);<br>
- b->entry_point = entry_point;<br>
+ case SpvOpEntryPoint:<br>
+ vtn_handle_entry_point(b, w, count);<br>
break;<br>
- }<br>
<br>
case SpvOpString:<br>
vtn_push_value(b, w[1], vtn_value_type_string)->str =<br>
@@ -3775,12 +3782,10 @@ vtn_handle_body_instruction(<wbr>struct vtn_builder *b, SpvOp opcode,<br>
<span class=""> return true;<br>
}<br>
<br>
-nir_function *<br>
-spirv_to_nir(const uint32_t *words, size_t word_count,<br>
- struct nir_spirv_specialization *spec, unsigned num_spec,<br>
- gl_shader_stage stage, const char *entry_point_name,<br>
- const struct spirv_to_nir_options *options,<br>
- const nir_shader_compiler_options *nir_options)<br>
</span>+struct vtn_builder*<br>
+vtn_builder_create(const uint32_t *words, size_t word_count,<br>
<span class="">+ gl_shader_stage stage, const char *entry_point_name,<br>
+ const struct spirv_to_nir_options *options)<br></span></blockquote><div><br></div><div>Might be worth making this bit of refactoring its own patch. I don't care that much though.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">
</span><span class=""> {<br>
/* Initialize the stn_builder object */<br>
struct vtn_builder *b = rzalloc(NULL, struct vtn_builder);<br>
</span>@@ -3794,14 +3799,6 @@ spirv_to_nir(const uint32_t *words, size_t word_count,<br>
<span class=""> b->entry_point_name = entry_point_name;<br>
b->options = options;<br>
<br>
- /* See also _vtn_fail() */<br>
- if (setjmp(b->fail_jump)) {<br>
- ralloc_free(b);<br>
- return NULL;<br>
- }<br>
-<br>
- const uint32_t *word_end = words + word_count;<br>
-<br>
/* Handle the SPIR-V header (first 4 dwords) */<br>
vtn_assert(word_count > 5);<br>
<br>
</span>@@ -3811,11 +3808,37 @@ spirv_to_nir(const uint32_t *words, size_t word_count,<br>
<span class=""> unsigned value_id_bound = words[3];<br>
vtn_assert(words[4] == 0);<br>
<br>
- words+= 5;<br>
-<br>
b->value_id_bound = value_id_bound;<br>
b->values = rzalloc_array(b, struct vtn_value, value_id_bound);<br>
<br>
+ return b;<br>
+}<br>
+<br>
</span><span class="">+nir_function *<br>
+spirv_to_nir(const uint32_t *words, size_t word_count,<br>
+ struct nir_spirv_specialization *spec, unsigned num_spec,<br>
+ gl_shader_stage stage, const char *entry_point_name,<br>
+ const struct spirv_to_nir_options *options,<br>
+ const nir_shader_compiler_options *nir_options)<br>
+<br>
+{<br>
+ const uint32_t *word_end = words + word_count;<br>
+<br>
</span>+ struct vtn_builder *b = vtn_builder_create(words, word_count,<br>
<span class="">+ stage, entry_point_name,<br>
+ options);<br>
+<br>
</span><span class="">+ if (b == NULL)<br>
+ return NULL;<br>
</span><span class="">+<br>
+ /* See also _vtn_fail() */<br>
+ if (setjmp(b->fail_jump)) {<br>
+ ralloc_free(b);<br>
</span>+ return NULL;<br>
+ }<br>
<span class="">+<br>
+ words+= 5;<br>
+<br>
/* Handle all the preamble instructions */<br>
words = vtn_foreach_instruction(b, words, word_end,<br>
vtn_handle_preamble_<wbr>instruction);<br>
</span>diff --git a/src/compiler/spirv/vtn_<wbr>private.h b/src/compiler/spirv/vtn_<wbr>private.h<br>
index 3e49df4dac8..04c59a160d0 100644<br>
--- a/src/compiler/spirv/vtn_<wbr>private.h<br>
+++ b/src/compiler/spirv/vtn_<wbr>private.h<br>
@@ -710,6 +710,16 @@ void vtn_handle_alu(struct vtn_builder *b, SpvOp opcode,<br>
bool vtn_handle_glsl450_<wbr>instruction(struct vtn_builder *b, uint32_t ext_opcode,<br>
const uint32_t *words, unsigned count);<br>
<br>
+struct vtn_builder* vtn_builder_create(const uint32_t *words, size_t word_count,<br>
<span class="">+ gl_shader_stage stage, const char *entry_point_name,<br>
</span>+ const struct spirv_to_nir_options *options);<br>
+<br>
+void vtn_handle_entry_point(struct vtn_builder *b, const uint32_t *w,<br>
+ unsigned count);<br>
+<br>
+void vtn_handle_decoration(struct vtn_builder *b, SpvOp opcode,<br>
<span class="">+ const uint32_t *w, unsigned count);<br>
+<br>
</span> static inline uint32_t<br>
vtn_align_u32(uint32_t v, uint32_t a)<br>
{<br>
<span class="HOEnZb"><font color="#888888">--<br>
2.11.0<br>
<br>
</font></span></blockquote></div><br></div></div>