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