普通文本  |  1855行  |  67.27 KB

#!/usr/bin/env python
# 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.

"""code generator for GL/GLES extension wrangler."""

import optparse
import os
import collections
import re
import sys

GL_FUNCTIONS = [
{ 'return_type': 'void',
  'names': ['glActiveTexture'],
  'arguments': 'GLenum texture', },
{ 'return_type': 'void',
  'names': ['glAttachShader'],
  'arguments': 'GLuint program, GLuint shader', },
{ 'return_type': 'void',
  'names': ['glBeginQuery'],
  'arguments': 'GLenum target, GLuint id', },
{ 'return_type': 'void',
  'names': ['glBeginQueryARB', 'glBeginQueryEXT'],
  'arguments': 'GLenum target, GLuint id', },
{ 'return_type': 'void',
  'names': ['glBindAttribLocation'],
  'arguments': 'GLuint program, GLuint index, const char* name', },
{ 'return_type': 'void',
  'names': ['glBindBuffer'],
  'arguments': 'GLenum target, GLuint buffer', },
{ 'return_type': 'void',
  'names': ['glBindFragDataLocation'],
  'arguments': 'GLuint program, GLuint colorNumber, const char* name', },
{ 'return_type': 'void',
  'names': ['glBindFragDataLocationIndexed'],
  'arguments':
      'GLuint program, GLuint colorNumber, GLuint index, const char* name', },
{ 'return_type': 'void',
  'names': ['glBindFramebufferEXT', 'glBindFramebuffer'],
  'arguments': 'GLenum target, GLuint framebuffer', },
{ 'return_type': 'void',
  'names': ['glBindRenderbufferEXT', 'glBindRenderbuffer'],
  'arguments': 'GLenum target, GLuint renderbuffer', },
{ 'return_type': 'void',
  'names': ['glBindTexture'],
  'arguments': 'GLenum target, GLuint texture', },
{ 'return_type': 'void',
  'names': ['glBlendColor'],
  'arguments': 'GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha', },
{ 'return_type': 'void',
  'names': ['glBlendEquation'],
  'arguments': ' GLenum mode ', },
{ 'return_type': 'void',
  'names': ['glBlendEquationSeparate'],
  'arguments': 'GLenum modeRGB, GLenum modeAlpha', },
{ 'return_type': 'void',
  'names': ['glBlendFunc'],
  'arguments': 'GLenum sfactor, GLenum dfactor', },
{ 'return_type': 'void',
  'names': ['glBlendFuncSeparate'],
  'arguments':
      'GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha', },
{ 'return_type': 'void',
  'names': ['glBlitFramebuffer'],
  'arguments': 'GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, '
               'GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, '
               'GLbitfield mask, GLenum filter', },
{ 'return_type': 'void',
  'names': ['glBlitFramebufferEXT', 'glBlitFramebuffer'],
  'arguments': 'GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, '
               'GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, '
               'GLbitfield mask, GLenum filter', },
{ 'return_type': 'void',
  'names': ['glBlitFramebufferANGLE', 'glBlitFramebuffer'],
  'arguments': 'GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, '
               'GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, '
               'GLbitfield mask, GLenum filter', },
{ 'return_type': 'void',
  'names': ['glBufferData'],
  'arguments': 'GLenum target, GLsizei size, const void* data, GLenum usage', },
{ 'return_type': 'void',
  'names': ['glBufferSubData'],
  'arguments': 'GLenum target, GLint offset, GLsizei size, const void* data', },
{ 'return_type': 'GLenum',
  'names': ['glCheckFramebufferStatusEXT',
            'glCheckFramebufferStatus'],
  'arguments': 'GLenum target',
  'logging_code': """
  GL_SERVICE_LOG("GL_RESULT: " << GLES2Util::GetStringEnum(result));
""", },
{ 'return_type': 'void',
  'names': ['glClear'],
  'arguments': 'GLbitfield mask', },
{ 'return_type': 'void',
  'names': ['glClearColor'],
  'arguments': 'GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha', },
{ 'return_type': 'void',
  'names': ['glClearDepth'],
  'arguments': 'GLclampd depth', },
{ 'return_type': 'void',
  'names': ['glClearDepthf'],
  'arguments': 'GLclampf depth', },
{ 'return_type': 'void',
  'names': ['glClearStencil'],
  'arguments': 'GLint s', },
{ 'return_type': 'void',
  'names': ['glColorMask'],
  'arguments':
      'GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha', },
{ 'return_type': 'void',
  'names': ['glCompileShader'],
  'arguments': 'GLuint shader', },
{ 'return_type': 'void',
  'names': ['glCompressedTexImage2D'],
  'arguments':
      'GLenum target, GLint level, GLenum internalformat, GLsizei width, '
      'GLsizei height, GLint border, GLsizei imageSize, const void* data', },
{ 'return_type': 'void',
  'names': ['glCompressedTexSubImage2D'],
  'arguments':
     'GLenum target, GLint level, GLint xoffset, GLint yoffset, '
     'GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, '
     'const void* data', },
{ 'return_type': 'void',
  'names': ['glCopyTexImage2D'],
  'arguments':
      'GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, '
      'GLsizei width, GLsizei height, GLint border', },
{ 'return_type': 'void',
  'names': ['glCopyTexSubImage2D'],
  'arguments':
      'GLenum target, GLint level, GLint xoffset, '
      'GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height', },
{ 'return_type': 'GLuint',
  'names': ['glCreateProgram'],
  'arguments': 'void', },
{ 'return_type': 'GLuint',
  'names': ['glCreateShader'],
  'arguments': 'GLenum type', },
{ 'return_type': 'void',
  'names': ['glCullFace'],
  'arguments': 'GLenum mode', },
{ 'return_type': 'void',
  'names': ['glDeleteBuffersARB', 'glDeleteBuffers'],
  'arguments': 'GLsizei n, const GLuint* buffers', },
{ 'return_type': 'void',
  'names': ['glDeleteFramebuffersEXT', 'glDeleteFramebuffers'],
  'arguments': 'GLsizei n, const GLuint* framebuffers', },
{ 'return_type': 'void',
  'names': ['glDeleteProgram'],
  'arguments': 'GLuint program', },
{ 'return_type': 'void',
  'names': ['glDeleteQueries'],
  'arguments': 'GLsizei n, const GLuint* ids', },
{ 'return_type': 'void',
  'names': ['glDeleteQueriesARB', 'glDeleteQueriesEXT'],
  'arguments': 'GLsizei n, const GLuint* ids', },
{ 'return_type': 'void',
  'names': ['glDeleteRenderbuffersEXT', 'glDeleteRenderbuffers'],
  'arguments': 'GLsizei n, const GLuint* renderbuffers', },
{ 'return_type': 'void',
  'names': ['glDeleteShader'],
  'arguments': 'GLuint shader', },
{ 'return_type': 'void',
  'names': ['glDeleteTextures'],
  'arguments': 'GLsizei n, const GLuint* textures', },
{ 'return_type': 'void',
  'names': ['glDepthFunc'],
  'arguments': 'GLenum func', },
{ 'return_type': 'void',
  'names': ['glDepthMask'],
  'arguments': 'GLboolean flag', },
{ 'return_type': 'void',
  'names': ['glDepthRange'],
  'arguments': 'GLclampd zNear, GLclampd zFar', },
{ 'return_type': 'void',
  'names': ['glDepthRangef'],
  'arguments': 'GLclampf zNear, GLclampf zFar', },
{ 'return_type': 'void',
  'names': ['glDetachShader'],
  'arguments': 'GLuint program, GLuint shader', },
{ 'return_type': 'void',
  'names': ['glDisable'],
  'arguments': 'GLenum cap', },
{ 'return_type': 'void',
  'names': ['glDisableVertexAttribArray'],
  'arguments': 'GLuint index', },
{ 'return_type': 'void',
  'names': ['glDrawArrays'],
  'arguments': 'GLenum mode, GLint first, GLsizei count', },
{ 'return_type': 'void',
  'names': ['glDrawBuffer'],
  'arguments': 'GLenum mode', },
{ 'return_type': 'void',
  'names': ['glDrawBuffersARB', 'glDrawBuffersEXT'],
  'arguments': 'GLsizei n, const GLenum* bufs', },
{ 'return_type': 'void',
  'names': ['glDrawElements'],
  'arguments':
      'GLenum mode, GLsizei count, GLenum type, const void* indices', },
{ 'return_type': 'void',
  'names': ['glEGLImageTargetTexture2DOES'],
  'arguments': 'GLenum target, GLeglImageOES image', },
{ 'return_type': 'void',
  'names': ['glEGLImageTargetRenderbufferStorageOES'],
  'arguments': 'GLenum target, GLeglImageOES image', },
{ 'return_type': 'void',
  'names': ['glEnable'],
  'arguments': 'GLenum cap', },
{ 'return_type': 'void',
  'names': ['glEnableVertexAttribArray'],
  'arguments': 'GLuint index', },
{ 'return_type': 'void',
  'names': ['glEndQuery'],
  'arguments': 'GLenum target', },
{ 'return_type': 'void',
  'names': ['glEndQueryARB', 'glEndQueryEXT'],
  'arguments': 'GLenum target', },
{ 'return_type': 'void',
  'names': ['glFinish'],
  'arguments': 'void', },
{ 'return_type': 'void',
  'names': ['glFlush'],
  'arguments': 'void', },
{ 'return_type': 'void',
  'names': ['glFramebufferRenderbufferEXT', 'glFramebufferRenderbuffer'],
  'arguments': \
      'GLenum target, GLenum attachment, GLenum renderbuffertarget, '
      'GLuint renderbuffer', },
{ 'return_type': 'void',
  'names': ['glFramebufferTexture2DEXT', 'glFramebufferTexture2D'],
  'arguments':
      'GLenum target, GLenum attachment, GLenum textarget, GLuint texture, '
      'GLint level', },
{ 'return_type': 'void',
  'names': ['glFramebufferTexture2DMultisampleEXT'],
  'arguments':
      'GLenum target, GLenum attachment, GLenum textarget, GLuint texture, '
      'GLint level, GLsizei samples', },
{ 'return_type': 'void',
  'names': ['glFramebufferTexture2DMultisampleIMG'],
  'arguments':
      'GLenum target, GLenum attachment, GLenum textarget, GLuint texture, '
      'GLint level, GLsizei samples', },
{ 'return_type': 'void',
  'names': ['glFrontFace'],
  'arguments': 'GLenum mode', },
{ 'return_type': 'void',
  'names': ['glGenBuffersARB', 'glGenBuffers'],
  'arguments': 'GLsizei n, GLuint* buffers', },
{ 'return_type': 'void',
  'names': ['glGenQueries'],
  'arguments': 'GLsizei n, GLuint* ids', },
{ 'return_type': 'void',
  'names': ['glGenQueriesARB', 'glGenQueriesEXT'],
  'arguments': 'GLsizei n, GLuint* ids', },
{ 'return_type': 'void',
  'names': ['glGenerateMipmapEXT', 'glGenerateMipmap'],
  'arguments': 'GLenum target', },
{ 'return_type': 'void',
  'names': ['glGenFramebuffersEXT', 'glGenFramebuffers'],
  'arguments': 'GLsizei n, GLuint* framebuffers', },
{ 'return_type': 'void',
  'names': ['glGenRenderbuffersEXT', 'glGenRenderbuffers'],
  'arguments': 'GLsizei n, GLuint* renderbuffers', },
{ 'return_type': 'void',
  'names': ['glGenTextures'],
  'arguments': 'GLsizei n, GLuint* textures', },
{ 'return_type': 'void',
  'names': ['glGetActiveAttrib'],
  'arguments':
      'GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, '
      'GLint* size, GLenum* type, char* name', },
{ 'return_type': 'void',
  'names': ['glGetActiveUniform'],
  'arguments':
      'GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, '
      'GLint* size, GLenum* type, char* name', },
{ 'return_type': 'void',
  'names': ['glGetAttachedShaders'],
  'arguments':
      'GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders', },
{ 'return_type': 'GLint',
  'names': ['glGetAttribLocation'],
  'arguments': 'GLuint program, const char* name', },
{ 'return_type': 'void',
  'names': ['glGetBooleanv'],
  'arguments': 'GLenum pname, GLboolean* params', },
{ 'return_type': 'void',
  'names': ['glGetBufferParameteriv'],
  'arguments': 'GLenum target, GLenum pname, GLint* params', },
{ 'return_type': 'GLenum',
  'names': ['glGetError'],
  'arguments': 'void',
  'logging_code': """
  GL_SERVICE_LOG("GL_RESULT: " << GLES2Util::GetStringError(result));
""", },
{ 'return_type': 'void',
  'names': ['glGetFloatv'],
  'arguments': 'GLenum pname, GLfloat* params', },
{ 'return_type': 'void',
  'names': ['glGetFramebufferAttachmentParameterivEXT',
            'glGetFramebufferAttachmentParameteriv'],
  'arguments': 'GLenum target, '
               'GLenum attachment, GLenum pname, GLint* params', },
{ 'return_type': 'GLenum',
  'names': ['glGetGraphicsResetStatusARB',
            'glGetGraphicsResetStatusEXT'],
  'arguments': 'void', },
{ 'return_type': 'void',
  'names': ['glGetIntegerv'],
  'arguments': 'GLenum pname, GLint* params', },
{ 'return_type': 'void',
  'names': ['glGetProgramBinary', 'glGetProgramBinaryOES'],
  'arguments': 'GLuint program, GLsizei bufSize, GLsizei* length, '
               'GLenum* binaryFormat, GLvoid* binary',
  'other_extensions': ['ARB_get_program_binary',
                       'OES_get_program_binary'] },
{ 'return_type': 'void',
  'names': ['glGetProgramiv'],
  'arguments': 'GLuint program, GLenum pname, GLint* params', },
{ 'return_type': 'void',
  'names': ['glGetProgramInfoLog'],
  'arguments':
      'GLuint program, GLsizei bufsize, GLsizei* length, char* infolog', },
{ 'return_type': 'void',
  'names': ['glGetQueryiv'],
  'arguments': 'GLenum target, GLenum pname, GLint* params', },
{ 'return_type': 'void',
  'names': ['glGetQueryivARB', 'glGetQueryivEXT'],
  'arguments': 'GLenum target, GLenum pname, GLint* params', },
{ 'return_type': 'void',
  'names': ['glGetQueryObjecti64v'],
  'arguments': 'GLuint id, GLenum pname, GLint64* params', },
{ 'return_type': 'void',
  'names': ['glGetQueryObjectiv'],
  'arguments': 'GLuint id, GLenum pname, GLint* params', },
{ 'return_type': 'void',
  'names': ['glGetQueryObjectui64v'],
  'arguments': 'GLuint id, GLenum pname, GLuint64* params', },
{ 'return_type': 'void',
  'names': ['glGetQueryObjectuiv'],
  'arguments': 'GLuint id, GLenum pname, GLuint* params', },
{ 'return_type': 'void',
  'names': ['glGetQueryObjectuivARB', 'glGetQueryObjectuivEXT'],
  'arguments': 'GLuint id, GLenum pname, GLuint* params', },
{ 'return_type': 'void',
  'names': ['glGetRenderbufferParameterivEXT', 'glGetRenderbufferParameteriv'],
  'arguments': 'GLenum target, GLenum pname, GLint* params', },
{ 'return_type': 'void',
  'names': ['glGetShaderiv'],
  'arguments': 'GLuint shader, GLenum pname, GLint* params', },
{ 'return_type': 'void',
  'names': ['glGetShaderInfoLog'],
  'arguments':
      'GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog', },
{ 'return_type': 'void',
  'names': ['glGetShaderPrecisionFormat'],
  'arguments': 'GLenum shadertype, GLenum precisiontype, '
               'GLint* range, GLint* precision', },
{ 'return_type': 'void',
  'names': ['glGetShaderSource'],
  'arguments':
      'GLuint shader, GLsizei bufsize, GLsizei* length, char* source', },
{ 'return_type': 'const GLubyte*',
  'names': ['glGetString'],
  'arguments': 'GLenum name', },
{ 'return_type': 'void',
  'names': ['glGetTexLevelParameterfv'],
  'arguments': 'GLenum target, GLint level, GLenum pname, GLfloat* params', },
{ 'return_type': 'void',
  'names': ['glGetTexLevelParameteriv'],
  'arguments': 'GLenum target, GLint level, GLenum pname, GLint* params', },
{ 'return_type': 'void',
  'names': ['glGetTexParameterfv'],
  'arguments': 'GLenum target, GLenum pname, GLfloat* params', },
{ 'return_type': 'void',
  'names': ['glGetTexParameteriv'],
  'arguments': 'GLenum target, GLenum pname, GLint* params', },
{ 'return_type': 'void',
  'names': ['glGetTranslatedShaderSourceANGLE'],
  'arguments':
      'GLuint shader, GLsizei bufsize, GLsizei* length, char* source', },
{ 'return_type': 'void',
  'names': ['glGetUniformfv'],
  'arguments': 'GLuint program, GLint location, GLfloat* params', },
{ 'return_type': 'void',
  'names': ['glGetUniformiv'],
  'arguments': 'GLuint program, GLint location, GLint* params', },
{ 'return_type': 'GLint',
  'names': ['glGetUniformLocation'],
  'arguments': 'GLuint program, const char* name', },
{ 'return_type': 'void',
  'names': ['glGetVertexAttribfv'],
  'arguments': 'GLuint index, GLenum pname, GLfloat* params', },
{ 'return_type': 'void',
  'names': ['glGetVertexAttribiv'],
  'arguments': 'GLuint index, GLenum pname, GLint* params', },
{ 'return_type': 'void',
  'names': ['glGetVertexAttribPointerv'],
  'arguments': 'GLuint index, GLenum pname, void** pointer', },
{ 'return_type': 'void',
  'names': ['glHint'],
  'arguments': 'GLenum target, GLenum mode', },
{ 'return_type': 'GLboolean',
  'names': ['glIsBuffer'],
  'arguments': 'GLuint buffer', },
{ 'return_type': 'GLboolean',
  'names': ['glIsEnabled'],
  'arguments': 'GLenum cap', },
{ 'return_type': 'GLboolean',
  'names': ['glIsFramebufferEXT', 'glIsFramebuffer'],
  'arguments': 'GLuint framebuffer', },
{ 'return_type': 'GLboolean',
  'names': ['glIsProgram'],
  'arguments': 'GLuint program', },
{ 'return_type': 'GLboolean',
  'names': ['glIsQueryARB', 'glIsQueryEXT'],
  'arguments': 'GLuint query', },
{ 'return_type': 'GLboolean',
  'names': ['glIsRenderbufferEXT', 'glIsRenderbuffer'],
  'arguments': 'GLuint renderbuffer', },
{ 'return_type': 'GLboolean',
  'names': ['glIsShader'],
  'arguments': 'GLuint shader', },
{ 'return_type': 'GLboolean',
  'names': ['glIsTexture'],
  'arguments': 'GLuint texture', },
{ 'return_type': 'void',
  'names': ['glLineWidth'],
  'arguments': 'GLfloat width', },
{ 'return_type': 'void',
  'names': ['glLinkProgram'],
  'arguments': 'GLuint program', },
{ 'return_type': 'void*',
  'names': ['glMapBuffer', 'glMapBufferOES'],
  'arguments': 'GLenum target, GLenum access', },
{ 'return_type': 'void*',
  'names': ['glMapBufferRange'],
  'arguments':
      'GLenum target, GLintptr offset, GLsizeiptr length, GLenum access', },
{ 'return_type': 'void',
  'names': ['glFlushMappedBufferRange'],
  'arguments': 'GLenum target, GLintptr offset, GLsizeiptr length', },
{ 'return_type': 'void',
  'names': ['glPixelStorei'],
  'arguments': 'GLenum pname, GLint param', },
{ 'return_type': 'void',
  'names': ['glPointParameteri'],
  'arguments': 'GLenum pname, GLint param', },
{ 'return_type': 'void',
  'names': ['glPolygonOffset'],
  'arguments': 'GLfloat factor, GLfloat units', },
{ 'return_type': 'void',
  'names': ['glProgramBinary', 'glProgramBinaryOES'],
  'arguments': 'GLuint program, GLenum binaryFormat, '
               'const GLvoid* binary, GLsizei length',
  'other_extensions': ['ARB_get_program_binary',
                       'OES_get_program_binary'] },
{ 'return_type': 'void',
  'names': ['glProgramParameteri'],
  'arguments': 'GLuint program, GLenum pname, GLint value',
  'other_extensions': ['ARB_get_program_binary'] },
{ 'return_type': 'void',
  'names': ['glQueryCounter'],
  'arguments': 'GLuint id, GLenum target', },
{ 'return_type': 'void',
  'names': ['glReadBuffer'],
  'arguments': 'GLenum src', },
{ 'return_type': 'void',
  'names': ['glReadPixels'],
  'arguments':
    'GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, '
    'GLenum type, void* pixels', },
{ 'return_type': 'void',
  'names': ['glReleaseShaderCompiler'],
  'arguments': 'void', },
{ 'return_type': 'void',
  'names': ['glRenderbufferStorageMultisample'],
  'arguments': 'GLenum target, GLsizei samples, GLenum internalformat, '
               'GLsizei width, GLsizei height', },
{ 'return_type': 'void',
  'names': ['glRenderbufferStorageMultisampleEXT',
            'glRenderbufferStorageMultisample'],
  'arguments': 'GLenum target, GLsizei samples, GLenum internalformat, '
               'GLsizei width, GLsizei height', },
{ 'return_type': 'void',
  'names': ['glRenderbufferStorageMultisampleANGLE',
            'glRenderbufferStorageMultisample'],
  'arguments': 'GLenum target, GLsizei samples, GLenum internalformat, '
               'GLsizei width, GLsizei height', },
{ 'return_type': 'void',
  'names': ['glRenderbufferStorageMultisampleIMG'],
  'arguments': 'GLenum target, GLsizei samples, GLenum internalformat, '
               'GLsizei width, GLsizei height', },
{ 'return_type': 'void',
  'names': ['glRenderbufferStorageEXT', 'glRenderbufferStorage'],
  'arguments':
      'GLenum target, GLenum internalformat, GLsizei width, GLsizei height', },
{ 'return_type': 'void',
  'names': ['glSampleCoverage'],
  'arguments': 'GLclampf value, GLboolean invert', },
{ 'return_type': 'void',
  'names': ['glScissor'],
  'arguments': 'GLint x, GLint y, GLsizei width, GLsizei height', },
{ 'return_type': 'void',
  'names': ['glShaderBinary'],
  'arguments': 'GLsizei n, const GLuint* shaders, GLenum binaryformat, '
               'const void* binary, GLsizei length', },
{ 'return_type': 'void',
  'names': ['glShaderSource'],
  'arguments':
      'GLuint shader, GLsizei count, const char* const* str, const GLint* length',
  'logging_code': """
  GL_SERVICE_LOG_CODE_BLOCK({
    for (GLsizei ii = 0; ii < count; ++ii) {
      if (str[ii]) {
        if (length && length[ii] >= 0) {
          std::string source(str[ii], length[ii]);
          GL_SERVICE_LOG("  " << ii << ": ---\\n" << source << "\\n---");
        } else {
          GL_SERVICE_LOG("  " << ii << ": ---\\n" << str[ii] << "\\n---");
        }
      } else {
        GL_SERVICE_LOG("  " << ii << ": NULL");
      }
    }
  });
""", },
{ 'return_type': 'void',
  'names': ['glStencilFunc'],
  'arguments': 'GLenum func, GLint ref, GLuint mask', },
{ 'return_type': 'void',
  'names': ['glStencilFuncSeparate'],
  'arguments': 'GLenum face, GLenum func, GLint ref, GLuint mask', },
{ 'return_type': 'void',
  'names': ['glStencilMask'],
  'arguments': 'GLuint mask', },
{ 'return_type': 'void',
  'names': ['glStencilMaskSeparate'],
  'arguments': 'GLenum face, GLuint mask', },
{ 'return_type': 'void',
  'names': ['glStencilOp'],
  'arguments': 'GLenum fail, GLenum zfail, GLenum zpass', },
{ 'return_type': 'void',
  'names': ['glStencilOpSeparate'],
  'arguments': 'GLenum face, GLenum fail, GLenum zfail, GLenum zpass', },
{ 'return_type': 'void',
  'names': ['glTexImage2D'],
  'arguments':
      'GLenum target, GLint level, GLint internalformat, GLsizei width, '
      'GLsizei height, GLint border, GLenum format, GLenum type, '
      'const void* pixels', },
{ 'return_type': 'void',
  'names': ['glTexParameterf'],
  'arguments': 'GLenum target, GLenum pname, GLfloat param', },
{ 'return_type': 'void',
  'names': ['glTexParameterfv'],
  'arguments': 'GLenum target, GLenum pname, const GLfloat* params', },
{ 'return_type': 'void',
  'names': ['glTexParameteri'],
  'arguments': 'GLenum target, GLenum pname, GLint param', },
{ 'return_type': 'void',
  'names': ['glTexParameteriv'],
  'arguments': 'GLenum target, GLenum pname, const GLint* params', },
{ 'return_type': 'void',
  'names': ['glTexStorage2DEXT'],
  'arguments': 'GLenum target, GLsizei levels, GLenum internalformat, '
               'GLsizei width, GLsizei height', },
{ 'return_type': 'void',
  'names': ['glTexSubImage2D'],
  'arguments':
     'GLenum target, GLint level, GLint xoffset, GLint yoffset, '
     'GLsizei width, GLsizei height, GLenum format, GLenum type, '
     'const void* pixels', },
{ 'return_type': 'void',
  'names': ['glUniform1f'],
  'arguments': 'GLint location, GLfloat x', },
{ 'return_type': 'void',
  'names': ['glUniform1fv'],
  'arguments': 'GLint location, GLsizei count, const GLfloat* v', },
{ 'return_type': 'void',
  'names': ['glUniform1i'],
  'arguments': 'GLint location, GLint x', },
{ 'return_type': 'void',
  'names': ['glUniform1iv'],
  'arguments': 'GLint location, GLsizei count, const GLint* v', },
{ 'return_type': 'void',
  'names': ['glUniform2f'],
  'arguments': 'GLint location, GLfloat x, GLfloat y', },
{ 'return_type': 'void',
  'names': ['glUniform2fv'],
  'arguments': 'GLint location, GLsizei count, const GLfloat* v', },
{ 'return_type': 'void',
  'names': ['glUniform2i'],
  'arguments': 'GLint location, GLint x, GLint y', },
{ 'return_type': 'void',
  'names': ['glUniform2iv'],
  'arguments': 'GLint location, GLsizei count, const GLint* v', },
{ 'return_type': 'void',
  'names': ['glUniform3f'],
  'arguments': 'GLint location, GLfloat x, GLfloat y, GLfloat z', },
{ 'return_type': 'void',
  'names': ['glUniform3fv'],
  'arguments': 'GLint location, GLsizei count, const GLfloat* v', },
{ 'return_type': 'void',
  'names': ['glUniform3i'],
  'arguments': 'GLint location, GLint x, GLint y, GLint z', },
{ 'return_type': 'void',
  'names': ['glUniform3iv'],
  'arguments': 'GLint location, GLsizei count, const GLint* v', },
{ 'return_type': 'void',
  'names': ['glUniform4f'],
  'arguments': 'GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w', },
{ 'return_type': 'void',
  'names': ['glUniform4fv'],
  'arguments': 'GLint location, GLsizei count, const GLfloat* v', },
{ 'return_type': 'void',
  'names': ['glUniform4i'],
  'arguments': 'GLint location, GLint x, GLint y, GLint z, GLint w', },
{ 'return_type': 'void',
  'names': ['glUniform4iv'],
  'arguments': 'GLint location, GLsizei count, const GLint* v', },
{ 'return_type': 'void',
  'names': ['glUniformMatrix2fv'],
  'arguments': 'GLint location, GLsizei count, '
               'GLboolean transpose, const GLfloat* value', },
{ 'return_type': 'void',
  'names': ['glUniformMatrix3fv'],
  'arguments': 'GLint location, GLsizei count, '
               'GLboolean transpose, const GLfloat* value', },
{ 'return_type': 'void',
  'names': ['glUniformMatrix4fv'],
  'arguments': 'GLint location, GLsizei count, '
               'GLboolean transpose, const GLfloat* value', },
{ 'return_type': 'GLboolean',
  'names': ['glUnmapBuffer', 'glUnmapBufferOES'],
  'arguments': 'GLenum target', },
{ 'return_type': 'void',
  'names': ['glUseProgram'],
  'arguments': 'GLuint program', },
{ 'return_type': 'void',
  'names': ['glValidateProgram'],
  'arguments': 'GLuint program', },
{ 'return_type': 'void',
  'names': ['glVertexAttrib1f'],
  'arguments': 'GLuint indx, GLfloat x', },
{ 'return_type': 'void',
  'names': ['glVertexAttrib1fv'],
  'arguments': 'GLuint indx, const GLfloat* values', },
{ 'return_type': 'void',
  'names': ['glVertexAttrib2f'],
  'arguments': 'GLuint indx, GLfloat x, GLfloat y', },
{ 'return_type': 'void',
  'names': ['glVertexAttrib2fv'],
  'arguments': 'GLuint indx, const GLfloat* values', },
{ 'return_type': 'void',
  'names': ['glVertexAttrib3f'],
  'arguments': 'GLuint indx, GLfloat x, GLfloat y, GLfloat z', },
{ 'return_type': 'void',
  'names': ['glVertexAttrib3fv'],
  'arguments': 'GLuint indx, const GLfloat* values', },
{ 'return_type': 'void',
  'names': ['glVertexAttrib4f'],
  'arguments': 'GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w', },
{ 'return_type': 'void',
  'names': ['glVertexAttrib4fv'],
  'arguments': 'GLuint indx, const GLfloat* values', },
{ 'return_type': 'void',
  'names': ['glVertexAttribPointer'],
  'arguments': 'GLuint indx, GLint size, GLenum type, GLboolean normalized, '
               'GLsizei stride, const void* ptr', },
{ 'return_type': 'void',
  'names': ['glViewport'],
  'arguments': 'GLint x, GLint y, GLsizei width, GLsizei height', },
{ 'return_type': 'void',
  'names': ['glGenFencesNV'],
  'arguments': 'GLsizei n, GLuint* fences', },
{ 'return_type': 'void',
  'names': ['glDeleteFencesNV'],
  'arguments': 'GLsizei n, const GLuint* fences', },
{ 'return_type': 'void',
  'names': ['glSetFenceNV'],
  'arguments': 'GLuint fence, GLenum condition', },
{ 'return_type': 'GLboolean',
  'names': ['glTestFenceNV'],
  'arguments': 'GLuint fence', },
{ 'return_type': 'void',
  'names': ['glFinishFenceNV'],
  'arguments': 'GLuint fence', },
{ 'return_type': 'GLboolean',
  'names': ['glIsFenceNV'],
  'arguments': 'GLuint fence', },
{ 'return_type': 'void',
  'names': ['glGetFenceivNV'],
  'arguments': 'GLuint fence, GLenum pname, GLint* params', },
{ 'return_type': 'GLsync',
  'names': ['glFenceSync'],
  'arguments': 'GLenum condition, GLbitfield flags', },
{ 'return_type': 'void',
  'names': ['glDeleteSync'],
  'arguments': 'GLsync sync', },
{ 'return_type': 'void',
  'names': ['glGetSynciv'],
  'arguments':
    'GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length,'
    'GLint* values', },
{ 'return_type': 'GLenum',
  'names': ['glClientWaitSync'],
  'arguments':
    'GLsync sync, GLbitfield flags, GLuint64 timeout', },
{ 'return_type': 'GLenum',
  'names': ['glWaitSync'],
  'arguments':
    'GLsync sync, GLbitfield flags, GLuint64 timeout', },
{ 'return_type': 'void',
  'names': ['glDrawArraysInstancedANGLE', 'glDrawArraysInstancedARB'],
  'arguments': 'GLenum mode, GLint first, GLsizei count, GLsizei primcount', },
{ 'return_type': 'void',
  'names': ['glDrawElementsInstancedANGLE', 'glDrawElementsInstancedARB'],
  'arguments':
      'GLenum mode, GLsizei count, GLenum type, const void* indices, '
      'GLsizei primcount', },
{ 'return_type': 'void',
  'names': ['glVertexAttribDivisorANGLE', 'glVertexAttribDivisorARB'],
  'arguments':
      'GLuint index, GLuint divisor', },
{ 'return_type': 'void',
  'names': ['glGenVertexArraysOES',
            'glGenVertexArraysAPPLE',
            'glGenVertexArrays'],
  'arguments': 'GLsizei n, GLuint* arrays',
  'other_extensions': ['OES_vertex_array_object',
                       'APPLE_vertex_array_object',
                       'ARB_vertex_array_object'] },
{ 'return_type': 'void',
  'names': ['glDeleteVertexArraysOES',
            'glDeleteVertexArraysAPPLE',
            'glDeleteVertexArrays'],
  'arguments': 'GLsizei n, const GLuint* arrays',
  'other_extensions': ['OES_vertex_array_object',
                       'APPLE_vertex_array_object',
                       'ARB_vertex_array_object'] },
{ 'return_type': 'void',
  'names': ['glBindVertexArrayOES',
            'glBindVertexArrayAPPLE',
            'glBindVertexArray'],
  'arguments': 'GLuint array',
  'other_extensions': ['OES_vertex_array_object',
                       'APPLE_vertex_array_object',
                       'ARB_vertex_array_object'] },
{ 'return_type': 'GLboolean',
  'names': ['glIsVertexArrayOES',
            'glIsVertexArrayAPPLE',
            'glIsVertexArray'],
  'arguments': 'GLuint array',
  'other_extensions': ['OES_vertex_array_object',
                       'APPLE_vertex_array_object',
                       'ARB_vertex_array_object'] },
{ 'return_type': 'void',
  'names': ['glDiscardFramebufferEXT', 'glInvalidateFramebuffer'],
  'arguments': 'GLenum target, GLsizei numAttachments, '
      'const GLenum* attachments' },
]

