• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * This file is part of FFmpeg.
3  *
4  * FFmpeg is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * FFmpeg is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with FFmpeg; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 #include <pthread.h>
20 
21 extern "C" {
22 #include "libavutil/mem.h"
23 #include "libavutil/avassert.h"
24 }
25 
26 #include <glslang/Include/ResourceLimits.h>
27 #include <glslang/Public/ShaderLang.h>
28 #include <glslang/SPIRV/GlslangToSpv.h>
29 
30 #include "glslang.h"
31 
32 using namespace glslang;
33 
34 static pthread_mutex_t glslang_mutex = PTHREAD_MUTEX_INITIALIZER;
35 static int glslang_refcount = 0;
36 
37 /* We require Vulkan 1.1 */
38 #define GLSL_VERSION EShTargetVulkan_1_1
39 
40 /* Vulkan 1.1 implementations require SPIR-V 1.3 to be implemented */
41 #define SPIRV_VERSION EShTargetSpv_1_3
42 
43 // Taken from glslang's examples, which apparently generally bases the choices
44 // on OpenGL specification limits
45 static const TBuiltInResource DefaultTBuiltInResource = {
46     /* .MaxLights = */ 32,
47     /* .MaxClipPlanes = */ 6,
48     /* .MaxTextureUnits = */ 32,
49     /* .MaxTextureCoords = */ 32,
50     /* .MaxVertexAttribs = */ 64,
51     /* .MaxVertexUniformComponents = */ 4096,
52     /* .MaxVaryingFloats = */ 64,
53     /* .MaxVertexTextureImageUnits = */ 32,
54     /* .MaxCombinedTextureImageUnits = */ 80,
55     /* .MaxTextureImageUnits = */ 32,
56     /* .MaxFragmentUniformComponents = */ 4096,
57     /* .MaxDrawBuffers = */ 32,
58     /* .MaxVertexUniformVectors = */ 128,
59     /* .MaxVaryingVectors = */ 8,
60     /* .MaxFragmentUniformVectors = */ 16,
61     /* .MaxVertexOutputVectors = */ 16,
62     /* .MaxFragmentInputVectors = */ 15,
63     /* .MinProgramTexelOffset = */ -8,
64     /* .MaxProgramTexelOffset = */ 7,
65     /* .MaxClipDistances = */ 8,
66     /* .MaxComputeWorkGroupCountX = */ 65535,
67     /* .MaxComputeWorkGroupCountY = */ 65535,
68     /* .MaxComputeWorkGroupCountZ = */ 65535,
69     /* .MaxComputeWorkGroupSizeX = */ 1024,
70     /* .MaxComputeWorkGroupSizeY = */ 1024,
71     /* .MaxComputeWorkGroupSizeZ = */ 64,
72     /* .MaxComputeUniformComponents = */ 1024,
73     /* .MaxComputeTextureImageUnits = */ 16,
74     /* .MaxComputeImageUniforms = */ 8,
75     /* .MaxComputeAtomicCounters = */ 8,
76     /* .MaxComputeAtomicCounterBuffers = */ 1,
77     /* .MaxVaryingComponents = */ 60,
78     /* .MaxVertexOutputComponents = */ 64,
79     /* .MaxGeometryInputComponents = */ 64,
80     /* .MaxGeometryOutputComponents = */ 128,
81     /* .MaxFragmentInputComponents = */ 128,
82     /* .MaxImageUnits = */ 8,
83     /* .MaxCombinedImageUnitsAndFragmentOutputs = */ 8,
84     /* .MaxCombinedShaderOutputResources = */ 8,
85     /* .MaxImageSamples = */ 0,
86     /* .MaxVertexImageUniforms = */ 0,
87     /* .MaxTessControlImageUniforms = */ 0,
88     /* .MaxTessEvaluationImageUniforms = */ 0,
89     /* .MaxGeometryImageUniforms = */ 0,
90     /* .MaxFragmentImageUniforms = */ 8,
91     /* .MaxCombinedImageUniforms = */ 8,
92     /* .MaxGeometryTextureImageUnits = */ 16,
93     /* .MaxGeometryOutputVertices = */ 256,
94     /* .MaxGeometryTotalOutputComponents = */ 1024,
95     /* .MaxGeometryUniformComponents = */ 1024,
96     /* .MaxGeometryVaryingComponents = */ 64,
97     /* .MaxTessControlInputComponents = */ 128,
98     /* .MaxTessControlOutputComponents = */ 128,
99     /* .MaxTessControlTextureImageUnits = */ 16,
100     /* .MaxTessControlUniformComponents = */ 1024,
101     /* .MaxTessControlTotalOutputComponents = */ 4096,
102     /* .MaxTessEvaluationInputComponents = */ 128,
103     /* .MaxTessEvaluationOutputComponents = */ 128,
104     /* .MaxTessEvaluationTextureImageUnits = */ 16,
105     /* .MaxTessEvaluationUniformComponents = */ 1024,
106     /* .MaxTessPatchComponents = */ 120,
107     /* .MaxPatchVertices = */ 32,
108     /* .MaxTessGenLevel = */ 64,
109     /* .MaxViewports = */ 16,
110     /* .MaxVertexAtomicCounters = */ 0,
111     /* .MaxTessControlAtomicCounters = */ 0,
112     /* .MaxTessEvaluationAtomicCounters = */ 0,
113     /* .MaxGeometryAtomicCounters = */ 0,
114     /* .MaxFragmentAtomicCounters = */ 8,
115     /* .MaxCombinedAtomicCounters = */ 8,
116     /* .MaxAtomicCounterBindings = */ 1,
117     /* .MaxVertexAtomicCounterBuffers = */ 0,
118     /* .MaxTessControlAtomicCounterBuffers = */ 0,
119     /* .MaxTessEvaluationAtomicCounterBuffers = */ 0,
120     /* .MaxGeometryAtomicCounterBuffers = */ 0,
121     /* .MaxFragmentAtomicCounterBuffers = */ 1,
122     /* .MaxCombinedAtomicCounterBuffers = */ 1,
123     /* .MaxAtomicCounterBufferSize = */ 16384,
124     /* .MaxTransformFeedbackBuffers = */ 4,
125     /* .MaxTransformFeedbackInterleavedComponents = */ 64,
126     /* .MaxCullDistances = */ 8,
127     /* .MaxCombinedClipAndCullDistances = */ 8,
128     /* .MaxSamples = */ 4,
129     /* .maxMeshOutputVerticesNV = */ 256,
130     /* .maxMeshOutputPrimitivesNV = */ 512,
131     /* .maxMeshWorkGroupSizeX_NV = */ 32,
132     /* .maxMeshWorkGroupSizeY_NV = */ 1,
133     /* .maxMeshWorkGroupSizeZ_NV = */ 1,
134     /* .maxTaskWorkGroupSizeX_NV = */ 32,
135     /* .maxTaskWorkGroupSizeY_NV = */ 1,
136     /* .maxTaskWorkGroupSizeZ_NV = */ 1,
137     /* .maxMeshViewCountNV = */ 4,
138 
139     .limits = {
140         /* .nonInductiveForLoops = */ 1,
141         /* .whileLoops = */ 1,
142         /* .doWhileLoops = */ 1,
143         /* .generalUniformIndexing = */ 1,
144         /* .generalAttributeMatrixVectorIndexing = */ 1,
145         /* .generalVaryingIndexing = */ 1,
146         /* .generalSamplerIndexing = */ 1,
147         /* .generalVariableIndexing = */ 1,
148         /* .generalConstantMatrixVectorIndexing = */ 1,
149     }
150 };
151 
glslang_compile(const char * glsl,enum GLSlangStage stage)152 GLSlangResult *glslang_compile(const char *glsl, enum GLSlangStage stage)
153 {
154     GLSlangResult *res = (GLSlangResult *)av_mallocz(sizeof(*res));
155     if (!res)
156         return NULL;
157 
158     static const EShLanguage lang[] = {
159         [GLSLANG_VERTEX]   = EShLangVertex,
160         [GLSLANG_FRAGMENT] = EShLangFragment,
161         [GLSLANG_COMPUTE]  = EShLangCompute,
162     };
163 
164     assert(glslang_refcount);
165     TShader *shader = new TShader(lang[stage]);
166     if (!shader) {
167         res->rval = AVERROR(ENOMEM);
168         return res;
169     }
170 
171     shader->setEnvClient(EShClientVulkan, GLSL_VERSION);
172     shader->setEnvTarget(EShTargetSpv, SPIRV_VERSION);
173     shader->setStrings(&glsl, 1);
174     if (!shader->parse(&DefaultTBuiltInResource, GLSL_VERSION, true, EShMsgDefault)) {
175         res->error_msg = av_strdup(shader->getInfoLog());
176         res->rval = AVERROR_EXTERNAL;
177         delete shader;
178         return res;
179     }
180 
181     TProgram *prog = new TProgram();
182     if (!prog) {
183         res->rval = AVERROR(ENOMEM);
184         delete shader;
185         return res;
186     }
187 
188     prog->addShader(shader);
189     if (!prog->link(EShMsgDefault)) {
190         res->error_msg = av_strdup(prog->getInfoLog());
191         res->rval = AVERROR_EXTERNAL;
192         delete shader;
193         delete prog;
194         return res;
195     }
196 
197     std::vector<unsigned int> spirv; /* Result */
198 
199     SpvOptions options; /* Options - by default all optimizations are off */
200     options.generateDebugInfo = false; /* Makes sense for files but not here */
201     options.disassemble = false; /* Will print disassembly on compilation */
202     options.validate = false; /* Validates the generated SPIRV, unneeded */
203     options.disableOptimizer = false; /* For debugging */
204     options.optimizeSize = true; /* Its faster */
205 
206     GlslangToSpv(*prog->getIntermediate(lang[stage]), spirv, NULL, &options);
207 
208     res->size = spirv.size()*sizeof(unsigned int);
209     res->data = av_memdup(spirv.data(), res->size);
210     if (!res->data) {
211         res->rval = AVERROR(ENOMEM);
212         delete shader;
213         delete prog;
214         return res;
215     }
216 
217     delete shader;
218     delete prog;
219 
220     return res;
221 }
222 
glslang_init(void)223 int glslang_init(void)
224 {
225     int ret = 0;
226 
227     pthread_mutex_lock(&glslang_mutex);
228     if (glslang_refcount++ == 0)
229         ret = !InitializeProcess();
230     pthread_mutex_unlock(&glslang_mutex);
231 
232     return ret;
233 }
234 
glslang_uninit(void)235 void glslang_uninit(void)
236 {
237     pthread_mutex_lock(&glslang_mutex);
238     if (glslang_refcount && (--glslang_refcount == 0))
239         FinalizeProcess();
240     pthread_mutex_unlock(&glslang_mutex);
241 }
242