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.
7 #include "base/at_exit.h"
8 #include "base/base_paths.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"
28 #if defined(ENABLE_SWIFTSHADER)
29 #include "software_renderer.h"
36 const wchar_t kD3DCompiler
[] = L
"D3DCompiler_46.dll";
38 void GL_BINDING_CALL
MarshalClearDepthToClearDepthf(GLclampd depth
) {
39 glClearDepthf(static_cast<GLclampf
>(depth
));
42 void GL_BINDING_CALL
MarshalDepthRangeToDepthRangef(GLclampd z_near
,
44 glDepthRangef(static_cast<GLclampf
>(z_near
), static_cast<GLclampf
>(z_far
));
47 bool LoadD3DXLibrary(const base::FilePath
& module_path
,
48 const base::FilePath::StringType
& name
) {
49 base::NativeLibrary library
=
50 base::LoadNativeLibrary(base::FilePath(name
), NULL
);
52 library
= base::LoadNativeLibrary(module_path
.Append(name
), NULL
);
54 DVLOG(1) << name
<< " not found.";
61 const unsigned char* AngleGetTraceCategoryEnabledFlag(const char* name
) {
62 return TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(name
);
65 void AngleAddTraceEvent(char phase
,
66 const unsigned char* category_group_enabled
,
68 unsigned long long id
,
70 const char** arg_names
,
71 const unsigned char* arg_types
,
72 const unsigned long long* arg_values
,
73 unsigned char flags
) {
74 TRACE_EVENT_API_ADD_TRACE_EVENT(phase
,
75 category_group_enabled
,
86 typedef const unsigned char* (*GetCategoryEnabledFlagFunc
)(const char* name
);
87 typedef void (*AddTraceEventFunc
)(char phase
,
88 const unsigned char* categoryGroupEnabled
,
90 unsigned long long id
,
92 const char** argNames
,
93 const unsigned char* argTypes
,
94 const unsigned long long* argValues
,
96 typedef void (__stdcall
*SetTraceFunctionPointersFunc
)(
97 GetCategoryEnabledFlagFunc get_category_enabled_flag
,
98 AddTraceEventFunc add_trace_event_func
);
102 void GetAllowedGLImplementations(std::vector
<GLImplementation
>* impls
) {
103 impls
->push_back(kGLImplementationEGLGLES2
);
104 impls
->push_back(kGLImplementationDesktopGL
);
105 impls
->push_back(kGLImplementationOSMesaGL
);
108 bool InitializeStaticGLBindings(GLImplementation implementation
) {
109 // Prevent reinitialization with a different implementation. Once the gpu
110 // unit tests have initialized with kGLImplementationMock, we don't want to
111 // later switch to another GL implementation.
112 DCHECK_EQ(kGLImplementationNone
, GetGLImplementation());
114 // Allow the main thread or another to initialize these bindings
115 // after instituting restrictions on I/O. Going forward they will
116 // likely be used in the browser process on most platforms. The
117 // one-time initialization cost is small, between 2 and 5 ms.
118 base::ThreadRestrictions::ScopedAllowIO allow_io
;
120 switch (implementation
) {
121 case kGLImplementationOSMesaGL
: {
122 base::FilePath module_path
;
123 if (!PathService::Get(base::DIR_MODULE
, &module_path
)) {
124 LOG(ERROR
) << "PathService::Get failed.";
128 base::NativeLibrary library
= base::LoadNativeLibrary(
129 module_path
.Append(L
"osmesa.dll"), NULL
);
131 DVLOG(1) << "osmesa.dll not found";
135 GLGetProcAddressProc get_proc_address
=
136 reinterpret_cast<GLGetProcAddressProc
>(
137 base::GetFunctionPointerFromNativeLibrary(
138 library
, "OSMesaGetProcAddress"));
139 if (!get_proc_address
) {
140 DLOG(ERROR
) << "OSMesaGetProcAddress not found.";
141 base::UnloadNativeLibrary(library
);
145 SetGLGetProcAddressProc(get_proc_address
);
146 AddGLNativeLibrary(library
);
147 SetGLImplementation(kGLImplementationOSMesaGL
);
149 InitializeStaticGLBindingsGL();
150 InitializeStaticGLBindingsOSMESA();
153 case kGLImplementationEGLGLES2
: {
154 base::FilePath module_path
;
155 if (!PathService::Get(base::DIR_MODULE
, &module_path
))
158 // Attempt to load the D3DX shader compiler using the default search path
159 // and if that fails, using an absolute path. This is to ensure these DLLs
160 // are loaded before ANGLE is loaded in case they are not in the default
162 LoadD3DXLibrary(module_path
, kD3DCompiler
);
164 base::FilePath gles_path
;
165 const CommandLine
* command_line
= CommandLine::ForCurrentProcess();
166 bool using_swift_shader
=
167 command_line
->GetSwitchValueASCII(switches::kUseGL
) == "swiftshader";
168 if (using_swift_shader
) {
169 if (!command_line
->HasSwitch(switches::kSwiftShaderPath
))
172 command_line
->GetSwitchValuePath(switches::kSwiftShaderPath
);
174 LoadLibrary(L
"ddraw.dll");
176 gles_path
= module_path
;
179 // Load libglesv2.dll before libegl.dll because the latter is dependent on
180 // the former and if there is another version of libglesv2.dll in the dll
181 // search path, it will get loaded instead.
182 base::NativeLibrary gles_library
= base::LoadNativeLibrary(
183 gles_path
.Append(L
"libglesv2.dll"), NULL
);
185 DVLOG(1) << "libglesv2.dll not found";
189 // When using EGL, first try eglGetProcAddress and then Windows
190 // GetProcAddress on both the EGL and GLES2 DLLs.
191 base::NativeLibrary egl_library
= base::LoadNativeLibrary(
192 gles_path
.Append(L
"libegl.dll"), NULL
);
194 DVLOG(1) << "libegl.dll not found.";
195 base::UnloadNativeLibrary(gles_library
);
199 #if defined(ENABLE_SWIFTSHADER)
200 if (using_swift_shader
) {
201 SetupSoftwareRenderer(gles_library
);
205 if (!using_swift_shader
) {
206 SetTraceFunctionPointersFunc set_trace_function_pointers
=
207 reinterpret_cast<SetTraceFunctionPointersFunc
>(
208 base::GetFunctionPointerFromNativeLibrary(
209 gles_library
, "SetTraceFunctionPointers"));
210 if (set_trace_function_pointers
) {
211 set_trace_function_pointers(&AngleGetTraceCategoryEnabledFlag
,
212 &AngleAddTraceEvent
);
216 GLGetProcAddressProc get_proc_address
=
217 reinterpret_cast<GLGetProcAddressProc
>(
218 base::GetFunctionPointerFromNativeLibrary(
219 egl_library
, "eglGetProcAddress"));
220 if (!get_proc_address
) {
221 LOG(ERROR
) << "eglGetProcAddress not found.";
222 base::UnloadNativeLibrary(egl_library
);
223 base::UnloadNativeLibrary(gles_library
);
227 SetGLGetProcAddressProc(get_proc_address
);
228 AddGLNativeLibrary(egl_library
);
229 AddGLNativeLibrary(gles_library
);
230 SetGLImplementation(kGLImplementationEGLGLES2
);
232 InitializeStaticGLBindingsGL();
233 InitializeStaticGLBindingsEGL();
235 // These two functions take single precision float rather than double
236 // precision float parameters in GLES.
237 ::gfx::g_driver_gl
.fn
.glClearDepthFn
= MarshalClearDepthToClearDepthf
;
238 ::gfx::g_driver_gl
.fn
.glDepthRangeFn
= MarshalDepthRangeToDepthRangef
;
241 case kGLImplementationDesktopGL
: {
242 base::NativeLibrary library
= base::LoadNativeLibrary(
243 base::FilePath(L
"opengl32.dll"), NULL
);
245 DVLOG(1) << "opengl32.dll not found";
249 GLGetProcAddressProc get_proc_address
=
250 reinterpret_cast<GLGetProcAddressProc
>(
251 base::GetFunctionPointerFromNativeLibrary(
252 library
, "wglGetProcAddress"));
253 if (!get_proc_address
) {
254 LOG(ERROR
) << "wglGetProcAddress not found.";
255 base::UnloadNativeLibrary(library
);
259 SetGLGetProcAddressProc(get_proc_address
);
260 AddGLNativeLibrary(library
);
261 SetGLImplementation(kGLImplementationDesktopGL
);
263 // Initialize GL surface and get some functions needed for the context
265 if (!GLSurfaceWGL::InitializeOneOff()) {
266 LOG(ERROR
) << "GLSurfaceWGL::InitializeOneOff failed.";
269 wglCreateContextProc wglCreateContextFn
=
270 reinterpret_cast<wglCreateContextProc
>(
271 GetGLProcAddress("wglCreateContext"));
272 wglDeleteContextProc wglDeleteContextFn
=
273 reinterpret_cast<wglDeleteContextProc
>(
274 GetGLProcAddress("wglDeleteContext"));
275 wglMakeCurrentProc wglMakeCurrentFn
=
276 reinterpret_cast<wglMakeCurrentProc
>(
277 GetGLProcAddress("wglMakeCurrent"));
279 // Create a temporary GL context to bind to entry points. This is needed
280 // because wglGetProcAddress is specified to return NULL for all queries
281 // if a context is not current in MSDN documentation, and the static
282 // bindings may contain functions that need to be queried with
283 // wglGetProcAddress. OpenGL wiki further warns that other error values
284 // than NULL could also be returned from wglGetProcAddress on some
285 // implementations, so we need to clear the WGL bindings and reinitialize
286 // them after the context creation.
287 HGLRC gl_context
= wglCreateContextFn(GLSurfaceWGL::GetDisplayDC());
289 LOG(ERROR
) << "Failed to create temporary context.";
292 if (!wglMakeCurrentFn(GLSurfaceWGL::GetDisplayDC(), gl_context
)) {
293 LOG(ERROR
) << "Failed to make temporary GL context current.";
294 wglDeleteContextFn(gl_context
);
298 InitializeStaticGLBindingsGL();
299 InitializeStaticGLBindingsWGL();
301 wglMakeCurrent(NULL
, NULL
);
302 wglDeleteContext(gl_context
);
306 case kGLImplementationMockGL
: {
307 SetGLImplementation(kGLImplementationMockGL
);
308 InitializeStaticGLBindingsGL();
318 bool InitializeDynamicGLBindings(GLImplementation implementation
,
319 GLContext
* context
) {
320 switch (implementation
) {
321 case kGLImplementationOSMesaGL
:
322 InitializeDynamicGLBindingsGL(context
);
323 InitializeDynamicGLBindingsOSMESA(context
);
325 case kGLImplementationEGLGLES2
:
326 InitializeDynamicGLBindingsGL(context
);
327 InitializeDynamicGLBindingsEGL(context
);
329 case kGLImplementationDesktopGL
:
330 InitializeDynamicGLBindingsGL(context
);
331 InitializeDynamicGLBindingsWGL(context
);
333 case kGLImplementationMockGL
:
335 scoped_refptr
<GLContextStubWithExtensions
> mock_context(
336 new GLContextStubWithExtensions());
337 mock_context
->SetGLVersionString("3.0");
338 InitializeDynamicGLBindingsGL(mock_context
.get());
340 InitializeDynamicGLBindingsGL(context
);
349 void InitializeDebugGLBindings() {
350 InitializeDebugGLBindingsEGL();
351 InitializeDebugGLBindingsGL();
352 InitializeDebugGLBindingsOSMESA();
353 InitializeDebugGLBindingsWGL();
356 void ClearGLBindings() {
357 ClearGLBindingsEGL();
359 ClearGLBindingsOSMESA();
360 ClearGLBindingsWGL();
361 SetGLImplementation(kGLImplementationNone
);
362 UnloadGLNativeLibraries();
365 bool GetGLWindowSystemBindingInfo(GLWindowSystemBindingInfo
* info
) {
366 switch (GetGLImplementation()) {
367 case kGLImplementationDesktopGL
:
368 return GetGLWindowSystemBindingInfoWGL(info
);
369 case kGLImplementationEGLGLES2
:
370 return GetGLWindowSystemBindingInfoEGL(info
);