OSMESA_FUNCTIONS = [
{ 'return_type': 'OSMesaContext',
  'names': ['OSMesaCreateContext'],
  'arguments': 'GLenum format, OSMesaContext sharelist', },
{ 'return_type': 'OSMesaContext',
  'names': ['OSMesaCreateContextExt'],
  'arguments':
      'GLenum format, GLint depthBits, GLint stencilBits, GLint accumBits, '
      'OSMesaContext sharelist', },
{ 'return_type': 'void',
  'names': ['OSMesaDestroyContext'],
  'arguments': 'OSMesaContext ctx', },
{ 'return_type': 'GLboolean',
  'names': ['OSMesaMakeCurrent'],
  'arguments': 'OSMesaContext ctx, void* buffer, GLenum type, GLsizei width, '
               'GLsizei height', },
{ 'return_type': 'OSMesaContext',
  'names': ['OSMesaGetCurrentContext'],
  'arguments': 'void', },
{ 'return_type': 'void',
  'names': ['OSMesaPixelStore'],
  'arguments': 'GLint pname, GLint value', },
{ 'return_type': 'void',
  'names': ['OSMesaGetIntegerv'],
  'arguments': 'GLint pname, GLint* value', },
{ 'return_type': 'GLboolean',
  'names': ['OSMesaGetDepthBuffer'],
  'arguments':
      'OSMesaContext c, GLint* width, GLint* height, GLint* bytesPerValue, '
      'void** buffer', },
{ 'return_type': 'GLboolean',
  'names': ['OSMesaGetColorBuffer'],
  'arguments': 'OSMesaContext c, GLint* width, GLint* height, GLint* format, '
               'void** buffer', },
{ 'return_type': 'OSMESAproc',
  'names': ['OSMesaGetProcAddress'],
  'arguments': 'const char* funcName', },
{ 'return_type': 'void',
  'names': ['OSMesaColorClamp'],
  'arguments': 'GLboolean enable', },
]

