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