OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/gl/init/gl_initializer.h" | 5 #include "ui/gl/init/gl_initializer.h" |
6 | 6 |
7 #include "base/at_exit.h" | |
8 #include "base/base_paths.h" | |
9 #include "base/bind.h" | |
10 #include "base/command_line.h" | |
11 #include "base/files/file_path.h" | |
12 #include "base/lazy_instance.h" | |
13 #include "base/logging.h" | 7 #include "base/logging.h" |
14 #include "base/native_library.h" | 8 #include "ui/gl/gl_implementation.h" |
15 #include "base/path_service.h" | |
16 #include "base/strings/stringprintf.h" | |
17 #include "base/threading/thread_restrictions.h" | |
18 #include "base/trace_event/trace_event.h" | |
19 #include "base/win/windows_version.h" | |
20 // TODO(jmadill): Apply to all platforms eventually | |
21 #include "ui/gl/angle_platform_impl.h" | |
22 #include "ui/gl/gl_bindings.h" | |
23 #include "ui/gl/gl_egl_api_implementation.h" | |
24 #include "ui/gl/gl_gl_api_implementation.h" | |
25 #include "ui/gl/gl_osmesa_api_implementation.h" | |
26 #include "ui/gl/gl_surface_egl.h" | 9 #include "ui/gl/gl_surface_egl.h" |
27 #include "ui/gl/gl_surface_wgl.h" | 10 #include "ui/gl/gl_surface_wgl.h" |
28 #include "ui/gl/gl_wgl_api_implementation.h" | |
29 #include "ui/gl/vsync_provider_win.h" | 11 #include "ui/gl/vsync_provider_win.h" |
30 | 12 |
31 #if defined(ENABLE_SWIFTSHADER) | |
32 #include "software_renderer.h" | |
33 #endif | |
34 | |
35 namespace gl { | 13 namespace gl { |
36 namespace init { | 14 namespace init { |
37 | 15 |
38 namespace { | |
39 | |
40 const wchar_t kD3DCompiler[] = L"D3DCompiler_47.dll"; | |
41 | |
42 // TODO(jmadill): Apply to all platforms eventually | |
43 base::LazyInstance<ANGLEPlatformImpl> g_angle_platform_impl = | |
44 LAZY_INSTANCE_INITIALIZER; | |
45 | |
46 ANGLEPlatformShutdownFunc g_angle_platform_shutdown = nullptr; | |
47 | |
48 bool LoadD3DXLibrary(const base::FilePath& module_path, | |
49 const base::FilePath::StringType& name) { | |
50 base::NativeLibrary library = | |
51 base::LoadNativeLibrary(base::FilePath(name), nullptr); | |
52 if (!library) { | |
53 library = base::LoadNativeLibrary(module_path.Append(name), nullptr); | |
54 if (!library) { | |
55 DVLOG(1) << name << " not found."; | |
56 return false; | |
57 } | |
58 } | |
59 return true; | |
60 } | |
61 | |
62 bool InitializeStaticOSMesaInternal() { | |
63 base::FilePath module_path; | |
64 PathService::Get(base::DIR_MODULE, &module_path); | |
65 base::NativeLibrary library = | |
66 base::LoadNativeLibrary(module_path.Append(L"osmesa.dll"), nullptr); | |
67 if (!library) { | |
68 PathService::Get(base::DIR_EXE, &module_path); | |
69 library = | |
70 base::LoadNativeLibrary(module_path.Append(L"osmesa.dll"), nullptr); | |
71 if (!library) { | |
72 DVLOG(1) << "osmesa.dll not found"; | |
73 return false; | |
74 } | |
75 } | |
76 | |
77 GLGetProcAddressProc get_proc_address = | |
78 reinterpret_cast<GLGetProcAddressProc>( | |
79 base::GetFunctionPointerFromNativeLibrary(library, | |
80 "OSMesaGetProcAddress")); | |
81 if (!get_proc_address) { | |
82 DLOG(ERROR) << "OSMesaGetProcAddress not found."; | |
83 base::UnloadNativeLibrary(library); | |
84 return false; | |
85 } | |
86 | |
87 SetGLGetProcAddressProc(get_proc_address); | |
88 AddGLNativeLibrary(library); | |
89 SetGLImplementation(kGLImplementationOSMesaGL); | |
90 | |
91 InitializeStaticGLBindingsGL(); | |
92 InitializeStaticGLBindingsOSMESA(); | |
93 | |
94 return true; | |
95 } | |
96 | |
97 bool InitializeStaticEGLInternal() { | |
98 base::FilePath module_path; | |
99 if (!PathService::Get(base::DIR_MODULE, &module_path)) | |
100 return false; | |
101 | |
102 // Attempt to load the D3DX shader compiler using the default search path | |
103 // and if that fails, using an absolute path. This is to ensure these DLLs | |
104 // are loaded before ANGLE is loaded in case they are not in the default | |
105 // search path. | |
106 LoadD3DXLibrary(module_path, kD3DCompiler); | |
107 | |
108 base::FilePath gles_path; | |
109 const base::CommandLine* command_line = | |
110 base::CommandLine::ForCurrentProcess(); | |
111 bool using_swift_shader = | |
112 command_line->GetSwitchValueASCII(switches::kUseGL) == | |
113 kGLImplementationSwiftShaderName; | |
114 if (using_swift_shader) { | |
115 if (!command_line->HasSwitch(switches::kSwiftShaderPath)) | |
116 return false; | |
117 gles_path = command_line->GetSwitchValuePath(switches::kSwiftShaderPath); | |
118 // Preload library | |
119 LoadLibrary(L"ddraw.dll"); | |
120 } else { | |
121 gles_path = module_path; | |
122 } | |
123 | |
124 // Load libglesv2.dll before libegl.dll because the latter is dependent on | |
125 // the former and if there is another version of libglesv2.dll in the dll | |
126 // search path, it will get loaded instead. | |
127 base::NativeLibrary gles_library = | |
128 base::LoadNativeLibrary(gles_path.Append(L"libglesv2.dll"), nullptr); | |
129 if (!gles_library) { | |
130 DVLOG(1) << "libglesv2.dll not found"; | |
131 return false; | |
132 } | |
133 | |
134 // When using EGL, first try eglGetProcAddress and then Windows | |
135 // GetProcAddress on both the EGL and GLES2 DLLs. | |
136 base::NativeLibrary egl_library = | |
137 base::LoadNativeLibrary(gles_path.Append(L"libegl.dll"), nullptr); | |
138 if (!egl_library) { | |
139 DVLOG(1) << "libegl.dll not found."; | |
140 base::UnloadNativeLibrary(gles_library); | |
141 return false; | |
142 } | |
143 | |
144 #if defined(ENABLE_SWIFTSHADER) | |
145 if (using_swift_shader) { | |
146 SetupSoftwareRenderer(gles_library); | |
147 } | |
148 #endif | |
149 | |
150 if (!using_swift_shader) { | |
151 // Init ANGLE platform here, before we call GetPlatformDisplay(). | |
152 // TODO(jmadill): Apply to all platforms eventually | |
153 ANGLEPlatformInitializeFunc angle_platform_init = | |
154 reinterpret_cast<ANGLEPlatformInitializeFunc>( | |
155 base::GetFunctionPointerFromNativeLibrary( | |
156 gles_library, "ANGLEPlatformInitialize")); | |
157 if (angle_platform_init) { | |
158 angle_platform_init(&g_angle_platform_impl.Get()); | |
159 | |
160 g_angle_platform_shutdown = reinterpret_cast<ANGLEPlatformShutdownFunc>( | |
161 base::GetFunctionPointerFromNativeLibrary(gles_library, | |
162 "ANGLEPlatformShutdown")); | |
163 } | |
164 } | |
165 | |
166 GLGetProcAddressProc get_proc_address = | |
167 reinterpret_cast<GLGetProcAddressProc>( | |
168 base::GetFunctionPointerFromNativeLibrary(egl_library, | |
169 "eglGetProcAddress")); | |
170 if (!get_proc_address) { | |
171 LOG(ERROR) << "eglGetProcAddress not found."; | |
172 base::UnloadNativeLibrary(egl_library); | |
173 base::UnloadNativeLibrary(gles_library); | |
174 return false; | |
175 } | |
176 | |
177 SetGLGetProcAddressProc(get_proc_address); | |
178 AddGLNativeLibrary(egl_library); | |
179 AddGLNativeLibrary(gles_library); | |
180 SetGLImplementation(kGLImplementationEGLGLES2); | |
181 | |
182 InitializeStaticGLBindingsGL(); | |
183 InitializeStaticGLBindingsEGL(); | |
184 | |
185 return true; | |
186 } | |
187 | |
188 bool InitializeStaticWGLInternal() { | |
189 base::NativeLibrary library = | |
190 base::LoadNativeLibrary(base::FilePath(L"opengl32.dll"), nullptr); | |
191 if (!library) { | |
192 DVLOG(1) << "opengl32.dll not found"; | |
193 return false; | |
194 } | |
195 | |
196 GLGetProcAddressProc get_proc_address = | |
197 reinterpret_cast<GLGetProcAddressProc>( | |
198 base::GetFunctionPointerFromNativeLibrary(library, | |
199 "wglGetProcAddress")); | |
200 if (!get_proc_address) { | |
201 LOG(ERROR) << "wglGetProcAddress not found."; | |
202 base::UnloadNativeLibrary(library); | |
203 return false; | |
204 } | |
205 | |
206 SetGLGetProcAddressProc(get_proc_address); | |
207 AddGLNativeLibrary(library); | |
208 SetGLImplementation(kGLImplementationDesktopGL); | |
209 | |
210 // Initialize GL surface and get some functions needed for the context | |
211 // creation below. | |
212 if (!GLSurfaceWGL::InitializeOneOff()) { | |
213 LOG(ERROR) << "GLSurfaceWGL::InitializeOneOff failed."; | |
214 return false; | |
215 } | |
216 wglCreateContextProc wglCreateContextFn = | |
217 reinterpret_cast<wglCreateContextProc>( | |
218 GetGLProcAddress("wglCreateContext")); | |
219 wglDeleteContextProc wglDeleteContextFn = | |
220 reinterpret_cast<wglDeleteContextProc>( | |
221 GetGLProcAddress("wglDeleteContext")); | |
222 wglMakeCurrentProc wglMakeCurrentFn = | |
223 reinterpret_cast<wglMakeCurrentProc>(GetGLProcAddress("wglMakeCurrent")); | |
224 | |
225 // Create a temporary GL context to bind to entry points. This is needed | |
226 // because wglGetProcAddress is specified to return nullptr for all queries | |
227 // if a context is not current in MSDN documentation, and the static | |
228 // bindings may contain functions that need to be queried with | |
229 // wglGetProcAddress. OpenGL wiki further warns that other error values | |
230 // than nullptr could also be returned from wglGetProcAddress on some | |
231 // implementations, so we need to clear the WGL bindings and reinitialize | |
232 // them after the context creation. | |
233 HGLRC gl_context = wglCreateContextFn(GLSurfaceWGL::GetDisplayDC()); | |
234 if (!gl_context) { | |
235 LOG(ERROR) << "Failed to create temporary context."; | |
236 return false; | |
237 } | |
238 if (!wglMakeCurrentFn(GLSurfaceWGL::GetDisplayDC(), gl_context)) { | |
239 LOG(ERROR) << "Failed to make temporary GL context current."; | |
240 wglDeleteContextFn(gl_context); | |
241 return false; | |
242 } | |
243 | |
244 InitializeStaticGLBindingsGL(); | |
245 InitializeStaticGLBindingsWGL(); | |
246 | |
247 wglMakeCurrent(nullptr, nullptr); | |
248 wglDeleteContext(gl_context); | |
249 | |
250 return true; | |
251 } | |
252 | |
253 } // namespace | |
254 | |
255 bool InitializeGLOneOffPlatform() { | 16 bool InitializeGLOneOffPlatform() { |
256 VSyncProviderWin::InitializeOneOff(); | 17 VSyncProviderWin::InitializeOneOff(); |
257 | 18 |
258 switch (GetGLImplementation()) { | 19 switch (GetGLImplementation()) { |
259 case kGLImplementationDesktopGL: | 20 case kGLImplementationDesktopGL: |
260 if (!GLSurfaceWGL::InitializeOneOff()) { | 21 if (!GLSurfaceWGL::InitializeOneOff()) { |
261 LOG(ERROR) << "GLSurfaceWGL::InitializeOneOff failed."; | 22 LOG(ERROR) << "GLSurfaceWGL::InitializeOneOff failed."; |
262 return false; | 23 return false; |
263 } | 24 } |
264 break; | 25 break; |
265 case kGLImplementationEGLGLES2: | 26 case kGLImplementationEGLGLES2: |
266 if (!GLSurfaceEGL::InitializeOneOff()) { | 27 if (!GLSurfaceEGL::InitializeOneOff()) { |
267 LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed."; | 28 LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed."; |
268 return false; | 29 return false; |
269 } | 30 } |
270 break; | 31 break; |
271 case kGLImplementationOSMesaGL: | 32 case kGLImplementationOSMesaGL: |
272 case kGLImplementationMockGL: | 33 case kGLImplementationMockGL: |
273 break; | 34 break; |
274 default: | 35 default: |
275 NOTREACHED(); | 36 NOTREACHED(); |
276 } | 37 } |
277 return true; | 38 return true; |
278 } | 39 } |
279 | 40 |
280 bool InitializeStaticGLBindings(GLImplementation implementation) { | |
281 // Prevent reinitialization with a different implementation. Once the gpu | |
282 // unit tests have initialized with kGLImplementationMock, we don't want to | |
283 // later switch to another GL implementation. | |
284 DCHECK_EQ(kGLImplementationNone, GetGLImplementation()); | |
285 | |
286 // Allow the main thread or another to initialize these bindings | |
287 // after instituting restrictions on I/O. Going forward they will | |
288 // likely be used in the browser process on most platforms. The | |
289 // one-time initialization cost is small, between 2 and 5 ms. | |
290 base::ThreadRestrictions::ScopedAllowIO allow_io; | |
291 | |
292 switch (implementation) { | |
293 case kGLImplementationOSMesaGL: | |
294 return InitializeStaticOSMesaInternal(); | |
295 case kGLImplementationEGLGLES2: | |
296 return InitializeStaticEGLInternal(); | |
297 case kGLImplementationDesktopGL: | |
298 return InitializeStaticWGLInternal(); | |
299 case kGLImplementationMockGL: | |
300 SetGLImplementation(kGLImplementationMockGL); | |
301 InitializeStaticGLBindingsGL(); | |
302 return true; | |
303 default: | |
304 NOTREACHED(); | |
305 } | |
306 | |
307 return false; | |
308 } | |
309 | |
310 void InitializeDebugGLBindings() { | |
311 InitializeDebugGLBindingsEGL(); | |
312 InitializeDebugGLBindingsGL(); | |
313 InitializeDebugGLBindingsOSMESA(); | |
314 InitializeDebugGLBindingsWGL(); | |
315 } | |
316 | |
317 void ClearGLBindingsPlatform() { | |
318 // TODO(jmadill): Apply to all platforms eventually | |
319 if (g_angle_platform_shutdown) { | |
320 g_angle_platform_shutdown(); | |
321 } | |
322 | |
323 ClearGLBindingsEGL(); | |
324 ClearGLBindingsGL(); | |
325 ClearGLBindingsOSMESA(); | |
326 ClearGLBindingsWGL(); | |
327 } | |
328 | |
329 } // namespace init | 41 } // namespace init |
330 } // namespace gl | 42 } // namespace gl |
OLD | NEW |