EGL_FUNCTIONS = [
{ 'return_type': 'EGLint',
  'names': ['eglGetError'],
  'arguments': 'void', },
{ 'return_type': 'EGLDisplay',
  'names': ['eglGetDisplay'],
  'arguments': 'EGLNativeDisplayType display_id', },
{ 'return_type': 'EGLBoolean',
  'names': ['eglInitialize'],
  'arguments': 'EGLDisplay dpy, EGLint* major, EGLint* minor', },
{ 'return_type': 'EGLBoolean',
  'names': ['eglTerminate'],
  'arguments': 'EGLDisplay dpy', },
{ 'return_type': 'const char*',
  'names': ['eglQueryString'],
  'arguments': 'EGLDisplay dpy, EGLint name', },
{ 'return_type': 'EGLBoolean',
  'names': ['eglGetConfigs'],
  'arguments': 'EGLDisplay dpy, EGLConfig* configs, EGLint config_size, '
               'EGLint* num_config', },
{ 'return_type': 'EGLBoolean',
  'names': ['eglChooseConfig'],
  'arguments': 'EGLDisplay dpy, const EGLint* attrib_list, EGLConfig* configs, '
               'EGLint config_size, EGLint* num_config', },
{ 'return_type': 'EGLBoolean',
  'names': ['eglGetConfigAttrib'],
  'arguments':
      'EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint* value', },
{ 'return_type': 'EGLImageKHR',
  'names': ['eglCreateImageKHR'],
  'arguments':
      'EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, '
      'const EGLint* attrib_list',
  'other_extensions': ['EGL_KHR_image_base', 'EGL_KHR_gl_texture_2D_image'] },
{ 'return_type': 'EGLBoolean',
  'names': ['eglDestroyImageKHR'],
  'arguments': 'EGLDisplay dpy, EGLImageKHR image',
  'other_extensions': ['EGL_KHR_image_base'] },
{ 'return_type': 'EGLSurface',
  'names': ['eglCreateWindowSurface'],
  'arguments': 'EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, '
               'const EGLint* attrib_list', },
{ 'return_type': 'EGLSurface',
  'names': ['eglCreatePbufferSurface'],
  'arguments': 'EGLDisplay dpy, EGLConfig config, const EGLint* attrib_list', },
{ 'return_type': 'EGLSurface',
  'names': ['eglCreatePixmapSurface'],
  'arguments': 'EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, '
               'const EGLint* attrib_list', },
{ 'return_type': 'EGLBoolean',
  'names': ['eglDestroySurface'],
  'arguments': 'EGLDisplay dpy, EGLSurface surface', },
{ 'return_type': 'EGLBoolean',
  'names': ['eglQuerySurface'],
  'arguments':
      'EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint* value', },
{ 'return_type': 'EGLBoolean',
  'names': ['eglBindAPI'],
  'arguments': 'EGLenum api', },
{ 'return_type': 'EGLenum',
  'names': ['eglQueryAPI'],
  'arguments': 'void', },
{ 'return_type': 'EGLBoolean',
  'names': ['eglWaitClient'],
  'arguments': 'void', },
{ 'return_type': 'EGLBoolean',
  'names': ['eglReleaseThread'],
  'arguments': 'void', },
{ 'return_type': 'EGLSurface',
  'names': ['eglCreatePbufferFromClientBuffer'],
  'arguments':
      'EGLDisplay dpy, EGLenum buftype, void* buffer, EGLConfig config, '
      'const EGLint* attrib_list', },
{ 'return_type': 'EGLBoolean',
  'names': ['eglSurfaceAttrib'],
  'arguments':
      'EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value', },
{ 'return_type': 'EGLBoolean',
  'names': ['eglBindTexImage'],
  'arguments': 'EGLDisplay dpy, EGLSurface surface, EGLint buffer', },
{ 'return_type': 'EGLBoolean',
  'names': ['eglReleaseTexImage'],
  'arguments': 'EGLDisplay dpy, EGLSurface surface, EGLint buffer', },
{ 'return_type': 'EGLBoolean',
  'names': ['eglSwapInterval'],
  'arguments': 'EGLDisplay dpy, EGLint interval', },
{ 'return_type': 'EGLContext',
  'names': ['eglCreateContext'],
  'arguments': 'EGLDisplay dpy, EGLConfig config, EGLContext share_context, '
              'const EGLint* attrib_list', },
{ 'return_type': 'EGLBoolean',
  'names': ['eglDestroyContext'],
  'arguments': 'EGLDisplay dpy, EGLContext ctx', },
{ 'return_type': 'EGLBoolean',
  'names': ['eglMakeCurrent'],
  'arguments':
      'EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx', },
{ 'return_type': 'EGLContext',
  'names': ['eglGetCurrentContext'],
  'arguments': 'void', },
{ 'return_type': 'EGLSurface',
  'names': ['eglGetCurrentSurface'],
  'arguments': 'EGLint readdraw', },
{ 'return_type': 'EGLDisplay',
  'names': ['eglGetCurrentDisplay'],
  'arguments': 'void', },
{ 'return_type': 'EGLBoolean',
  'names': ['eglQueryContext'],
  'arguments':
      'EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint* value', },
{ 'return_type': 'EGLBoolean',
  'names': ['eglWaitGL'],
  'arguments': 'void', },
{ 'return_type': 'EGLBoolean',
  'names': ['eglWaitNative'],
  'arguments': 'EGLint engine', },
{ 'return_type': 'EGLBoolean',
  'names': ['eglSwapBuffers'],
  'arguments': 'EGLDisplay dpy, EGLSurface surface', },
{ 'return_type': 'EGLBoolean',
  'names': ['eglCopyBuffers'],
  'arguments':
      'EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target', },
{ 'return_type': '__eglMustCastToProperFunctionPointerType',
  'names': ['eglGetProcAddress'],
  'arguments': 'const char* procname', },
{ 'return_type': 'EGLBoolean',
  'names': ['eglPostSubBufferNV'],
  'arguments': 'EGLDisplay dpy, EGLSurface surface, '
    'EGLint x, EGLint y, EGLint width, EGLint height', },
{ 'return_type': 'EGLBoolean',
  'names': ['eglQuerySurfacePointerANGLE'],
  'arguments':
      'EGLDisplay dpy, EGLSurface surface, EGLint attribute, void** value', },
{ 'return_type': 'EGLSyncKHR',
  'names': ['eglCreateSyncKHR'],
  'arguments': 'EGLDisplay dpy, EGLenum type, const EGLint* attrib_list',
  'other_extensions': ['EGL_KHR_fence_sync'] },
{ 'return_type': 'EGLint',
  'names': ['eglClientWaitSyncKHR'],
  'arguments': 'EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, '
      'EGLTimeKHR timeout',
  'other_extensions': ['EGL_KHR_fence_sync'] },
{ 'return_type': 'EGLBoolean',
  'names': ['eglGetSyncAttribKHR'],
  'arguments': 'EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, '
      'EGLint* value',
  'other_extensions': ['EGL_KHR_fence_sync'] },
{ 'return_type': 'EGLBoolean',
  'names': ['eglDestroySyncKHR'],
  'arguments': 'EGLDisplay dpy, EGLSyncKHR sync',
  'other_extensions': ['EGL_KHR_fence_sync'] },
{ 'return_type': 'EGLBoolean',
  'names': ['eglGetSyncValuesCHROMIUM'],
  'arguments':
      'EGLDisplay dpy, EGLSurface surface, '
      'EGLuint64CHROMIUM* ust, EGLuint64CHROMIUM* msc, '
      'EGLuint64CHROMIUM* sbc', },
{ 'return_type': 'EGLint',
  'names': ['eglWaitSyncKHR'],
  'arguments': 'EGLDisplay dpy, EGLSyncKHR sync, EGLint flags',
  'other_extensions': ['EGL_KHR_wait_sync'] },
]

