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/utilities.h"
12 #include "libANGLE/Caps.h"
13 #include "libANGLE/Compiler.h"
14 #include "libANGLE/Context.h"
15 #include "libANGLE/Shader.h"
16 #include "libANGLE/features.h"
17 #include "libANGLE/renderer/d3d/ProgramD3D.h"
18 #include "libANGLE/renderer/d3d/RendererD3D.h"
19 #include "libANGLE/trace.h"
20 
21 namespace rx
22 {
23 
24 class TranslateTaskD3D : public angle::Closure
25 {
26   public:
TranslateTaskD3D(ShHandle handle,ShCompileOptions options,const std::string & source,const std::string & sourcePath)27     TranslateTaskD3D(ShHandle handle,
28                      ShCompileOptions options,
29                      const std::string &source,
30                      const std::string &sourcePath)
31         : mHandle(handle),
32           mOptions(options),
33           mSource(source),
34           mSourcePath(sourcePath),
35           mResult(false)
36     {}
37 
operator ()()38     void operator()() override
39     {
40         ANGLE_TRACE_EVENT1("gpu.angle", "TranslateTask::run", "source", mSource);
41         std::vector<const char *> srcStrings;
42         if (!mSourcePath.empty())
43         {
44             srcStrings.push_back(mSourcePath.c_str());
45         }
46         srcStrings.push_back(mSource.c_str());
47 
48         mResult = sh::Compile(mHandle, &srcStrings[0], srcStrings.size(), mOptions);
49     }
50 
getResult()51     bool getResult() { return mResult; }
52 
53   private:
54     ShHandle mHandle;
55     ShCompileOptions mOptions;
56     std::string mSource;
57     std::string mSourcePath;
58     bool mResult;
59 };
60 
61 using PostTranslateFunctor =
62     std::function<bool(gl::ShCompilerInstance *compiler, std::string *infoLog)>;
63 
64 class WaitableCompileEventD3D final : public WaitableCompileEvent
65 {
66   public:
WaitableCompileEventD3D(std::shared_ptr<angle::WaitableEvent> waitableEvent,gl::ShCompilerInstance * compilerInstance,PostTranslateFunctor && postTranslateFunctor,std::shared_ptr<TranslateTaskD3D> translateTask)67     WaitableCompileEventD3D(std::shared_ptr<angle::WaitableEvent> waitableEvent,
68                             gl::ShCompilerInstance *compilerInstance,
69                             PostTranslateFunctor &&postTranslateFunctor,
70                             std::shared_ptr<TranslateTaskD3D> translateTask)
71         : WaitableCompileEvent(waitableEvent),
72           mCompilerInstance(compilerInstance),
73           mPostTranslateFunctor(std::move(postTranslateFunctor)),
74           mTranslateTask(translateTask)
75     {}
76 
getResult()77     bool getResult() override { return mTranslateTask->getResult(); }
78 
postTranslate(std::string * infoLog)79     bool postTranslate(std::string *infoLog) override
80     {
81         return mPostTranslateFunctor(mCompilerInstance, infoLog);
82     }
83 
84   private:
85     gl::ShCompilerInstance *mCompilerInstance;
86     PostTranslateFunctor mPostTranslateFunctor;
87     std::shared_ptr<TranslateTaskD3D> mTranslateTask;
88 };
89 
ShaderD3D(const gl::ShaderState & state,const angle::FeaturesD3D & features,const gl::Extensions & extensions)90 ShaderD3D::ShaderD3D(const gl::ShaderState &state,
91                      const angle::FeaturesD3D &features,
92                      const gl::Extensions &extensions)
93     : ShaderImpl(state), mAdditionalOptions(0)
94 {
95     uncompile();
96 
97     if (features.expandIntegerPowExpressions.enabled)
98     {
99         mAdditionalOptions |= SH_EXPAND_SELECT_HLSL_INTEGER_POW_EXPRESSIONS;
100     }
101 
102     if (features.getDimensionsIgnoresBaseLevel.enabled)
103     {
104         mAdditionalOptions |= SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL;
105     }
106 
107     if (features.preAddTexelFetchOffsets.enabled)
108     {
109         mAdditionalOptions |= SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH;
110     }
111     if (features.rewriteUnaryMinusOperator.enabled)
112     {
113         mAdditionalOptions |= SH_REWRITE_INTEGER_UNARY_MINUS_OPERATOR;
114     }
115     if (features.emulateIsnanFloat.enabled)
116     {
117         mAdditionalOptions |= SH_EMULATE_ISNAN_FLOAT_FUNCTION;
118     }
119     if (features.skipVSConstantRegisterZero.enabled &&
120         mState.getShaderType() == gl::ShaderType::Vertex)
121     {
122         mAdditionalOptions |= SH_SKIP_D3D_CONSTANT_REGISTER_ZERO;
123     }
124     if (features.forceAtomicValueResolution.enabled)
125     {
126         mAdditionalOptions |= SH_FORCE_ATOMIC_VALUE_RESOLUTION;
127     }
128     if (features.allowTranslateUniformBlockToStructuredBuffer.enabled)
129     {
130         mAdditionalOptions |= SH_ALLOW_TRANSLATE_UNIFORM_BLOCK_TO_STRUCTUREDBUFFER;
131     }
132     if (extensions.multiview || extensions.multiview2)
133     {
134         mAdditionalOptions |= SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW;
135     }
136 }
137 
~ShaderD3D()138 ShaderD3D::~ShaderD3D() {}
139 
getDebugInfo() const140 std::string ShaderD3D::getDebugInfo() const
141 {
142     if (mDebugInfo.empty())
143     {
144         return "";
145     }
146 
147     return mDebugInfo + std::string("\n// ") + gl::GetShaderTypeString(mState.getShaderType()) +
148            " SHADER END\n";
149 }
150 
151 // initialize/clean up previous state
uncompile()152 void ShaderD3D::uncompile()
153 {
154     // set by compileToHLSL
155     mCompilerOutputType = SH_ESSL_OUTPUT;
156 
157     mUsesMultipleRenderTargets   = false;
158     mUsesFragColor               = false;
159     mUsesFragData                = false;
160     mUsesSecondaryColor          = false;
161     mUsesFragCoord               = false;
162     mUsesFrontFacing             = false;
163     mUsesHelperInvocation        = false;
164     mUsesPointSize               = false;
165     mUsesPointCoord              = false;
166     mUsesDepthRange              = false;
167     mUsesFragDepth               = false;
168     mHasANGLEMultiviewEnabled    = false;
169     mUsesVertexID                = false;
170     mUsesViewID                  = false;
171     mUsesDiscardRewriting        = false;
172     mUsesNestedBreak             = false;
173     mRequiresIEEEStrictCompiling = false;
174 
175     mDebugInfo.clear();
176 }
177 
generateWorkarounds(angle::CompilerWorkaroundsD3D * workarounds) const178 void ShaderD3D::generateWorkarounds(angle::CompilerWorkaroundsD3D *workarounds) const
179 {
180     if (mUsesDiscardRewriting)
181     {
182         // ANGLE issue 486:
183         // Work-around a D3D9 compiler bug that presents itself when using conditional discard, by
184         // disabling optimization
185         workarounds->skipOptimization = true;
186     }
187     else if (mUsesNestedBreak)
188     {
189         // ANGLE issue 603:
190         // Work-around a D3D9 compiler bug that presents itself when using break in a nested loop,
191         // by maximizing optimization We want to keep the use of
192         // ANGLE_D3D_WORKAROUND_MAX_OPTIMIZATION minimal to prevent hangs, so usesDiscard takes
193         // precedence
194         workarounds->useMaxOptimization = true;
195     }
196 
197     if (mRequiresIEEEStrictCompiling)
198     {
199         // IEEE Strictness for D3D compiler needs to be enabled for NaNs to work.
200         workarounds->enableIEEEStrictness = true;
201     }
202 }
203 
getUniformRegister(const std::string & uniformName) const204 unsigned int ShaderD3D::getUniformRegister(const std::string &uniformName) const
205 {
206     ASSERT(mUniformRegisterMap.count(uniformName) > 0);
207     return mUniformRegisterMap.find(uniformName)->second;
208 }
209 
getUniformBlockRegister(const std::string & blockName) const210 unsigned int ShaderD3D::getUniformBlockRegister(const std::string &blockName) const
211 {
212     ASSERT(mUniformBlockRegisterMap.count(blockName) > 0);
213     return mUniformBlockRegisterMap.find(blockName)->second;
214 }
215 
shouldUniformBlockUseStructuredBuffer(const std::string & blockName) const216 bool ShaderD3D::shouldUniformBlockUseStructuredBuffer(const std::string &blockName) const
217 {
218     ASSERT(mUniformBlockUseStructuredBufferMap.count(blockName) > 0);
219     return mUniformBlockUseStructuredBufferMap.find(blockName)->second;
220 }
221 
getShaderStorageBlockRegister(const std::string & blockName) const222 unsigned int ShaderD3D::getShaderStorageBlockRegister(const std::string &blockName) const
223 {
224     ASSERT(mShaderStorageBlockRegisterMap.count(blockName) > 0);
225     return mShaderStorageBlockRegisterMap.find(blockName)->second;
226 }
227 
getCompilerOutputType() const228 ShShaderOutput ShaderD3D::getCompilerOutputType() const
229 {
230     return mCompilerOutputType;
231 }
232 
useImage2DFunction(const std::string & functionName) const233 bool ShaderD3D::useImage2DFunction(const std::string &functionName) const
234 {
235     if (mUsedImage2DFunctionNames.empty())
236     {
237         return false;
238     }
239 
240     return mUsedImage2DFunctionNames.find(functionName) != mUsedImage2DFunctionNames.end();
241 }
242 
getSlowCompilingUniformBlockSet() const243 const std::set<std::string> &ShaderD3D::getSlowCompilingUniformBlockSet() const
244 {
245     return mSlowCompilingUniformBlockSet;
246 }
247 
GetUniformRegisterMap(const std::map<std::string,unsigned int> * uniformRegisterMap)248 const std::map<std::string, unsigned int> &GetUniformRegisterMap(
249     const std::map<std::string, unsigned int> *uniformRegisterMap)
250 {
251     ASSERT(uniformRegisterMap);
252     return *uniformRegisterMap;
253 }
254 
GetSlowCompilingUniformBlockSet(const std::set<std::string> * slowCompilingUniformBlockSet)255 const std::set<std::string> &GetSlowCompilingUniformBlockSet(
256     const std::set<std::string> *slowCompilingUniformBlockSet)
257 {
258     ASSERT(slowCompilingUniformBlockSet);
259     return *slowCompilingUniformBlockSet;
260 }
261 
GetUsedImage2DFunctionNames(const std::set<std::string> * usedImage2DFunctionNames)262 const std::set<std::string> &GetUsedImage2DFunctionNames(
263     const std::set<std::string> *usedImage2DFunctionNames)
264 {
265     ASSERT(usedImage2DFunctionNames);
266     return *usedImage2DFunctionNames;
267 }
268 
compile(const gl::Context * context,gl::ShCompilerInstance * compilerInstance,ShCompileOptions options)269 std::shared_ptr<WaitableCompileEvent> ShaderD3D::compile(const gl::Context *context,
270                                                          gl::ShCompilerInstance *compilerInstance,
271                                                          ShCompileOptions options)
272 {
273     std::string sourcePath;
274     uncompile();
275 
276     ShCompileOptions additionalOptions = 0;
277 
278     const std::string &source = mState.getSource();
279 
280 #if !defined(ANGLE_ENABLE_WINDOWS_UWP)
281     if (gl::DebugAnnotationsActive())
282     {
283         sourcePath = getTempPath();
284         writeFile(sourcePath.c_str(), source.c_str(), source.length());
285         additionalOptions |= SH_LINE_DIRECTIVES | SH_SOURCE_PATH;
286     }
287 #endif
288 
289     additionalOptions |= mAdditionalOptions;
290 
291     options |= additionalOptions;
292 
293     auto postTranslateFunctor = [this](gl::ShCompilerInstance *compiler, std::string *infoLog) {
294         // TODO(jmadill): We shouldn't need to cache this.
295         mCompilerOutputType = compiler->getShaderOutputType();
296 
297         const std::string &translatedSource = mState.getTranslatedSource();
298 
299         mUsesMultipleRenderTargets = translatedSource.find("GL_USES_MRT") != std::string::npos;
300         mUsesFragColor      = translatedSource.find("GL_USES_FRAG_COLOR") != std::string::npos;
301         mUsesFragData       = translatedSource.find("GL_USES_FRAG_DATA") != std::string::npos;
302         mUsesSecondaryColor = translatedSource.find("GL_USES_SECONDARY_COLOR") != std::string::npos;
303         mUsesFragCoord      = translatedSource.find("GL_USES_FRAG_COORD") != std::string::npos;
304         mUsesFrontFacing    = translatedSource.find("GL_USES_FRONT_FACING") != std::string::npos;
305         mUsesHelperInvocation =
306             translatedSource.find("GL_USES_HELPER_INVOCATION") != std::string::npos;
307         mUsesPointSize  = translatedSource.find("GL_USES_POINT_SIZE") != std::string::npos;
308         mUsesPointCoord = translatedSource.find("GL_USES_POINT_COORD") != std::string::npos;
309         mUsesDepthRange = translatedSource.find("GL_USES_DEPTH_RANGE") != std::string::npos;
310         mUsesFragDepth  = translatedSource.find("GL_USES_FRAG_DEPTH") != std::string::npos;
311         mHasANGLEMultiviewEnabled =
312             translatedSource.find("GL_ANGLE_MULTIVIEW_ENABLED") != std::string::npos;
313         mUsesVertexID = translatedSource.find("GL_USES_VERTEX_ID") != std::string::npos;
314         mUsesViewID   = translatedSource.find("GL_USES_VIEW_ID") != std::string::npos;
315         mUsesDiscardRewriting =
316             translatedSource.find("ANGLE_USES_DISCARD_REWRITING") != std::string::npos;
317         mUsesNestedBreak = translatedSource.find("ANGLE_USES_NESTED_BREAK") != std::string::npos;
318         mRequiresIEEEStrictCompiling =
319             translatedSource.find("ANGLE_REQUIRES_IEEE_STRICT_COMPILING") != std::string::npos;
320 
321         ShHandle compilerHandle = compiler->getHandle();
322 
323         mUniformRegisterMap = GetUniformRegisterMap(sh::GetUniformRegisterMap(compilerHandle));
324         mReadonlyImage2DRegisterIndex = sh::GetReadonlyImage2DRegisterIndex(compilerHandle);
325         mImage2DRegisterIndex         = sh::GetImage2DRegisterIndex(compilerHandle);
326         mUsedImage2DFunctionNames =
327             GetUsedImage2DFunctionNames(sh::GetUsedImage2DFunctionNames(compilerHandle));
328 
329         for (const sh::InterfaceBlock &interfaceBlock : mState.getUniformBlocks())
330         {
331             if (interfaceBlock.active)
332             {
333                 unsigned int index = static_cast<unsigned int>(-1);
334                 bool blockRegisterResult =
335                     sh::GetUniformBlockRegister(compilerHandle, interfaceBlock.name, &index);
336                 ASSERT(blockRegisterResult);
337                 bool useStructuredBuffer =
338                     sh::ShouldUniformBlockUseStructuredBuffer(compilerHandle, interfaceBlock.name);
339 
340                 mUniformBlockRegisterMap[interfaceBlock.name]            = index;
341                 mUniformBlockUseStructuredBufferMap[interfaceBlock.name] = useStructuredBuffer;
342             }
343         }
344 
345         mSlowCompilingUniformBlockSet =
346             GetSlowCompilingUniformBlockSet(sh::GetSlowCompilingUniformBlockSet(compilerHandle));
347 
348         for (const sh::InterfaceBlock &interfaceBlock : mState.getShaderStorageBlocks())
349         {
350             if (interfaceBlock.active)
351             {
352                 unsigned int index = static_cast<unsigned int>(-1);
353                 bool blockRegisterResult =
354                     sh::GetShaderStorageBlockRegister(compilerHandle, interfaceBlock.name, &index);
355                 ASSERT(blockRegisterResult);
356 
357                 mShaderStorageBlockRegisterMap[interfaceBlock.name] = index;
358             }
359         }
360 
361         mDebugInfo += std::string("// ") + gl::GetShaderTypeString(mState.getShaderType()) +
362                       " SHADER BEGIN\n";
363         mDebugInfo += "\n// GLSL BEGIN\n\n" + mState.getSource() + "\n\n// GLSL END\n\n\n";
364         mDebugInfo +=
365             "// INITIAL HLSL BEGIN\n\n" + translatedSource + "\n// INITIAL HLSL END\n\n\n";
366         // Successive steps will append more info
367         return true;
368     };
369 
370     auto workerThreadPool = context->getWorkerThreadPool();
371     auto translateTask = std::make_shared<TranslateTaskD3D>(compilerInstance->getHandle(), options,
372                                                             source, sourcePath);
373 
374     return std::make_shared<WaitableCompileEventD3D>(
375         angle::WorkerThreadPool::PostWorkerTask(workerThreadPool, translateTask), compilerInstance,
376         std::move(postTranslateFunctor), translateTask);
377 }
378 
hasUniform(const std::string & name) const379 bool ShaderD3D::hasUniform(const std::string &name) const
380 {
381     return mUniformRegisterMap.find(name) != mUniformRegisterMap.end();
382 }
383 
384 }  // namespace rx
385