xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/vulkan/ShaderVk.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2016 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 // ShaderVk.cpp:
7 //    Implements the class methods for ShaderVk.
8 //
9 
10 #include "libANGLE/renderer/vulkan/ShaderVk.h"
11 
12 #include "common/debug.h"
13 #include "libANGLE/Context.h"
14 #include "libANGLE/Display.h"
15 #include "libANGLE/renderer/vulkan/ContextVk.h"
16 
17 namespace rx
18 {
ShaderVk(const gl::ShaderState & state)19 ShaderVk::ShaderVk(const gl::ShaderState &state) : ShaderImpl(state) {}
20 
~ShaderVk()21 ShaderVk::~ShaderVk() {}
22 
compile(const gl::Context * context,ShCompileOptions * options)23 std::shared_ptr<ShaderTranslateTask> ShaderVk::compile(const gl::Context *context,
24                                                        ShCompileOptions *options)
25 {
26     ContextVk *contextVk = vk::GetImpl(context);
27 
28     if (context->isWebGL())
29     {
30         // Only WebGL requires initialization of local variables, others don't.
31         // Extra initialization in spirv shader may affect performance.
32         options->initializeUninitializedLocals = true;
33 
34         // WebGL shaders may contain OOB array accesses which in turn cause undefined behavior,
35         // which may result in security issues. See https://crbug.com/1189110.
36         options->clampIndirectArrayBounds = true;
37 
38         if (mState.getShaderType() != gl::ShaderType::Compute)
39         {
40             options->initOutputVariables = true;
41         }
42     }
43 
44     if (contextVk->getFeatures().supportsSPIRV14.enabled)
45     {
46         options->emitSPIRV14 = true;
47     }
48 
49     if (contextVk->getFeatures().retainSPIRVDebugInfo.enabled)
50     {
51         options->outputDebugInfo = true;
52     }
53 
54     // robustBufferAccess on Vulkan doesn't support bound check on shader local variables
55     // but the GL_EXT_robustness does support.
56     // Enable the flag clampIndirectArrayBounds to ensure out of bounds local variable writes in
57     // shaders are protected when the context has GL_EXT_robustness enabled
58     if (contextVk->getShareGroup()->hasAnyContextWithRobustness())
59     {
60         options->clampIndirectArrayBounds = true;
61     }
62 
63     if (contextVk->getFeatures().clampPointSize.enabled)
64     {
65         options->clampPointSize = true;
66     }
67 
68     if (contextVk->getFeatures().emulateAdvancedBlendEquations.enabled)
69     {
70         options->addAdvancedBlendEquationsEmulation = true;
71     }
72 
73     if (!contextVk->getFeatures().enablePrecisionQualifiers.enabled)
74     {
75         options->ignorePrecisionQualifiers = true;
76     }
77 
78     if (contextVk->getFeatures().forceFragmentShaderPrecisionHighpToMediump.enabled)
79     {
80         options->forceShaderPrecisionHighpToMediump = true;
81     }
82 
83     // Let compiler use specialized constant for pre-rotation.
84     if (!contextVk->getFeatures().preferDriverUniformOverSpecConst.enabled)
85     {
86         options->useSpecializationConstant = true;
87     }
88 
89     if (contextVk->getFeatures().clampFragDepth.enabled)
90     {
91         options->clampFragDepth = true;
92     }
93 
94     if (!contextVk->getFeatures().supportsDepthClipControl.enabled)
95     {
96         options->addVulkanDepthCorrection = true;
97     }
98 
99     if (contextVk->getFeatures().supportsTransformFeedbackExtension.enabled)
100     {
101         options->addVulkanXfbExtensionSupportCode = true;
102     }
103     else if (mState.getShaderType() == gl::ShaderType::Vertex &&
104              contextVk->getFeatures().emulateTransformFeedback.enabled)
105     {
106         options->addVulkanXfbEmulationSupportCode = true;
107     }
108 
109     if (contextVk->getFeatures().roundOutputAfterDithering.enabled)
110     {
111         options->roundOutputAfterDithering = true;
112     }
113 
114     if (contextVk->getFeatures().appendAliasedMemoryDecorations.enabled)
115     {
116         options->aliasedUnlessRestrict = true;
117     }
118 
119     if (contextVk->getFeatures().explicitlyCastMediumpFloatTo16Bit.enabled)
120     {
121         options->castMediumpFloatTo16Bit = true;
122     }
123 
124     if (contextVk->getExtensions().shaderPixelLocalStorageANGLE)
125     {
126         options->pls = contextVk->getNativePixelLocalStorageOptions();
127     }
128 
129     if (contextVk->getFeatures().avoidOpSelectWithMismatchingRelaxedPrecision.enabled)
130     {
131         options->avoidOpSelectWithMismatchingRelaxedPrecision = true;
132     }
133 
134     if (contextVk->getFeatures().wrapSwitchInIfTrue.enabled)
135     {
136         options->wrapSwitchInIfTrue = true;
137     }
138 
139     if (contextVk->getFeatures().emulateR32fImageAtomicExchange.enabled)
140     {
141         options->emulateR32fImageAtomicExchange = true;
142     }
143 
144     // The Vulkan backend needs no post-processing of the translated shader.
145     return std::shared_ptr<ShaderTranslateTask>(new ShaderTranslateTask);
146 }
147 
load(const gl::Context * context,gl::BinaryInputStream * stream)148 std::shared_ptr<ShaderTranslateTask> ShaderVk::load(const gl::Context *context,
149                                                     gl::BinaryInputStream *stream)
150 {
151     return std::shared_ptr<ShaderTranslateTask>(new ShaderTranslateTask);
152 }
153 
getDebugInfo() const154 std::string ShaderVk::getDebugInfo() const
155 {
156     const sh::BinaryBlob &spirv = mState.getCompiledState()->compiledBinary;
157     if (spirv.empty())
158     {
159         return "";
160     }
161 
162     std::ostringstream blob;
163     if (!mState.getCompiledState()->inputVaryings.empty())
164     {
165         blob << "Inputs:";
166         for (const sh::ShaderVariable &var : mState.getCompiledState()->inputVaryings)
167         {
168             blob << " " << var.name;
169         }
170         blob << std::endl;
171     }
172     if (!mState.getCompiledState()->activeAttributes.empty())
173     {
174         blob << "Inputs:";
175         for (const sh::ShaderVariable &var : mState.getCompiledState()->activeAttributes)
176         {
177             blob << " " << var.name;
178         }
179         blob << std::endl;
180     }
181     if (!mState.getCompiledState()->outputVaryings.empty())
182     {
183         blob << "Outputs:";
184         for (const sh::ShaderVariable &var : mState.getCompiledState()->outputVaryings)
185         {
186             blob << " " << var.name;
187         }
188         blob << std::endl;
189     }
190     if (!mState.getCompiledState()->activeOutputVariables.empty())
191     {
192         blob << "Outputs:";
193         for (const sh::ShaderVariable &var : mState.getCompiledState()->activeOutputVariables)
194         {
195             blob << " " << var.name;
196         }
197         blob << std::endl;
198     }
199     if (!mState.getCompiledState()->uniforms.empty())
200     {
201         blob << "Uniforms:";
202         for (const sh::ShaderVariable &var : mState.getCompiledState()->uniforms)
203         {
204             blob << " " << var.name;
205         }
206         blob << std::endl;
207     }
208     if (!mState.getCompiledState()->uniformBlocks.empty())
209     {
210         blob << "Uniform blocks:";
211         for (const sh::InterfaceBlock &block : mState.getCompiledState()->uniformBlocks)
212         {
213             blob << " " << block.name;
214         }
215         blob << std::endl;
216     }
217     if (!mState.getCompiledState()->shaderStorageBlocks.empty())
218     {
219         blob << "Storage blocks:";
220         for (const sh::InterfaceBlock &block : mState.getCompiledState()->shaderStorageBlocks)
221         {
222             blob << " " << block.name;
223         }
224         blob << std::endl;
225     }
226 
227     blob << R"(
228 Paste the following SPIR-V binary in https://www.khronos.org/spir/visualizer/ or pass to a recent build of `spirv-dis` (optionally with `--comment --nested-indent`)
229 
230 Setting the environment variable ANGLE_FEATURE_OVERRIDES_ENABLED=retainSPIRVDebugInfo will retain debug info
231 
232 )";
233 
234     constexpr size_t kIndicesPerRow = 10;
235     size_t rowOffset                = 0;
236     for (size_t index = 0; index < spirv.size(); ++index, ++rowOffset)
237     {
238         if (rowOffset == kIndicesPerRow)
239         {
240             blob << std::endl;
241             rowOffset = 0;
242         }
243         blob << "0x" << std::uppercase << std::setfill('0') << std::setw(8) << std::hex
244              << spirv[index] << ",";
245     }
246 
247     return blob.str();
248 }
249 
250 }  // namespace rx
251