WGL_FUNCTIONS = [
{ 'return_type': 'HGLRC',
  'names': ['wglCreateContext'],
  'arguments': 'HDC hdc', },
{ 'return_type': 'HGLRC',
  'names': ['wglCreateLayerContext'],
  'arguments': 'HDC hdc, int iLayerPlane', },
{ 'return_type': 'BOOL',
  'names': ['wglCopyContext'],
  'arguments': 'HGLRC hglrcSrc, HGLRC hglrcDst, UINT mask', },
{ 'return_type': 'BOOL',
  'names': ['wglDeleteContext'],
  'arguments': 'HGLRC hglrc', },
{ 'return_type': 'HGLRC',
  'names': ['wglGetCurrentContext'],
  'arguments': '', },
{ 'return_type': 'HDC',
  'names': ['wglGetCurrentDC'],
  'arguments': '', },
{ 'return_type': 'BOOL',
  'names': ['wglMakeCurrent'],
  'arguments': 'HDC hdc, HGLRC hglrc', },
{ 'return_type': 'BOOL',
  'names': ['wglShareLists'],
  'arguments': 'HGLRC hglrc1, HGLRC hglrc2', },
{ 'return_type': 'BOOL',
  'names': ['wglSwapIntervalEXT'],
  'arguments': 'int interval', },
{ 'return_type': 'BOOL',
  'names': ['wglSwapLayerBuffers'],
  'arguments': 'HDC hdc, UINT fuPlanes', },
{ 'return_type': 'const char*',
  'names': ['wglGetExtensionsStringARB'],
  'arguments': 'HDC hDC', },
{ 'return_type': 'const char*',
  'names': ['wglGetExtensionsStringEXT'],
  'arguments': '', },
{ 'return_type': 'BOOL',
  'names': ['wglChoosePixelFormatARB'],
  'arguments':
      'HDC dc, const int* int_attrib_list, const float* float_attrib_list, '
      'UINT max_formats, int* formats, UINT* num_formats', },
{ 'return_type': 'HPBUFFERARB',
  'names': ['wglCreatePbufferARB'],
  'arguments': 'HDC hDC, int iPixelFormat, int iWidth, int iHeight, '
               'const int* piAttribList', },
{ 'return_type': 'HDC',
  'names': ['wglGetPbufferDCARB'],
  'arguments': 'HPBUFFERARB hPbuffer', },
{ 'return_type': 'int',
  'names': ['wglReleasePbufferDCARB'],
  'arguments': 'HPBUFFERARB hPbuffer, HDC hDC', },
{ 'return_type': 'BOOL',
  'names': ['wglDestroyPbufferARB'],
  'arguments': 'HPBUFFERARB hPbuffer', },
{ 'return_type': 'BOOL',
  'names': ['wglQueryPbufferARB'],
  'arguments': 'HPBUFFERARB hPbuffer, int iAttribute, int* piValue', },
]

