• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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