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_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 
     32 namespace gfx {
     33 
     34 namespace {
     35 
     36 const wchar_t kD3DCompiler[] = 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 const unsigned char* AngleGetTraceCategoryEnabledFlag(const char* name) {
     62   return TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(name);
     63 }
     64 
     65 void 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 
     86 typedef const unsigned char* (*GetCategoryEnabledFlagFunc)(const char* name);
     87 typedef 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);
     96 typedef void (__stdcall *SetTraceFunctionPointersFunc)(
     97     GetCategoryEnabledFlagFunc get_category_enabled_flag,
     98     AddTraceEventFunc add_trace_event_func);
     99 
    100 }  // namespace
    101 
    102 void GetAllowedGLImplementations(std::vector<GLImplementation>* impls) {
    103   impls->push_back(kGLImplementationEGLGLES2);
    104   impls->push_back(kGLImplementationDesktopGL);
    105   impls->push_back(kGLImplementationOSMesaGL);
    106 }
    107 
    108 bool 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 
    318 bool 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 
    349 void InitializeDebugGLBindings() {
    350   InitializeDebugGLBindingsEGL();
    351   InitializeDebugGLBindingsGL();
    352   InitializeDebugGLBindingsOSMESA();
    353   InitializeDebugGLBindingsWGL();
    354 }
    355 
    356 void ClearGLBindings() {
    357   ClearGLBindingsEGL();
    358   ClearGLBindingsGL();
    359   ClearGLBindingsOSMESA();
    360   ClearGLBindingsWGL();
    361   SetGLImplementation(kGLImplementationNone);
    362   UnloadGLNativeLibraries();
    363 }
    364 
    365 bool 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