GLX_FUNCTIONS = [
{ 'return_type': 'int',
  'names': ['glXWaitVideoSyncSGI'],
  'arguments': 'int divisor, int remainder, unsigned int* count', },
{ 'return_type': 'XVisualInfo*',
  'names': ['glXChooseVisual'],
  'arguments': 'Display* dpy, int screen, int* attribList', },
{ 'return_type': 'void',
  'names': ['glXCopySubBufferMESA'],
  'arguments': 'Display* dpy, GLXDrawable drawable, '
               'int x, int y, int width, int height', },
{ 'return_type': 'GLXContext',
  'names': ['glXCreateContext'],
  'arguments':
      'Display* dpy, XVisualInfo* vis, GLXContext shareList, int direct', },
{ 'return_type': 'void',
  'names': ['glXBindTexImageEXT'],
  'arguments':
      'Display* dpy, GLXDrawable drawable, int buffer, int* attribList', },
{ 'return_type': 'void',
  'names': ['glXReleaseTexImageEXT'],
  'arguments': 'Display* dpy, GLXDrawable drawable, int buffer', },
{ 'return_type': 'void',
  'names': ['glXDestroyContext'],
  'arguments': 'Display* dpy, GLXContext ctx', },
{ 'return_type': 'int',
  'names': ['glXMakeCurrent'],
  'arguments': 'Display* dpy, GLXDrawable drawable, GLXContext ctx', },
{ 'return_type': 'void',
  'names': ['glXCopyContext'],
  'arguments':
      'Display* dpy, GLXContext src, GLXContext dst, unsigned long mask', },
{ 'return_type': 'void',
  'names': ['glXSwapBuffers'],
  'arguments': 'Display* dpy, GLXDrawable drawable', },
{ 'return_type': 'GLXPixmap',
  'names': ['glXCreateGLXPixmap'],
  'arguments': 'Display* dpy, XVisualInfo* visual, Pixmap pixmap', },
{ 'return_type': 'void',
  'names': ['glXDestroyGLXPixmap'],
  'arguments': 'Display* dpy, GLXPixmap pixmap', },
{ 'return_type': 'int',
  'names': ['glXQueryExtension'],
  'arguments': 'Display* dpy, int* errorb, int* event', },
{ 'return_type': 'int',
  'names': ['glXQueryVersion'],
  'arguments': 'Display* dpy, int* maj, int* min', },
{ 'return_type': 'int',
  'names': ['glXIsDirect'],
  'arguments': 'Display* dpy, GLXContext ctx', },
{ 'return_type': 'int',
  'names': ['glXGetConfig'],
  'arguments': 'Display* dpy, XVisualInfo* visual, int attrib, int* value', },
{ 'return_type': 'GLXContext',
  'names': ['glXGetCurrentContext'],
  'arguments': 'void', },
{ 'return_type': 'GLXDrawable',
  'names': ['glXGetCurrentDrawable'],
  'arguments': 'void', },
{ 'return_type': 'void',
  'names': ['glXWaitGL'],
  'arguments': 'void', },
{ 'return_type': 'void',
  'names': ['glXWaitX'],
  'arguments': 'void', },
{ 'return_type': 'void',
  'names': ['glXUseXFont'],
  'arguments': 'Font font, int first, int count, int list', },
{ 'return_type': 'const char*',
  'names': ['glXQueryExtensionsString'],
  'arguments': 'Display* dpy, int screen', },
{ 'return_type': 'const char*',
  'names': ['glXQueryServerString'],
  'arguments': 'Display* dpy, int screen, int name', },
{ 'return_type': 'const char*',
  'names': ['glXGetClientString'],
  'arguments': 'Display* dpy, int name', },
{ 'return_type': 'Display*',
  'names': ['glXGetCurrentDisplay'],
  'arguments': 'void', },
{ 'return_type': 'GLXFBConfig*',
  'names': ['glXChooseFBConfig'],
  'arguments':
      'Display* dpy, int screen, const int* attribList, int* nitems', },
{ 'return_type': 'int',
  'names': ['glXGetFBConfigAttrib'],
  'arguments': 'Display* dpy, GLXFBConfig config, int attribute, int* value', },
{ 'return_type': 'GLXFBConfig*',
  'names': ['glXGetFBConfigs'],
  'arguments': 'Display* dpy, int screen, int* nelements', },
{ 'return_type': 'XVisualInfo*',
  'names': ['glXGetVisualFromFBConfig'],
  'arguments': 'Display* dpy, GLXFBConfig config', },
{ 'return_type': 'GLXWindow',
  'names': ['glXCreateWindow'],
  'arguments':
      'Display* dpy, GLXFBConfig config, Window win, const int* attribList', },
{ 'return_type': 'void',
  'names': ['glXDestroyWindow'],
  'arguments': 'Display* dpy, GLXWindow window', },
{ 'return_type': 'GLXPixmap',
  'names': ['glXCreatePixmap'],
  'arguments': 'Display* dpy, GLXFBConfig config, '
               'Pixmap pixmap, const int* attribList', },
{ 'return_type': 'void',
  'names': ['glXDestroyPixmap'],
  'arguments': 'Display* dpy, GLXPixmap pixmap', },
{ 'return_type': 'GLXPbuffer',
  'names': ['glXCreatePbuffer'],
  'arguments': 'Display* dpy, GLXFBConfig config, const int* attribList', },
{ 'return_type': 'void',
  'names': ['glXDestroyPbuffer'],
  'arguments': 'Display* dpy, GLXPbuffer pbuf', },
{ 'return_type': 'void',
  'names': ['glXQueryDrawable'],
  'arguments':
      'Display* dpy, GLXDrawable draw, int attribute, unsigned int* value', },
{ 'return_type': 'GLXContext',
  'names': ['glXCreateNewContext'],
  'arguments': 'Display* dpy, GLXFBConfig config, int renderType, '
               'GLXContext shareList, int direct', },
{ 'return_type': 'int',
  'names': ['glXMakeContextCurrent'],
  'arguments':
      'Display* dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx', },
{ 'return_type': 'GLXDrawable',
  'names': ['glXGetCurrentReadDrawable'],
  'arguments': 'void', },
{ 'return_type': 'int',
  'names': ['glXQueryContext'],
  'arguments': 'Display* dpy, GLXContext ctx, int attribute, int* value', },
{ 'return_type': 'void',
  'names': ['glXSelectEvent'],
  'arguments': 'Display* dpy, GLXDrawable drawable, unsigned long mask', },
{ 'return_type': 'void',
  'names': ['glXGetSelectedEvent'],
  'arguments': 'Display* dpy, GLXDrawable drawable, unsigned long* mask', },
{ 'return_type': 'void',
  'names': ['glXSwapIntervalMESA'],
  'arguments': 'unsigned int interval', },
{ 'return_type': 'void',
  'names': ['glXSwapIntervalEXT'],
  'arguments': 'Display* dpy, GLXDrawable drawable, int interval', },
{ 'return_type': 'GLXFBConfig',
  'names': ['glXGetFBConfigFromVisualSGIX'],
  'arguments': 'Display* dpy, XVisualInfo* visualInfo', },
{ 'return_type': 'GLXContext',
  'names': ['glXCreateContextAttribsARB'],
  'arguments':
      'Display* dpy, GLXFBConfig config, GLXContext share_context, int direct, '
      'const int* attrib_list', },
{ 'return_type': 'bool',
  'names': ['glXGetSyncValuesOML'],
  'arguments':
      'Display* dpy, GLXDrawable drawable, int64* ust, int64* msc, '
      'int64* sbc' },
{ 'return_type': 'bool',
  'names': ['glXGetMscRateOML'],
  'arguments':
      'Display* dpy, GLXDrawable drawable, int32* numerator, '
      'int32* denominator' },
]

