1 //
2 // Copyright 2021 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // glslang_wrapper:
7 // A wrapper to compile GLSL strings to SPIR-V blobs. glslang here refers to the Khronos
8 // compiler.
9 //
10 // This file is separated as glslang's header contains conflicting macro definitions with ANGLE's.
11 //
12
13 #include "compiler/translator/glslang_wrapper.h"
14
15 // glslang has issues with some specific warnings.
16 ANGLE_DISABLE_SHADOWING_WARNING
17 ANGLE_DISABLE_SUGGEST_OVERRIDE_WARNINGS
18
19 // glslang's version of ShaderLang.h, not to be confused with ANGLE's.
20 #include <glslang/Public/ShaderLang.h>
21
22 // Other glslang includes.
23 #include <SPIRV/GlslangToSpv.h>
24 #include <StandAlone/ResourceLimits.h>
25
26 // SPIR-V tools include for disassembly
27 #include <spirv-tools/libspirv.hpp>
28
29 // Enable this for debug logging of pre-transform SPIR-V:
30 #if !defined(ANGLE_DEBUG_SPIRV_GENERATION)
31 # define ANGLE_DEBUG_SPIRV_GENERATION 0
32 #endif // !defined(ANGLE_DEBUG_SPIRV_GENERATION)
33
34 ANGLE_REENABLE_SUGGEST_OVERRIDE_WARNINGS
35 ANGLE_REENABLE_SHADOWING_WARNING
36
37 namespace sh
38 {
39 namespace
40 {
41 // Run at startup to warm up glslang's internals to avoid hitches on first shader compile.
Warmup()42 void Warmup()
43 {
44 EShMessages messages = static_cast<EShMessages>(EShMsgSpvRules | EShMsgVulkanRules);
45
46 const TBuiltInResource builtInResources(glslang::DefaultTBuiltInResource);
47 glslang::TShader warmUpShader(EShLangVertex);
48
49 const char *kShaderString = R"(#version 450 core
50 void main(){}
51 )";
52 const int kShaderLength = static_cast<int>(strlen(kShaderString));
53
54 warmUpShader.setStringsWithLengths(&kShaderString, &kShaderLength, 1);
55 warmUpShader.setEntryPoint("main");
56
57 bool result = warmUpShader.parse(&builtInResources, 450, ECoreProfile, false, false, messages);
58 ASSERT(result);
59 }
60
61 // Generate glslang resources from ANGLE translator resources.
GetBuiltInResources(const ShBuiltInResources & resources,TBuiltInResource * outResources)62 void GetBuiltInResources(const ShBuiltInResources &resources, TBuiltInResource *outResources)
63 {
64 outResources->maxDrawBuffers = resources.MaxDrawBuffers;
65 outResources->maxAtomicCounterBindings = resources.MaxAtomicCounterBindings;
66 outResources->maxAtomicCounterBufferSize = resources.MaxAtomicCounterBufferSize;
67 outResources->maxCombinedAtomicCounterBuffers = resources.MaxCombinedAtomicCounterBuffers;
68 outResources->maxCombinedAtomicCounters = resources.MaxCombinedAtomicCounters;
69 outResources->maxCombinedImageUniforms = resources.MaxCombinedImageUniforms;
70 outResources->maxCombinedTextureImageUnits = resources.MaxCombinedTextureImageUnits;
71 outResources->maxCombinedShaderOutputResources = resources.MaxCombinedShaderOutputResources;
72 outResources->maxComputeWorkGroupCountX = resources.MaxComputeWorkGroupCount[0];
73 outResources->maxComputeWorkGroupCountY = resources.MaxComputeWorkGroupCount[1];
74 outResources->maxComputeWorkGroupCountZ = resources.MaxComputeWorkGroupCount[2];
75 outResources->maxComputeWorkGroupSizeX = resources.MaxComputeWorkGroupSize[0];
76 outResources->maxComputeWorkGroupSizeY = resources.MaxComputeWorkGroupSize[1];
77 outResources->maxComputeWorkGroupSizeZ = resources.MaxComputeWorkGroupSize[2];
78 outResources->minProgramTexelOffset = resources.MinProgramTexelOffset;
79 outResources->maxFragmentUniformVectors = resources.MaxFragmentUniformVectors;
80 outResources->maxGeometryInputComponents = resources.MaxGeometryInputComponents;
81 outResources->maxGeometryOutputComponents = resources.MaxGeometryOutputComponents;
82 outResources->maxGeometryOutputVertices = resources.MaxGeometryOutputVertices;
83 outResources->maxGeometryTotalOutputComponents = resources.MaxGeometryTotalOutputComponents;
84 outResources->maxPatchVertices = resources.MaxPatchVertices;
85 outResources->maxProgramTexelOffset = resources.MaxProgramTexelOffset;
86 outResources->maxVaryingVectors = resources.MaxVaryingVectors;
87 outResources->maxVertexUniformVectors = resources.MaxVertexUniformVectors;
88 outResources->maxClipDistances = resources.MaxClipDistances;
89 outResources->maxSamples = resources.MaxSamples;
90 outResources->maxCullDistances = resources.MaxCullDistances;
91 outResources->maxCombinedClipAndCullDistances = resources.MaxCombinedClipAndCullDistances;
92 }
93 } // anonymous namespace
94
GlslangInitialize()95 void GlslangInitialize()
96 {
97 int result = ShInitialize();
98 ASSERT(result != 0);
99 Warmup();
100 }
101
GlslangFinalize()102 void GlslangFinalize()
103 {
104 int result = ShFinalize();
105 ASSERT(result != 0);
106 }
107
GlslangCompileToSpirv(const ShBuiltInResources & resources,sh::GLenum shaderType,const std::string & shaderSource,angle::spirv::Blob * spirvBlobOut)108 ANGLE_NO_DISCARD bool GlslangCompileToSpirv(const ShBuiltInResources &resources,
109 sh::GLenum shaderType,
110 const std::string &shaderSource,
111 angle::spirv::Blob *spirvBlobOut)
112 {
113 TBuiltInResource builtInResources(glslang::DefaultTBuiltInResource);
114 GetBuiltInResources(resources, &builtInResources);
115
116 EShLanguage language = EShLangVertex;
117
118 switch (shaderType)
119 {
120 case GL_VERTEX_SHADER:
121 language = EShLangVertex;
122 break;
123 case GL_TESS_CONTROL_SHADER:
124 language = EShLangTessControl;
125 break;
126 case GL_TESS_EVALUATION_SHADER_EXT:
127 language = EShLangTessEvaluation;
128 break;
129 case GL_GEOMETRY_SHADER:
130 language = EShLangGeometry;
131 break;
132 case GL_FRAGMENT_SHADER:
133 language = EShLangFragment;
134 break;
135 case GL_COMPUTE_SHADER:
136 language = EShLangCompute;
137 break;
138 default:
139 UNREACHABLE();
140 }
141
142 glslang::TShader shader(language);
143 glslang::TProgram program;
144
145 // Enable SPIR-V and Vulkan rules when parsing GLSL
146 constexpr EShMessages messages = static_cast<EShMessages>(EShMsgSpvRules | EShMsgVulkanRules);
147
148 const char *shaderString = shaderSource.c_str();
149 int shaderLength = static_cast<int>(shaderSource.size());
150
151 shader.setStringsWithLengths(&shaderString, &shaderLength, 1);
152 shader.setEntryPoint("main");
153
154 #if ANGLE_DEBUG_SPIRV_GENERATION
155 fprintf(stderr, "%s\n", shaderString);
156 #endif // ANGLE_DEBUG_SPIRV_GENERATION
157
158 bool result = shader.parse(&builtInResources, 450, ECoreProfile, false, false, messages);
159 if (!result)
160 {
161 WARN() << "Internal error parsing Vulkan shader corresponding to " << shaderType << ":\n"
162 << shader.getInfoLog() << "\n"
163 << shader.getInfoDebugLog() << "\n";
164 return false;
165 }
166
167 program.addShader(&shader);
168
169 bool linkResult = program.link(messages);
170 if (!linkResult)
171 {
172 WARN() << "Internal error linking Vulkan shader:\n" << program.getInfoLog() << "\n";
173 }
174
175 glslang::TIntermediate *intermediate = program.getIntermediate(language);
176 glslang::GlslangToSpv(*intermediate, *spirvBlobOut);
177
178 #if ANGLE_DEBUG_SPIRV_GENERATION
179 spvtools::SpirvTools spirvTools(SPV_ENV_VULKAN_1_1);
180 std::string readableSpirv;
181 spirvTools.Disassemble(*spirvBlobOut, &readableSpirv, 0);
182 fprintf(stderr, "%s\n", readableSpirv.c_str());
183 #endif // ANGLE_DEBUG_SPIRV_GENERATION
184
185 return true;
186 }
187 } // namespace sh
188