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

Unified Diff: ui/gfx/gl/generate_bindings.py

Issue 8381001: Split GL binding init into core and extension part (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Use existing glext.h/wglext.h/glxext.h headers from Mesa. Created 9 years, 2 months 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 | « gpu/command_buffer/common/gles2_cmd_format.h ('k') | ui/gfx/gl/gl_bindings_skia_in_process.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ui/gfx/gl/generate_bindings.py
diff --git a/ui/gfx/gl/generate_bindings.py b/ui/gfx/gl/generate_bindings.py
index b3f52fbe93fbe80c19f6c83c0ae188cade18e5b4..cf45e43037e89306b777229f02c3e9d9aff93ad2 100644
--- a/ui/gfx/gl/generate_bindings.py
+++ b/ui/gfx/gl/generate_bindings.py
@@ -7,6 +7,7 @@
"""code generator for GL/GLES extension wrangler."""
import os
+import collections
import re
import sys
@@ -19,7 +20,7 @@ GL_FUNCTIONS = [
['void', ['glBindBuffer'], 'GLenum target, GLuint buffer'],
['void', ['glBindFragDataLocation'],
'GLuint program, GLuint colorNumber, const char* name'],
-['void', ['glBindFragDataLocationIndexedARB'],
+['void', ['glBindFragDataLocationIndexed'],
'GLuint program, GLuint colorNumber, GLuint index, const char* name'],
['void', ['glBindFramebufferEXT', 'glBindFramebuffer'],
'GLenum target, GLuint framebuffer'],
@@ -33,11 +34,11 @@ GL_FUNCTIONS = [
['void', ['glBlendFunc'], 'GLenum sfactor, GLenum dfactor'],
['void', ['glBlendFuncSeparate'],
'GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha'],
-['void', ['glBlitFramebufferEXT', 'BlitFramebuffer'],
+['void', ['glBlitFramebufferEXT', 'glBlitFramebuffer'],
'GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, '
'GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, '
'GLbitfield mask, GLenum filter'],
-['void', ['glBlitFramebufferANGLE', 'BlitFramebuffer'],
+['void', ['glBlitFramebufferANGLE', 'glBlitFramebuffer'],
'GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, '
'GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, '
'GLbitfield mask, GLenum filter'],
@@ -181,7 +182,7 @@ GL_FUNCTIONS = [
['GLboolean', ['glIsTexture'], 'GLuint texture'],
['void', ['glLineWidth'], 'GLfloat width'],
['void', ['glLinkProgram'], 'GLuint program'],
-['void*', ['glMapBuffer'], 'GLenum target, GLenum access'],
+['void*', ['glMapBuffer', 'glMapBufferOES'], 'GLenum target, GLenum access'],
['void', ['glPixelStorei'], 'GLenum pname, GLint param'],
['void', ['glPolygonOffset'], 'GLfloat factor, GLfloat units'],
['void', ['glQueryCounter'], 'GLuint id, GLenum target'],
@@ -251,7 +252,7 @@ GL_FUNCTIONS = [
'GLint location, GLsizei count, GLboolean transpose, const GLfloat* value'],
['void', ['glUniformMatrix4fv'],
'GLint location, GLsizei count, GLboolean transpose, const GLfloat* value'],
-['GLboolean', ['glUnmapBuffer'], 'GLenum target'],
+['GLboolean', ['glUnmapBuffer', 'glUnmapBufferOES'], 'GLenum target'],
['void', ['glUseProgram'], 'GLuint program'],
['void', ['glValidateProgram'], 'GLuint program'],
['void', ['glVertexAttrib1f'], 'GLuint indx, GLfloat x'],
@@ -463,11 +464,14 @@ GLX_FUNCTIONS = [
]
FUNCTION_SETS = [
- [GL_FUNCTIONS, 'gl'],
- [OSMESA_FUNCTIONS, 'osmesa'],
- [EGL_FUNCTIONS, 'egl'],
- [WGL_FUNCTIONS, 'wgl'],
- [GLX_FUNCTIONS, 'glx'],
+ [GL_FUNCTIONS, 'gl', ['../../../third_party/mesa/MesaLib/include/GL/glext.h',
+ '../../../gpu/GLES2/gl2ext.h']],
+ [OSMESA_FUNCTIONS, 'osmesa', []],
+ [EGL_FUNCTIONS, 'egl', ['../../../gpu/EGL/eglext.h']],
+ [WGL_FUNCTIONS, 'wgl', [
+ '../../../third_party/mesa/MesaLib/include/GL/wglext.h']],
+ [GLX_FUNCTIONS, 'glx', [
+ '../../../third_party/mesa/MesaLib/include/GL/glxext.h']],
]
def GenerateHeader(file, functions, set_name):
@@ -487,7 +491,11 @@ def GenerateHeader(file, functions, set_name):
file.write('\n')
file.write('namespace gfx {\n')
file.write('\n')
+ file.write('class GLContext;\n')
+ file.write('\n')
file.write('void InitializeGLBindings%s();\n' % set_name.upper())
+ file.write('void InitializeGLExtensionBindings%s(GLContext* context);\n' %
+ set_name.upper())
file.write('void InitializeDebugGLBindings%s();\n' % set_name.upper())
# Write typedefs for function pointer types. Always use the GL name for the
@@ -517,7 +525,7 @@ def GenerateHeader(file, functions, set_name):
set_name.upper())
-def GenerateSource(file, functions, set_name):
+def GenerateSource(file, functions, set_name, used_extension_functions):
"""Generates gl_binding_autogen_x.cc"""
# Write file header.
@@ -528,12 +536,16 @@ def GenerateSource(file, functions, set_name):
file.write('// This file is automatically generated.\n')
file.write('\n')
file.write('#include "ui/gfx/gl/gl_bindings.h"\n')
+ file.write('#include "ui/gfx/gl/gl_context.h"\n')
file.write('#include "ui/gfx/gl/gl_implementation.h"\n')
# Write definitions of function pointers.
file.write('\n')
file.write('namespace gfx {\n')
file.write('\n')
+ file.write('static bool g_debugBindingsInitialized;\n')
+ file.write('static void UpdateDebugGLExtensionBindings();\n')
+ file.write('\n')
for [return_type, names, arguments] in functions:
file.write('%sProc g_%s;\n' % (names[0], names[0]))
@@ -541,18 +553,45 @@ def GenerateSource(file, functions, set_name):
for [return_type, names, arguments] in functions:
file.write('static %sProc g_debug_%s;\n' % (names[0], names[0]))
- # Write function to initialize the function pointers.
+ # 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 InitializeGLBindings%s() {\n' % set_name.upper())
for [return_type, names, arguments] in functions:
- for name in names:
- file.write(' if (!g_%s)\n' % names[0])
+ for i, name in enumerate(names):
+ if i:
+ file.write(' if (!g_%s)\n ' % names[0])
file.write(
- ' g_%s = reinterpret_cast<%sProc>(GetGLProcAddress("%s"));\n' %
+ ' g_%s = reinterpret_cast<%sProc>(GetGLCoreProcAddress("%s"));\n' %
(names[0], names[0], 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 InitializeGLExtensionBindings%s(GLContext* context) {\n' %
+ set_name.upper())
+ file.write(' DCHECK(context && context->IsCurrent(NULL));\n')
+ for extension, ext_functions in used_extension_functions:
+ file.write(' if (context->HasExtension("%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 (!g_%s)\n ' % entry_point_name)
+ file.write(
+ ' g_%s = 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(' UpdateDebugGLExtensionBindings();\n')
+ file.write('}\n')
+ file.write('\n')
+
# Write logging wrappers for each function.
file.write('extern "C" {\n')
for [return_type, names, arguments] in functions:
@@ -595,19 +634,31 @@ def GenerateSource(file, functions, set_name):
file.write('}\n')
file.write('} // extern "C"\n')
- # Write function to initialize the function pointers.
+ # Write function to initialize the debug function pointers.
file.write('\n')
file.write('void InitializeDebugGLBindings%s() {\n' % set_name.upper())
for [return_type, names, arguments] in functions:
- for name in names:
- file.write(' if (!g_debug_%s) {\n' % names[0])
- file.write(' g_debug_%s = g_%s;\n' % (names[0], names[0]))
- file.write(' g_%s = Debug_%s;\n' % (names[0], names[0]))
- file.write(' }\n')
+ file.write(' if (!g_debug_%s) {\n' % names[0])
+ file.write(' g_debug_%s = g_%s;\n' % (names[0], names[0]))
+ file.write(' g_%s = Debug_%s;\n' % (names[0], names[0]))
+ 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('static void UpdateDebugGLExtensionBindings() {\n')
+ for extension, ext_functions in used_extension_functions:
+ for name, _ in ext_functions:
+ file.write(' if (g_debug_%s != g_%s &&\n' % (name, name))
+ file.write(' g_%s != Debug_%s) {\n' % (name, name))
+ file.write(' g_debug_%s = g_%s;\n' % (name, name))
+ file.write(' g_%s = Debug_%s;\n' % (name, name))
+ file.write(' }\n')
+ file.write('}\n')
- file.write( '} // namespace gfx\n')
+ file.write('} // namespace gfx\n')
def GenerateMockSource(file, functions):
@@ -644,18 +695,135 @@ def GenerateMockSource(file, functions):
(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(' DCHECK(0);\n')
apatrick_chromium 2011/10/26 18:29:11 This could be NOTREACHED()
Sami 2011/10/27 13:46:06 Done.
+ 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 [return_type, names, arguments] in functions:
file.write(' if (strcmp(name, "%s") == 0)\n' % names[0])
file.write(' return reinterpret_cast<void*>(Mock_%s);\n' % names[0])
- file.write(' return NULL;\n')
+ # 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'#define ([A-Z]+_[A-Z]+_[a-zA-Z]\w+) 1')
+ 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_extension = {}
+ for extension, functions in extensions.items():
+ for function in functions:
+ assert function not in function_to_extension, \
+ "Duplicate function: " + function
+ function_to_extension[function] = extension
+ return function_to_extension
+
+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):
+ """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 [return_type, names, arguments] in functions:
+ for name in 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:
+ extension = functions_to_extensions[name]
+ used_extension_functions[extension].append((names[0], name))
+
+ 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 main(argv):
"""This is the main function."""
@@ -665,7 +833,7 @@ def main(argv):
else:
dir = '.'
- for [functions, set_name] in FUNCTION_SETS:
+ for [functions, set_name, extension_headers] in FUNCTION_SETS:
header_file = open(
os.path.join(dir, 'gl_bindings_autogen_%s.h' % set_name), 'wb')
GenerateHeader(header_file, functions, set_name)
@@ -673,7 +841,9 @@ def main(argv):
source_file = open(
os.path.join(dir, 'gl_bindings_autogen_%s.cc' % set_name), 'wb')
- GenerateSource(source_file, functions, set_name)
+ used_extension_functions = GetUsedExtensionFunctions(
+ functions, extension_headers)
+ GenerateSource(source_file, functions, set_name, used_extension_functions)
source_file.close()
source_file = open(os.path.join(dir, 'gl_bindings_autogen_mock.cc'), 'wb')
« no previous file with comments | « gpu/command_buffer/common/gles2_cmd_format.h ('k') | ui/gfx/gl/gl_bindings_skia_in_process.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698