1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <vector>
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/debug/trace_event.h"
12 #include "base/files/file_path.h"
13 #include "base/logging.h"
14 #include "base/native_library.h"
15 #include "base/path_service.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/threading/thread_restrictions.h"
18 #include "base/win/windows_version.h"
19 #include "ui/gl/gl_bindings.h"
20 #include "ui/gl/gl_context_stub_with_extensions.h"
21 #include "ui/gl/gl_egl_api_implementation.h"
22 #include "ui/gl/gl_gl_api_implementation.h"
23 #include "ui/gl/gl_implementation.h"
24 #include "ui/gl/gl_osmesa_api_implementation.h"
25 #include "ui/gl/gl_surface_wgl.h"
26 #include "ui/gl/gl_wgl_api_implementation.h"
27
28 #if defined(ENABLE_SWIFTSHADER)
29 #include "software_renderer.h"
30 #endif
31
32 namespace gfx {
33
34 namespace {
35
36 // Version 43 is the latest version of D3DCompiler_nn.dll that works prior to
37 // Windows Vista.
38 const wchar_t kPreVistaD3DCompiler[] = L"D3DCompiler_43.dll";
39 const wchar_t kPostVistaD3DCompiler[] = L"D3DCompiler_46.dll";
40
MarshalClearDepthToClearDepthf(GLclampd depth)41 void GL_BINDING_CALL MarshalClearDepthToClearDepthf(GLclampd depth) {
42 glClearDepthf(static_cast<GLclampf>(depth));
43 }
44
MarshalDepthRangeToDepthRangef(GLclampd z_near,GLclampd z_far)45 void GL_BINDING_CALL MarshalDepthRangeToDepthRangef(GLclampd z_near,
46 GLclampd z_far) {
47 glDepthRangef(static_cast<GLclampf>(z_near), static_cast<GLclampf>(z_far));
48 }
49
LoadD3DXLibrary(const base::FilePath & module_path,const base::FilePath::StringType & name)50 bool LoadD3DXLibrary(const base::FilePath& module_path,
51 const base::FilePath::StringType& name) {
52 base::NativeLibrary library =
53 base::LoadNativeLibrary(base::FilePath(name), NULL);
54 if (!library) {
55 library = base::LoadNativeLibrary(module_path.Append(name), NULL);
56 if (!library) {
57 DVLOG(1) << name << " not found.";
58 return false;
59 }
60 }
61 return true;
62 }
63
AngleGetTraceCategoryEnabledFlag(const char * name)64 const unsigned char* AngleGetTraceCategoryEnabledFlag(const char* name) {
65 return TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(name);
66 }
67
AngleAddTraceEvent(char phase,const unsigned char * category_group_enabled,const char * name,unsigned long long id,int num_args,const char ** arg_names,const unsigned char * arg_types,const unsigned long long * arg_values,unsigned char flags)68 void AngleAddTraceEvent(char phase,
69 const unsigned char* category_group_enabled,
70 const char* name,
71 unsigned long long id,
72 int num_args,
73 const char** arg_names,
74 const unsigned char* arg_types,
75 const unsigned long long* arg_values,
76 unsigned char flags) {
77 TRACE_EVENT_API_ADD_TRACE_EVENT(phase,
78 category_group_enabled,
79 name,
80 id,
81 num_args,
82 arg_names,
83 arg_types,
84 arg_values,
85 NULL,
86 flags);
87 }
88
89 typedef const unsigned char* (*GetCategoryEnabledFlagFunc)(const char* name);
90 typedef void (*AddTraceEventFunc)(char phase,
91 const unsigned char* categoryGroupEnabled,
92 const char* name,
93 unsigned long long id,
94 int numArgs,
95 const char** argNames,
96 const unsigned char* argTypes,
97 const unsigned long long* argValues,
98 unsigned char flags);
99 typedef void (__stdcall *SetTraceFunctionPointersFunc)(
100 GetCategoryEnabledFlagFunc get_category_enabled_flag,
101 AddTraceEventFunc add_trace_event_func);
102
103 } // namespace
104
GetAllowedGLImplementations(std::vector<GLImplementation> * impls)105 void GetAllowedGLImplementations(std::vector<GLImplementation>* impls) {
106 impls->push_back(kGLImplementationEGLGLES2);
107 impls->push_back(kGLImplementationDesktopGL);
108 impls->push_back(kGLImplementationOSMesaGL);
109 }
110
InitializeStaticGLBindings(GLImplementation implementation)111 bool InitializeStaticGLBindings(GLImplementation implementation) {
112 // Prevent reinitialization with a different implementation. Once the gpu
113 // unit tests have initialized with kGLImplementationMock, we don't want to
114 // later switch to another GL implementation.
115 DCHECK_EQ(kGLImplementationNone, GetGLImplementation());
116
117 // Allow the main thread or another to initialize these bindings
118 // after instituting restrictions on I/O. Going forward they will
119 // likely be used in the browser process on most platforms. The
120 // one-time initialization cost is small, between 2 and 5 ms.
121 base::ThreadRestrictions::ScopedAllowIO allow_io;
122
123 switch (implementation) {
124 case kGLImplementationOSMesaGL: {
125 base::FilePath module_path;
126 if (!PathService::Get(base::DIR_MODULE, &module_path)) {
127 LOG(ERROR) << "PathService::Get failed.";
128 return false;
129 }
130
131 base::NativeLibrary library = base::LoadNativeLibrary(
132 module_path.Append(L"osmesa.dll"), NULL);
133 if (!library) {
134 DVLOG(1) << "osmesa.dll not found";
135 return false;
136 }
137
138 GLGetProcAddressProc get_proc_address =
139 reinterpret_cast<GLGetProcAddressProc>(
140 base::GetFunctionPointerFromNativeLibrary(
141 library, "OSMesaGetProcAddress"));
142 if (!get_proc_address) {
143 DLOG(ERROR) << "OSMesaGetProcAddress not found.";
144 base::UnloadNativeLibrary(library);
145 return false;
146 }
147
148 SetGLGetProcAddressProc(get_proc_address);
149 AddGLNativeLibrary(library);
150 SetGLImplementation(kGLImplementationOSMesaGL);
151
152 InitializeStaticGLBindingsGL();
153 InitializeStaticGLBindingsOSMESA();
154 break;
155 }
156 case kGLImplementationEGLGLES2: {
157 base::FilePath module_path;
158 if (!PathService::Get(base::DIR_MODULE, &module_path))
159 return false;
160
161 // Attempt to load the D3DX shader compiler using the default search path
162 // and if that fails, using an absolute path. This is to ensure these DLLs
163 // are loaded before ANGLE is loaded in case they are not in the default
164 // search path. Prefer the post vista version.
165 if (base::win::GetVersion() < base::win::VERSION_VISTA ||
166 !LoadD3DXLibrary(module_path, kPostVistaD3DCompiler)) {
167 LoadD3DXLibrary(module_path, kPreVistaD3DCompiler);
168 }
169
170 base::FilePath gles_path;
171 const CommandLine* command_line = CommandLine::ForCurrentProcess();
172 bool using_swift_shader =
173 command_line->GetSwitchValueASCII(switches::kUseGL) == "swiftshader";
174 if (using_swift_shader) {
175 if (!command_line->HasSwitch(switches::kSwiftShaderPath))
176 return false;
177 gles_path =
178 command_line->GetSwitchValuePath(switches::kSwiftShaderPath);
179 // Preload library
180 LoadLibrary(L"ddraw.dll");
181 } else {
182 gles_path = module_path;
183 }
184
185 // Load libglesv2.dll before libegl.dll because the latter is dependent on
186 // the former and if there is another version of libglesv2.dll in the dll
187 // search path, it will get loaded instead.
188 base::NativeLibrary gles_library = base::LoadNativeLibrary(
189 gles_path.Append(L"libglesv2.dll"), NULL);
190 if (!gles_library) {
191 DVLOG(1) << "libglesv2.dll not found";
192 return false;
193 }
194
195 // When using EGL, first try eglGetProcAddress and then Windows
196 // GetProcAddress on both the EGL and GLES2 DLLs.
197 base::NativeLibrary egl_library = base::LoadNativeLibrary(
198 gles_path.Append(L"libegl.dll"), NULL);
199 if (!egl_library) {
200 DVLOG(1) << "libegl.dll not found.";
201 base::UnloadNativeLibrary(gles_library);
202 return false;
203 }
204
205 #if defined(ENABLE_SWIFTSHADER)
206 if (using_swift_shader) {
207 SetupSoftwareRenderer(gles_library);
208 }
209 #endif
210
211 if (!using_swift_shader) {
212 SetTraceFunctionPointersFunc set_trace_function_pointers =
213 reinterpret_cast<SetTraceFunctionPointersFunc>(
214 base::GetFunctionPointerFromNativeLibrary(
215 gles_library, "SetTraceFunctionPointers"));
216 if (set_trace_function_pointers) {
217 set_trace_function_pointers(&AngleGetTraceCategoryEnabledFlag,
218 &AngleAddTraceEvent);
219 }
220 }
221
222 GLGetProcAddressProc get_proc_address =
223 reinterpret_cast<GLGetProcAddressProc>(
224 base::GetFunctionPointerFromNativeLibrary(
225 egl_library, "eglGetProcAddress"));
226 if (!get_proc_address) {
227 LOG(ERROR) << "eglGetProcAddress not found.";
228 base::UnloadNativeLibrary(egl_library);
229 base::UnloadNativeLibrary(gles_library);
230 return false;
231 }
232
233 SetGLGetProcAddressProc(get_proc_address);
234 AddGLNativeLibrary(egl_library);
235 AddGLNativeLibrary(gles_library);
236 SetGLImplementation(kGLImplementationEGLGLES2);
237
238 InitializeStaticGLBindingsGL();
239 InitializeStaticGLBindingsEGL();
240
241 // These two functions take single precision float rather than double
242 // precision float parameters in GLES.
243 ::gfx::g_driver_gl.fn.glClearDepthFn = MarshalClearDepthToClearDepthf;
244 ::gfx::g_driver_gl.fn.glDepthRangeFn = MarshalDepthRangeToDepthRangef;
245 break;
246 }
247 case kGLImplementationDesktopGL: {
248 base::NativeLibrary library = base::LoadNativeLibrary(
249 base::FilePath(L"opengl32.dll"), NULL);
250 if (!library) {
251 DVLOG(1) << "opengl32.dll not found";
252 return false;
253 }
254
255 GLGetProcAddressProc get_proc_address =
256 reinterpret_cast<GLGetProcAddressProc>(
257 base::GetFunctionPointerFromNativeLibrary(
258 library, "wglGetProcAddress"));
259 if (!get_proc_address) {
260 LOG(ERROR) << "wglGetProcAddress not found.";
261 base::UnloadNativeLibrary(library);
262 return false;
263 }
264
265 SetGLGetProcAddressProc(get_proc_address);
266 AddGLNativeLibrary(library);
267 SetGLImplementation(kGLImplementationDesktopGL);
268
269 // Initialize GL surface and get some functions needed for the context
270 // creation below.
271 if (!GLSurfaceWGL::InitializeOneOff()) {
272 LOG(ERROR) << "GLSurfaceWGL::InitializeOneOff failed.";
273 return false;
274 }
275 wglCreateContextProc wglCreateContextFn =
276 reinterpret_cast<wglCreateContextProc>(
277 GetGLProcAddress("wglCreateContext"));
278 wglDeleteContextProc wglDeleteContextFn =
279 reinterpret_cast<wglDeleteContextProc>(
280 GetGLProcAddress("wglDeleteContext"));
281 wglMakeCurrentProc wglMakeCurrentFn =
282 reinterpret_cast<wglMakeCurrentProc>(
283 GetGLProcAddress("wglMakeCurrent"));
284
285 // Create a temporary GL context to bind to entry points. This is needed
286 // because wglGetProcAddress is specified to return NULL for all queries
287 // if a context is not current in MSDN documentation, and the static
288 // bindings may contain functions that need to be queried with
289 // wglGetProcAddress. OpenGL wiki further warns that other error values
290 // than NULL could also be returned from wglGetProcAddress on some
291 // implementations, so we need to clear the WGL bindings and reinitialize
292 // them after the context creation.
293 HGLRC gl_context = wglCreateContextFn(GLSurfaceWGL::GetDisplayDC());
294 if (!gl_context) {
295 LOG(ERROR) << "Failed to create temporary context.";
296 return false;
297 }
298 if (!wglMakeCurrentFn(GLSurfaceWGL::GetDisplayDC(), gl_context)) {
299 LOG(ERROR) << "Failed to make temporary GL context current.";
300 wglDeleteContextFn(gl_context);
301 return false;
302 }
303
304 InitializeStaticGLBindingsGL();
305 InitializeStaticGLBindingsWGL();
306
307 wglMakeCurrent(NULL, NULL);
308 wglDeleteContext(gl_context);
309
310 break;
311 }
312 case kGLImplementationMockGL: {
313 SetGLImplementation(kGLImplementationMockGL);
314 InitializeStaticGLBindingsGL();
315 break;
316 }
317 default:
318 return false;
319 }
320
321 return true;
322 }
323
InitializeDynamicGLBindings(GLImplementation implementation,GLContext * context)324 bool InitializeDynamicGLBindings(GLImplementation implementation,
325 GLContext* context) {
326 switch (implementation) {
327 case kGLImplementationOSMesaGL:
328 InitializeDynamicGLBindingsGL(context);
329 InitializeDynamicGLBindingsOSMESA(context);
330 break;
331 case kGLImplementationEGLGLES2:
332 InitializeDynamicGLBindingsGL(context);
333 InitializeDynamicGLBindingsEGL(context);
334 break;
335 case kGLImplementationDesktopGL:
336 InitializeDynamicGLBindingsGL(context);
337 InitializeDynamicGLBindingsWGL(context);
338 break;
339 case kGLImplementationMockGL:
340 if (!context) {
341 scoped_refptr<GLContextStubWithExtensions> mock_context(
342 new GLContextStubWithExtensions());
343 mock_context->SetGLVersionString("3.0");
344 InitializeDynamicGLBindingsGL(mock_context.get());
345 } else
346 InitializeDynamicGLBindingsGL(context);
347 break;
348 default:
349 return false;
350 }
351
352 return true;
353 }
354
InitializeDebugGLBindings()355 void InitializeDebugGLBindings() {
356 InitializeDebugGLBindingsEGL();
357 InitializeDebugGLBindingsGL();
358 InitializeDebugGLBindingsOSMESA();
359 InitializeDebugGLBindingsWGL();
360 }
361
ClearGLBindings()362 void ClearGLBindings() {
363 ClearGLBindingsEGL();
364 ClearGLBindingsGL();
365 ClearGLBindingsOSMESA();
366 ClearGLBindingsWGL();
367 SetGLImplementation(kGLImplementationNone);
368 UnloadGLNativeLibraries();
369 }
370
GetGLWindowSystemBindingInfo(GLWindowSystemBindingInfo * info)371 bool GetGLWindowSystemBindingInfo(GLWindowSystemBindingInfo* info) {
372 switch (GetGLImplementation()) {
373 case kGLImplementationDesktopGL:
374 return GetGLWindowSystemBindingInfoWGL(info);
375 case kGLImplementationEGLGLES2:
376 return GetGLWindowSystemBindingInfoEGL(info);
377 default:
378 return false;
379 }
380 }
381
382 } // namespace gfx
383