gl_implementation_win.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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/files/file_path.h"
12#include "base/logging.h"
13#include "base/native_library.h"
14#include "base/path_service.h"
15#include "base/stringprintf.h"
16#include "base/threading/thread_restrictions.h"
17#include "base/win/windows_version.h"
18#include "ui/gl/gl_bindings.h"
19#include "ui/gl/gl_egl_api_implementation.h"
20#include "ui/gl/gl_gl_api_implementation.h"
21#include "ui/gl/gl_implementation.h"
22#include "ui/gl/gl_osmesa_api_implementation.h"
23#include "ui/gl/gl_wgl_api_implementation.h"
24
25#if defined(ENABLE_SWIFTSHADER)
26#include "software_renderer.h"
27#endif
28
29namespace gfx {
30
31namespace {
32
33// Version 43 is the latest version of D3DCompiler_nn.dll that works prior to
34// Windows Vista.
35const wchar_t kPreVistaD3DCompiler[] = L"D3DCompiler_43.dll";
36const wchar_t kPostVistaD3DCompiler[] = L"D3DCompiler_46.dll";
37
38void GL_BINDING_CALL MarshalClearDepthToClearDepthf(GLclampd depth) {
39  glClearDepthf(static_cast<GLclampf>(depth));
40}
41
42void GL_BINDING_CALL MarshalDepthRangeToDepthRangef(GLclampd z_near,
43                                                    GLclampd z_far) {
44  glDepthRangef(static_cast<GLclampf>(z_near), static_cast<GLclampf>(z_far));
45}
46
47bool LoadD3DXLibrary(const base::FilePath& module_path,
48                     const base::FilePath::StringType& name) {
49  base::NativeLibrary library =
50      base::LoadNativeLibrary(base::FilePath(name), NULL);
51  if (!library) {
52    library = base::LoadNativeLibrary(module_path.Append(name), NULL);
53    if (!library) {
54      DVLOG(1) << name << " not found.";
55      return false;
56    }
57  }
58  return true;
59}
60
61}  // namespace
62
63void GetAllowedGLImplementations(std::vector<GLImplementation>* impls) {
64  impls->push_back(kGLImplementationEGLGLES2);
65  impls->push_back(kGLImplementationDesktopGL);
66  impls->push_back(kGLImplementationOSMesaGL);
67}
68
69bool InitializeGLBindings(GLImplementation implementation) {
70  // Prevent reinitialization with a different implementation. Once the gpu
71  // unit tests have initialized with kGLImplementationMock, we don't want to
72  // later switch to another GL implementation.
73  if (GetGLImplementation() != kGLImplementationNone)
74    return true;
75
76  // Allow the main thread or another to initialize these bindings
77  // after instituting restrictions on I/O. Going forward they will
78  // likely be used in the browser process on most platforms. The
79  // one-time initialization cost is small, between 2 and 5 ms.
80  base::ThreadRestrictions::ScopedAllowIO allow_io;
81
82  switch (implementation) {
83    case kGLImplementationOSMesaGL: {
84      base::FilePath module_path;
85      if (!PathService::Get(base::DIR_MODULE, &module_path)) {
86        LOG(ERROR) << "PathService::Get failed.";
87        return false;
88      }
89
90      base::NativeLibrary library = base::LoadNativeLibrary(
91          module_path.Append(L"osmesa.dll"), NULL);
92      if (!library) {
93        DVLOG(1) << "osmesa.dll not found";
94        return false;
95      }
96
97      GLGetProcAddressProc get_proc_address =
98          reinterpret_cast<GLGetProcAddressProc>(
99              base::GetFunctionPointerFromNativeLibrary(
100                  library, "OSMesaGetProcAddress"));
101      if (!get_proc_address) {
102        DLOG(ERROR) << "OSMesaGetProcAddress not found.";
103        base::UnloadNativeLibrary(library);
104        return false;
105      }
106
107      SetGLGetProcAddressProc(get_proc_address);
108      AddGLNativeLibrary(library);
109      SetGLImplementation(kGLImplementationOSMesaGL);
110
111      InitializeGLBindingsGL();
112      InitializeGLBindingsOSMESA();
113      break;
114    }
115    case kGLImplementationEGLGLES2: {
116      base::FilePath module_path;
117      if (!PathService::Get(base::DIR_MODULE, &module_path))
118        return false;
119
120      // Attempt to load the D3DX shader compiler using the default search path
121      // and if that fails, using an absolute path. This is to ensure these DLLs
122      // are loaded before ANGLE is loaded in case they are not in the default
123      // search path. Prefer the post vista version.
124      if (base::win::GetVersion() < base::win::VERSION_VISTA ||
125          !LoadD3DXLibrary(module_path, kPostVistaD3DCompiler)) {
126        LoadD3DXLibrary(module_path, kPreVistaD3DCompiler);
127      }
128
129      base::FilePath gles_path;
130      const CommandLine* command_line = CommandLine::ForCurrentProcess();
131      bool using_swift_shader =
132          command_line->GetSwitchValueASCII(switches::kUseGL) == "swiftshader";
133      if (using_swift_shader) {
134        if (!command_line->HasSwitch(switches::kSwiftShaderPath))
135          return false;
136        gles_path =
137            command_line->GetSwitchValuePath(switches::kSwiftShaderPath);
138        // Preload library
139        LoadLibrary(L"ddraw.dll");
140      } else {
141        gles_path = module_path;
142      }
143
144      // Load libglesv2.dll before libegl.dll because the latter is dependent on
145      // the former and if there is another version of libglesv2.dll in the dll
146      // search path, it will get loaded instead.
147      base::NativeLibrary gles_library = base::LoadNativeLibrary(
148          gles_path.Append(L"libglesv2.dll"), NULL);
149      if (!gles_library) {
150        DVLOG(1) << "libglesv2.dll not found";
151        return false;
152      }
153
154      // When using EGL, first try eglGetProcAddress and then Windows
155      // GetProcAddress on both the EGL and GLES2 DLLs.
156      base::NativeLibrary egl_library = base::LoadNativeLibrary(
157          gles_path.Append(L"libegl.dll"), NULL);
158      if (!egl_library) {
159        DVLOG(1) << "libegl.dll not found.";
160        base::UnloadNativeLibrary(gles_library);
161        return false;
162      }
163
164#if defined(ENABLE_SWIFTSHADER)
165      if (using_swift_shader) {
166        SetupSoftwareRenderer(gles_library);
167      }
168#endif
169
170      GLGetProcAddressProc get_proc_address =
171          reinterpret_cast<GLGetProcAddressProc>(
172              base::GetFunctionPointerFromNativeLibrary(
173                  egl_library, "eglGetProcAddress"));
174      if (!get_proc_address) {
175        LOG(ERROR) << "eglGetProcAddress not found.";
176        base::UnloadNativeLibrary(egl_library);
177        base::UnloadNativeLibrary(gles_library);
178        return false;
179      }
180
181      SetGLGetProcAddressProc(get_proc_address);
182      AddGLNativeLibrary(egl_library);
183      AddGLNativeLibrary(gles_library);
184      SetGLImplementation(kGLImplementationEGLGLES2);
185
186      InitializeGLBindingsGL();
187      InitializeGLBindingsEGL();
188
189      // These two functions take single precision float rather than double
190      // precision float parameters in GLES.
191      ::gfx::g_driver_gl.fn.glClearDepthFn = MarshalClearDepthToClearDepthf;
192      ::gfx::g_driver_gl.fn.glDepthRangeFn = MarshalDepthRangeToDepthRangef;
193      break;
194    }
195    case kGLImplementationDesktopGL: {
196      // When using Windows OpenGL, first try wglGetProcAddress and then
197      // Windows GetProcAddress.
198      base::NativeLibrary library = base::LoadNativeLibrary(
199          base::FilePath(L"opengl32.dll"), NULL);
200      if (!library) {
201        DVLOG(1) << "opengl32.dll not found";
202        return false;
203      }
204
205      GLGetProcAddressProc get_proc_address =
206          reinterpret_cast<GLGetProcAddressProc>(
207              base::GetFunctionPointerFromNativeLibrary(
208                  library, "wglGetProcAddress"));
209      if (!get_proc_address) {
210        LOG(ERROR) << "wglGetProcAddress not found.";
211        base::UnloadNativeLibrary(library);
212        return false;
213      }
214
215      SetGLGetProcAddressProc(get_proc_address);
216      AddGLNativeLibrary(library);
217      SetGLImplementation(kGLImplementationDesktopGL);
218
219      InitializeGLBindingsGL();
220      InitializeGLBindingsWGL();
221      break;
222    }
223    case kGLImplementationMockGL: {
224      SetGLGetProcAddressProc(GetMockGLProcAddress);
225      SetGLImplementation(kGLImplementationMockGL);
226      InitializeGLBindingsGL();
227      break;
228    }
229    default:
230      return false;
231  }
232
233  return true;
234}
235
236bool InitializeGLExtensionBindings(GLImplementation implementation,
237    GLContext* context) {
238  switch (implementation) {
239    case kGLImplementationOSMesaGL:
240      InitializeGLExtensionBindingsGL(context);
241      InitializeGLExtensionBindingsOSMESA(context);
242      break;
243    case kGLImplementationEGLGLES2:
244      InitializeGLExtensionBindingsGL(context);
245      InitializeGLExtensionBindingsEGL(context);
246      break;
247    case kGLImplementationDesktopGL:
248      InitializeGLExtensionBindingsGL(context);
249      InitializeGLExtensionBindingsWGL(context);
250      break;
251    case kGLImplementationMockGL:
252      InitializeGLExtensionBindingsGL(context);
253      break;
254    default:
255      return false;
256  }
257
258  return true;
259}
260
261void InitializeDebugGLBindings() {
262  InitializeDebugGLBindingsEGL();
263  InitializeDebugGLBindingsGL();
264  InitializeDebugGLBindingsOSMESA();
265  InitializeDebugGLBindingsWGL();
266}
267
268void ClearGLBindings() {
269  ClearGLBindingsEGL();
270  ClearGLBindingsGL();
271  ClearGLBindingsOSMESA();
272  ClearGLBindingsWGL();
273  SetGLImplementation(kGLImplementationNone);
274  UnloadGLNativeLibraries();
275}
276
277}  // namespace gfx
278