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 namespace
26 {
GetUniformRegisterMap(const std::map<std::string,unsigned int> * uniformRegisterMap)27 const std::map<std::string, unsigned int> &GetUniformRegisterMap(
28 const std::map<std::string, unsigned int> *uniformRegisterMap)
29 {
30 ASSERT(uniformRegisterMap);
31 return *uniformRegisterMap;
32 }
33
GetSlowCompilingUniformBlockSet(const std::set<std::string> * slowCompilingUniformBlockSet)34 const std::set<std::string> &GetSlowCompilingUniformBlockSet(
35 const std::set<std::string> *slowCompilingUniformBlockSet)
36 {
37 ASSERT(slowCompilingUniformBlockSet);
38 return *slowCompilingUniformBlockSet;
39 }
40
GetUsedImage2DFunctionNames(const std::set<std::string> * usedImage2DFunctionNames)41 const std::set<std::string> &GetUsedImage2DFunctionNames(
42 const std::set<std::string> *usedImage2DFunctionNames)
43 {
44 ASSERT(usedImage2DFunctionNames);
45 return *usedImage2DFunctionNames;
46 }
47
48 class ShaderTranslateTaskD3D final : public ShaderTranslateTask
49 {
50 public:
ShaderTranslateTaskD3D(const SharedCompiledShaderStateD3D & shader,std::string && sourcePath)51 ShaderTranslateTaskD3D(const SharedCompiledShaderStateD3D &shader, std::string &&sourcePath)
52 : mSourcePath(std::move(sourcePath)), mShader(shader)
53 {}
54 ~ShaderTranslateTaskD3D() override = default;
55
translate(ShHandle compiler,const ShCompileOptions & options,const std::string & source)56 bool translate(ShHandle compiler,
57 const ShCompileOptions &options,
58 const std::string &source) override
59 {
60 ANGLE_TRACE_EVENT1("gpu.angle", "ShaderTranslateTaskD3D::run", "source", source);
61 angle::FixedVector<const char *, 2> srcStrings;
62 if (!mSourcePath.empty())
63 {
64 srcStrings.push_back(mSourcePath.c_str());
65 }
66 srcStrings.push_back(source.c_str());
67
68 return sh::Compile(compiler, srcStrings.data(), srcStrings.size(), options);
69 }
70
postTranslate(ShHandle compiler,const gl::CompiledShaderState & compiledState)71 void postTranslate(ShHandle compiler, const gl::CompiledShaderState &compiledState) override
72 {
73 const std::string &translatedSource = compiledState.translatedSource;
74 CompiledShaderStateD3D *state = mShader.get();
75
76 // Note: We shouldn't need to cache this.
77 state->compilerOutputType = sh::GetShaderOutputType(compiler);
78
79 state->usesMultipleRenderTargets =
80 translatedSource.find("GL_USES_MRT") != std::string::npos;
81 state->usesFragColor = translatedSource.find("GL_USES_FRAG_COLOR") != std::string::npos;
82 state->usesFragData = translatedSource.find("GL_USES_FRAG_DATA") != std::string::npos;
83 state->usesSecondaryColor =
84 translatedSource.find("GL_USES_SECONDARY_COLOR") != std::string::npos;
85 state->usesFragCoord = translatedSource.find("GL_USES_FRAG_COORD") != std::string::npos;
86 state->usesFrontFacing = translatedSource.find("GL_USES_FRONT_FACING") != std::string::npos;
87 state->usesSampleID = translatedSource.find("GL_USES_SAMPLE_ID") != std::string::npos;
88 state->usesSamplePosition =
89 translatedSource.find("GL_USES_SAMPLE_POSITION") != std::string::npos;
90 state->usesSampleMaskIn =
91 translatedSource.find("GL_USES_SAMPLE_MASK_IN") != std::string::npos;
92 state->usesSampleMask =
93 translatedSource.find("GL_USES_SAMPLE_MASK_OUT") != std::string::npos;
94 state->usesHelperInvocation =
95 translatedSource.find("GL_USES_HELPER_INVOCATION") != std::string::npos;
96 state->usesPointSize = translatedSource.find("GL_USES_POINT_SIZE") != std::string::npos;
97 state->usesPointCoord = translatedSource.find("GL_USES_POINT_COORD") != std::string::npos;
98 state->usesDepthRange = translatedSource.find("GL_USES_DEPTH_RANGE") != std::string::npos;
99 state->hasMultiviewEnabled =
100 translatedSource.find("GL_MULTIVIEW_ENABLED") != std::string::npos;
101 state->usesVertexID = translatedSource.find("GL_USES_VERTEX_ID") != std::string::npos;
102 state->usesViewID = translatedSource.find("GL_USES_VIEW_ID") != std::string::npos;
103 state->usesDiscardRewriting =
104 translatedSource.find("ANGLE_USES_DISCARD_REWRITING") != std::string::npos;
105 state->usesNestedBreak =
106 translatedSource.find("ANGLE_USES_NESTED_BREAK") != std::string::npos;
107 state->requiresIEEEStrictCompiling =
108 translatedSource.find("ANGLE_REQUIRES_IEEE_STRICT_COMPILING") != std::string::npos;
109
110 if (translatedSource.find("GL_USES_FRAG_DEPTH_GREATER") != std::string::npos)
111 {
112 state->fragDepthUsage = FragDepthUsage::Greater;
113 }
114 else if (translatedSource.find("GL_USES_FRAG_DEPTH_LESS") != std::string::npos)
115 {
116 state->fragDepthUsage = FragDepthUsage::Less;
117 }
118 else if (translatedSource.find("GL_USES_FRAG_DEPTH") != std::string::npos)
119 {
120 state->fragDepthUsage = FragDepthUsage::Any;
121 }
122 state->clipDistanceSize = sh::GetClipDistanceArraySize(compiler);
123 state->cullDistanceSize = sh::GetCullDistanceArraySize(compiler);
124 state->uniformRegisterMap = GetUniformRegisterMap(sh::GetUniformRegisterMap(compiler));
125 state->readonlyImage2DRegisterIndex = sh::GetReadonlyImage2DRegisterIndex(compiler);
126 state->image2DRegisterIndex = sh::GetImage2DRegisterIndex(compiler);
127 state->usedImage2DFunctionNames =
128 GetUsedImage2DFunctionNames(sh::GetUsedImage2DFunctionNames(compiler));
129
130 for (const sh::InterfaceBlock &interfaceBlock : compiledState.uniformBlocks)
131 {
132 if (interfaceBlock.active)
133 {
134 unsigned int index = static_cast<unsigned int>(-1);
135 bool blockRegisterResult =
136 sh::GetUniformBlockRegister(compiler, interfaceBlock.name, &index);
137 ASSERT(blockRegisterResult);
138 bool useStructuredBuffer =
139 sh::ShouldUniformBlockUseStructuredBuffer(compiler, interfaceBlock.name);
140
141 state->uniformBlockRegisterMap[interfaceBlock.name] = index;
142 state->uniformBlockUseStructuredBufferMap[interfaceBlock.name] =
143 useStructuredBuffer;
144 }
145 }
146
147 state->slowCompilingUniformBlockSet =
148 GetSlowCompilingUniformBlockSet(sh::GetSlowCompilingUniformBlockSet(compiler));
149
150 for (const sh::InterfaceBlock &interfaceBlock : compiledState.shaderStorageBlocks)
151 {
152 if (interfaceBlock.active)
153 {
154 unsigned int index = static_cast<unsigned int>(-1);
155 bool blockRegisterResult =
156 sh::GetShaderStorageBlockRegister(compiler, interfaceBlock.name, &index);
157 ASSERT(blockRegisterResult);
158
159 state->shaderStorageBlockRegisterMap[interfaceBlock.name] = index;
160 }
161 }
162
163 state->debugInfo +=
164 "// INITIAL HLSL BEGIN\n\n" + translatedSource + "\n// INITIAL HLSL END\n\n\n";
165 }
166
167 private:
168 std::string mSourcePath;
169 SharedCompiledShaderStateD3D mShader;
170 };
171 } // anonymous namespace
172
CompiledShaderStateD3D()173 CompiledShaderStateD3D::CompiledShaderStateD3D()
174 : compilerOutputType(SH_ESSL_OUTPUT),
175 usesMultipleRenderTargets(false),
176 usesFragColor(false),
177 usesFragData(false),
178 usesSecondaryColor(false),
179 usesFragCoord(false),
180 usesFrontFacing(false),
181 usesHelperInvocation(false),
182 usesPointSize(false),
183 usesPointCoord(false),
184 usesDepthRange(false),
185 usesSampleID(false),
186 usesSamplePosition(false),
187 usesSampleMaskIn(false),
188 usesSampleMask(false),
189 hasMultiviewEnabled(false),
190 usesVertexID(false),
191 usesViewID(false),
192 usesDiscardRewriting(false),
193 usesNestedBreak(false),
194 requiresIEEEStrictCompiling(false),
195 fragDepthUsage(FragDepthUsage::Unused),
196 clipDistanceSize(0),
197 cullDistanceSize(0),
198 readonlyImage2DRegisterIndex(0),
199 image2DRegisterIndex(0)
200 {}
201
202 CompiledShaderStateD3D::~CompiledShaderStateD3D() = default;
203
ShaderD3D(const gl::ShaderState & state,RendererD3D * renderer)204 ShaderD3D::ShaderD3D(const gl::ShaderState &state, RendererD3D *renderer)
205 : ShaderImpl(state), mRenderer(renderer)
206 {}
207
~ShaderD3D()208 ShaderD3D::~ShaderD3D() {}
209
getDebugInfo() const210 std::string ShaderD3D::getDebugInfo() const
211 {
212 if (!mCompiledState || mCompiledState->debugInfo.empty())
213 {
214 return "";
215 }
216
217 return mCompiledState->debugInfo + std::string("\n// ") +
218 gl::GetShaderTypeString(mState.getShaderType()) + " SHADER END\n";
219 }
220
generateWorkarounds(CompilerWorkaroundsD3D * workarounds) const221 void CompiledShaderStateD3D::generateWorkarounds(CompilerWorkaroundsD3D *workarounds) const
222 {
223 if (usesDiscardRewriting)
224 {
225 // ANGLE issue 486:
226 // Work-around a D3D9 compiler bug that presents itself when using conditional discard, by
227 // disabling optimization
228 workarounds->skipOptimization = true;
229 }
230 else if (usesNestedBreak)
231 {
232 // ANGLE issue 603:
233 // Work-around a D3D9 compiler bug that presents itself when using break in a nested loop,
234 // by maximizing optimization We want to keep the use of
235 // ANGLE_D3D_WORKAROUND_MAX_OPTIMIZATION minimal to prevent hangs, so usesDiscard takes
236 // precedence
237 workarounds->useMaxOptimization = true;
238 }
239
240 if (requiresIEEEStrictCompiling)
241 {
242 // IEEE Strictness for D3D compiler needs to be enabled for NaNs to work.
243 workarounds->enableIEEEStrictness = true;
244 }
245 }
246
getUniformRegister(const std::string & uniformName) const247 unsigned int CompiledShaderStateD3D::getUniformRegister(const std::string &uniformName) const
248 {
249 ASSERT(uniformRegisterMap.count(uniformName) > 0);
250 return uniformRegisterMap.find(uniformName)->second;
251 }
252
getUniformBlockRegister(const std::string & blockName) const253 unsigned int CompiledShaderStateD3D::getUniformBlockRegister(const std::string &blockName) const
254 {
255 ASSERT(uniformBlockRegisterMap.count(blockName) > 0);
256 return uniformBlockRegisterMap.find(blockName)->second;
257 }
258
shouldUniformBlockUseStructuredBuffer(const std::string & blockName) const259 bool CompiledShaderStateD3D::shouldUniformBlockUseStructuredBuffer(
260 const std::string &blockName) const
261 {
262 ASSERT(uniformBlockUseStructuredBufferMap.count(blockName) > 0);
263 return uniformBlockUseStructuredBufferMap.find(blockName)->second;
264 }
265
getShaderStorageBlockRegister(const std::string & blockName) const266 unsigned int CompiledShaderStateD3D::getShaderStorageBlockRegister(
267 const std::string &blockName) const
268 {
269 ASSERT(shaderStorageBlockRegisterMap.count(blockName) > 0);
270 return shaderStorageBlockRegisterMap.find(blockName)->second;
271 }
272
useImage2DFunction(const std::string & functionName) const273 bool CompiledShaderStateD3D::useImage2DFunction(const std::string &functionName) const
274 {
275 if (usedImage2DFunctionNames.empty())
276 {
277 return false;
278 }
279
280 return usedImage2DFunctionNames.find(functionName) != usedImage2DFunctionNames.end();
281 }
282
getSlowCompilingUniformBlockSet() const283 const std::set<std::string> &CompiledShaderStateD3D::getSlowCompilingUniformBlockSet() const
284 {
285 return slowCompilingUniformBlockSet;
286 }
287
compile(const gl::Context * context,ShCompileOptions * options)288 std::shared_ptr<ShaderTranslateTask> ShaderD3D::compile(const gl::Context *context,
289 ShCompileOptions *options)
290 {
291 // Create a new compiled shader state. Currently running program link jobs will use the
292 // previous state.
293 mCompiledState = std::make_shared<CompiledShaderStateD3D>();
294
295 std::string sourcePath;
296
297 const angle::FeaturesD3D &features = mRenderer->getFeatures();
298 const gl::Extensions &extensions = mRenderer->getNativeExtensions();
299
300 const std::string &source = mState.getSource();
301
302 #if !defined(ANGLE_ENABLE_WINDOWS_UWP)
303 if (gl::DebugAnnotationsActive(context))
304 {
305 sourcePath = angle::CreateTemporaryFile().value();
306 writeFile(sourcePath.c_str(), source.c_str(), source.length());
307 options->lineDirectives = true;
308 options->sourcePath = true;
309 }
310 #endif
311
312 if (features.expandIntegerPowExpressions.enabled)
313 {
314 options->expandSelectHLSLIntegerPowExpressions = true;
315 }
316
317 if (features.getDimensionsIgnoresBaseLevel.enabled)
318 {
319 options->HLSLGetDimensionsIgnoresBaseLevel = true;
320 }
321
322 if (features.preAddTexelFetchOffsets.enabled)
323 {
324 options->rewriteTexelFetchOffsetToTexelFetch = true;
325 }
326 if (features.rewriteUnaryMinusOperator.enabled)
327 {
328 options->rewriteIntegerUnaryMinusOperator = true;
329 }
330 if (features.emulateIsnanFloat.enabled)
331 {
332 options->emulateIsnanFloatFunction = true;
333 }
334 if (features.skipVSConstantRegisterZero.enabled &&
335 mState.getShaderType() == gl::ShaderType::Vertex)
336 {
337 options->skipD3DConstantRegisterZero = true;
338 }
339 if (features.forceAtomicValueResolution.enabled)
340 {
341 options->forceAtomicValueResolution = true;
342 }
343 if (features.allowTranslateUniformBlockToStructuredBuffer.enabled)
344 {
345 options->allowTranslateUniformBlockToStructuredBuffer = true;
346 }
347 if (extensions.multiviewOVR || extensions.multiview2OVR)
348 {
349 options->initializeBuiltinsForInstancedMultiview = true;
350 }
351 if (extensions.shaderPixelLocalStorageANGLE)
352 {
353 options->pls = mRenderer->getNativePixelLocalStorageOptions();
354 }
355
356 // D3D11 Feature Level 9_3 and below do not support non-constant loop indexes in fragment
357 // shaders. Shader compilation will fail. To provide a better error message we can instruct
358 // the compiler to pre-validate.
359 if (!features.supportsNonConstantLoopIndexing.enabled)
360 {
361 options->validateLoopIndexing = true;
362 }
363
364 // The D3D translations are not currently validation-error-free
365 options->validateAST = false;
366
367 return std::shared_ptr<ShaderTranslateTask>(
368 new ShaderTranslateTaskD3D(mCompiledState, std::move(sourcePath)));
369 }
370
load(const gl::Context * context,gl::BinaryInputStream * stream)371 std::shared_ptr<ShaderTranslateTask> ShaderD3D::load(const gl::Context *context,
372 gl::BinaryInputStream *stream)
373 {
374 UNREACHABLE();
375 return std::shared_ptr<ShaderTranslateTask>(new ShaderTranslateTask);
376 }
377
hasUniform(const std::string & name) const378 bool CompiledShaderStateD3D::hasUniform(const std::string &name) const
379 {
380 return uniformRegisterMap.find(name) != uniformRegisterMap.end();
381 }
382
383 } // namespace rx
384