FUNCTION_SETS = [
  [GL_FUNCTIONS, 'gl', [
      'GL/glext.h',
      'GLES2/gl2ext.h',
      # Files below are Chromium-specific and shipped with Chromium sources.
      'GL/glextchromium.h',
      'GLES2/gl2chromium.h',
      'GLES2/gl2extchromium.h'
  ], []],
  [OSMESA_FUNCTIONS, 'osmesa', [], []],
  [EGL_FUNCTIONS, 'egl', [
      'EGL/eglext.h',
      # Files below are Chromium-specific and shipped with Chromium sources.
      'EGL/eglextchromium.h',
    ],
    [
      'EGL_ANGLE_d3d_share_handle_client_buffer',
      'EGL_ANGLE_surface_d3d_texture_2d_share_handle',
    ],
  ],
  [WGL_FUNCTIONS, 'wgl', ['GL/wglext.h'], []],
  [GLX_FUNCTIONS, 'glx', ['GL/glx.h', 'GL/glxext.h'], []],
]

def GenerateHeader(file, functions, set_name, used_extension_functions):
  """Generates gl_bindings_autogen_x.h"""

  # Write file header.
  file.write(
"""// 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.

// This file is automatically generated.

#ifndef UI_GFX_GL_GL_BINDINGS_AUTOGEN_%(name)s_H_
#define UI_GFX_GL_GL_BINDINGS_AUTOGEN_%(name)s_H_

namespace gfx {

class GLContext;

""" % {'name': set_name.upper()})

  # Write typedefs for function pointer types. Always use the GL name for the
  # typedef.
  file.write('\n')
  for func in functions:
    file.write('typedef %s (GL_BINDING_CALL *%sProc)(%s);\n' %
        (func['return_type'], func['names'][0], func['arguments']))

  # Write declarations for booleans indicating which extensions are available.
  file.write('\n')
  file.write("struct Extensions%s {\n" % set_name.upper())
  for extension, ext_functions in used_extension_functions:
    file.write('  bool b_%s;\n' % extension)
  file.write('};\n')
  file.write('\n')

  # Write Procs struct.
  file.write("struct Procs%s {\n" % set_name.upper())
  for func in functions:
    file.write('  %sProc %sFn;\n' % (func['names'][0], func['names'][0]))
  file.write('};\n')
  file.write('\n')

  # Write Api class.
  file.write(
"""class GL_EXPORT %(name)sApi {
 public:
  %(name)sApi();
  virtual ~%(name)sApi();

""" % {'name': set_name.upper()})
  for func in functions:
    file.write('  virtual %s %sFn(%s) = 0;\n' %
      (func['return_type'], func['names'][0], func['arguments']))
  file.write('};\n')
  file.write('\n')

  file.write( '}  // namespace gfx\n')

  # Write macros to invoke function pointers. Always use the GL name for the
  # macro.
  file.write('\n')
  for func in functions:
    file.write('#define %s ::gfx::g_current_%s_context->%sFn\n' %
        (func['names'][0], set_name.lower(), func['names'][0]))

  file.write('\n')
  file.write('#endif  //  UI_GFX_GL_GL_BINDINGS_AUTOGEN_%s_H_\n' %
      set_name.upper())


def GenerateAPIHeader(file, functions, set_name, used_extension_functions):
  """Generates gl_bindings_api_autogen_x.h"""

  # Write file header.
  file.write(
"""// 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.

// This file is automatically generated.

""" % {'name': set_name.upper()})

  # Write API declaration.
  for func in functions:
    file.write('  virtual %s %sFn(%s) OVERRIDE;\n' %
      (func['return_type'], func['names'][0], func['arguments']))

  file.write('\n')


