text: // Copyright (c) 2011 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 "ui/gfx/gl/gl_implementation.h"
  
  #include <algorithm>
  #include <string>
  
  #include "base/at_exit.h"
  #include "base/command_line.h"
  #include "base/logging.h"
  
  namespace gfx {
  
  namespace {
  
  const struct {
    const char* name;
    GLImplementation implementation;
  } kGLImplementationNamePairs[] = {
    { kGLImplementationDesktopName, kGLImplementationDesktopGL },
    { kGLImplementationOSMesaName, kGLImplementationOSMesaGL },
  #if defined(OS_MACOSX)
    { kGLImplementationAppleName, kGLImplementationAppleGL },
  #endif
    { kGLImplementationEGLName, kGLImplementationEGLGLES2 },
    { kGLImplementationMockName, kGLImplementationMockGL }
  };
  
  typedef std::vector<base::NativeLibrary> LibraryArray;
  
  GLImplementation g_gl_implementation = kGLImplementationNone;
  LibraryArray* g_libraries;
  GLGetProcAddressProc g_get_proc_address;
  
  void CleanupNativeLibraries(void* unused) {
    if (g_libraries) {
      for (LibraryArray::iterator it = g_libraries->begin();
           it != g_libraries->end(); ++it) {
        base::UnloadNativeLibrary(*it);
      }
      delete g_libraries;
      g_libraries = NULL;
    }
  }
  
  bool ExportsCoreFunctionsFromGetProcAddress(GLImplementation implementation) {
    switch (GetGLImplementation()) {
      case kGLImplementationDesktopGL:
      case kGLImplementationOSMesaGL:
      case kGLImplementationAppleGL:
      case kGLImplementationMockGL:
        return true;
      case kGLImplementationEGLGLES2:
        return false;
      default:
        NOTREACHED();
        return true;
    }
  }
  
  }
  
  GLImplementation GetNamedGLImplementation(const std::string& name) {
    for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kGLImplementationNamePairs); ++i) {
      if (name == kGLImplementationNamePairs[i].name)
        return kGLImplementationNamePairs[i].implementation;
    }
  
    return kGLImplementationNone;
  }
  
  const char* GetGLImplementationName(GLImplementation implementation) {
    for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kGLImplementationNamePairs); ++i) {
      if (implementation == kGLImplementationNamePairs[i].implementation)
        return kGLImplementationNamePairs[i].name;
    }
  
    return "unknown";
  }
  
  void SetGLImplementation(GLImplementation implementation) {
    g_gl_implementation = implementation;
  }
  
  GLImplementation GetGLImplementation() {
    return g_gl_implementation;
  }
  
  bool HasDesktopGLFeatures() {
    return kGLImplementationDesktopGL == g_gl_implementation ||
           kGLImplementationOSMesaGL == g_gl_implementation ||
           kGLImplementationAppleGL == g_gl_implementation;
  }
  
  void AddGLNativeLibrary(base::NativeLibrary library) {
    DCHECK(library);
  
    if (!g_libraries) {
      g_libraries = new LibraryArray;
      base::AtExitManager::RegisterCallback(CleanupNativeLibraries, NULL);
    }
  
    g_libraries->push_back(library);
  }
  
  void UnloadGLNativeLibraries() {
    CleanupNativeLibraries(NULL);
  }
  
  void SetGLGetProcAddressProc(GLGetProcAddressProc proc) {
    DCHECK(proc);
    g_get_proc_address = proc;
  }
  
  void* GetGLCoreProcAddress(const char* name) {
    DCHECK(g_gl_implementation != kGLImplementationNone);
  
    if (g_libraries) {
      for (size_t i = 0; i < g_libraries->size(); ++i) {
        void* proc = base::GetFunctionPointerFromNativeLibrary((*g_libraries)[i],
                                                               name);
        if (proc)
          return proc;
      }
    }
    if (ExportsCoreFunctionsFromGetProcAddress(g_gl_implementation) &&
        g_get_proc_address) {
      void* proc = g_get_proc_address(name);
      if (proc)
        return proc;
    }
  
    return NULL;
  }
  
  void* GetGLProcAddress(const char* name) {
    DCHECK(g_gl_implementation != kGLImplementationNone);
  
    void* proc = GetGLCoreProcAddress(name);
    if (!proc && g_get_proc_address) {
      proc = g_get_proc_address(name);
      if (proc)
        return proc;
    }
  
    return proc;
  }
  
  }  // namespace gfx
  