xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/d3d/ShaderD3D.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2014 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 
7 // ShaderD3D.cpp: Defines the rx::ShaderD3D class which implements rx::ShaderImpl.
8 
9 #include "libANGLE/renderer/d3d/ShaderD3D.h"
10 
11 #include "common/system_utils.h"
12 #include "common/utilities.h"
13 #include "libANGLE/Caps.h"
14 #include "libANGLE/Compiler.h"
15 #include "libANGLE/Context.h"
16 #include "libANGLE/Shader.h"
17 #include "libANGLE/features.h"
18 #include "libANGLE/renderer/ContextImpl.h"
19 #include "libANGLE/renderer/d3d/ProgramD3D.h"
20 #include "libANGLE/renderer/d3d/RendererD3D.h"
21 #include "libANGLE/trace.h"
22 
23 namespace rx
24 {
25 namespace
26 {
GetUniformRegisterMap(const std::map<std::string,unsigned int> * uniformRegisterMap)27 const std::map<std::string, unsigned int> &GetUniformRegisterMap(
28     const std::map<std::string, unsigned int> *uniformRegisterMap)
29 {
30     ASSERT(uniformRegisterMap);
31     return *uniformRegisterMap;
32 }
33 
GetSlowCompilingUniformBlockSet(const std::set<std::string> * slowCompilingUniformBlockSet)34 const std::set<std::string> &GetSlowCompilingUniformBlockSet(
35     const std::set<std::string> *slowCompilingUniformBlockSet)
36 {
37     ASSERT(slowCompilingUniformBlockSet);
38     return *slowCompilingUniformBlockSet;
39 }
40 
GetUsedImage2DFunctionNames(const std::set<std::string> * usedImage2DFunctionNames)41 const std::set<std::string> &GetUsedImage2DFunctionNames(
42     const std::set<std::string> *usedImage2DFunctionNames)
43 {
44     ASSERT(usedImage2DFunctionNames);
45     return *usedImage2DFunctionNames;
46 }
47 
48 class ShaderTranslateTaskD3D final : public ShaderTranslateTask
49 {
50   public:
ShaderTranslateTaskD3D(const SharedCompiledShaderStateD3D & shader,std::string && sourcePath)51     ShaderTranslateTaskD3D(const SharedCompiledShaderStateD3D &shader, std::string &&sourcePath)
52         : mSourcePath(std::move(sourcePath)), mShader(shader)
53     {}
54     ~ShaderTranslateTaskD3D() override = default;
55 
translate(ShHandle compiler,const ShCompileOptions & options,const std::string & source)56     bool translate(ShHandle compiler,
57                    const ShCompileOptions &options,
58                    const std::string &source) override
59     {
60         ANGLE_TRACE_EVENT1("gpu.angle", "ShaderTranslateTaskD3D::run", "source", source);
61         angle::FixedVector<const char *, 2> srcStrings;
62         if (!mSourcePath.empty())
63         {
64             srcStrings.push_back(mSourcePath.c_str());
65         }
66         srcStrings.push_back(source.c_str());
67 
68         return sh::Compile(compiler, srcStrings.data(), srcStrings.size(), options);
69     }
70 
postTranslate(ShHandle compiler,const gl::CompiledShaderState & compiledState)71     void postTranslate(ShHandle compiler, const gl::CompiledShaderState &compiledState) override
72     {
73         const std::string &translatedSource = compiledState.translatedSource;
74         CompiledShaderStateD3D *state       = mShader.get();
75 
76         // Note: We shouldn't need to cache this.
77         state->compilerOutputType = sh::GetShaderOutputType(compiler);
78 
79         state->usesMultipleRenderTargets =
80             translatedSource.find("GL_USES_MRT") != std::string::npos;
81         state->usesFragColor = translatedSource.find("GL_USES_FRAG_COLOR") != std::string::npos;
82         state->usesFragData  = translatedSource.find("GL_USES_FRAG_DATA") != std::string::npos;
83         state->usesSecondaryColor =
84             translatedSource.find("GL_USES_SECONDARY_COLOR") != std::string::npos;
85         state->usesFragCoord   = translatedSource.find("GL_USES_FRAG_COORD") != std::string::npos;
86         state->usesFrontFacing = translatedSource.find("GL_USES_FRONT_FACING") != std::string::npos;
87         state->usesSampleID    = translatedSource.find("GL_USES_SAMPLE_ID") != std::string::npos;
88         state->usesSamplePosition =
89             translatedSource.find("GL_USES_SAMPLE_POSITION") != std::string::npos;
90         state->usesSampleMaskIn =
91             translatedSource.find("GL_USES_SAMPLE_MASK_IN") != std::string::npos;
92         state->usesSampleMask =
93             translatedSource.find("GL_USES_SAMPLE_MASK_OUT") != std::string::npos;
94         state->usesHelperInvocation =
95             translatedSource.find("GL_USES_HELPER_INVOCATION") != std::string::npos;
96         state->usesPointSize  = translatedSource.find("GL_USES_POINT_SIZE") != std::string::npos;
97         state->usesPointCoord = translatedSource.find("GL_USES_POINT_COORD") != std::string::npos;
98         state->usesDepthRange = translatedSource.find("GL_USES_DEPTH_RANGE") != std::string::npos;
99         state->hasMultiviewEnabled =
100             translatedSource.find("GL_MULTIVIEW_ENABLED") != std::string::npos;
101         state->usesVertexID = translatedSource.find("GL_USES_VERTEX_ID") != std::string::npos;
102         state->usesViewID   = translatedSource.find("GL_USES_VIEW_ID") != std::string::npos;
103         state->usesDiscardRewriting =
104             translatedSource.find("ANGLE_USES_DISCARD_REWRITING") != std::string::npos;
105         state->usesNestedBreak =
106             translatedSource.find("ANGLE_USES_NESTED_BREAK") != std::string::npos;
107         state->requiresIEEEStrictCompiling =
108             translatedSource.find("ANGLE_REQUIRES_IEEE_STRICT_COMPILING") != std::string::npos;
109 
110         if (translatedSource.find("GL_USES_FRAG_DEPTH_GREATER") != std::string::npos)
111         {
112             state->fragDepthUsage = FragDepthUsage::Greater;
113         }
114         else if (translatedSource.find("GL_USES_FRAG_DEPTH_LESS") != std::string::npos)
115         {
116             state->fragDepthUsage = FragDepthUsage::Less;
117         }
118         else if (translatedSource.find("GL_USES_FRAG_DEPTH") != std::string::npos)
119         {
120             state->fragDepthUsage = FragDepthUsage::Any;
121         }
122         state->clipDistanceSize   = sh::GetClipDistanceArraySize(compiler);
123         state->cullDistanceSize   = sh::GetCullDistanceArraySize(compiler);
124         state->uniformRegisterMap = GetUniformRegisterMap(sh::GetUniformRegisterMap(compiler));
125         state->readonlyImage2DRegisterIndex = sh::GetReadonlyImage2DRegisterIndex(compiler);
126         state->image2DRegisterIndex         = sh::GetImage2DRegisterIndex(compiler);
127         state->usedImage2DFunctionNames =
128             GetUsedImage2DFunctionNames(sh::GetUsedImage2DFunctionNames(compiler));
129 
130         for (const sh::InterfaceBlock &interfaceBlock : compiledState.uniformBlocks)
131         {
132             if (interfaceBlock.active)
133             {
134                 unsigned int index = static_cast<unsigned int>(-1);
135                 bool blockRegisterResult =
136                     sh::GetUniformBlockRegister(compiler, interfaceBlock.name, &index);
137                 ASSERT(blockRegisterResult);
138                 bool useStructuredBuffer =
139                     sh::ShouldUniformBlockUseStructuredBuffer(compiler, interfaceBlock.name);
140 
141                 state->uniformBlockRegisterMap[interfaceBlock.name] = index;
142                 state->uniformBlockUseStructuredBufferMap[interfaceBlock.name] =
143                     useStructuredBuffer;
144             }
145         }
146 
147         state->slowCompilingUniformBlockSet =
148             GetSlowCompilingUniformBlockSet(sh::GetSlowCompilingUniformBlockSet(compiler));
149 
150         for (const sh::InterfaceBlock &interfaceBlock : compiledState.shaderStorageBlocks)
151         {
152             if (interfaceBlock.active)
153             {
154                 unsigned int index = static_cast<unsigned int>(-1);
155                 bool blockRegisterResult =
156                     sh::GetShaderStorageBlockRegister(compiler, interfaceBlock.name, &index);
157                 ASSERT(blockRegisterResult);
158 
159                 state->shaderStorageBlockRegisterMap[interfaceBlock.name] = index;
160             }
161         }
162 
163         state->debugInfo +=
164             "// INITIAL HLSL BEGIN\n\n" + translatedSource + "\n// INITIAL HLSL END\n\n\n";
165     }
166 
167   private:
168     std::string mSourcePath;
169     SharedCompiledShaderStateD3D mShader;
170 };
171 }  // anonymous namespace
172 
CompiledShaderStateD3D()173 CompiledShaderStateD3D::CompiledShaderStateD3D()
174     : compilerOutputType(SH_ESSL_OUTPUT),
175       usesMultipleRenderTargets(false),
176       usesFragColor(false),
177       usesFragData(false),
178       usesSecondaryColor(false),
179       usesFragCoord(false),
180       usesFrontFacing(false),
181       usesHelperInvocation(false),
182       usesPointSize(false),
183       usesPointCoord(false),
184       usesDepthRange(false),
185       usesSampleID(false),
186       usesSamplePosition(false),
187       usesSampleMaskIn(false),
188       usesSampleMask(false),
189       hasMultiviewEnabled(false),
190       usesVertexID(false),
191       usesViewID(false),
192       usesDiscardRewriting(false),
193       usesNestedBreak(false),
194       requiresIEEEStrictCompiling(false),
195       fragDepthUsage(FragDepthUsage::Unused),
196       clipDistanceSize(0),
197       cullDistanceSize(0),
198       readonlyImage2DRegisterIndex(0),
199       image2DRegisterIndex(0)
200 {}
201 
202 CompiledShaderStateD3D::~CompiledShaderStateD3D() = default;
203 
ShaderD3D(const gl::ShaderState & state,RendererD3D * renderer)204 ShaderD3D::ShaderD3D(const gl::ShaderState &state, RendererD3D *renderer)
205     : ShaderImpl(state), mRenderer(renderer)
206 {}
207 
~ShaderD3D()208 ShaderD3D::~ShaderD3D() {}
209 
getDebugInfo() const210 std::string ShaderD3D::getDebugInfo() const
211 {
212     if (!mCompiledState || mCompiledState->debugInfo.empty())
213     {
214         return "";
215     }
216 
217     return mCompiledState->debugInfo + std::string("\n// ") +
218            gl::GetShaderTypeString(mState.getShaderType()) + " SHADER END\n";
219 }
220 
generateWorkarounds(CompilerWorkaroundsD3D * workarounds) const221 void CompiledShaderStateD3D::generateWorkarounds(CompilerWorkaroundsD3D *workarounds) const
222 {
223     if (usesDiscardRewriting)
224     {
225         // ANGLE issue 486:
226         // Work-around a D3D9 compiler bug that presents itself when using conditional discard, by
227         // disabling optimization
228         workarounds->skipOptimization = true;
229     }
230     else if (usesNestedBreak)
231     {
232         // ANGLE issue 603:
233         // Work-around a D3D9 compiler bug that presents itself when using break in a nested loop,
234         // by maximizing optimization We want to keep the use of
235         // ANGLE_D3D_WORKAROUND_MAX_OPTIMIZATION minimal to prevent hangs, so usesDiscard takes
236         // precedence
237         workarounds->useMaxOptimization = true;
238     }
239 
240     if (requiresIEEEStrictCompiling)
241     {
242         // IEEE Strictness for D3D compiler needs to be enabled for NaNs to work.
243         workarounds->enableIEEEStrictness = true;
244     }
245 }
246 
getUniformRegister(const std::string & uniformName) const247 unsigned int CompiledShaderStateD3D::getUniformRegister(const std::string &uniformName) const
248 {
249     ASSERT(uniformRegisterMap.count(uniformName) > 0);
250     return uniformRegisterMap.find(uniformName)->second;
251 }
252 
getUniformBlockRegister(const std::string & blockName) const253 unsigned int CompiledShaderStateD3D::getUniformBlockRegister(const std::string &blockName) const
254 {
255     ASSERT(uniformBlockRegisterMap.count(blockName) > 0);
256     return uniformBlockRegisterMap.find(blockName)->second;
257 }
258 
shouldUniformBlockUseStructuredBuffer(const std::string & blockName) const259 bool CompiledShaderStateD3D::shouldUniformBlockUseStructuredBuffer(
260     const std::string &blockName) const
261 {
262     ASSERT(uniformBlockUseStructuredBufferMap.count(blockName) > 0);
263     return uniformBlockUseStructuredBufferMap.find(blockName)->second;
264 }
265 
getShaderStorageBlockRegister(const std::string & blockName) const266 unsigned int CompiledShaderStateD3D::getShaderStorageBlockRegister(
267     const std::string &blockName) const
268 {
269     ASSERT(shaderStorageBlockRegisterMap.count(blockName) > 0);
270     return shaderStorageBlockRegisterMap.find(blockName)->second;
271 }
272 
useImage2DFunction(const std::string & functionName) const273 bool CompiledShaderStateD3D::useImage2DFunction(const std::string &functionName) const
274 {
275     if (usedImage2DFunctionNames.empty())
276     {
277         return false;
278     }
279 
280     return usedImage2DFunctionNames.find(functionName) != usedImage2DFunctionNames.end();
281 }
282 
getSlowCompilingUniformBlockSet() const283 const std::set<std::string> &CompiledShaderStateD3D::getSlowCompilingUniformBlockSet() const
284 {
285     return slowCompilingUniformBlockSet;
286 }
287 
compile(const gl::Context * context,ShCompileOptions * options)288 std::shared_ptr<ShaderTranslateTask> ShaderD3D::compile(const gl::Context *context,
289                                                         ShCompileOptions *options)
290 {
291     // Create a new compiled shader state.  Currently running program link jobs will use the
292     // previous state.
293     mCompiledState = std::make_shared<CompiledShaderStateD3D>();
294 
295     std::string sourcePath;
296 
297     const angle::FeaturesD3D &features = mRenderer->getFeatures();
298     const gl::Extensions &extensions   = mRenderer->getNativeExtensions();
299 
300     const std::string &source = mState.getSource();
301 
302 #if !defined(ANGLE_ENABLE_WINDOWS_UWP)
303     if (gl::DebugAnnotationsActive(context))
304     {
305         sourcePath = angle::CreateTemporaryFile().value();
306         writeFile(sourcePath.c_str(), source.c_str(), source.length());
307         options->lineDirectives = true;
308         options->sourcePath     = true;
309     }
310 #endif
311 
312     if (features.expandIntegerPowExpressions.enabled)
313     {
314         options->expandSelectHLSLIntegerPowExpressions = true;
315     }
316 
317     if (features.getDimensionsIgnoresBaseLevel.enabled)
318     {
319         options->HLSLGetDimensionsIgnoresBaseLevel = true;
320     }
321 
322     if (features.preAddTexelFetchOffsets.enabled)
323     {
324         options->rewriteTexelFetchOffsetToTexelFetch = true;
325     }
326     if (features.rewriteUnaryMinusOperator.enabled)
327     {
328         options->rewriteIntegerUnaryMinusOperator = true;
329     }
330     if (features.emulateIsnanFloat.enabled)
331     {
332         options->emulateIsnanFloatFunction = true;
333     }
334     if (features.skipVSConstantRegisterZero.enabled &&
335         mState.getShaderType() == gl::ShaderType::Vertex)
336     {
337         options->skipD3DConstantRegisterZero = true;
338     }
339     if (features.forceAtomicValueResolution.enabled)
340     {
341         options->forceAtomicValueResolution = true;
342     }
343     if (features.allowTranslateUniformBlockToStructuredBuffer.enabled)
344     {
345         options->allowTranslateUniformBlockToStructuredBuffer = true;
346     }
347     if (extensions.multiviewOVR || extensions.multiview2OVR)
348     {
349         options->initializeBuiltinsForInstancedMultiview = true;
350     }
351     if (extensions.shaderPixelLocalStorageANGLE)
352     {
353         options->pls = mRenderer->getNativePixelLocalStorageOptions();
354     }
355 
356     // D3D11 Feature Level 9_3 and below do not support non-constant loop indexes in fragment
357     // shaders.  Shader compilation will fail.  To provide a better error message we can instruct
358     // the compiler to pre-validate.
359     if (!features.supportsNonConstantLoopIndexing.enabled)
360     {
361         options->validateLoopIndexing = true;
362     }
363 
364     // The D3D translations are not currently validation-error-free
365     options->validateAST = false;
366 
367     return std::shared_ptr<ShaderTranslateTask>(
368         new ShaderTranslateTaskD3D(mCompiledState, std::move(sourcePath)));
369 }
370 
load(const gl::Context * context,gl::BinaryInputStream * stream)371 std::shared_ptr<ShaderTranslateTask> ShaderD3D::load(const gl::Context *context,
372                                                      gl::BinaryInputStream *stream)
373 {
374     UNREACHABLE();
375     return std::shared_ptr<ShaderTranslateTask>(new ShaderTranslateTask);
376 }
377 
hasUniform(const std::string & name) const378 bool CompiledShaderStateD3D::hasUniform(const std::string &name) const
379 {
380     return uniformRegisterMap.find(name) != uniformRegisterMap.end();
381 }
382 
383 }  // namespace rx
384