def GenerateMockHeader(file, functions, set_name, used_extension_functions):
  """Generates gl_mock_autogen_x.h"""

  # Write file header.
  file.write(
"""// 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.

// This file is automatically generated.

""" % {'name': set_name.upper()})

  # Write API declaration.
  for func in functions:
    args = func['arguments']
    if args == 'void':
      args = ''
    arg_count = 0
    if len(args):
      arg_count = func['arguments'].count(',') + 1
    file.write('  MOCK_METHOD%d(%s, %s(%s));\n' %
      (arg_count, func['names'][0][2:], func['return_type'], args))

  file.write('\n')


def GenerateInterfaceHeader(
    file, functions, set_name, used_extension_functions):
  """Generates gl_interface_autogen_x.h"""

  # Write file header.
  file.write(
"""// 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.

// This file is automatically generated.

""" % {'name': set_name.upper()})

  # Write API declaration.
  for func in functions:
    args = func['arguments']
    if args == 'void':
      args = ''
    file.write('  virtual %s %s(%s) = 0;\n' %
      (func['return_type'], func['names'][0][2:], args))

  file.write('\n')


def GenerateSource(file, functions, set_name, used_extension_functions):
  """Generates gl_bindings_autogen_x.cc"""

  # Write file header.
  file.write(
"""// 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.

// This file is automatically generated.

#include <string>
#include "base/debug/trace_event.h"
#include "gpu/command_buffer/common/gles2_cmd_utils.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_%s_api_implementation.h"

using gpu::gles2::GLES2Util;

namespace gfx {
""" % set_name.lower())

  # Write definitions of function pointers.
  file.write('\n')
  file.write('static bool g_debugBindingsInitialized;\n')
  file.write('Driver%s g_driver_%s;\n' % (set_name.upper(), set_name.lower()))
  file.write('\n')

  # Write function to initialize the core function pointers. The code assumes
  # any non-NULL pointer returned by GetGLCoreProcAddress() is valid, although
  # it may be overwritten by an extension function pointer later.
  file.write('\n')
  file.write('void Driver%s::InitializeBindings() {\n' %
             set_name.upper())
  for func in functions:
    first_name = func['names'][0]
    for i, name in enumerate(func['names']):
      if i:
        file.write('  if (!fn.%sFn)\n  ' % first_name)
      file.write(
          '  fn.%sFn = reinterpret_cast<%sProc>('
          'GetGLCoreProcAddress("%s"));\n' %
          (first_name, first_name, name))
  file.write('}\n')
  file.write('\n')

  # Write function to initialize the extension function pointers. This function
  # uses a current context to query which extensions are actually supported.
  file.write("""void Driver%s::InitializeExtensionBindings(
    GLContext* context) {
""" % set_name.upper())
  file.write('  DCHECK(context && context->IsCurrent(NULL));\n')
  for extension, ext_functions in used_extension_functions:
    file.write('  ext.b_%s = context->HasExtension("%s");\n' %
        (extension, extension))
    file.write('  if (ext.b_%s) {\n' %
        (extension))
    queried_entry_points = set()
    for entry_point_name, function_name in ext_functions:
      # Replace the pointer unconditionally unless this extension has several
      # alternatives for the same entry point (e.g.,
      # GL_ARB_blend_func_extended).
      if entry_point_name in queried_entry_points:
        file.write('    if (!fn.%sFn)\n  ' % entry_point_name)
      file.write(
         '    fn.%sFn = reinterpret_cast<%sProc>(GetGLProcAddress("%s"));\n' %
             (entry_point_name, entry_point_name, function_name))
      queried_entry_points.add(entry_point_name)
    file.write('  }\n')
  file.write('  if (g_debugBindingsInitialized)\n')
  file.write('    UpdateDebugExtensionBindings();\n')
  file.write('}\n')
  file.write('\n')

  # Write logging wrappers for each function.
  file.write('extern "C" {\n')
  for func in functions:
    names = func['names']
    return_type = func['return_type']
    arguments = func['arguments']
    file.write('\n')
    file.write('static %s GL_BINDING_CALL Debug_%s(%s) {\n' %
        (return_type, names[0], arguments))
    argument_names = re.sub(
        r'(const )?[a-zA-Z0-9_]+\** ([a-zA-Z0-9_]+)', r'\2', arguments)
    argument_names = re.sub(
        r'(const )?[a-zA-Z0-9_]+\** ([a-zA-Z0-9_]+)', r'\2', argument_names)
    log_argument_names = re.sub(
        r'const char\* ([a-zA-Z0-9_]+)', r'CONSTCHAR_\1', arguments)
    log_argument_names = re.sub(
        r'(const )?[a-zA-Z0-9_]+\* ([a-zA-Z0-9_]+)',
        r'CONSTVOID_\2', log_argument_names)
    log_argument_names = re.sub(
        r'(?<!E)GLenum ([a-zA-Z0-9_]+)', r'GLenum_\1', log_argument_names)
    log_argument_names = re.sub(
        r'(?<!E)GLboolean ([a-zA-Z0-9_]+)', r'GLboolean_\1', log_argument_names)
    log_argument_names = re.sub(
        r'(const )?[a-zA-Z0-9_]+\** ([a-zA-Z0-9_]+)', r'\2',
        log_argument_names)
    log_argument_names = re.sub(
        r'(const )?[a-zA-Z0-9_]+\** ([a-zA-Z0-9_]+)', r'\2',
        log_argument_names)
    log_argument_names = re.sub(
        r'CONSTVOID_([a-zA-Z0-9_]+)',
        r'static_cast<const void*>(\1)', log_argument_names);
    log_argument_names = re.sub(
        r'CONSTCHAR_([a-zA-Z0-9_]+)', r'\1', log_argument_names);
    log_argument_names = re.sub(
        r'GLenum_([a-zA-Z0-9_]+)', r'GLES2Util::GetStringEnum(\1)',
        log_argument_names)
    log_argument_names = re.sub(
        r'GLboolean_([a-zA-Z0-9_]+)', r'GLES2Util::GetStringBool(\1)',
        log_argument_names)
    log_argument_names = log_argument_names.replace(',', ' << ", " <<')
    if argument_names == 'void' or argument_names == '':
      argument_names = ''
      log_argument_names = ''
    else:
      log_argument_names = " << " + log_argument_names
    function_name = names[0]
    if return_type == 'void':
      file.write('  GL_SERVICE_LOG("%s" << "(" %s << ")");\n' %
          (function_name, log_argument_names))
      file.write('  g_driver_%s.debug_fn.%sFn(%s);\n' %
          (set_name.lower(), function_name, argument_names))
      if 'logging_code' in func:
        file.write("%s\n" % func['logging_code'])
    else:
      file.write('  GL_SERVICE_LOG("%s" << "(" %s << ")");\n' %
          (function_name, log_argument_names))
      file.write('  %s result = g_driver_%s.debug_fn.%sFn(%s);\n' %
          (return_type, set_name.lower(), function_name, argument_names))
      if 'logging_code' in func:
        file.write("%s\n" % func['logging_code'])
      else:
        file.write('  GL_SERVICE_LOG("GL_RESULT: " << result);\n');
      file.write('  return result;\n')
    file.write('}\n')
  file.write('}  // extern "C"\n')

  # Write function to initialize the debug function pointers.
  file.write('\n')
  file.write('void Driver%s::InitializeDebugBindings() {\n' %
             set_name.upper())
  for func in functions:
    first_name = func['names'][0]
    file.write('  if (!debug_fn.%sFn) {\n' % first_name)
    file.write('    debug_fn.%sFn = fn.%sFn;\n' % (first_name, first_name))
    file.write('    fn.%sFn = Debug_%s;\n' % (first_name, first_name))
    file.write('  }\n')
  file.write('  g_debugBindingsInitialized = true;\n')
  file.write('}\n')

  # Write function to update the debug function pointers to extension functions
  # after the extensions have been initialized.
  file.write('\n')
  file.write('void Driver%s::UpdateDebugExtensionBindings() {\n' %
             set_name.upper())
  for extension, ext_functions in used_extension_functions:
    for name, _ in ext_functions:
      file.write('  if (debug_fn.%sFn != fn.%sFn &&\n' % (name, name))
      file.write('      fn.%sFn != Debug_%s) {\n' % (name, name))
      file.write('    debug_fn.%sFn = fn.%sFn;\n' % (name, name))
      file.write('    fn.%sFn = Debug_%s;\n' % (name, name))
      file.write('  }\n')
  file.write('}\n')

  # Write function to clear all function pointers.
  file.write('\n')
  file.write("""void Driver%s::ClearBindings() {
  memset(this, 0, sizeof(*this));
}
""" % set_name.upper())

  # Write GLApiBase functions
  for func in functions:
    names = func['names']
    return_type = func['return_type']
    arguments = func['arguments']
    file.write('\n')
    file.write('%s %sApiBase::%sFn(%s) {\n' %
        (return_type, set_name.upper(), names[0], arguments))
    argument_names = re.sub(
        r'(const )?[a-zA-Z0-9_]+\** ([a-zA-Z0-9_]+)', r'\2', arguments)
    argument_names = re.sub(
        r'(const )?[a-zA-Z0-9_]+\** ([a-zA-Z0-9_]+)', r'\2', argument_names)
    if argument_names == 'void' or argument_names == '':
      argument_names = ''
    function_name = names[0]
    if return_type == 'void':
      file.write('  driver_->fn.%sFn(%s);\n' %
          (function_name, argument_names))
    else:
      file.write('  return driver_->fn.%sFn(%s);\n' %
          (function_name, argument_names))
    file.write('}\n')

  # Write TraceGLApi functions
  for func in functions:
    names = func['names']
    return_type = func['return_type']
    arguments = func['arguments']
    file.write('\n')
    file.write('%s Trace%sApi::%sFn(%s) {\n' %
        (return_type, set_name.upper(), names[0], arguments))
    argument_names = re.sub(
        r'(const )?[a-zA-Z0-9_]+\** ([a-zA-Z0-9_]+)', r'\2', arguments)
    argument_names = re.sub(
        r'(const )?[a-zA-Z0-9_]+\** ([a-zA-Z0-9_]+)', r'\2', argument_names)
    if argument_names == 'void' or argument_names == '':
      argument_names = ''
    function_name = names[0]
    file.write('  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::%s")\n' %
               function_name)
    if return_type == 'void':
      file.write('  %s_api_->%sFn(%s);\n' %
          (set_name.lower(), function_name, argument_names))
    else:
      file.write('  return %s_api_->%sFn(%s);\n' %
          (set_name.lower(), function_name, argument_names))
    file.write('}\n')

  file.write('\n')
  file.write('}  // namespace gfx\n')


