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     bool result = shader.parse(&builtInResources, 450, ECoreProfile, false, false, messages);
155     if (!result)
156     {
157         WARN() << "Internal error parsing Vulkan shader corresponding to " << shaderType << ":\n"
158                << shader.getInfoLog() << "\n"
159                << shader.getInfoDebugLog() << "\n";
160         return false;
161     }
162 
163     program.addShader(&shader);
164 
165     bool linkResult = program.link(messages);
166     if (!linkResult)
167     {
168         WARN() << "Internal error linking Vulkan shader:\n" << program.getInfoLog() << "\n";
169     }
170 
171     glslang::TIntermediate *intermediate = program.getIntermediate(language);
172     glslang::GlslangToSpv(*intermediate, *spirvBlobOut);
173 
174 #if ANGLE_DEBUG_SPIRV_GENERATION
175     spvtools::SpirvTools spirvTools(SPV_ENV_VULKAN_1_1);
176     std::string readableSpirv;
177     spirvTools.Disassemble(*spirvBlobOut, &readableSpirv, 0);
178     fprintf(stderr, "%s\n%s\n", shaderString, readableSpirv.c_str());
179 #endif  // ANGLE_DEBUG_SPIRV_GENERATION
180 
181     return true;
182 }
183 }  // namespace sh
184