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/files/file_path.h"
12 #include "base/lazy_instance.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/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_context_stub_with_extensions.h"
24 #include "ui/gl/gl_egl_api_implementation.h"
25 #include "ui/gl/gl_gl_api_implementation.h"
26 #include "ui/gl/gl_implementation.h"
27 #include "ui/gl/gl_osmesa_api_implementation.h"
28 #include "ui/gl/gl_surface_wgl.h"
29 #include "ui/gl/gl_wgl_api_implementation.h"
31 #if defined(ENABLE_SWIFTSHADER)
32 #include "software_renderer.h"
39 const wchar_t kD3DCompiler
[] = L
"D3DCompiler_47.dll";
41 void GL_BINDING_CALL
MarshalClearDepthToClearDepthf(GLclampd depth
) {
42 glClearDepthf(static_cast<GLclampf
>(depth
));
45 void GL_BINDING_CALL
MarshalDepthRangeToDepthRangef(GLclampd z_near
,
47 glDepthRangef(static_cast<GLclampf
>(z_near
), static_cast<GLclampf
>(z_far
));
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
);
55 library
= base::LoadNativeLibrary(module_path
.Append(name
), NULL
);
57 DVLOG(1) << name
<< " not found.";
64 // TODO(jmadill): Apply to all platforms eventually
65 base::LazyInstance
<ANGLEPlatformImpl
> g_angle_platform_impl
=
66 LAZY_INSTANCE_INITIALIZER
;
68 ANGLEPlatformShutdownFunc g_angle_platform_shutdown
= nullptr;
72 void GetAllowedGLImplementations(std::vector
<GLImplementation
>* impls
) {
73 impls
->push_back(kGLImplementationEGLGLES2
);
74 impls
->push_back(kGLImplementationDesktopGL
);
75 impls
->push_back(kGLImplementationOSMesaGL
);
78 bool InitializeStaticGLBindings(GLImplementation implementation
) {
79 // Prevent reinitialization with a different implementation. Once the gpu
80 // unit tests have initialized with kGLImplementationMock, we don't want to
81 // later switch to another GL implementation.
82 DCHECK_EQ(kGLImplementationNone
, GetGLImplementation());
84 // Allow the main thread or another to initialize these bindings
85 // after instituting restrictions on I/O. Going forward they will
86 // likely be used in the browser process on most platforms. The
87 // one-time initialization cost is small, between 2 and 5 ms.
88 base::ThreadRestrictions::ScopedAllowIO allow_io
;
90 switch (implementation
) {
91 case kGLImplementationOSMesaGL
: {
92 base::FilePath module_path
;
93 if (!PathService::Get(base::DIR_MODULE
, &module_path
)) {
94 LOG(ERROR
) << "PathService::Get failed.";
98 base::NativeLibrary library
= base::LoadNativeLibrary(
99 module_path
.Append(L
"osmesa.dll"), NULL
);
101 DVLOG(1) << "osmesa.dll not found";
105 GLGetProcAddressProc get_proc_address
=
106 reinterpret_cast<GLGetProcAddressProc
>(
107 base::GetFunctionPointerFromNativeLibrary(
108 library
, "OSMesaGetProcAddress"));
109 if (!get_proc_address
) {
110 DLOG(ERROR
) << "OSMesaGetProcAddress not found.";
111 base::UnloadNativeLibrary(library
);
115 SetGLGetProcAddressProc(get_proc_address
);
116 AddGLNativeLibrary(library
);
117 SetGLImplementation(kGLImplementationOSMesaGL
);
119 InitializeStaticGLBindingsGL();
120 InitializeStaticGLBindingsOSMESA();
123 case kGLImplementationEGLGLES2
: {
124 base::FilePath module_path
;
125 if (!PathService::Get(base::DIR_MODULE
, &module_path
))
128 // Attempt to load the D3DX shader compiler using the default search path
129 // and if that fails, using an absolute path. This is to ensure these DLLs
130 // are loaded before ANGLE is loaded in case they are not in the default
132 LoadD3DXLibrary(module_path
, kD3DCompiler
);
134 base::FilePath gles_path
;
135 const base::CommandLine
* command_line
=
136 base::CommandLine::ForCurrentProcess();
137 bool using_swift_shader
=
138 command_line
->GetSwitchValueASCII(switches::kUseGL
) == "swiftshader";
139 if (using_swift_shader
) {
140 if (!command_line
->HasSwitch(switches::kSwiftShaderPath
))
143 command_line
->GetSwitchValuePath(switches::kSwiftShaderPath
);
145 LoadLibrary(L
"ddraw.dll");
147 gles_path
= module_path
;
150 // Load libglesv2.dll before libegl.dll because the latter is dependent on
151 // the former and if there is another version of libglesv2.dll in the dll
152 // search path, it will get loaded instead.
153 base::NativeLibrary gles_library
= base::LoadNativeLibrary(
154 gles_path
.Append(L
"libglesv2.dll"), NULL
);
156 DVLOG(1) << "libglesv2.dll not found";
160 // When using EGL, first try eglGetProcAddress and then Windows
161 // GetProcAddress on both the EGL and GLES2 DLLs.
162 base::NativeLibrary egl_library
= base::LoadNativeLibrary(
163 gles_path
.Append(L
"libegl.dll"), NULL
);
165 DVLOG(1) << "libegl.dll not found.";
166 base::UnloadNativeLibrary(gles_library
);
170 #if defined(ENABLE_SWIFTSHADER)
171 if (using_swift_shader
) {
172 SetupSoftwareRenderer(gles_library
);
176 if (!using_swift_shader
) {
177 // Init ANGLE platform here, before we call GetPlatformDisplay().
178 // TODO(jmadill): Apply to all platforms eventually
179 ANGLEPlatformInitializeFunc angle_platform_init
=
180 reinterpret_cast<ANGLEPlatformInitializeFunc
>(
181 base::GetFunctionPointerFromNativeLibrary(
183 "ANGLEPlatformInitialize"));
184 if (angle_platform_init
) {
185 angle_platform_init(&g_angle_platform_impl
.Get());
187 g_angle_platform_shutdown
=
188 reinterpret_cast<ANGLEPlatformShutdownFunc
>(
189 base::GetFunctionPointerFromNativeLibrary(
191 "ANGLEPlatformShutdown"));
195 GLGetProcAddressProc get_proc_address
=
196 reinterpret_cast<GLGetProcAddressProc
>(
197 base::GetFunctionPointerFromNativeLibrary(
198 egl_library
, "eglGetProcAddress"));
199 if (!get_proc_address
) {
200 LOG(ERROR
) << "eglGetProcAddress not found.";
201 base::UnloadNativeLibrary(egl_library
);
202 base::UnloadNativeLibrary(gles_library
);
206 SetGLGetProcAddressProc(get_proc_address
);
207 AddGLNativeLibrary(egl_library
);
208 AddGLNativeLibrary(gles_library
);
209 SetGLImplementation(kGLImplementationEGLGLES2
);
211 InitializeStaticGLBindingsGL();
212 InitializeStaticGLBindingsEGL();
214 // These two functions take single precision float rather than double
215 // precision float parameters in GLES.
216 ::gfx::g_driver_gl
.fn
.glClearDepthFn
= MarshalClearDepthToClearDepthf
;
217 ::gfx::g_driver_gl
.fn
.glDepthRangeFn
= MarshalDepthRangeToDepthRangef
;
220 case kGLImplementationDesktopGL
: {
221 base::NativeLibrary library
= base::LoadNativeLibrary(
222 base::FilePath(L
"opengl32.dll"), NULL
);
224 DVLOG(1) << "opengl32.dll not found";
228 GLGetProcAddressProc get_proc_address
=
229 reinterpret_cast<GLGetProcAddressProc
>(
230 base::GetFunctionPointerFromNativeLibrary(
231 library
, "wglGetProcAddress"));
232 if (!get_proc_address
) {
233 LOG(ERROR
) << "wglGetProcAddress not found.";
234 base::UnloadNativeLibrary(library
);
238 SetGLGetProcAddressProc(get_proc_address
);
239 AddGLNativeLibrary(library
);
240 SetGLImplementation(kGLImplementationDesktopGL
);
242 // Initialize GL surface and get some functions needed for the context
244 if (!GLSurfaceWGL::InitializeOneOff()) {
245 LOG(ERROR
) << "GLSurfaceWGL::InitializeOneOff failed.";
248 wglCreateContextProc wglCreateContextFn
=
249 reinterpret_cast<wglCreateContextProc
>(
250 GetGLProcAddress("wglCreateContext"));
251 wglDeleteContextProc wglDeleteContextFn
=
252 reinterpret_cast<wglDeleteContextProc
>(
253 GetGLProcAddress("wglDeleteContext"));
254 wglMakeCurrentProc wglMakeCurrentFn
=
255 reinterpret_cast<wglMakeCurrentProc
>(
256 GetGLProcAddress("wglMakeCurrent"));
258 // Create a temporary GL context to bind to entry points. This is needed
259 // because wglGetProcAddress is specified to return NULL for all queries
260 // if a context is not current in MSDN documentation, and the static
261 // bindings may contain functions that need to be queried with
262 // wglGetProcAddress. OpenGL wiki further warns that other error values
263 // than NULL could also be returned from wglGetProcAddress on some
264 // implementations, so we need to clear the WGL bindings and reinitialize
265 // them after the context creation.
266 HGLRC gl_context
= wglCreateContextFn(GLSurfaceWGL::GetDisplayDC());
268 LOG(ERROR
) << "Failed to create temporary context.";
271 if (!wglMakeCurrentFn(GLSurfaceWGL::GetDisplayDC(), gl_context
)) {
272 LOG(ERROR
) << "Failed to make temporary GL context current.";
273 wglDeleteContextFn(gl_context
);
277 InitializeStaticGLBindingsGL();
278 InitializeStaticGLBindingsWGL();
280 wglMakeCurrent(NULL
, NULL
);
281 wglDeleteContext(gl_context
);
285 case kGLImplementationMockGL
: {
286 SetGLImplementation(kGLImplementationMockGL
);
287 InitializeStaticGLBindingsGL();
297 bool InitializeDynamicGLBindings(GLImplementation implementation
,
298 GLContext
* context
) {
299 switch (implementation
) {
300 case kGLImplementationOSMesaGL
:
301 case kGLImplementationEGLGLES2
:
302 case kGLImplementationDesktopGL
:
303 InitializeDynamicGLBindingsGL(context
);
305 case kGLImplementationMockGL
:
307 scoped_refptr
<GLContextStubWithExtensions
> mock_context(
308 new GLContextStubWithExtensions());
309 mock_context
->SetGLVersionString("3.0");
310 InitializeDynamicGLBindingsGL(mock_context
.get());
312 InitializeDynamicGLBindingsGL(context
);
321 void InitializeDebugGLBindings() {
322 InitializeDebugGLBindingsEGL();
323 InitializeDebugGLBindingsGL();
324 InitializeDebugGLBindingsOSMESA();
325 InitializeDebugGLBindingsWGL();
328 void ClearGLBindings() {
329 // TODO(jmadill): Apply to all platforms eventually
330 if (g_angle_platform_shutdown
) {
331 g_angle_platform_shutdown();
334 ClearGLBindingsEGL();
336 ClearGLBindingsOSMESA();
337 ClearGLBindingsWGL();
338 SetGLImplementation(kGLImplementationNone
);
339 UnloadGLNativeLibraries();
342 bool GetGLWindowSystemBindingInfo(GLWindowSystemBindingInfo
* info
) {
343 switch (GetGLImplementation()) {
344 case kGLImplementationDesktopGL
:
345 return GetGLWindowSystemBindingInfoWGL(info
);
346 case kGLImplementationEGLGLES2
:
347 return GetGLWindowSystemBindingInfoEGL(info
);