• 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     /* .maxMeshOutputVerticesEXT = */ 256,
145     /* .maxMeshOutputPrimitivesEXT = */ 512,
146     /* .maxMeshWorkGroupSizeX_EXT = */ 32,
147     /* .maxMeshWorkGroupSizeY_EXT = */ 1,
148     /* .maxMeshWorkGroupSizeZ_EXT = */ 1,
149     /* .maxTaskWorkGroupSizeX_EXT = */ 32,
150     /* .maxTaskWorkGroupSizeY_EXT = */ 1,
151     /* .maxTaskWorkGroupSizeZ_EXT = */ 1,
152     /* .maxMeshViewCountEXT = */ 4,
153     /* .maxDualSourceDrawBuffersEXT = */ 1,
154 
155     /* .limits = */ {
156         /* .nonInductiveForLoops = */ 1,
157         /* .whileLoops = */ 1,
158         /* .doWhileLoops = */ 1,
159         /* .generalUniformIndexing = */ 1,
160         /* .generalAttributeMatrixVectorIndexing = */ 1,
161         /* .generalVaryingIndexing = */ 1,
162         /* .generalSamplerIndexing = */ 1,
163         /* .generalVariableIndexing = */ 1,
164         /* .generalConstantMatrixVectorIndexing = */ 1,
165     }};
166 
167 static bool initialized = false;
168 
169 extern "C" {
170 
171 /*
172  * Takes in a GLSL shader as a string and converts it to SPIR-V in binary form.
173  *
174  * |glsl|          Null-terminated string containing the shader to be converted.
175  * |stage_int|     Magic number indicating the type of shader being processed.
176 *                  Legal values are as follows:
177  *                   Vertex = 0
178  *                   Fragment = 4
179  *                   Compute = 5
180  * |gen_debug|     Flag to indicate if debug information should be generated.
181  * |spirv|         Output parameter for a pointer to the resulting SPIR-V data.
182  * |spirv_len|     Output parameter for the length of the output binary buffer.
183  *
184  * Returns a void* pointer which, if not null, must be destroyed by
185  * destroy_output_buffer.o. (This is not the same pointer returned in |spirv|.)
186  * If null, the compilation failed.
187  */
188 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)189 void* convert_glsl_to_spirv(const char* glsl,
190                             int stage_int,
191                             bool gen_debug,
192                             glslang::EShTargetLanguageVersion spirv_version,
193                             uint32_t** spirv,
194                             size_t* spirv_len)
195 {
196     if (glsl == nullptr) {
197         fprintf(stderr, "Input pointer null\n");
198         return nullptr;
199     }
200     if (spirv == nullptr || spirv_len == nullptr) {
201         fprintf(stderr, "Output pointer null\n");
202         return nullptr;
203     }
204     *spirv = nullptr;
205     *spirv_len = 0;
206 
207     if (stage_int != 0 && stage_int != 4 && stage_int != 5) {
208         fprintf(stderr, "Invalid shader stage\n");
209         return nullptr;
210     }
211     EShLanguage stage = static_cast<EShLanguage>(stage_int);
212     switch (spirv_version) {
213         case glslang::EShTargetSpv_1_0:
214         case glslang::EShTargetSpv_1_1:
215         case glslang::EShTargetSpv_1_2:
216         case glslang::EShTargetSpv_1_3:
217         case glslang::EShTargetSpv_1_4:
218         case glslang::EShTargetSpv_1_5:
219             break;
220         default:
221             fprintf(stderr, "Invalid SPIR-V version number\n");
222             return nullptr;
223     }
224 
225     if (!initialized) {
226         glslang::InitializeProcess();
227         initialized = true;
228     }
229 
230     glslang::TShader shader(stage);
231     shader.setStrings(&glsl, 1);
232     shader.setEnvInput(glslang::EShSourceGlsl, stage, glslang::EShClientVulkan, 100);
233     shader.setEnvClient(glslang::EShClientVulkan, glslang::EShTargetVulkan_1_0);
234     shader.setEnvTarget(glslang::EShTargetSpv, spirv_version);
235     if (!shader.parse(&DefaultTBuiltInResource, 100, true, EShMsgDefault)) {
236         fprintf(stderr, "Parse failed\n");
237         fprintf(stderr, "%s\n", shader.getInfoLog());
238         return nullptr;
239     }
240 
241     glslang::TProgram program;
242     program.addShader(&shader);
243     if (!program.link(EShMsgDefault)) {
244         fprintf(stderr, "Link failed\n");
245         fprintf(stderr, "%s\n", program.getInfoLog());
246         return nullptr;
247     }
248 
249     glslang::SpvOptions spvOptions;
250     spvOptions.generateDebugInfo = gen_debug;
251     spvOptions.optimizeSize = false;
252     spvOptions.disassemble = false;
253     spvOptions.validate = false;
254 
255     std::vector<uint32_t>* output = new std::vector<uint32_t>;
256     glslang::GlslangToSpv(*program.getIntermediate(stage), *output, nullptr, &spvOptions);
257 
258     *spirv_len = output->size();
259     *spirv = output->data();
260     return output;
261 }
262 
263 /*
264  * Destroys a buffer created by convert_glsl_to_spirv
265  */
266 EMSCRIPTEN_KEEPALIVE
destroy_output_buffer(void * p)267 void destroy_output_buffer(void* p)
268 {
269     delete static_cast<std::vector<uint32_t>*>(p);
270 }
271 
272 }  // extern "C"
273 
274 /*
275  * For non-Emscripten builds we supply a generic main, so that the glslang.js
276  * build target can generate an executable with a trivial use case instead of
277  * generating a WASM binary. This is done so that there is a target that can be
278  * built and output analyzed using desktop tools, since WASM binaries are
279  * specific to the Emscripten toolchain.
280  */
281 #ifndef __EMSCRIPTEN__
main()282 int main() {
283     const char* input = R"(#version 310 es
284 
285 void main() { })";
286 
287     uint32_t* output;
288     size_t output_len;
289 
290     void* id = convert_glsl_to_spirv(input, 4, false, glslang::EShTargetSpv_1_0, &output, &output_len);
291     assert(output != nullptr);
292     assert(output_len != 0);
293     destroy_output_buffer(id);
294     return 0;
295 }
296 #endif  // ifndef __EMSCRIPTEN__
297