Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(133)

Unified Diff: ui/gl/generate_bindings.py

Issue 94963003: Take GL version and extensions correctly into account when binding functions (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Improve Windows initialization and renderBufferMultisample explanation Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ui/compositor/test/test_suite.cc ('k') | ui/gl/gl.gyp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
« no previous file with comments | « ui/compositor/test/test_suite.cc ('k') | ui/gl/gl.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698