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
32namespace gfx {
33
34namespace {
35
36const wchar_t kD3DCompiler[] = 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
61const unsigned char* AngleGetTraceCategoryEnabledFlag(const char* name) {
62  return TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(name);
63}
64
65void AngleAddTraceEvent(char phase,
66                        const unsigned char* category_group_enabled,
67                        const char* name,
68                        unsigned long long id,
69                        int num_args,
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,
76                                  name,
77                                  id,
78                                  num_args,
79                                  arg_names,
80                                  arg_types,
81                                  arg_values,
82                                  NULL,
83                                  flags);
84}
85
86typedef const unsigned char* (*GetCategoryEnabledFlagFunc)(const char* name);
87typedef void (*AddTraceEventFunc)(char phase,
88                                  const unsigned char* categoryGroupEnabled,
89                                  const char* name,
90                                  unsigned long long id,
91                                  int numArgs,
92                                  const char** argNames,
93                                  const unsigned char* argTypes,
94                                  const unsigned long long* argValues,
95                                  unsigned char flags);
96typedef void (__stdcall *SetTraceFunctionPointersFunc)(
97    GetCategoryEnabledFlagFunc get_category_enabled_flag,
98    AddTraceEventFunc add_trace_event_func);
99
100}  // namespace
101
102void GetAllowedGLImplementations(std::vector<GLImplementation>* impls) {
103  impls->push_back(kGLImplementationEGLGLES2);
104  impls->push_back(kGLImplementationDesktopGL);
105  impls->push_back(kGLImplementationOSMesaGL);
106}
107
108bool 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());
113
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;
119
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.";
125        return false;
126      }
127
128      base::NativeLibrary library = base::LoadNativeLibrary(
129          module_path.Append(L"osmesa.dll"), NULL);
130      if (!library) {
131        DVLOG(1) << "osmesa.dll not found";
132        return false;
133      }
134
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);
142        return false;
143      }
144
145      SetGLGetProcAddressProc(get_proc_address);
146      AddGLNativeLibrary(library);
147      SetGLImplementation(kGLImplementationOSMesaGL);
148
149      InitializeStaticGLBindingsGL();
150      InitializeStaticGLBindingsOSMESA();
151      break;
152    }
153    case kGLImplementationEGLGLES2: {
154      base::FilePath module_path;
155      if (!PathService::Get(base::DIR_MODULE, &module_path))
156        return false;
157
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
161      // search path.
162      LoadD3DXLibrary(module_path, kD3DCompiler);
163
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))
170          return false;
171        gles_path =
172            command_line->GetSwitchValuePath(switches::kSwiftShaderPath);
173        // Preload library
174        LoadLibrary(L"ddraw.dll");
175      } else {
176        gles_path = module_path;
177      }
178
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);
184      if (!gles_library) {
185        DVLOG(1) << "libglesv2.dll not found";
186        return false;
187      }
188
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);
193      if (!egl_library) {
194        DVLOG(1) << "libegl.dll not found.";
195        base::UnloadNativeLibrary(gles_library);
196        return false;
197      }
198
199#if defined(ENABLE_SWIFTSHADER)
200      if (using_swift_shader) {
201        SetupSoftwareRenderer(gles_library);
202      }
203#endif
204
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);
213        }
214      }
215
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);
224        return false;
225      }
226
227      SetGLGetProcAddressProc(get_proc_address);
228      AddGLNativeLibrary(egl_library);
229      AddGLNativeLibrary(gles_library);
230      SetGLImplementation(kGLImplementationEGLGLES2);
231
232      InitializeStaticGLBindingsGL();
233      InitializeStaticGLBindingsEGL();
234
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;
239      break;
240    }
241    case kGLImplementationDesktopGL: {
242      base::NativeLibrary library = base::LoadNativeLibrary(
243          base::FilePath(L"opengl32.dll"), NULL);
244      if (!library) {
245        DVLOG(1) << "opengl32.dll not found";
246        return false;
247      }
248
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);
256        return false;
257      }
258
259      SetGLGetProcAddressProc(get_proc_address);
260      AddGLNativeLibrary(library);
261      SetGLImplementation(kGLImplementationDesktopGL);
262
263      // Initialize GL surface and get some functions needed for the context
264      // creation below.
265      if (!GLSurfaceWGL::InitializeOneOff()) {
266        LOG(ERROR) << "GLSurfaceWGL::InitializeOneOff failed.";
267        return false;
268      }
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"));
278
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());
288      if (!gl_context) {
289        LOG(ERROR) << "Failed to create temporary context.";
290        return false;
291      }
292      if (!wglMakeCurrentFn(GLSurfaceWGL::GetDisplayDC(), gl_context)) {
293        LOG(ERROR) << "Failed to make temporary GL context current.";
294        wglDeleteContextFn(gl_context);
295        return false;
296      }
297
298      InitializeStaticGLBindingsGL();
299      InitializeStaticGLBindingsWGL();
300
301      wglMakeCurrent(NULL, NULL);
302      wglDeleteContext(gl_context);
303
304      break;
305    }
306    case kGLImplementationMockGL: {
307      SetGLImplementation(kGLImplementationMockGL);
308      InitializeStaticGLBindingsGL();
309      break;
310    }
311    default:
312      return false;
313  }
314
315  return true;
316}
317
318bool InitializeDynamicGLBindings(GLImplementation implementation,
319    GLContext* context) {
320  switch (implementation) {
321    case kGLImplementationOSMesaGL:
322      InitializeDynamicGLBindingsGL(context);
323      InitializeDynamicGLBindingsOSMESA(context);
324      break;
325    case kGLImplementationEGLGLES2:
326      InitializeDynamicGLBindingsGL(context);
327      InitializeDynamicGLBindingsEGL(context);
328      break;
329    case kGLImplementationDesktopGL:
330      InitializeDynamicGLBindingsGL(context);
331      InitializeDynamicGLBindingsWGL(context);
332      break;
333    case kGLImplementationMockGL:
334      if (!context) {
335        scoped_refptr<GLContextStubWithExtensions> mock_context(
336            new GLContextStubWithExtensions());
337        mock_context->SetGLVersionString("3.0");
338        InitializeDynamicGLBindingsGL(mock_context.get());
339      } else
340        InitializeDynamicGLBindingsGL(context);
341      break;
342    default:
343      return false;
344  }
345
346  return true;
347}
348
349void InitializeDebugGLBindings() {
350  InitializeDebugGLBindingsEGL();
351  InitializeDebugGLBindingsGL();
352  InitializeDebugGLBindingsOSMESA();
353  InitializeDebugGLBindingsWGL();
354}
355
356void ClearGLBindings() {
357  ClearGLBindingsEGL();
358  ClearGLBindingsGL();
359  ClearGLBindingsOSMESA();
360  ClearGLBindingsWGL();
361  SetGLImplementation(kGLImplementationNone);
362  UnloadGLNativeLibraries();
363}
364
365bool GetGLWindowSystemBindingInfo(GLWindowSystemBindingInfo* info) {
366  switch (GetGLImplementation()) {
367    case kGLImplementationDesktopGL:
368      return GetGLWindowSystemBindingInfoWGL(info);
369    case kGLImplementationEGLGLES2:
370      return GetGLWindowSystemBindingInfoEGL(info);
371    default:
372      return false;
373  }
374}
375
376}  // namespace gfx
377