def GenerateMockSource(file, functions):
  """Generates functions that invoke a mock GLInterface"""

  file.write(
"""// 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.

// This file is automatically generated.

#include <string.h>

#include "ui/gl/gl_interface.h"

namespace gfx {
""")
  # Write function that trampoline into the GLInterface.
  for func in functions:
    file.write('\n')
    file.write('%s GL_BINDING_CALL Mock_%s(%s) {\n' %
        (func['return_type'], func['names'][0], func['arguments']))
    argument_names = re.sub(r'(const )?[a-zA-Z0-9]+((\s*const\s*)?\*)* ([a-zA-Z0-9]+)', r'\4',
                              func['arguments'])
    if argument_names == 'void':
      argument_names = ''
    function_name = func['names'][0][2:]
    if func['return_type'] == 'void':
      file.write('  GLInterface::GetGLInterface()->%s(%s);\n' %
          (function_name, argument_names))
    else:
      file.write('  return GLInterface::GetGLInterface()->%s(%s);\n' %
          (function_name, argument_names))
    file.write('}\n')

  # Write an 'invalid' function to catch code calling through uninitialized
  # function pointers or trying to interpret the return value of
  # GLProcAddress().
  file.write('\n')
  file.write('static void MockInvalidFunction() {\n')
  file.write('  NOTREACHED();\n')
  file.write('}\n')

  # Write a function to lookup a mock GL function based on its name.
  file.write('\n')
  file.write('void* GL_BINDING_CALL GetMockGLProcAddress(const char* name) {\n')
  for func in functions:
    first_name = func['names'][0]
    file.write('  if (strcmp(name, "%s") == 0)\n' % first_name)
    file.write('    return reinterpret_cast<void*>(Mock_%s);\n' % first_name)
  # Always return a non-NULL pointer like some EGL implementations do.
  file.write('  return reinterpret_cast<void*>(&MockInvalidFunction);\n')
  file.write('}\n');

  file.write('\n')
  file.write('}  // namespace gfx\n')


def ParseExtensionFunctionsFromHeader(header_file):
  """Parse a C extension header file and return a map from extension names to
  a list of functions.

  Args:
    header_file: Line-iterable C header file.
  Returns:
    Map of extension name => functions.
  """
  extension_start = re.compile(
      r'#ifndef ((?:GL|EGL|WGL|GLX)_[A-Z]+_[a-zA-Z]\w+)')
  extension_function = re.compile(r'.+\s+([a-z]+\w+)\s*\(')
  typedef = re.compile(r'typedef .*')
  macro_start = re.compile(r'^#(if|ifdef|ifndef).*')
  macro_end = re.compile(r'^#endif.*')
  macro_depth = 0
  current_extension = None
  current_extension_depth = 0
  extensions = collections.defaultdict(lambda: [])
  for line in header_file:
    if macro_start.match(line):
      macro_depth += 1
    elif macro_end.match(line):
      macro_depth -= 1
      if macro_depth < current_extension_depth:
        current_extension = None
    match = extension_start.match(line)
    if match:
      current_extension = match.group(1)
      current_extension_depth = macro_depth
      assert current_extension not in extensions, \
          "Duplicate extension: " + current_extension
    match = extension_function.match(line)
    if match and current_extension and not typedef.match(line):
      extensions[current_extension].append(match.group(1))
  return extensions


def GetExtensionFunctions(extension_headers):
  """Parse extension functions from a list of header files.

  Args:
    extension_headers: List of header file names.
  Returns:
    Map of extension name => list of functions.
  """
  extensions = {}
  for header in extension_headers:
    extensions.update(ParseExtensionFunctionsFromHeader(open(header)))
  return extensions


def GetFunctionToExtensionMap(extensions):
  """Construct map from a function names to extensions which define the
  function.

  Args:
    extensions: Map of extension name => functions.
  Returns:
    Map of function name => extension name.
  """
  function_to_extensions = {}
  for extension, functions in extensions.items():
    for function in functions:
      if not function in function_to_extensions:
        function_to_extensions[function] = []
      function_to_extensions[function].append(extension)
  return function_to_extensions


def LooksLikeExtensionFunction(function):
  """Heuristic to see if a function name is consistent with extension function
  naming."""
  vendor = re.match(r'\w+?([A-Z][A-Z]+)$', function)
  return vendor is not None and not vendor.group(1) in ['GL', 'API', 'DC']


def GetUsedExtensionFunctions(functions, extension_headers, extra_extensions):
  """Determine which functions belong to extensions.

  Args:
    functions: List of (return type, function names, arguments).
    extension_headers: List of header file names.
  Returns:
    List of (extension name, [function name alternatives]) sorted with least
    preferred extensions first.
  """
  # Parse known extensions.
  extensions = GetExtensionFunctions(extension_headers)
  functions_to_extensions = GetFunctionToExtensionMap(extensions)

  # Collect all used extension functions.
  used_extension_functions = collections.defaultdict(lambda: [])
  for func in functions:
    for name in func['names']:
      # Make sure we know about all extension functions.
      if (LooksLikeExtensionFunction(name) and
          not name in functions_to_extensions):
        raise RuntimeError('%s looks like an extension function but does not '
            'belong to any of the known extensions.' % name)
      if name in functions_to_extensions:
        extensions = functions_to_extensions[name][:]
        if 'other_extensions' in func:
          extensions.extend(func['other_extensions'])
        for extension in extensions:
          used_extension_functions[extension].append((func['names'][0], name))

  # Add extensions that do not have any functions.
  used_extension_functions.update(dict(
      [(e, []) for e in extra_extensions if e not in used_extension_functions]))

  def ExtensionSortKey(name):
    # Prefer ratified extensions and EXTs.
    preferences = ['_ARB_', '_OES_', '_EXT_', '']
    for i, category in enumerate(preferences):
      if category in name:
        return -i
  used_extension_functions = sorted(used_extension_functions.items(),
      key = lambda item: ExtensionSortKey(item[0]))
  return used_extension_functions


def ResolveHeader(header, header_paths):
  paths = header_paths.split(':')

  # Always use a path for Chromium-specific extensions. They are extracted
  # to separate files.
  paths.append('.')
  paths.append('../../gpu')

  root = os.path.abspath(os.path.dirname(__file__))

  for path in paths:
    result = os.path.join(path, header)
    if not os.path.isabs(path):
      result = os.path.relpath(os.path.join(root, result), os.getcwd())
    if os.path.exists(result):
      # Always use forward slashes as path separators. Otherwise backslashes
      # may be incorrectly interpreted as escape characters.
      return result.replace(os.path.sep, '/')

  raise Exception('Header %s not found.' % header)


def main(argv):
  """This is the main function."""

  parser = optparse.OptionParser()
  parser.add_option('--inputs', action='store_true')
  parser.add_option('--header-paths')

  options, args = parser.parse_args(argv)

  if options.inputs:
    for [_, _, headers, _] in FUNCTION_SETS:
      for header in headers:
        print ResolveHeader(header, options.header_paths)
    return 0

  if len(args) >= 1:
    dir = args[0]
  else:
    dir = '.'

  for [functions, set_name, extension_headers, extensions] in FUNCTION_SETS:
    extension_headers = [ResolveHeader(h, options.header_paths)
                         for h in extension_headers]
    used_extension_functions = GetUsedExtensionFunctions(
        functions, extension_headers, extensions)

    header_file = open(
        os.path.join(dir, 'gl_bindings_autogen_%s.h' % set_name), 'wb')
    GenerateHeader(header_file, functions, set_name, used_extension_functions)
    header_file.close()

    header_file = open(
        os.path.join(dir, 'gl_bindings_api_autogen_%s.h' % set_name), 'wb')
    GenerateAPIHeader(
        header_file, functions, set_name, used_extension_functions)
    header_file.close()

    source_file = open(
        os.path.join(dir, 'gl_bindings_autogen_%s.cc' % set_name), 'wb')
    GenerateSource(source_file, functions, set_name, used_extension_functions)
    source_file.close()

    header_file = open(
        os.path.join(dir, 'gl_interface_autogen_%s.h' % set_name), 'wb')
    GenerateInterfaceHeader(
        header_file, functions, set_name, used_extension_functions)
    header_file.close()

    header_file = open(
        os.path.join(dir, 'gl_mock_autogen_%s.h' % set_name), 'wb')
    GenerateMockHeader(
        header_file, functions, set_name, used_extension_functions)
    header_file.close()

  source_file = open(os.path.join(dir, 'gl_bindings_autogen_mock.cc'), 'wb')
  GenerateMockSource(source_file, GL_FUNCTIONS)
  source_file.close()
  return 0


if __name__ == '__main__':
  sys.exit(main(sys.argv[1:]))