blob: 59a6a2f476daed1654bbf7103cac631585479420 [file] [log] [blame]
Jamie Madillea247592014-08-28 10:37:08 -04001//
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
Geoff Langdad5ed32014-02-10 12:59:17 -05007#include "libGLESv2/renderer/d3d/HLSLCompiler.h"
8#include "libGLESv2/Program.h"
9#include "libGLESv2/main.h"
10
11#include "common/utilities.h"
12
13#include "third_party/trace_event/trace_event.h"
14
Tibor den Ouden2221f472014-10-22 15:07:05 +020015// Definitions local to the translation unit
16namespace
17{
18
19#ifdef CREATE_COMPILER_FLAG_INFO
20 #undef CREATE_COMPILER_FLAG_INFO
21#endif
22
23#define CREATE_COMPILER_FLAG_INFO(flag) { flag, #flag }
24
25struct CompilerFlagInfo
26{
27 UINT mFlag;
28 const char *mName;
29};
30
31CompilerFlagInfo CompilerFlagInfos[] =
32{
33 // NOTE: The data below is copied from d3dcompiler.h
34 // If something changes there it should be changed here as well
35 CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_DEBUG), // (1 << 0)
36 CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_SKIP_VALIDATION), // (1 << 1)
37 CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_SKIP_OPTIMIZATION), // (1 << 2)
38 CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_PACK_MATRIX_ROW_MAJOR), // (1 << 3)
39 CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR), // (1 << 4)
40 CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_PARTIAL_PRECISION), // (1 << 5)
41 CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_FORCE_VS_SOFTWARE_NO_OPT), // (1 << 6)
42 CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_FORCE_PS_SOFTWARE_NO_OPT), // (1 << 7)
43 CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_NO_PRESHADER), // (1 << 8)
44 CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_AVOID_FLOW_CONTROL), // (1 << 9)
45 CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_PREFER_FLOW_CONTROL), // (1 << 10)
46 CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_ENABLE_STRICTNESS), // (1 << 11)
47 CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY), // (1 << 12)
48 CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_IEEE_STRICTNESS), // (1 << 13)
49 CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_OPTIMIZATION_LEVEL0), // (1 << 14)
50 CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_OPTIMIZATION_LEVEL1), // 0
51 CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_OPTIMIZATION_LEVEL2), // ((1 << 14) | (1 << 15))
52 CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_OPTIMIZATION_LEVEL3), // (1 << 15)
53 CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_RESERVED16), // (1 << 16)
54 CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_RESERVED17), // (1 << 17)
55 CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_WARNINGS_ARE_ERRORS) // (1 << 18)
56};
57
58#undef CREATE_COMPILER_FLAG_INFO
59
60bool IsCompilerFlagSet(UINT mask, UINT flag)
61{
62 bool isFlagSet = IsMaskFlagSet(mask, flag);
63
64 switch(flag)
65 {
66 case D3DCOMPILE_OPTIMIZATION_LEVEL0:
67 return isFlagSet && !IsMaskFlagSet(mask, UINT(D3DCOMPILE_OPTIMIZATION_LEVEL3));
68
69 case D3DCOMPILE_OPTIMIZATION_LEVEL1:
70 return (mask & D3DCOMPILE_OPTIMIZATION_LEVEL2) == UINT(0);
71
72 case D3DCOMPILE_OPTIMIZATION_LEVEL3:
73 return isFlagSet && !IsMaskFlagSet(mask, UINT(D3DCOMPILE_OPTIMIZATION_LEVEL0));
74
75 default:
76 return isFlagSet;
77 }
78}
79
80const char *GetCompilerFlagName(UINT mask, size_t flagIx)
81{
82 const CompilerFlagInfo &flagInfo = CompilerFlagInfos[flagIx];
83 if (IsCompilerFlagSet(mask, flagInfo.mFlag))
84 {
85 return flagInfo.mName;
86 }
87
88 return nullptr;
89}
90
91}
92
Geoff Langdad5ed32014-02-10 12:59:17 -050093namespace rx
94{
95
Geoff Lang3935e512014-09-23 13:15:19 -040096CompileConfig::CompileConfig()
97 : flags(0),
98 name()
99{
100}
101
102CompileConfig::CompileConfig(UINT flags, const std::string &name)
103 : flags(flags),
104 name(name)
105{
106}
107
Geoff Langdad5ed32014-02-10 12:59:17 -0500108HLSLCompiler::HLSLCompiler()
109 : mD3DCompilerModule(NULL),
Tibor den Ouden97049c62014-10-06 21:39:16 +0200110 mD3DCompileFunc(NULL),
111 mD3DDisassembleFunc(NULL)
Geoff Langdad5ed32014-02-10 12:59:17 -0500112{
113}
114
115HLSLCompiler::~HLSLCompiler()
116{
117 release();
118}
119
120bool HLSLCompiler::initialize()
121{
122 TRACE_EVENT0("gpu", "initializeCompiler");
Cooper Partin88d3b8c2014-10-08 10:41:56 -0700123#if !defined(ANGLE_ENABLE_WINDOWS_STORE)
Geoff Langdad5ed32014-02-10 12:59:17 -0500124#if defined(ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES)
125 // Find a D3DCompiler module that had already been loaded based on a predefined list of versions.
Jamie Madill07d49ef2014-07-25 11:52:38 -0400126 static const char *d3dCompilerNames[] = ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES;
Geoff Langdad5ed32014-02-10 12:59:17 -0500127
128 for (size_t i = 0; i < ArraySize(d3dCompilerNames); ++i)
129 {
Jamie Madill07d49ef2014-07-25 11:52:38 -0400130 if (GetModuleHandleExA(0, d3dCompilerNames[i], &mD3DCompilerModule))
Geoff Langdad5ed32014-02-10 12:59:17 -0500131 {
132 break;
133 }
134 }
135#endif // ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES
136
137 if (!mD3DCompilerModule)
138 {
139 // Load the version of the D3DCompiler DLL associated with the Direct3D version ANGLE was built with.
140 mD3DCompilerModule = LoadLibrary(D3DCOMPILER_DLL);
141 }
142
143 if (!mD3DCompilerModule)
144 {
145 ERR("No D3D compiler module found - aborting!\n");
146 return false;
147 }
148
Geoff Lang3935e512014-09-23 13:15:19 -0400149 mD3DCompileFunc = reinterpret_cast<pD3DCompile>(GetProcAddress(mD3DCompilerModule, "D3DCompile"));
Geoff Langdad5ed32014-02-10 12:59:17 -0500150 ASSERT(mD3DCompileFunc);
Cooper Partin73b8de72014-10-28 08:34:30 -0700151
152 mD3DDisassembleFunc = reinterpret_cast<pD3DDisassemble>(GetProcAddress(mD3DCompilerModule, "D3DDisassemble"));
153 ASSERT(mD3DDisassembleFunc);
154
Cooper Partin88d3b8c2014-10-08 10:41:56 -0700155#else
156 // D3D Shader compiler is linked already into this module, so the export
157 // can be directly assigned.
158 mD3DCompilerModule = NULL;
159 mD3DCompileFunc = reinterpret_cast<pD3DCompile>(D3DCompile);
Cooper Partin73b8de72014-10-28 08:34:30 -0700160 mD3DDisassembleFunc = reinterpret_cast<pD3DDisassemble>(D3DDisassemble);
Cooper Partin88d3b8c2014-10-08 10:41:56 -0700161#endif
Geoff Langdad5ed32014-02-10 12:59:17 -0500162
163 return mD3DCompileFunc != NULL;
164}
165
166void HLSLCompiler::release()
167{
168 if (mD3DCompilerModule)
169 {
170 FreeLibrary(mD3DCompilerModule);
171 mD3DCompilerModule = NULL;
172 mD3DCompileFunc = NULL;
Tibor den Ouden97049c62014-10-06 21:39:16 +0200173 mD3DDisassembleFunc = NULL;
Geoff Langdad5ed32014-02-10 12:59:17 -0500174 }
175}
176
Geoff Langb543aff2014-09-30 14:52:54 -0400177gl::Error HLSLCompiler::compileToBinary(gl::InfoLog &infoLog, const std::string &hlsl, const std::string &profile,
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400178 const std::vector<CompileConfig> &configs, const D3D_SHADER_MACRO *overrideMacros,
Tibor den Ouden97049c62014-10-06 21:39:16 +0200179 ID3DBlob **outCompiledBlob, std::string *outDebugInfo) const
Geoff Langdad5ed32014-02-10 12:59:17 -0500180{
Cooper Partin88d3b8c2014-10-08 10:41:56 -0700181#if !defined(ANGLE_ENABLE_WINDOWS_STORE)
182 ASSERT(mD3DCompilerModule);
183#endif
184 ASSERT(mD3DCompileFunc);
Geoff Langdad5ed32014-02-10 12:59:17 -0500185
Austin Kinross922a9fb2014-10-21 14:26:33 -0700186#if !defined(ANGLE_ENABLE_WINDOWS_STORE)
Geoff Langf7ed7052014-09-23 13:39:31 -0400187 if (gl::perfActive())
188 {
189 std::string sourcePath = getTempPath();
190 std::string sourceText = FormatString("#line 2 \"%s\"\n\n%s", sourcePath.c_str(), hlsl.c_str());
191 writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size());
192 }
Austin Kinross922a9fb2014-10-21 14:26:33 -0700193#endif
Geoff Langf7ed7052014-09-23 13:39:31 -0400194
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400195 const D3D_SHADER_MACRO *macros = overrideMacros ? overrideMacros : NULL;
196
Geoff Lang3935e512014-09-23 13:15:19 -0400197 for (size_t i = 0; i < configs.size(); ++i)
Geoff Langdad5ed32014-02-10 12:59:17 -0500198 {
199 ID3DBlob *errorMessage = NULL;
200 ID3DBlob *binary = NULL;
201
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400202 HRESULT result = mD3DCompileFunc(hlsl.c_str(), hlsl.length(), gl::g_fakepath, macros, NULL, "main", profile.c_str(),
Geoff Lang3935e512014-09-23 13:15:19 -0400203 configs[i].flags, 0, &binary, &errorMessage);
Nicolas Capens93faad92014-05-10 12:14:13 -0400204
Geoff Langdad5ed32014-02-10 12:59:17 -0500205 if (errorMessage)
206 {
Tibor den Ouden97049c62014-10-06 21:39:16 +0200207 std::string message = reinterpret_cast<const char*>(errorMessage->GetBufferPointer());
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400208 SafeRelease(errorMessage);
Geoff Langdad5ed32014-02-10 12:59:17 -0500209
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400210 infoLog.appendSanitized(message.c_str());
Tibor den Ouden97049c62014-10-06 21:39:16 +0200211 TRACE("\n%s", hlsl.c_str());
212 TRACE("\n%s", message.c_str());
Geoff Langdad5ed32014-02-10 12:59:17 -0500213
Nicolas Capens5e0c80a2014-10-10 10:11:54 -0400214 if (message.find("error X3531:") != std::string::npos) // "can't unroll loops marked with loop attribute"
215 {
216 macros = NULL; // Disable [loop] and [flatten]
217
218 // Retry without changing compiler flags
219 i--;
220 continue;
221 }
Geoff Langdad5ed32014-02-10 12:59:17 -0500222 }
223
224 if (SUCCEEDED(result))
225 {
Geoff Langb543aff2014-09-30 14:52:54 -0400226 *outCompiledBlob = binary;
Tibor den Ouden97049c62014-10-06 21:39:16 +0200227
228#ifdef ANGLE_GENERATE_SHADER_DEBUG_INFO
229 (*outDebugInfo) += "// COMPILER INPUT HLSL BEGIN\n\n" + hlsl + "\n// COMPILER INPUT HLSL END\n";
230 (*outDebugInfo) += "\n\n// ASSEMBLY BEGIN\n\n";
231 (*outDebugInfo) += "// Compiler configuration: " + configs[i].name + "\n// Flags:\n";
Tibor den Ouden2221f472014-10-22 15:07:05 +0200232 for (size_t fIx = 0; fIx < ArraySize(CompilerFlagInfos); ++fIx)
233 {
234 const char *flagName = GetCompilerFlagName(configs[i].flags, fIx);
235 if (flagName != nullptr)
236 {
237 (*outDebugInfo) += std::string("// ") + flagName + "\n";
238 }
239 }
240
241 (*outDebugInfo) += "// Macros:\n";
242 if (macros == nullptr)
243 {
244 (*outDebugInfo) += "// - : -\n";
245 }
246 else
247 {
248 for (const D3D_SHADER_MACRO *mIt = macros; mIt->Name != nullptr; ++mIt)
249 {
250 (*outDebugInfo) += std::string("// ") + mIt->Name + " : " + mIt->Definition + "\n";
251 }
252 }
253
Tibor den Ouden97049c62014-10-06 21:39:16 +0200254 (*outDebugInfo) += "\n" + disassembleBinary(binary) + "\n// ASSEMBLY END\n";
255#endif
256
Geoff Langb543aff2014-09-30 14:52:54 -0400257 return gl::Error(GL_NO_ERROR);
Geoff Langdad5ed32014-02-10 12:59:17 -0500258 }
259 else
260 {
261 if (result == E_OUTOFMEMORY)
262 {
Geoff Langb543aff2014-09-30 14:52:54 -0400263 *outCompiledBlob = NULL;
264 return gl::Error(GL_OUT_OF_MEMORY, "HLSL compiler had an unexpected failure, result: 0x%X.", result);
Geoff Langdad5ed32014-02-10 12:59:17 -0500265 }
266
Geoff Lang3935e512014-09-23 13:15:19 -0400267 infoLog.append("Warning: D3D shader compilation failed with %s flags.", configs[i].name.c_str());
Jamie Madill2c976a42014-08-04 11:37:53 -0400268
Geoff Lang3935e512014-09-23 13:15:19 -0400269 if (i + 1 < configs.size())
Geoff Langdad5ed32014-02-10 12:59:17 -0500270 {
Geoff Lang3935e512014-09-23 13:15:19 -0400271 infoLog.append(" Retrying with %s.\n", configs[i + 1].name.c_str());
Geoff Langdad5ed32014-02-10 12:59:17 -0500272 }
273 }
274 }
275
Geoff Langb543aff2014-09-30 14:52:54 -0400276 // None of the configurations succeeded in compiling this shader but the compiler is still intact
277 *outCompiledBlob = NULL;
278 return gl::Error(GL_NO_ERROR);
Geoff Langdad5ed32014-02-10 12:59:17 -0500279}
280
Tibor den Ouden97049c62014-10-06 21:39:16 +0200281std::string HLSLCompiler::disassembleBinary(ID3DBlob *shaderBinary) const
282{
283 // Retrieve disassembly
284 UINT flags = D3D_DISASM_ENABLE_DEFAULT_VALUE_PRINTS | D3D_DISASM_ENABLE_INSTRUCTION_NUMBERING;
285 ID3DBlob *disassembly = NULL;
286 pD3DDisassemble disassembleFunc = reinterpret_cast<pD3DDisassemble>(mD3DDisassembleFunc);
287 LPCVOID buffer = shaderBinary->GetBufferPointer();
288 SIZE_T bufSize = shaderBinary->GetBufferSize();
289 HRESULT result = disassembleFunc(buffer, bufSize, flags, "", &disassembly);
290
291 std::string asmSrc;
292 if (SUCCEEDED(result))
293 {
294 asmSrc = reinterpret_cast<const char*>(disassembly->GetBufferPointer());
295 }
296
297 SafeRelease(disassembly);
298
299 return asmSrc;
300}
301
Geoff Langdad5ed32014-02-10 12:59:17 -0500302}