| Index: ui/gl/generate_bindings.py
|
| diff --git a/ui/gl/generate_bindings.py b/ui/gl/generate_bindings.py
|
| index 98c75028bb515f4da108c0d18b603c0e7d85dfcc..c93e3548651ca7b16e828fe2c81c8eafa61dffce 100755
|
| --- a/ui/gl/generate_bindings.py
|
| +++ b/ui/gl/generate_bindings.py
|
| @@ -11,6 +11,28 @@ import collections
|
| import re
|
| import sys
|
|
|
| +"""In case there are multiple versions of the same function, one that's listed
|
| +first takes priority if its conditions are met. If the function is an extension
|
| +function, finding the extension from the extension string is a condition for
|
| +binding it. The last version of the function is treated as a fallback option in
|
| +case no other versions were bound, so a non-null function pointer in the
|
| +bindings does not guarantee that the function is supported.
|
| +
|
| +Function binding conditions can be specified manually by supplying a versions
|
| +array instead of the names array. Each version has the following keys:
|
| + name: Mandatory. Name of the function. Multiple versions can have the same
|
| + name but different conditions.
|
| + gl_versions: List of GL versions where the function is found.
|
| + extension/extensions: Extensions where the function is found. If not
|
| + specified, the extensions are determined based on GL
|
| + header files.
|
| + If the function exists in an extension header, you
|
| + may specify an empty array to prevent making that a
|
| + condition for binding.
|
| +
|
| +By default, the function gets its name from the first name in its names or
|
| +versions array. This can be overridden by supplying a 'known_as' key.
|
| +"""
|
| GL_FUNCTIONS = [
|
| { 'return_type': 'void',
|
| 'names': ['glActiveTexture'],
|
| @@ -313,11 +335,13 @@ GL_FUNCTIONS = [
|
| 'names': ['glGetIntegerv'],
|
| 'arguments': 'GLenum pname, GLint* params', },
|
| { 'return_type': 'void',
|
| - 'names': ['glGetProgramBinary', 'glGetProgramBinaryOES'],
|
| + 'known_as': 'glGetProgramBinary',
|
| + 'versions': [{ 'name': 'glGetProgramBinaryOES' },
|
| + { 'name': 'glGetProgramBinary',
|
| + 'extension': 'GL_ARB_get_program_binary' },
|
| + { 'name': 'glGetProgramBinary' }],
|
| 'arguments': 'GLuint program, GLsizei bufSize, GLsizei* length, '
|
| - 'GLenum* binaryFormat, GLvoid* binary',
|
| - 'other_extensions': ['ARB_get_program_binary',
|
| - 'OES_get_program_binary'] },
|
| + 'GLenum* binaryFormat, GLvoid* binary' },
|
| { 'return_type': 'void',
|
| 'names': ['glGetProgramiv'],
|
| 'arguments': 'GLuint program, GLenum pname, GLint* params', },
|
| @@ -435,7 +459,8 @@ GL_FUNCTIONS = [
|
| 'names': ['glLinkProgram'],
|
| 'arguments': 'GLuint program', },
|
| { 'return_type': 'void*',
|
| - 'names': ['glMapBuffer', 'glMapBufferOES'],
|
| + 'known_as': 'glMapBuffer',
|
| + 'names': ['glMapBufferOES', 'glMapBuffer'],
|
| 'arguments': 'GLenum target, GLenum access', },
|
| { 'return_type': 'void*',
|
| 'names': ['glMapBufferRange'],
|
| @@ -454,15 +479,18 @@ GL_FUNCTIONS = [
|
| 'names': ['glPolygonOffset'],
|
| 'arguments': 'GLfloat factor, GLfloat units', },
|
| { 'return_type': 'void',
|
| - 'names': ['glProgramBinary', 'glProgramBinaryOES'],
|
| + 'known_as': 'glProgramBinary',
|
| + 'versions': [{ 'name': 'glProgramBinaryOES' },
|
| + { 'name': 'glProgramBinary',
|
| + 'extension': 'GL_ARB_get_program_binary' },
|
| + { 'name': 'glProgramBinary' }],
|
| 'arguments': 'GLuint program, GLenum binaryFormat, '
|
| - 'const GLvoid* binary, GLsizei length',
|
| - 'other_extensions': ['ARB_get_program_binary',
|
| - 'OES_get_program_binary'] },
|
| + 'const GLvoid* binary, GLsizei length' },
|
| { 'return_type': 'void',
|
| - 'names': ['glProgramParameteri'],
|
| - 'arguments': 'GLuint program, GLenum pname, GLint value',
|
| - 'other_extensions': ['ARB_get_program_binary'] },
|
| + 'versions': [{ 'name': 'glProgramParameteri',
|
| + 'extension': 'GL_ARB_get_program_binary' },
|
| + { 'name': 'glProgramParameteri' }],
|
| + 'arguments': 'GLuint program, GLenum pname, GLint value' },
|
| { 'return_type': 'void',
|
| 'names': ['glQueryCounter'],
|
| 'arguments': 'GLuint id, GLenum target', },
|
| @@ -477,10 +505,27 @@ GL_FUNCTIONS = [
|
| { 'return_type': 'void',
|
| 'names': ['glReleaseShaderCompiler'],
|
| 'arguments': 'void', },
|
| +# Multisampling API is different in different GL versions, some require an
|
| +# explicit resolve step for renderbuffers and/or FBO texture attachments and
|
| +# some do not. Multiple alternatives might be present in a single
|
| +# implementation, which require different use of the API and may have
|
| +# different performance (explicit resolve performing worse, for example).
|
| +# So even though the function signature is the same across versions, we split
|
| +# their definitions so that the function to use can be chosen correctly at a
|
| +# higher level.
|
| +# TODO(oetuaho@nvidia.com): Some of these might still be possible to combine.
|
| +# This could also fix weirdness in the mock bindings that's caused by the same
|
| +# function name appearing multiple times.
|
| +# This is the ES3 function, which requires explicit resolve:
|
| { 'return_type': 'void',
|
| 'names': ['glRenderbufferStorageMultisample'],
|
| 'arguments': 'GLenum target, GLsizei samples, GLenum internalformat, '
|
| 'GLsizei width, GLsizei height', },
|
| +# In desktop GL, EXT and core versions both have an explicit resolve step,
|
| +# though desktop core GL implicitly resolves when drawing to a window.
|
| +# TODO(oetuaho@nvidia.com): Right now this function also doubles as ES2 EXT
|
| +# function, which has implicit resolve, and for which the fallback is wrong.
|
| +# Fix this.
|
| { 'return_type': 'void',
|
| 'names': ['glRenderbufferStorageMultisampleEXT',
|
| 'glRenderbufferStorageMultisample'],
|
| @@ -511,8 +556,8 @@ GL_FUNCTIONS = [
|
| 'const void* binary, GLsizei length', },
|
| { 'return_type': 'void',
|
| 'names': ['glShaderSource'],
|
| - 'arguments':
|
| - 'GLuint shader, GLsizei count, const char* const* str, const GLint* length',
|
| + '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) {
|
| @@ -636,7 +681,8 @@ GL_FUNCTIONS = [
|
| 'arguments': 'GLint location, GLsizei count, '
|
| 'GLboolean transpose, const GLfloat* value', },
|
| { 'return_type': 'GLboolean',
|
| - 'names': ['glUnmapBuffer', 'glUnmapBufferOES'],
|
| + 'known_as': 'glUnmapBuffer',
|
| + 'names': ['glUnmapBufferOES', 'glUnmapBuffer'],
|
| 'arguments': 'GLenum target', },
|
| { 'return_type': 'void',
|
| 'names': ['glUseProgram'],
|
| @@ -712,51 +758,67 @@ GL_FUNCTIONS = [
|
| 'arguments':
|
| 'GLsync sync, GLbitfield flags, GLuint64 timeout', },
|
| { 'return_type': 'void',
|
| - 'names': ['glDrawArraysInstancedANGLE', 'glDrawArraysInstancedARB'],
|
| + 'known_as': 'glDrawArraysInstancedANGLE',
|
| + 'names': ['glDrawArraysInstancedARB', 'glDrawArraysInstancedANGLE'],
|
| 'arguments': 'GLenum mode, GLint first, GLsizei count, GLsizei primcount', },
|
| { 'return_type': 'void',
|
| - 'names': ['glDrawElementsInstancedANGLE', 'glDrawElementsInstancedARB'],
|
| + 'known_as': 'glDrawElementsInstancedANGLE',
|
| + 'names': ['glDrawElementsInstancedARB', 'glDrawElementsInstancedANGLE'],
|
| 'arguments':
|
| 'GLenum mode, GLsizei count, GLenum type, const void* indices, '
|
| 'GLsizei primcount', },
|
| { 'return_type': 'void',
|
| - 'names': ['glVertexAttribDivisorANGLE', 'glVertexAttribDivisorARB'],
|
| + 'known_as': 'glVertexAttribDivisorANGLE',
|
| + 'names': ['glVertexAttribDivisorARB', 'glVertexAttribDivisorANGLE'],
|
| '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'] },
|
| + 'known_as': 'glGenVertexArraysOES',
|
| + 'versions': [{ 'name': 'glGenVertexArrays',
|
| + 'gl_versions': ['gl3', 'gl4'] },
|
| + { 'name': 'glGenVertexArrays',
|
| + 'extension': 'GL_ARB_vertex_array_object' },
|
| + { 'name': 'glGenVertexArraysOES' },
|
| + { 'name': 'glGenVertexArraysAPPLE',
|
| + 'extension': 'GL_APPLE_vertex_array_object' }],
|
| + 'arguments': 'GLsizei n, GLuint* arrays', },
|
| +{ 'return_type': 'void',
|
| + 'known_as': 'glDeleteVertexArraysOES',
|
| + 'versions': [{ 'name': 'glDeleteVertexArrays',
|
| + 'gl_versions': ['gl3', 'gl4'] },
|
| + { 'name': 'glDeleteVertexArrays',
|
| + 'extension': 'GL_ARB_vertex_array_object' },
|
| + { 'name': 'glDeleteVertexArraysOES' },
|
| + { 'name': 'glDeleteVertexArraysAPPLE',
|
| + 'extension': 'GL_APPLE_vertex_array_object' }],
|
| + 'arguments': 'GLsizei n, const GLuint* arrays' },
|
| +{ 'return_type': 'void',
|
| + 'known_as': 'glBindVertexArrayOES',
|
| + 'versions': [{ 'name': 'glBindVertexArray',
|
| + 'gl_versions': ['gl3', 'gl4'] },
|
| + { 'name': 'glBindVertexArray',
|
| + 'extension': 'GL_ARB_vertex_array_object' },
|
| + { 'name': 'glBindVertexArrayOES' },
|
| + { 'name': 'glBindVertexArrayAPPLE',
|
| + 'extension': 'GL_APPLE_vertex_array_object' }],
|
| + 'arguments': 'GLuint array' },
|
| { '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'],
|
| + 'known_as': 'glIsVertexArrayOES',
|
| + 'versions': [{ 'name': 'glIsVertexArray',
|
| + 'gl_versions': ['gl3', 'gl4'] },
|
| + { 'name': 'glIsVertexArray',
|
| + 'extension': 'GL_ARB_vertex_array_object' },
|
| + { 'name': 'glIsVertexArrayOES' },
|
| + { 'name': 'glIsVertexArrayAPPLE',
|
| + 'extension': 'GL_APPLE_vertex_array_object' }],
|
| + 'arguments': 'GLuint array' },
|
| +{ 'return_type': 'void',
|
| + 'known_as': 'glDiscardFramebufferEXT',
|
| + 'versions': [{ 'name': 'glInvalidateFramebuffer',
|
| + 'gl_versions': ['es3'],
|
| + 'extensions': [] },
|
| + { 'name': 'glDiscardFramebufferEXT',
|
| + 'gl_versions': ['es1', 'es2'] }],
|
| 'arguments': 'GLenum target, GLsizei numAttachments, '
|
| 'const GLenum* attachments' },
|
| ]
|
| @@ -832,15 +894,15 @@ EGL_FUNCTIONS = [
|
| 'arguments':
|
| 'EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint* value', },
|
| { 'return_type': 'EGLImageKHR',
|
| - 'names': ['eglCreateImageKHR'],
|
| + 'versions': [{ 'name': 'eglCreateImageKHR',
|
| + 'extension': 'EGL_KHR_image_base' }],
|
| 'arguments':
|
| 'EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, '
|
| - 'const EGLint* attrib_list',
|
| - 'other_extensions': ['EGL_KHR_image_base'] },
|
| + 'const EGLint* attrib_list' },
|
| { 'return_type': 'EGLBoolean',
|
| - 'names': ['eglDestroyImageKHR'],
|
| - 'arguments': 'EGLDisplay dpy, EGLImageKHR image',
|
| - 'other_extensions': ['EGL_KHR_image_base'] },
|
| + 'versions': [{ 'name' : 'eglDestroyImageKHR',
|
| + 'extension': 'EGL_KHR_image_base' }],
|
| + 'arguments': 'EGLDisplay dpy, EGLImageKHR image' },
|
| { 'return_type': 'EGLSurface',
|
| 'names': ['eglCreateWindowSurface'],
|
| 'arguments': 'EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, '
|
| @@ -938,23 +1000,23 @@ EGL_FUNCTIONS = [
|
| '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'] },
|
| + 'versions': [{ 'name': 'eglCreateSyncKHR',
|
| + 'extension': 'EGL_KHR_fence_sync' }],
|
| + 'arguments': 'EGLDisplay dpy, EGLenum type, const EGLint* attrib_list' },
|
| { 'return_type': 'EGLint',
|
| - 'names': ['eglClientWaitSyncKHR'],
|
| + 'versions': [{ 'name': 'eglClientWaitSyncKHR',
|
| + 'extension': 'EGL_KHR_fence_sync' }],
|
| 'arguments': 'EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, '
|
| - 'EGLTimeKHR timeout',
|
| - 'other_extensions': ['EGL_KHR_fence_sync'] },
|
| + 'EGLTimeKHR timeout' },
|
| { 'return_type': 'EGLBoolean',
|
| - 'names': ['eglGetSyncAttribKHR'],
|
| + 'versions': [{ 'name': 'eglGetSyncAttribKHR',
|
| + 'extension': 'EGL_KHR_fence_sync' }],
|
| 'arguments': 'EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, '
|
| - 'EGLint* value',
|
| - 'other_extensions': ['EGL_KHR_fence_sync'] },
|
| + 'EGLint* value' },
|
| { 'return_type': 'EGLBoolean',
|
| - 'names': ['eglDestroySyncKHR'],
|
| - 'arguments': 'EGLDisplay dpy, EGLSyncKHR sync',
|
| - 'other_extensions': ['EGL_KHR_fence_sync'] },
|
| + 'versions': [{ 'name': 'eglDestroySyncKHR',
|
| + 'extension': 'EGL_KHR_fence_sync' }],
|
| + 'arguments': 'EGLDisplay dpy, EGLSyncKHR sync' },
|
| { 'return_type': 'EGLBoolean',
|
| 'names': ['eglGetSyncValuesCHROMIUM'],
|
| 'arguments':
|
| @@ -962,9 +1024,9 @@ EGL_FUNCTIONS = [
|
| 'EGLuint64CHROMIUM* ust, EGLuint64CHROMIUM* msc, '
|
| 'EGLuint64CHROMIUM* sbc', },
|
| { 'return_type': 'EGLint',
|
| - 'names': ['eglWaitSyncKHR'],
|
| - 'arguments': 'EGLDisplay dpy, EGLSyncKHR sync, EGLint flags',
|
| - 'other_extensions': ['EGL_KHR_wait_sync'] },
|
| + 'versions': [{ 'name': 'eglWaitSyncKHR',
|
| + 'extension': 'EGL_KHR_fence_sync' }],
|
| + 'arguments': 'EGLDisplay dpy, EGLSyncKHR sync, EGLint flags' }
|
| ]
|
|
|
| WGL_FUNCTIONS = [
|
| @@ -1214,7 +1276,7 @@ FUNCTION_SETS = [
|
| [GLX_FUNCTIONS, 'glx', ['GL/glx.h', 'GL/glxext.h'], []],
|
| ]
|
|
|
| -def GenerateHeader(file, functions, set_name, used_extension_functions):
|
| +def GenerateHeader(file, functions, set_name, used_extensions):
|
| """Generates gl_bindings_autogen_x.h"""
|
|
|
| # Write file header.
|
| @@ -1239,12 +1301,12 @@ class GLContext;
|
| 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']))
|
| + (func['return_type'], func['known_as'], 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:
|
| + for extension in used_extensions:
|
| file.write(' bool b_%s;\n' % extension)
|
| file.write('};\n')
|
| file.write('\n')
|
| @@ -1252,7 +1314,7 @@ class GLContext;
|
| # 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(' %sProc %sFn;\n' % (func['known_as'], func['known_as']))
|
| file.write('};\n')
|
| file.write('\n')
|
|
|
| @@ -1266,7 +1328,7 @@ class GLContext;
|
| """ % {'name': set_name.upper()})
|
| for func in functions:
|
| file.write(' virtual %s %sFn(%s) = 0;\n' %
|
| - (func['return_type'], func['names'][0], func['arguments']))
|
| + (func['return_type'], func['known_as'], func['arguments']))
|
| file.write('};\n')
|
| file.write('\n')
|
|
|
| @@ -1277,14 +1339,14 @@ class GLContext;
|
| 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]))
|
| + (func['known_as'], set_name.lower(), func['known_as']))
|
|
|
| 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):
|
| +def GenerateAPIHeader(file, functions, set_name):
|
| """Generates gl_bindings_api_autogen_x.h"""
|
|
|
| # Write file header.
|
| @@ -1300,12 +1362,12 @@ def GenerateAPIHeader(file, functions, set_name, used_extension_functions):
|
| # Write API declaration.
|
| for func in functions:
|
| file.write(' virtual %s %sFn(%s) OVERRIDE;\n' %
|
| - (func['return_type'], func['names'][0], func['arguments']))
|
| + (func['return_type'], func['known_as'], func['arguments']))
|
|
|
| file.write('\n')
|
|
|
|
|
| -def GenerateMockHeader(file, functions, set_name, used_extension_functions):
|
| +def GenerateMockHeader(file, functions, set_name):
|
| """Generates gl_mock_autogen_x.h"""
|
|
|
| # Write file header.
|
| @@ -1327,13 +1389,12 @@ def GenerateMockHeader(file, functions, set_name, used_extension_functions):
|
| 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))
|
| + (arg_count, func['known_as'][2:], func['return_type'], args))
|
|
|
| file.write('\n')
|
|
|
|
|
| -def GenerateInterfaceHeader(
|
| - file, functions, set_name, used_extension_functions):
|
| +def GenerateInterfaceHeader(file, functions, set_name):
|
| """Generates gl_interface_autogen_x.h"""
|
|
|
| # Write file header.
|
| @@ -1352,12 +1413,12 @@ def GenerateInterfaceHeader(
|
| if args == 'void':
|
| args = ''
|
| file.write(' virtual %s %s(%s) = 0;\n' %
|
| - (func['return_type'], func['names'][0][2:], args))
|
| + (func['return_type'], func['known_as'][2:], args))
|
|
|
| file.write('\n')
|
|
|
|
|
| -def GenerateSource(file, functions, set_name, used_extension_functions):
|
| +def GenerateSource(file, functions, set_name, used_extensions):
|
| """Generates gl_bindings_autogen_x.cc"""
|
|
|
| # Write file header.
|
| @@ -1374,6 +1435,7 @@ def GenerateSource(file, functions, set_name, used_extension_functions):
|
| #include "ui/gl/gl_bindings.h"
|
| #include "ui/gl/gl_context.h"
|
| #include "ui/gl/gl_implementation.h"
|
| +#include "ui/gl/gl_version_info.h"
|
| #include "ui/gl/gl_%s_api_implementation.h"
|
|
|
| using gpu::gles2::GLES2Util;
|
| @@ -1381,67 +1443,146 @@ 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.
|
| + # Write stub functions that take the place of some functions before a context
|
| + # is initialized. This is done to provide clear asserts on debug build and to
|
| + # avoid crashing in case of a bug on release build.
|
| + file.write('\n')
|
| + for func in functions:
|
| + if len(func['names']) > 1:
|
| + file.write('%s %sNotBound(%s) {\n' %
|
| + (func['return_type'], func['known_as'], func['arguments']))
|
| + file.write(' NOTREACHED();\n')
|
| + return_type = func['return_type'].lower()
|
| + # Returning 0 works for booleans, integers and pointers.
|
| + if return_type != 'void':
|
| + file.write(' return 0;\n')
|
| + file.write('}\n')
|
| +
|
| + # Write function to initialize the function pointers that are always the same
|
| + # and to initialize bindings where choice of the function depends on the
|
| + # extension string or the GL version to point to stub functions.
|
| file.write('\n')
|
| - file.write('void Driver%s::InitializeBindings() {\n' %
|
| + file.write('void Driver%s::InitializeStaticBindings() {\n' %
|
| set_name.upper())
|
| +
|
| + def WriteFuncBinding(file, known_as, version_name):
|
| + file.write(
|
| + ' fn.%sFn = reinterpret_cast<%sProc>(GetGLProcAddress("%s"));\n' %
|
| + (known_as, known_as, version_name))
|
| +
|
| 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))
|
| + if len(func['names']) == 1:
|
| + WriteFuncBinding(file, func['known_as'], func['known_as'])
|
| + else:
|
| + file.write(' fn.%sFn = reinterpret_cast<%sProc>(%sNotBound);\n' %
|
| + (func['known_as'], func['known_as'], func['known_as']))
|
| +
|
| 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) {
|
| + # Write function to initialize bindings where choice of the function depends
|
| + # on the extension string or the GL version.
|
| + file.write("""void Driver%s::InitializeDynamicBindings(GLContext* context) {
|
| + DCHECK(context && context->IsCurrent(NULL));
|
| + const GLVersionInfo* ver ALLOW_UNUSED = context->GetVersionInfo();
|
| + std::string extensions ALLOW_UNUSED = context->GetExtensions();
|
| + extensions += " ";
|
| +
|
| """ % 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' %
|
| + for extension in used_extensions:
|
| + # Extra space at the end of the extension name is intentional, it is used
|
| + # as a separator
|
| + file.write(' ext.b_%s = extensions.find("%s ") != std::string::npos;\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')
|
| +
|
| + def VersionCondition(version):
|
| + conditions = []
|
| + if 'gl_versions' in version:
|
| + gl_versions = version['gl_versions']
|
| + version_cond = ' || '.join(['ver->is_%s' % gl for gl in gl_versions])
|
| + conditions.append(version_cond)
|
| + ext = []
|
| + if 'extension' in version:
|
| + ext.append(version['extension'])
|
| + if 'extensions' in version:
|
| + ext.extend([e for e in version['extensions'] if e not in ext])
|
| + if ext:
|
| + ext_cond = ' || '.join(['ext.b_%s' % e for e in ext])
|
| + conditions.append(ext_cond)
|
| + def Wrap(cond):
|
| + if ' || ' in cond:
|
| + return '(%s)' % cond
|
| + return cond
|
| + return ' && '.join([Wrap(cond) for cond in conditions])
|
| +
|
| + def WriteConditionalFuncBinding(file, func):
|
| + assert len(func['versions']) > 1
|
| + known_as = func['known_as']
|
| + i = 0
|
| + first_version = True
|
| + while i < len(func['versions']):
|
| + version = func['versions'][i]
|
| + cond = VersionCondition(version)
|
| + combined_conditions = [cond]
|
| + while i + 1 < len(func['versions']) and \
|
| + func['versions'][i + 1]['name'] == version['name']:
|
| + i += 1
|
| + combined_conditions.append(VersionCondition(func['versions'][i]))
|
| + if len(combined_conditions) > 1:
|
| + if [1 for cond in combined_conditions if cond == '']:
|
| + cond = ''
|
| + else:
|
| + def Wrap(cond):
|
| + if ' && ' in cond:
|
| + return '(%s)' % cond
|
| + return cond
|
| + cond = ' || '.join([Wrap(cond) for cond in combined_conditions])
|
| + # Don't make the last possible binding conditional on anything else but
|
| + # that the function isn't already bound to avoid verbose specification
|
| + # of functions which have both ARB and core versions with the same name,
|
| + # and to be able to bind to mock extension functions in unit tests which
|
| + # call InitializeDynamicGLBindings with a stub context that doesn't have
|
| + # extensions in its extension string.
|
| + # TODO(oetuaho@nvidia.com): Get rid of the fallback.
|
| + # http://crbug.com/325668
|
| + if cond != '' and i + 1 < len(func['versions']):
|
| + if not first_version:
|
| + file.write(' if (!fn.%sFn && (%s))\n ' % (known_as, cond))
|
| + else:
|
| + file.write(' if (%s)\n ' % cond)
|
| + elif not first_version:
|
| + file.write(' if (!fn.%sFn)\n ' % known_as)
|
| + WriteFuncBinding(file, known_as, version['name'])
|
| + i += 1
|
| + first_version = False
|
| +
|
| + for func in functions:
|
| + if len(func['names']) > 1:
|
| + file.write('\n')
|
| + file.write(' fn.%sFn = 0;\n' % func['known_as'])
|
| + file.write(' debug_fn.%sFn = 0;\n' % func['known_as'])
|
| + WriteConditionalFuncBinding(file, func)
|
| +
|
| + # Some new function pointers have been added, so update them in debug bindings
|
| + file.write('\n')
|
| file.write(' if (g_debugBindingsInitialized)\n')
|
| - file.write(' UpdateDebugExtensionBindings();\n')
|
| + file.write(' InitializeDebugBindings();\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))
|
| + (return_type, func['known_as'], arguments))
|
| argument_names = re.sub(
|
| r'(const )?[a-zA-Z0-9_]+\** ([a-zA-Z0-9_]+)', r'\2', arguments)
|
| argument_names = re.sub(
|
| @@ -1463,9 +1604,9 @@ namespace gfx {
|
| log_argument_names)
|
| log_argument_names = re.sub(
|
| r'CONSTVOID_([a-zA-Z0-9_]+)',
|
| - r'static_cast<const void*>(\1)', log_argument_names);
|
| + 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);
|
| + 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)
|
| @@ -1478,7 +1619,7 @@ namespace gfx {
|
| log_argument_names = ''
|
| else:
|
| log_argument_names = " << " + log_argument_names
|
| - function_name = names[0]
|
| + function_name = func['known_as']
|
| if return_type == 'void':
|
| file.write(' GL_SERVICE_LOG("%s" << "(" %s << ")");\n' %
|
| (function_name, log_argument_names))
|
| @@ -1494,7 +1635,7 @@ namespace gfx {
|
| if 'logging_code' in func:
|
| file.write("%s\n" % func['logging_code'])
|
| else:
|
| - file.write(' GL_SERVICE_LOG("GL_RESULT: " << result);\n');
|
| + file.write(' GL_SERVICE_LOG("GL_RESULT: " << result);\n')
|
| file.write(' return result;\n')
|
| file.write('}\n')
|
| file.write('} // extern "C"\n')
|
| @@ -1504,7 +1645,7 @@ namespace gfx {
|
| file.write('void Driver%s::InitializeDebugBindings() {\n' %
|
| set_name.upper())
|
| for func in functions:
|
| - first_name = func['names'][0]
|
| + first_name = func['known_as']
|
| 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))
|
| @@ -1512,20 +1653,6 @@ namespace gfx {
|
| 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() {
|
| @@ -1535,19 +1662,18 @@ namespace gfx {
|
|
|
| # 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))
|
| + (return_type, set_name.upper(), func['known_as'], 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]
|
| + function_name = func['known_as']
|
| if return_type == 'void':
|
| file.write(' driver_->fn.%sFn(%s);\n' %
|
| (function_name, argument_names))
|
| @@ -1558,19 +1684,18 @@ namespace gfx {
|
|
|
| # 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))
|
| + (return_type, set_name.upper(), func['known_as'], 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]
|
| + function_name = func['known_as']
|
| file.write(' TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::%s")\n' %
|
| function_name)
|
| if return_type == 'void':
|
| @@ -1605,12 +1730,12 @@ namespace gfx {
|
| 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'])
|
| + (func['return_type'], func['known_as'], func['arguments']))
|
| + arg_re = r'(const )?[a-zA-Z0-9]+((\s*const\s*)?\*)* ([a-zA-Z0-9]+)'
|
| + argument_names = re.sub(arg_re, r'\4', func['arguments'])
|
| if argument_names == 'void':
|
| argument_names = ''
|
| - function_name = func['names'][0][2:]
|
| + function_name = func['known_as'][2:]
|
| if func['return_type'] == 'void':
|
| file.write(' GLInterface::GetGLInterface()->%s(%s);\n' %
|
| (function_name, argument_names))
|
| @@ -1631,12 +1756,13 @@ namespace gfx {
|
| 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)
|
| + for name in func['names']:
|
| + file.write(' if (strcmp(name, "%s") == 0)\n' % name)
|
| + file.write(
|
| + ' return reinterpret_cast<void*>(Mock_%s);\n' % func['known_as'])
|
| # 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('\n')
|
| file.write('} // namespace gfx\n')
|
| @@ -1719,49 +1845,51 @@ def LooksLikeExtensionFunction(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.
|
| +def FillExtensionsFromHeaders(functions, extension_headers, extra_extensions):
|
| + """Determine which functions belong to extensions based on extension headers,
|
| + and fill in this information to the functions table for functions that don't
|
| + already have the information.
|
|
|
| Args:
|
| - functions: List of (return type, function names, arguments).
|
| + functions: List of (return type, function versions, arguments).
|
| extension_headers: List of header file names.
|
| + extra_extensions: Extensions to add to the list.
|
| Returns:
|
| - List of (extension name, [function name alternatives]) sorted with least
|
| - preferred extensions first.
|
| + List of used extensions.
|
| """
|
| # Parse known extensions.
|
| extensions = GetExtensionFunctions(extension_headers)
|
| functions_to_extensions = GetFunctionToExtensionMap(extensions)
|
|
|
| - # Collect all used extension functions.
|
| - used_extension_functions = collections.defaultdict(lambda: [])
|
| + # Fill in the extension information.
|
| + used_extensions = []
|
| 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):
|
| + for version in func['versions']:
|
| + name = version['name']
|
| + # Make sure we know about all extensions and extension functions.
|
| + if 'extension' in version:
|
| + if version['extension'] not in used_extensions:
|
| + used_extensions.append(version['extension'])
|
| + elif 'extensions' in version:
|
| + used_extensions.extend(
|
| + [e for e in version['extensions'] if e not in used_extensions])
|
| + elif name in functions_to_extensions:
|
| + # If there are multiple versions with the same name, assume that they
|
| + # already have all the correct conditions, we can't just blindly add
|
| + # the same extension conditions to all of them
|
| + if len([v for v in func['versions'] if v['name'] == name]) == 1:
|
| + version['extensions'] = functions_to_extensions[name]
|
| + used_extensions.extend(
|
| + [e for e in version['extensions'] if e not in used_extensions])
|
| + elif LooksLikeExtensionFunction(name):
|
| 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]))
|
| + used_extensions.extend(
|
| + [e for e in extra_extensions if e not in used_extensions])
|
|
|
| - 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
|
| + return used_extensions
|
|
|
|
|
| def ResolveHeader(header, header_paths):
|
| @@ -1801,46 +1929,60 @@ def main(argv):
|
| print ResolveHeader(header, options.header_paths)
|
| return 0
|
|
|
| + directory = '.'
|
| if len(args) >= 1:
|
| - dir = args[0]
|
| - else:
|
| - dir = '.'
|
| + directory = args[0]
|
|
|
| for [functions, set_name, extension_headers, extensions] in FUNCTION_SETS:
|
| + # Function names can be specified in two ways (list of unique names or list
|
| + # of versions with different binding conditions), fill in the data both
|
| + # ways:
|
| + for func in functions:
|
| + assert 'versions' in func or 'names' in func, 'Function with no names'
|
| + if 'versions' not in func:
|
| + func['versions'] = [{'name': n} for n in func['names']]
|
| + if 'names' not in func:
|
| + func['names'] = []
|
| + for version in func['versions']:
|
| + if version['name'] not in func['names']:
|
| + func['names'].append(version['name'])
|
| + # Use the first version's name unless otherwise specified
|
| + if 'known_as' not in func:
|
| + func['known_as'] = func['names'][0]
|
| +
|
| extension_headers = [ResolveHeader(h, options.header_paths)
|
| for h in extension_headers]
|
| - used_extension_functions = GetUsedExtensionFunctions(
|
| + used_extensions = FillExtensionsFromHeaders(
|
| 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)
|
| + os.path.join(directory, 'gl_bindings_autogen_%s.h' % set_name), 'wb')
|
| + GenerateHeader(header_file, functions, set_name, used_extensions)
|
| 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)
|
| + os.path.join(directory, 'gl_bindings_api_autogen_%s.h' % set_name),
|
| + 'wb')
|
| + GenerateAPIHeader(header_file, functions, set_name)
|
| 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)
|
| + os.path.join(directory, 'gl_bindings_autogen_%s.cc' % set_name), 'wb')
|
| + GenerateSource(source_file, functions, set_name, used_extensions)
|
| 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)
|
| + os.path.join(directory, 'gl_interface_autogen_%s.h' % set_name), 'wb')
|
| + GenerateInterfaceHeader(header_file, functions, set_name)
|
| 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)
|
| + os.path.join(directory, 'gl_mock_autogen_%s.h' % set_name), 'wb')
|
| + GenerateMockHeader(header_file, functions, set_name)
|
| header_file.close()
|
|
|
| - source_file = open(os.path.join(dir, 'gl_bindings_autogen_mock.cc'), 'wb')
|
| + source_file = open(os.path.join(directory, 'gl_bindings_autogen_mock.cc'),
|
| + 'wb')
|
| GenerateMockSource(source_file, GL_FUNCTIONS)
|
| source_file.close()
|
| return 0
|
|
|