text: // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #include "base/base_paths.h"
  #include "base/file_path.h"
  #include "base/logging.h"
  #include "base/mac/foundation_util.h"
  #include "base/native_library.h"
  #include "base/path_service.h"
  #include "base/threading/thread_restrictions.h"
  #include "ui/gl/gl_bindings.h"
  #include "ui/gl/gl_gl_api_implementation.h"
  #include "ui/gl/gl_implementation.h"
  #include "ui/gl/gl_osmesa_api_implementation.h"
  
  namespace gfx {
  namespace {
  const char kOpenGLFrameworkPath[] =
      "/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL";
  }  // namespace
  
  void GetAllowedGLImplementations(std::vector<GLImplementation>* impls) {
    impls->push_back(kGLImplementationDesktopGL);
    impls->push_back(kGLImplementationAppleGL);
    impls->push_back(kGLImplementationOSMesaGL);
  }
  
  bool InitializeGLBindings(GLImplementation implementation) {
    // Prevent reinitialization with a different implementation. Once the gpu
    // unit tests have initialized with kGLImplementationMock, we don't want to
    // later switch to another GL implementation.
    if (GetGLImplementation() != kGLImplementationNone)
      return true;
  
    // Allow the main thread or another to initialize these bindings
    // after instituting restrictions on I/O. Going forward they will
    // likely be used in the browser process on most platforms. The
    // one-time initialization cost is small, between 2 and 5 ms.
    base::ThreadRestrictions::ScopedAllowIO allow_io;
  
    switch (implementation) {
      case kGLImplementationOSMesaGL: {
        // osmesa.so is located in the build directory. This code path is only
        // valid in a developer build environment.
        FilePath exe_path;
        if (!PathService::Get(base::FILE_EXE, &exe_path)) {
          LOG(ERROR) << "PathService::Get failed.";
          return false;
        }
        FilePath bundle_path = base::mac::GetAppBundlePath(exe_path);
        FilePath build_dir_path = bundle_path.DirName();
        FilePath osmesa_path = build_dir_path.Append("osmesa.so");
  
        // When using OSMesa, just use OSMesaGetProcAddress to find entry points.
        base::NativeLibrary library = base::LoadNativeLibrary(osmesa_path, NULL);
        if (!library) {
          LOG(ERROR) << "osmesa.so not found at " << osmesa_path.value();
          return false;
        }
  
        GLGetProcAddressProc get_proc_address =
            reinterpret_cast<GLGetProcAddressProc>(
                base::GetFunctionPointerFromNativeLibrary(
                    library, "OSMesaGetProcAddress"));
        if (!get_proc_address) {
          LOG(ERROR) << "OSMesaGetProcAddress not found.";
          base::UnloadNativeLibrary(library);
          return false;
        }
  
        SetGLGetProcAddressProc(get_proc_address);
        AddGLNativeLibrary(library);
        SetGLImplementation(kGLImplementationOSMesaGL);
  
        InitializeGLBindingsGL();
        InitializeGLBindingsOSMESA();
        break;
      }
      case kGLImplementationDesktopGL:
      case kGLImplementationAppleGL: {
        base::NativeLibrary library = base::LoadNativeLibrary(
            FilePath(kOpenGLFrameworkPath), NULL);
        if (!library) {
          LOG(ERROR) << "OpenGL framework not found";
          return false;
        }
  
        AddGLNativeLibrary(library);
        SetGLImplementation(implementation);
  
        InitializeGLBindingsGL();
        break;
      }
      case kGLImplementationMockGL: {
        SetGLGetProcAddressProc(GetMockGLProcAddress);
        SetGLImplementation(kGLImplementationMockGL);
        InitializeGLBindingsGL();
        break;
      }
      default:
        return false;
    }
  
    return true;
  }
  
  bool InitializeGLExtensionBindings(GLImplementation implementation,
      GLContext* context) {
    switch (implementation) {
      case kGLImplementationOSMesaGL:
        InitializeGLExtensionBindingsGL(context);
        InitializeGLExtensionBindingsOSMESA(context);
        break;
      case kGLImplementationDesktopGL:
      case kGLImplementationAppleGL:
        InitializeGLExtensionBindingsGL(context);
        break;
      case kGLImplementationMockGL:
        InitializeGLExtensionBindingsGL(context);
        break;
      default:
        return false;
    }
  
    return true;
  }
  
  void InitializeDebugGLBindings() {
    InitializeDebugGLBindingsGL();
    InitializeDebugGLBindingsOSMESA();
  }
  
  void ClearGLBindings() {
    ClearGLBindingsGL();
    ClearGLBindingsOSMESA();
    SetGLImplementation(kGLImplementationNone);
  
    UnloadGLNativeLibraries();
  }
  
  }  // namespace gfx
  