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