blob: f45ba5bd9eb972b55514972981ea165453b0602f [file] [log] [blame]
Geoff Langdad5ed32014-02-10 12:59:17 -05001#include "precompiled.h"
2#include "libGLESv2/renderer/d3d/HLSLCompiler.h"
3#include "libGLESv2/Program.h"
4#include "libGLESv2/main.h"
5
6#include "common/utilities.h"
7
8#include "third_party/trace_event/trace_event.h"
9
10namespace rx
11{
12
13HLSLCompiler::HLSLCompiler()
14 : mD3DCompilerModule(NULL),
15 mD3DCompileFunc(NULL)
16{
17}
18
19HLSLCompiler::~HLSLCompiler()
20{
21 release();
22}
23
24bool HLSLCompiler::initialize()
25{
26 TRACE_EVENT0("gpu", "initializeCompiler");
27#if defined(ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES)
28 // Find a D3DCompiler module that had already been loaded based on a predefined list of versions.
29 static TCHAR* d3dCompilerNames[] = ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES;
30
31 for (size_t i = 0; i < ArraySize(d3dCompilerNames); ++i)
32 {
33 if (GetModuleHandleEx(0, d3dCompilerNames[i], &mD3DCompilerModule))
34 {
35 break;
36 }
37 }
38#endif // ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES
39
40 if (!mD3DCompilerModule)
41 {
42 // Load the version of the D3DCompiler DLL associated with the Direct3D version ANGLE was built with.
43 mD3DCompilerModule = LoadLibrary(D3DCOMPILER_DLL);
44 }
45
46 if (!mD3DCompilerModule)
47 {
48 ERR("No D3D compiler module found - aborting!\n");
49 return false;
50 }
51
52 mD3DCompileFunc = reinterpret_cast<CompileFuncPtr>(GetProcAddress(mD3DCompilerModule, "D3DCompile"));
53 ASSERT(mD3DCompileFunc);
54
55 return mD3DCompileFunc != NULL;
56}
57
58void HLSLCompiler::release()
59{
60 if (mD3DCompilerModule)
61 {
62 FreeLibrary(mD3DCompilerModule);
63 mD3DCompilerModule = NULL;
64 mD3DCompileFunc = NULL;
65 }
66}
67
68ShaderBlob *HLSLCompiler::compileToBinary(gl::InfoLog &infoLog, const char *hlsl, const char *profile,
69 unsigned int optimizationFlags, bool alternateFlags) const
70{
71 ASSERT(mD3DCompilerModule && mD3DCompileFunc);
72
73 if (!hlsl)
74 {
75 return NULL;
76 }
77
78 HRESULT result = S_OK;
79 UINT flags = 0;
80 std::string sourceText;
81 if (gl::perfActive())
82 {
83 flags |= D3DCOMPILE_DEBUG;
84
85#ifdef NDEBUG
86 flags |= optimizationFlags;
87#else
88 flags |= D3DCOMPILE_SKIP_OPTIMIZATION;
89#endif
90
91 std::string sourcePath = getTempPath();
92 sourceText = std::string("#line 2 \"") + sourcePath + std::string("\"\n\n") + std::string(hlsl);
93 writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size());
94 }
95 else
96 {
97 flags |= optimizationFlags;
98 sourceText = hlsl;
99 }
100
101 // Sometimes D3DCompile will fail with the default compilation flags for complicated shaders when it would otherwise pass with alternative options.
102 // Try the default flags first and if compilation fails, try some alternatives.
103 const static UINT extraFlags[] =
104 {
105 0,
106 D3DCOMPILE_AVOID_FLOW_CONTROL,
107 D3DCOMPILE_PREFER_FLOW_CONTROL
108 };
109
110 const static char * const extraFlagNames[] =
111 {
112 "default",
113 "avoid flow control",
114 "prefer flow control"
115 };
116
117 int attempts = alternateFlags ? ArraySize(extraFlags) : 1;
118 pD3DCompile compileFunc = reinterpret_cast<pD3DCompile>(mD3DCompileFunc);
119 for (int i = 0; i < attempts; ++i)
120 {
121 ID3DBlob *errorMessage = NULL;
122 ID3DBlob *binary = NULL;
123
124 result = compileFunc(hlsl, strlen(hlsl), gl::g_fakepath, NULL, NULL,
125 "main", profile, flags | extraFlags[i], 0, &binary, &errorMessage);
126 if (errorMessage)
127 {
128 const char *message = (const char*)errorMessage->GetBufferPointer();
129
130 infoLog.appendSanitized(message);
131 TRACE("\n%s", hlsl);
132 TRACE("\n%s", message);
133
134 SafeRelease(errorMessage);
135 }
136
137 if (SUCCEEDED(result))
138 {
139 return (ShaderBlob*)binary;
140 }
141 else
142 {
143 if (result == E_OUTOFMEMORY)
144 {
145 return gl::error(GL_OUT_OF_MEMORY, (ShaderBlob*)NULL);
146 }
147
148 infoLog.append("Warning: D3D shader compilation failed with ");
149 infoLog.append(extraFlagNames[i]);
150 infoLog.append(" flags.");
151 if (i + 1 < attempts)
152 {
153 infoLog.append(" Retrying with ");
154 infoLog.append(extraFlagNames[i + 1]);
155 infoLog.append(".\n");
156 }
157 }
158 }
159
160 return NULL;
161}
162
163}