Home | History | Annotate | Download | only in gl
      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/strings/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 
     29 namespace gfx {
     30 
     31 namespace {
     32 
     33 // Version 43 is the latest version of D3DCompiler_nn.dll that works prior to
     34 // Windows Vista.
     35 const wchar_t kPreVistaD3DCompiler[] = L"D3DCompiler_43.dll";
     36 const wchar_t kPostVistaD3DCompiler[] = L"D3DCompiler_46.dll";
     37 
     38 void GL_BINDING_CALL MarshalClearDepthToClearDepthf(GLclampd depth) {
     39   glClearDepthf(static_cast<GLclampf>(depth));
     40 }
     41 
     42 void 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 
     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);
     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 
     63 void GetAllowedGLImplementations(std::vector<GLImplementation>* impls) {
     64   impls->push_back(kGLImplementationEGLGLES2);
     65   impls->push_back(kGLImplementationDesktopGL);
     66   impls->push_back(kGLImplementationOSMesaGL);
     67 }
     68 
     69 bool 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 
    236 bool 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 
    261 void InitializeDebugGLBindings() {
    262   InitializeDebugGLBindingsEGL();
    263   InitializeDebugGLBindingsGL();
    264   InitializeDebugGLBindingsOSMESA();
    265   InitializeDebugGLBindingsWGL();
    266 }
    267 
    268 void ClearGLBindings() {
    269   ClearGLBindingsEGL();
    270   ClearGLBindingsGL();
    271   ClearGLBindingsOSMESA();
    272   ClearGLBindingsWGL();
    273   SetGLImplementation(kGLImplementationNone);
    274   UnloadGLNativeLibraries();
    275 }
    276 
    277 bool GetGLWindowSystemBindingInfo(GLWindowSystemBindingInfo* info) {
    278   switch (GetGLImplementation()) {
    279     case kGLImplementationDesktopGL:
    280       return GetGLWindowSystemBindingInfoWGL(info);
    281     case kGLImplementationEGLGLES2:
    282       return GetGLWindowSystemBindingInfoEGL(info);
    283     default:
    284       return false;
    285   }
    286   return false;
    287 }
    288 
    289 }  // namespace gfx
    290