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