Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/glslang/SPIRV/SpvTools.cpp
20957 views
1
//
2
// Copyright (C) 2014-2016 LunarG, Inc.
3
// Copyright (C) 2018-2020 Google, Inc.
4
//
5
// All rights reserved.
6
//
7
// Redistribution and use in source and binary forms, with or without
8
// modification, are permitted provided that the following conditions
9
// are met:
10
//
11
// Redistributions of source code must retain the above copyright
12
// notice, this list of conditions and the following disclaimer.
13
//
14
// Redistributions in binary form must reproduce the above
15
// copyright notice, this list of conditions and the following
16
// disclaimer in the documentation and/or other materials provided
17
// with the distribution.
18
//
19
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
20
// contributors may be used to endorse or promote products derived
21
// from this software without specific prior written permission.
22
//
23
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34
// POSSIBILITY OF SUCH DAMAGE.
35
36
//
37
// Call into SPIRV-Tools to disassemble, validate, and optimize.
38
//
39
40
#if ENABLE_OPT
41
42
#include <cstdio>
43
#include <iostream>
44
45
#include "SpvTools.h"
46
#include "spirv-tools/optimizer.hpp"
47
#include "glslang/MachineIndependent/localintermediate.h"
48
49
namespace glslang {
50
51
// Translate glslang's view of target versioning to what SPIRV-Tools uses.
52
spv_target_env MapToSpirvToolsEnv(const SpvVersion& spvVersion, spv::SpvBuildLogger* logger)
53
{
54
switch (spvVersion.vulkan) {
55
case glslang::EShTargetVulkan_1_0:
56
return spv_target_env::SPV_ENV_VULKAN_1_0;
57
case glslang::EShTargetVulkan_1_1:
58
switch (spvVersion.spv) {
59
case EShTargetSpv_1_0:
60
case EShTargetSpv_1_1:
61
case EShTargetSpv_1_2:
62
case EShTargetSpv_1_3:
63
return spv_target_env::SPV_ENV_VULKAN_1_1;
64
case EShTargetSpv_1_4:
65
return spv_target_env::SPV_ENV_VULKAN_1_1_SPIRV_1_4;
66
default:
67
logger->missingFunctionality("Target version for SPIRV-Tools validator");
68
return spv_target_env::SPV_ENV_VULKAN_1_1;
69
}
70
case glslang::EShTargetVulkan_1_2:
71
return spv_target_env::SPV_ENV_VULKAN_1_2;
72
case glslang::EShTargetVulkan_1_3:
73
return spv_target_env::SPV_ENV_VULKAN_1_3;
74
case glslang::EShTargetVulkan_1_4:
75
return spv_target_env::SPV_ENV_VULKAN_1_4;
76
default:
77
break;
78
}
79
80
if (spvVersion.openGl > 0)
81
return spv_target_env::SPV_ENV_OPENGL_4_5;
82
83
logger->missingFunctionality("Target version for SPIRV-Tools validator");
84
return spv_target_env::SPV_ENV_UNIVERSAL_1_0;
85
}
86
87
spv_target_env MapToSpirvToolsEnv(const glslang::TIntermediate& intermediate, spv::SpvBuildLogger* logger)
88
{
89
return MapToSpirvToolsEnv(intermediate.getSpv(), logger);
90
}
91
92
// Callback passed to spvtools::Optimizer::SetMessageConsumer
93
void OptimizerMesssageConsumer(spv_message_level_t level, const char *source,
94
const spv_position_t &position, const char *message)
95
{
96
auto &out = std::cerr;
97
switch (level)
98
{
99
case SPV_MSG_FATAL:
100
case SPV_MSG_INTERNAL_ERROR:
101
case SPV_MSG_ERROR:
102
out << "error: ";
103
break;
104
case SPV_MSG_WARNING:
105
out << "warning: ";
106
break;
107
case SPV_MSG_INFO:
108
case SPV_MSG_DEBUG:
109
out << "info: ";
110
break;
111
default:
112
break;
113
}
114
if (source)
115
{
116
out << source << ":";
117
}
118
out << position.line << ":" << position.column << ":" << position.index << ":";
119
if (message)
120
{
121
out << " " << message;
122
}
123
out << std::endl;
124
}
125
126
// Use the SPIRV-Tools disassembler to print SPIR-V using a SPV_ENV_UNIVERSAL_1_3 environment.
127
void SpirvToolsDisassemble(std::ostream& out, const std::vector<unsigned int>& spirv)
128
{
129
SpirvToolsDisassemble(out, spirv, spv_target_env::SPV_ENV_UNIVERSAL_1_3);
130
}
131
132
// Use the SPIRV-Tools disassembler to print SPIR-V with a provided SPIR-V environment.
133
void SpirvToolsDisassemble(std::ostream& out, const std::vector<unsigned int>& spirv,
134
spv_target_env requested_context)
135
{
136
// disassemble
137
spv_context context = spvContextCreate(requested_context);
138
spv_text text;
139
spv_diagnostic diagnostic = nullptr;
140
spvBinaryToText(context, spirv.data(), spirv.size(),
141
SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES | SPV_BINARY_TO_TEXT_OPTION_INDENT,
142
&text, &diagnostic);
143
144
// dump
145
if (diagnostic == nullptr)
146
out << text->str;
147
else
148
spvDiagnosticPrint(diagnostic);
149
150
// teardown
151
spvDiagnosticDestroy(diagnostic);
152
spvContextDestroy(context);
153
}
154
155
// Apply the SPIRV-Tools validator to generated SPIR-V.
156
void SpirvToolsValidate(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv,
157
spv::SpvBuildLogger* logger, bool prelegalization)
158
{
159
// validate
160
spv_context context = spvContextCreate(MapToSpirvToolsEnv(intermediate.getSpv(), logger));
161
spv_const_binary_t binary = { spirv.data(), spirv.size() };
162
spv_diagnostic diagnostic = nullptr;
163
spv_validator_options options = spvValidatorOptionsCreate();
164
spvValidatorOptionsSetRelaxBlockLayout(options, intermediate.usingHlslOffsets());
165
spvValidatorOptionsSetBeforeHlslLegalization(options, prelegalization);
166
spvValidatorOptionsSetScalarBlockLayout(options, intermediate.usingScalarBlockLayout());
167
spvValidatorOptionsSetWorkgroupScalarBlockLayout(options, intermediate.usingScalarBlockLayout());
168
spvValidatorOptionsSetAllowOffsetTextureOperand(options, intermediate.usingTextureOffsetNonConst());
169
spvValidateWithOptions(context, options, &binary, &diagnostic);
170
171
// report
172
if (diagnostic != nullptr) {
173
logger->error("SPIRV-Tools Validation Errors");
174
logger->error(diagnostic->error);
175
}
176
177
// tear down
178
spvValidatorOptionsDestroy(options);
179
spvDiagnosticDestroy(diagnostic);
180
spvContextDestroy(context);
181
}
182
183
// Apply the SPIRV-Tools optimizer to generated SPIR-V. HLSL SPIR-V is legalized in the process.
184
void SpirvToolsTransform(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv,
185
spv::SpvBuildLogger* logger, const SpvOptions* options)
186
{
187
spv_target_env target_env = MapToSpirvToolsEnv(intermediate.getSpv(), logger);
188
189
spvtools::Optimizer optimizer(target_env);
190
optimizer.SetMessageConsumer(OptimizerMesssageConsumer);
191
192
// If debug (specifically source line info) is being generated, propagate
193
// line information into all SPIR-V instructions. This avoids loss of
194
// information when instructions are deleted or moved. Later, remove
195
// redundant information to minimize final SPRIR-V size.
196
if (options->stripDebugInfo) {
197
optimizer.RegisterPass(spvtools::CreateStripDebugInfoPass());
198
}
199
optimizer.RegisterPass(spvtools::CreateWrapOpKillPass());
200
optimizer.RegisterPass(spvtools::CreateDeadBranchElimPass());
201
optimizer.RegisterPass(spvtools::CreateMergeReturnPass());
202
optimizer.RegisterPass(spvtools::CreateInlineExhaustivePass());
203
optimizer.RegisterPass(spvtools::CreateEliminateDeadFunctionsPass());
204
optimizer.RegisterPass(spvtools::CreateScalarReplacementPass());
205
optimizer.RegisterPass(spvtools::CreateLocalAccessChainConvertPass());
206
optimizer.RegisterPass(spvtools::CreateLocalSingleBlockLoadStoreElimPass());
207
optimizer.RegisterPass(spvtools::CreateLocalSingleStoreElimPass());
208
optimizer.RegisterPass(spvtools::CreateSimplificationPass());
209
optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());
210
optimizer.RegisterPass(spvtools::CreateVectorDCEPass());
211
optimizer.RegisterPass(spvtools::CreateDeadInsertElimPass());
212
optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());
213
optimizer.RegisterPass(spvtools::CreateDeadBranchElimPass());
214
optimizer.RegisterPass(spvtools::CreateBlockMergePass());
215
optimizer.RegisterPass(spvtools::CreateLocalMultiStoreElimPass());
216
optimizer.RegisterPass(spvtools::CreateIfConversionPass());
217
optimizer.RegisterPass(spvtools::CreateSimplificationPass());
218
optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());
219
optimizer.RegisterPass(spvtools::CreateVectorDCEPass());
220
optimizer.RegisterPass(spvtools::CreateDeadInsertElimPass());
221
optimizer.RegisterPass(spvtools::CreateInterpolateFixupPass());
222
if (options->optimizeSize) {
223
optimizer.RegisterPass(spvtools::CreateRedundancyEliminationPass());
224
optimizer.RegisterPass(spvtools::CreateEliminateDeadInputComponentsSafePass());
225
}
226
optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());
227
optimizer.RegisterPass(spvtools::CreateCFGCleanupPass());
228
229
spvtools::OptimizerOptions spvOptOptions;
230
if (options->optimizerAllowExpandedIDBound)
231
spvOptOptions.set_max_id_bound(0x3FFFFFFF);
232
optimizer.SetTargetEnv(MapToSpirvToolsEnv(intermediate.getSpv(), logger));
233
spvOptOptions.set_run_validator(false); // The validator may run as a separate step later on
234
optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions);
235
236
if (options->optimizerAllowExpandedIDBound) {
237
if (spirv.size() > 3 && spirv[3] > kDefaultMaxIdBound) {
238
spvtools::Optimizer optimizer2(target_env);
239
optimizer2.SetMessageConsumer(OptimizerMesssageConsumer);
240
optimizer2.RegisterPass(spvtools::CreateCompactIdsPass());
241
optimizer2.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions);
242
}
243
}
244
}
245
246
bool SpirvToolsAnalyzeDeadOutputStores(spv_target_env target_env, std::vector<unsigned int>& spirv,
247
std::unordered_set<uint32_t>* live_locs,
248
std::unordered_set<uint32_t>* live_builtins,
249
spv::SpvBuildLogger*)
250
{
251
spvtools::Optimizer optimizer(target_env);
252
optimizer.SetMessageConsumer(OptimizerMesssageConsumer);
253
254
optimizer.RegisterPass(spvtools::CreateAnalyzeLiveInputPass(live_locs, live_builtins));
255
256
spvtools::OptimizerOptions spvOptOptions;
257
optimizer.SetTargetEnv(target_env);
258
spvOptOptions.set_run_validator(false);
259
return optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions);
260
}
261
262
void SpirvToolsEliminateDeadOutputStores(spv_target_env target_env, std::vector<unsigned int>& spirv,
263
std::unordered_set<uint32_t>* live_locs,
264
std::unordered_set<uint32_t>* live_builtins,
265
spv::SpvBuildLogger*)
266
{
267
spvtools::Optimizer optimizer(target_env);
268
optimizer.SetMessageConsumer(OptimizerMesssageConsumer);
269
270
optimizer.RegisterPass(spvtools::CreateEliminateDeadOutputStoresPass(live_locs, live_builtins));
271
optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass(false, true));
272
optimizer.RegisterPass(spvtools::CreateEliminateDeadOutputComponentsPass());
273
optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass(false, true));
274
275
spvtools::OptimizerOptions spvOptOptions;
276
optimizer.SetTargetEnv(target_env);
277
spvOptOptions.set_run_validator(false);
278
optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions);
279
}
280
281
void SpirvToolsEliminateDeadInputComponents(spv_target_env target_env, std::vector<unsigned int>& spirv,
282
spv::SpvBuildLogger*)
283
{
284
spvtools::Optimizer optimizer(target_env);
285
optimizer.SetMessageConsumer(OptimizerMesssageConsumer);
286
287
optimizer.RegisterPass(spvtools::CreateEliminateDeadInputComponentsPass());
288
optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());
289
290
spvtools::OptimizerOptions spvOptOptions;
291
optimizer.SetTargetEnv(target_env);
292
spvOptOptions.set_run_validator(false);
293
optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions);
294
}
295
296
// Apply the SPIRV-Tools optimizer to strip debug info from SPIR-V. This is implicitly done by
297
// SpirvToolsTransform if spvOptions->stripDebugInfo is set, but can be called separately if
298
// optimization is disabled.
299
void SpirvToolsStripDebugInfo(const glslang::TIntermediate& intermediate,
300
std::vector<unsigned int>& spirv, spv::SpvBuildLogger* logger)
301
{
302
spv_target_env target_env = MapToSpirvToolsEnv(intermediate.getSpv(), logger);
303
304
spvtools::Optimizer optimizer(target_env);
305
optimizer.SetMessageConsumer(OptimizerMesssageConsumer);
306
307
optimizer.RegisterPass(spvtools::CreateStripDebugInfoPass());
308
309
spvtools::OptimizerOptions spvOptOptions;
310
optimizer.SetTargetEnv(MapToSpirvToolsEnv(intermediate.getSpv(), logger));
311
spvOptOptions.set_run_validator(false); // The validator may run as a separate step later on
312
optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions);
313
}
314
315
} // end namespace glslang
316
317
#endif
318
319