• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (C) 2019 Google, Inc.
3 //
4 // All rights reserved.
5 //
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions
8 // are met:
9 //
10 //    Redistributions of source code must retain the above copyright
11 //    notice, this list of conditions and the following disclaimer.
12 //
13 //    Redistributions in binary form must reproduce the above
14 //    copyright notice, this list of conditions and the following
15 //    disclaimer in the documentation and/or other materials provided
16 //    with the distribution.
17 //
18 //    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
19 //    contributors may be used to endorse or promote products derived
20 //    from this software without specific prior written permission.
21 //
22 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 // POSSIBILITY OF SUCH DAMAGE.
34 //
35 
36 #include <cstdio>
37 #include <cstdint>
38 #include <memory>
39 
40 #ifdef __EMSCRIPTEN__
41 #include <emscripten.h>
42 #endif
43 
44 #include "../../../SPIRV/GlslangToSpv.h"
45 #include "../../../glslang/Public/ShaderLang.h"
46 
47 #ifndef __EMSCRIPTEN__
48 #define EMSCRIPTEN_KEEPALIVE
49 #endif
50 
51 const TBuiltInResource DefaultTBuiltInResource = {
52     /* .MaxLights = */ 32,
53     /* .MaxClipPlanes = */ 6,
54     /* .MaxTextureUnits = */ 32,
55     /* .MaxTextureCoords = */ 32,
56     /* .MaxVertexAttribs = */ 64,
57     /* .MaxVertexUniformComponents = */ 4096,
58     /* .MaxVaryingFloats = */ 64,
59     /* .MaxVertexTextureImageUnits = */ 32,
60     /* .MaxCombinedTextureImageUnits = */ 80,
61     /* .MaxTextureImageUnits = */ 32,
62     /* .MaxFragmentUniformComponents = */ 4096,
63     /* .MaxDrawBuffers = */ 32,
64     /* .MaxVertexUniformVectors = */ 128,
65     /* .MaxVaryingVectors = */ 8,
66     /* .MaxFragmentUniformVectors = */ 16,
67     /* .MaxVertexOutputVectors = */ 16,
68     /* .MaxFragmentInputVectors = */ 15,
69     /* .MinProgramTexelOffset = */ -8,
70     /* .MaxProgramTexelOffset = */ 7,
71     /* .MaxClipDistances = */ 8,
72     /* .MaxComputeWorkGroupCountX = */ 65535,
73     /* .MaxComputeWorkGroupCountY = */ 65535,
74     /* .MaxComputeWorkGroupCountZ = */ 65535,
75     /* .MaxComputeWorkGroupSizeX = */ 1024,
76     /* .MaxComputeWorkGroupSizeY = */ 1024,
77     /* .MaxComputeWorkGroupSizeZ = */ 64,
78     /* .MaxComputeUniformComponents = */ 1024,
79     /* .MaxComputeTextureImageUnits = */ 16,
80     /* .MaxComputeImageUniforms = */ 8,
81     /* .MaxComputeAtomicCounters = */ 8,
82     /* .MaxComputeAtomicCounterBuffers = */ 1,
83     /* .MaxVaryingComponents = */ 60,
84     /* .MaxVertexOutputComponents = */ 64,
85     /* .MaxGeometryInputComponents = */ 64,
86     /* .MaxGeometryOutputComponents = */ 128,
87     /* .MaxFragmentInputComponents = */ 128,
88     /* .MaxImageUnits = */ 8,
89     /* .MaxCombinedImageUnitsAndFragmentOutputs = */ 8,
90     /* .MaxCombinedShaderOutputResources = */ 8,
91     /* .MaxImageSamples = */ 0,
92     /* .MaxVertexImageUniforms = */ 0,
93     /* .MaxTessControlImageUniforms = */ 0,
94     /* .MaxTessEvaluationImageUniforms = */ 0,
95     /* .MaxGeometryImageUniforms = */ 0,
96     /* .MaxFragmentImageUniforms = */ 8,
97     /* .MaxCombinedImageUniforms = */ 8,
98     /* .MaxGeometryTextureImageUnits = */ 16,
99     /* .MaxGeometryOutputVertices = */ 256,
100     /* .MaxGeometryTotalOutputComponents = */ 1024,
101     /* .MaxGeometryUniformComponents = */ 1024,
102     /* .MaxGeometryVaryingComponents = */ 64,
103     /* .MaxTessControlInputComponents = */ 128,
104     /* .MaxTessControlOutputComponents = */ 128,
105     /* .MaxTessControlTextureImageUnits = */ 16,
106     /* .MaxTessControlUniformComponents = */ 1024,
107     /* .MaxTessControlTotalOutputComponents = */ 4096,
108     /* .MaxTessEvaluationInputComponents = */ 128,
109     /* .MaxTessEvaluationOutputComponents = */ 128,
110     /* .MaxTessEvaluationTextureImageUnits = */ 16,
111     /* .MaxTessEvaluationUniformComponents = */ 1024,
112     /* .MaxTessPatchComponents = */ 120,
113     /* .MaxPatchVertices = */ 32,
114     /* .MaxTessGenLevel = */ 64,
115     /* .MaxViewports = */ 16,
116     /* .MaxVertexAtomicCounters = */ 0,
117     /* .MaxTessControlAtomicCounters = */ 0,
118     /* .MaxTessEvaluationAtomicCounters = */ 0,
119     /* .MaxGeometryAtomicCounters = */ 0,
120     /* .MaxFragmentAtomicCounters = */ 8,
121     /* .MaxCombinedAtomicCounters = */ 8,
122     /* .MaxAtomicCounterBindings = */ 1,
123     /* .MaxVertexAtomicCounterBuffers = */ 0,
124     /* .MaxTessControlAtomicCounterBuffers = */ 0,
125     /* .MaxTessEvaluationAtomicCounterBuffers = */ 0,
126     /* .MaxGeometryAtomicCounterBuffers = */ 0,
127     /* .MaxFragmentAtomicCounterBuffers = */ 1,
128     /* .MaxCombinedAtomicCounterBuffers = */ 1,
129     /* .MaxAtomicCounterBufferSize = */ 16384,
130     /* .MaxTransformFeedbackBuffers = */ 4,
131     /* .MaxTransformFeedbackInterleavedComponents = */ 64,
132     /* .MaxCullDistances = */ 8,
133     /* .MaxCombinedClipAndCullDistances = */ 8,
134     /* .MaxSamples = */ 4,
135     /* .maxMeshOutputVerticesNV = */ 256,
136     /* .maxMeshOutputPrimitivesNV = */ 512,
137     /* .maxMeshWorkGroupSizeX_NV = */ 32,
138     /* .maxMeshWorkGroupSizeY_NV = */ 1,
139     /* .maxMeshWorkGroupSizeZ_NV = */ 1,
140     /* .maxTaskWorkGroupSizeX_NV = */ 32,
141     /* .maxTaskWorkGroupSizeY_NV = */ 1,
142     /* .maxTaskWorkGroupSizeZ_NV = */ 1,
143     /* .maxMeshViewCountNV = */ 4,
144     /* .maxDualSourceDrawBuffersEXT = */ 1,
145 
146     /* .limits = */ {
147         /* .nonInductiveForLoops = */ 1,
148         /* .whileLoops = */ 1,
149         /* .doWhileLoops = */ 1,
150         /* .generalUniformIndexing = */ 1,
151         /* .generalAttributeMatrixVectorIndexing = */ 1,
152         /* .generalVaryingIndexing = */ 1,
153         /* .generalSamplerIndexing = */ 1,
154         /* .generalVariableIndexing = */ 1,
155         /* .generalConstantMatrixVectorIndexing = */ 1,
156     }};
157 
158 static bool initialized = false;
159 
160 extern "C" {
161 
162 /*
163  * Takes in a GLSL shader as a string and converts it to SPIR-V in binary form.
164  *
165  * |glsl|          Null-terminated string containing the shader to be converted.
166  * |stage_int|     Magic number indicating the type of shader being processed.
167 *                  Legal values are as follows:
168  *                   Vertex = 0
169  *                   Fragment = 4
170  *                   Compute = 5
171  * |gen_debug|     Flag to indicate if debug information should be generated.
172  * |spirv|         Output parameter for a pointer to the resulting SPIR-V data.
173  * |spirv_len|     Output parameter for the length of the output binary buffer.
174  *
175  * Returns a void* pointer which, if not null, must be destroyed by
176  * destroy_output_buffer.o. (This is not the same pointer returned in |spirv|.)
177  * If null, the compilation failed.
178  */
179 EMSCRIPTEN_KEEPALIVE
convert_glsl_to_spirv(const char * glsl,int stage_int,bool gen_debug,glslang::EShTargetLanguageVersion spirv_version,uint32_t ** spirv,size_t * spirv_len)180 void* convert_glsl_to_spirv(const char* glsl,
181                             int stage_int,
182                             bool gen_debug,
183                             glslang::EShTargetLanguageVersion spirv_version,
184                             uint32_t** spirv,
185                             size_t* spirv_len)
186 {
187     if (glsl == nullptr) {
188         fprintf(stderr, "Input pointer null\n");
189         return nullptr;
190     }
191     if (spirv == nullptr || spirv_len == nullptr) {
192         fprintf(stderr, "Output pointer null\n");
193         return nullptr;
194     }
195     *spirv = nullptr;
196     *spirv_len = 0;
197 
198     if (stage_int != 0 && stage_int != 4 && stage_int != 5) {
199         fprintf(stderr, "Invalid shader stage\n");
200         return nullptr;
201     }
202     EShLanguage stage = static_cast<EShLanguage>(stage_int);
203     switch (spirv_version) {
204         case glslang::EShTargetSpv_1_0:
205         case glslang::EShTargetSpv_1_1:
206         case glslang::EShTargetSpv_1_2:
207         case glslang::EShTargetSpv_1_3:
208         case glslang::EShTargetSpv_1_4:
209         case glslang::EShTargetSpv_1_5:
210             break;
211         default:
212             fprintf(stderr, "Invalid SPIR-V version number\n");
213             return nullptr;
214     }
215 
216     if (!initialized) {
217         glslang::InitializeProcess();
218         initialized = true;
219     }
220 
221     glslang::TShader shader(stage);
222     shader.setStrings(&glsl, 1);
223     shader.setEnvInput(glslang::EShSourceGlsl, stage, glslang::EShClientVulkan, 100);
224     shader.setEnvClient(glslang::EShClientVulkan, glslang::EShTargetVulkan_1_0);
225     shader.setEnvTarget(glslang::EShTargetSpv, spirv_version);
226     if (!shader.parse(&DefaultTBuiltInResource, 100, true, EShMsgDefault)) {
227         fprintf(stderr, "Parse failed\n");
228         fprintf(stderr, "%s\n", shader.getInfoLog());
229         return nullptr;
230     }
231 
232     glslang::TProgram program;
233     program.addShader(&shader);
234     if (!program.link(EShMsgDefault)) {
235         fprintf(stderr, "Link failed\n");
236         fprintf(stderr, "%s\n", program.getInfoLog());
237         return nullptr;
238     }
239 
240     glslang::SpvOptions spvOptions;
241     spvOptions.generateDebugInfo = gen_debug;
242     spvOptions.optimizeSize = false;
243     spvOptions.disassemble = false;
244     spvOptions.validate = false;
245 
246     std::vector<uint32_t>* output = new std::vector<uint32_t>;
247     glslang::GlslangToSpv(*program.getIntermediate(stage), *output, nullptr, &spvOptions);
248 
249     *spirv_len = output->size();
250     *spirv = output->data();
251     return output;
252 }
253 
254 /*
255  * Destroys a buffer created by convert_glsl_to_spirv
256  */
257 EMSCRIPTEN_KEEPALIVE
destroy_output_buffer(void * p)258 void destroy_output_buffer(void* p)
259 {
260     delete static_cast<std::vector<uint32_t>*>(p);
261 }
262 
263 }  // extern "C"
264 
265 /*
266  * For non-Emscripten builds we supply a generic main, so that the glslang.js
267  * build target can generate an executable with a trivial use case instead of
268  * generating a WASM binary. This is done so that there is a target that can be
269  * built and output analyzed using desktop tools, since WASM binaries are
270  * specific to the Emscripten toolchain.
271  */
272 #ifndef __EMSCRIPTEN__
main()273 int main() {
274     const char* input = R"(#version 310 es
275 
276 void main() { })";
277 
278     uint32_t* output;
279     size_t output_len;
280 
281     void* id = convert_glsl_to_spirv(input, 4, false, glslang::EShTargetSpv_1_0, &output, &output_len);
282     assert(output != nullptr);
283     assert(output_len != 0);
284     destroy_output_buffer(id);
285     return 0;
286 }
287 #endif  // ifndef __EMSCRIPTEN__
288