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