1 //
2 // Copyright (c) 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/Shader.h"
15 #include "libANGLE/features.h"
16 #include "libANGLE/renderer/d3d/ProgramD3D.h"
17 #include "libANGLE/renderer/d3d/RendererD3D.h"
18 
19 // Definitions local to the translation unit
20 namespace
21 {
22 
GetShaderTypeString(GLenum type)23 const char *GetShaderTypeString(GLenum type)
24 {
25     switch (type)
26     {
27         case GL_VERTEX_SHADER:
28             return "VERTEX";
29 
30         case GL_FRAGMENT_SHADER:
31             return "FRAGMENT";
32 
33         case GL_COMPUTE_SHADER:
34             return "COMPUTE";
35 
36         default:
37             UNREACHABLE();
38             return "";
39     }
40 }
41 
42 }  // anonymous namespace
43 
44 namespace rx
45 {
46 
ShaderD3D(const gl::ShaderState & data,const angle::WorkaroundsD3D & workarounds,const gl::Extensions & extensions)47 ShaderD3D::ShaderD3D(const gl::ShaderState &data,
48                      const angle::WorkaroundsD3D &workarounds,
49                      const gl::Extensions &extensions)
50     : ShaderImpl(data), mAdditionalOptions(0)
51 {
52     uncompile();
53 
54     if (workarounds.expandIntegerPowExpressions)
55     {
56         mAdditionalOptions |= SH_EXPAND_SELECT_HLSL_INTEGER_POW_EXPRESSIONS;
57     }
58 
59     if (workarounds.getDimensionsIgnoresBaseLevel)
60     {
61         mAdditionalOptions |= SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL;
62     }
63 
64     if (workarounds.preAddTexelFetchOffsets)
65     {
66         mAdditionalOptions |= SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH;
67     }
68     if (workarounds.rewriteUnaryMinusOperator)
69     {
70         mAdditionalOptions |= SH_REWRITE_INTEGER_UNARY_MINUS_OPERATOR;
71     }
72     if (workarounds.emulateIsnanFloat)
73     {
74         mAdditionalOptions |= SH_EMULATE_ISNAN_FLOAT_FUNCTION;
75     }
76     if (extensions.multiview)
77     {
78         mAdditionalOptions |= SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW;
79     }
80 }
81 
~ShaderD3D()82 ShaderD3D::~ShaderD3D()
83 {
84 }
85 
getDebugInfo() const86 std::string ShaderD3D::getDebugInfo() const
87 {
88     if (mDebugInfo.empty())
89     {
90         return "";
91     }
92 
93     return mDebugInfo + std::string("\n// ") + GetShaderTypeString(mData.getShaderType()) +
94            " SHADER END\n";
95 }
96 
97 // initialize/clean up previous state
uncompile()98 void ShaderD3D::uncompile()
99 {
100     // set by compileToHLSL
101     mCompilerOutputType = SH_ESSL_OUTPUT;
102 
103     mUsesMultipleRenderTargets = false;
104     mUsesFragColor = false;
105     mUsesFragData = false;
106     mUsesFragCoord = false;
107     mUsesFrontFacing = false;
108     mUsesPointSize = false;
109     mUsesPointCoord = false;
110     mUsesDepthRange = false;
111     mUsesFragDepth = false;
112     mHasANGLEMultiviewEnabled    = false;
113     mUsesViewID                  = false;
114     mUsesDiscardRewriting = false;
115     mUsesNestedBreak = false;
116     mRequiresIEEEStrictCompiling = false;
117 
118     mDebugInfo.clear();
119 }
120 
generateWorkarounds(angle::CompilerWorkaroundsD3D * workarounds) const121 void ShaderD3D::generateWorkarounds(angle::CompilerWorkaroundsD3D *workarounds) const
122 {
123     if (mUsesDiscardRewriting)
124     {
125         // ANGLE issue 486:
126         // Work-around a D3D9 compiler bug that presents itself when using conditional discard, by disabling optimization
127         workarounds->skipOptimization = true;
128     }
129     else if (mUsesNestedBreak)
130     {
131         // ANGLE issue 603:
132         // Work-around a D3D9 compiler bug that presents itself when using break in a nested loop, by maximizing optimization
133         // We want to keep the use of ANGLE_D3D_WORKAROUND_MAX_OPTIMIZATION minimal to prevent hangs, so usesDiscard takes precedence
134         workarounds->useMaxOptimization = true;
135     }
136 
137     if (mRequiresIEEEStrictCompiling)
138     {
139         // IEEE Strictness for D3D compiler needs to be enabled for NaNs to work.
140         workarounds->enableIEEEStrictness = true;
141     }
142 }
143 
getUniformRegister(const std::string & uniformName) const144 unsigned int ShaderD3D::getUniformRegister(const std::string &uniformName) const
145 {
146     ASSERT(mUniformRegisterMap.count(uniformName) > 0);
147     return mUniformRegisterMap.find(uniformName)->second;
148 }
149 
getUniformBlockRegister(const std::string & blockName) const150 unsigned int ShaderD3D::getUniformBlockRegister(const std::string &blockName) const
151 {
152     ASSERT(mUniformBlockRegisterMap.count(blockName) > 0);
153     return mUniformBlockRegisterMap.find(blockName)->second;
154 }
155 
getCompilerOutputType() const156 ShShaderOutput ShaderD3D::getCompilerOutputType() const
157 {
158     return mCompilerOutputType;
159 }
160 
prepareSourceAndReturnOptions(std::stringstream * shaderSourceStream,std::string * sourcePath)161 ShCompileOptions ShaderD3D::prepareSourceAndReturnOptions(std::stringstream *shaderSourceStream,
162                                                           std::string *sourcePath)
163 {
164     uncompile();
165 
166     ShCompileOptions additionalOptions = 0;
167 
168     const std::string &source = mData.getSource();
169 
170 #if !defined(ANGLE_ENABLE_WINDOWS_STORE)
171     if (gl::DebugAnnotationsActive())
172     {
173         *sourcePath = getTempPath();
174         writeFile(sourcePath->c_str(), source.c_str(), source.length());
175         additionalOptions |= SH_LINE_DIRECTIVES | SH_SOURCE_PATH;
176     }
177 #endif
178 
179     additionalOptions |= mAdditionalOptions;
180 
181     *shaderSourceStream << source;
182     return additionalOptions;
183 }
184 
hasUniform(const std::string & name) const185 bool ShaderD3D::hasUniform(const std::string &name) const
186 {
187     return mUniformRegisterMap.find(name) != mUniformRegisterMap.end();
188 }
189 
GetUniformRegisterMap(const std::map<std::string,unsigned int> * uniformRegisterMap)190 const std::map<std::string, unsigned int> &GetUniformRegisterMap(
191     const std::map<std::string, unsigned int> *uniformRegisterMap)
192 {
193     ASSERT(uniformRegisterMap);
194     return *uniformRegisterMap;
195 }
196 
postTranslateCompile(gl::Compiler * compiler,std::string * infoLog)197 bool ShaderD3D::postTranslateCompile(gl::Compiler *compiler, std::string *infoLog)
198 {
199     // TODO(jmadill): We shouldn't need to cache this.
200     mCompilerOutputType = compiler->getShaderOutputType();
201 
202     const std::string &translatedSource = mData.getTranslatedSource();
203 
204     mUsesMultipleRenderTargets = translatedSource.find("GL_USES_MRT") != std::string::npos;
205     mUsesFragColor             = translatedSource.find("GL_USES_FRAG_COLOR") != std::string::npos;
206     mUsesFragData              = translatedSource.find("GL_USES_FRAG_DATA") != std::string::npos;
207     mUsesFragCoord             = translatedSource.find("GL_USES_FRAG_COORD") != std::string::npos;
208     mUsesFrontFacing           = translatedSource.find("GL_USES_FRONT_FACING") != std::string::npos;
209     mUsesPointSize             = translatedSource.find("GL_USES_POINT_SIZE") != std::string::npos;
210     mUsesPointCoord            = translatedSource.find("GL_USES_POINT_COORD") != std::string::npos;
211     mUsesDepthRange            = translatedSource.find("GL_USES_DEPTH_RANGE") != std::string::npos;
212     mUsesFragDepth             = translatedSource.find("GL_USES_FRAG_DEPTH") != std::string::npos;
213     mHasANGLEMultiviewEnabled =
214         translatedSource.find("GL_ANGLE_MULTIVIEW_ENABLED") != std::string::npos;
215     mUsesViewID = translatedSource.find("GL_USES_VIEW_ID") != std::string::npos;
216     mUsesDiscardRewriting =
217         translatedSource.find("ANGLE_USES_DISCARD_REWRITING") != std::string::npos;
218     mUsesNestedBreak  = translatedSource.find("ANGLE_USES_NESTED_BREAK") != std::string::npos;
219     mRequiresIEEEStrictCompiling =
220         translatedSource.find("ANGLE_REQUIRES_IEEE_STRICT_COMPILING") != std::string::npos;
221 
222     ShHandle compilerHandle = compiler->getCompilerHandle(mData.getShaderType());
223 
224     mUniformRegisterMap = GetUniformRegisterMap(sh::GetUniformRegisterMap(compilerHandle));
225 
226     for (const sh::InterfaceBlock &interfaceBlock : mData.getUniformBlocks())
227     {
228         if (interfaceBlock.staticUse)
229         {
230             unsigned int index = static_cast<unsigned int>(-1);
231             bool blockRegisterResult =
232                 sh::GetUniformBlockRegister(compilerHandle, interfaceBlock.name, &index);
233             ASSERT(blockRegisterResult);
234 
235             mUniformBlockRegisterMap[interfaceBlock.name] = index;
236         }
237     }
238 
239     mDebugInfo +=
240         std::string("// ") + GetShaderTypeString(mData.getShaderType()) + " SHADER BEGIN\n";
241     mDebugInfo += "\n// GLSL BEGIN\n\n" + mData.getSource() + "\n\n// GLSL END\n\n\n";
242     mDebugInfo += "// INITIAL HLSL BEGIN\n\n" + translatedSource + "\n// INITIAL HLSL END\n\n\n";
243     // Successive steps will append more info
244     return true;
245 }
246 
247 }  // namespace rx
248