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