summaryrefslogtreecommitdiff
path: root/src/mesa/glapi/glX_proto_send.py
diff options
context:
space:
mode:
authorIan Romanick <idr@us.ibm.com>2005-01-07 02:39:09 +0000
committerIan Romanick <idr@us.ibm.com>2005-01-07 02:39:09 +0000
commit5f1f229f8da255ca9b390da1757ad781978cf619 (patch)
tree14a550730dc7a2ceb74ef84183b518460d2e1b68 /src/mesa/glapi/glX_proto_send.py
parent3385d7cec3308129f6f1fc5990023417e4e4be47 (diff)
Pixel oriented render functions are now generated by the
glX_proto_send.py script. This eliminates ~600 lines of non-generated code. With proper compiler optimization settings, it also decreases the size of libGL.so by about 3KB.
Diffstat (limited to 'src/mesa/glapi/glX_proto_send.py')
-rw-r--r--src/mesa/glapi/glX_proto_send.py348
1 files changed, 338 insertions, 10 deletions
diff --git a/src/mesa/glapi/glX_proto_send.py b/src/mesa/glapi/glX_proto_send.py
index 7a93ef10b6..e7cda2f779 100644
--- a/src/mesa/glapi/glX_proto_send.py
+++ b/src/mesa/glapi/glX_proto_send.py
@@ -1,6 +1,6 @@
#!/usr/bin/python2
-# (C) Copyright IBM Corporation 2004
+# (C) Copyright IBM Corporation 2004, 2005
# All Rights Reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a
@@ -32,15 +32,87 @@ from xml.sax.handler import feature_namespaces
import gl_XML
import glX_XML
import license
-import sys, getopt
+import sys, getopt, copy
+
+def hash_pixel_function(func):
+ """Generate a 'unique' key for a pixel function. The key is based on
+ the parameters written in the command packet. This includes any
+ padding that might be added for the original function and the 'NULL
+ image' flag."""
+
+ [dim, junk, junk, junk, junk] = func.dimensions()
+
+ d = (dim + 1) & ~1
+ h = "%uD%uD_" % (d - 1, d)
+
+ for p in func.parameterIterator(1, 1):
+ h = "%s%u" % (h, p.size())
+
+ if func.pad_after(p):
+ h += "4"
+
+ if func.image.img_null_flag:
+ h += "_NF"
+
+ n = func.name.replace("%uD" % (dim), "")
+ n = "__glx_%s_%uD%uD" % (n, d - 1, d)
+ return [h, n]
+
+
+class glXPixelFunctionUtility(glX_XML.glXFunction):
+ """Dummy class used to generate pixel "utility" functions that are
+ shared by multiple dimension image functions. For example, these
+ objects are used to generate shared functions used to send GLX
+ protocol for TexImage1D and TexImage2D, TexSubImage1D and
+ TexSubImage2D, etc."""
+
+ def __init__(self, func, name):
+ # The parameters to the utility function are the same as the
+ # parameters to the real function except for the added "pad"
+ # parameters.
+
+ self.name = name
+ self.image = copy.copy(func.image)
+ self.fn_parameters = []
+ for p in gl_XML.glFunction.parameterIterator(func):
+ self.fn_parameters.append(p)
+
+ pad_name = func.pad_after(p)
+ if pad_name:
+ pad = copy.copy(p)
+ pad.name = pad_name
+ self.fn_parameters.append(pad)
+
+
+ if self.image.height == None:
+ self.image.height = "height"
+
+ if self.image.img_yoff == None:
+ self.image.img_yoff = "yoffset"
+
+ if func.image.depth:
+ if self.image.extent == None:
+ self.image.extent = "extent"
+
+ if self.image.img_woff == None:
+ self.image.img_woff = "woffset"
+
+
+ self.set_return_type( func.fn_return_type )
+ self.glx_rop = ~0
+ self.can_be_large = func.can_be_large
+ self.count_parameters = func.count_parameters
+ self.counter = func.counter
+ return
class PrintGlxProtoStubs(glX_XML.GlxProto):
def __init__(self):
glX_XML.GlxProto.__init__(self)
self.last_category = ""
- self.license = license.bsd_license_template % ( "(C) Copyright IBM Corporation 2004", "IBM")
+ self.license = license.bsd_license_template % ( "(C) Copyright IBM Corporation 2004, 2005", "IBM")
self.generic_sizes = [3, 4, 6, 8, 12, 16, 24, 32]
+ self.pixel_stubs = {}
return
def printRealHeader(self):
@@ -48,7 +120,7 @@ class PrintGlxProtoStubs(glX_XML.GlxProto):
print '#include <GL/gl.h>'
print '#include "indirect.h"'
print '#include "glxclient.h"'
- print '#include "size.h"'
+ print '#include "indirect_size.h"'
print '#include <GL/glxproto.h>'
print ''
print '#define __GLX_PAD(n) (((n) + 3) & ~3)'
@@ -125,6 +197,19 @@ setup_vendor_request( __GLXcontext * gc, GLint code, GLint vop, GLint cmdlen )
req->contextTag = gc->currentContextTag;
return (GLubyte *)(req) + sz_xGLXVendorPrivateReq;
}
+
+const GLuint __glXDefaultPixelStore[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 1 };
+
+#define zero (__glXDefaultPixelStore+0)
+#define one (__glXDefaultPixelStore+8)
+#define default_pixel_store_1D (__glXDefaultPixelStore+4)
+#define default_pixel_store_1D_size 20
+#define default_pixel_store_2D (__glXDefaultPixelStore+4)
+#define default_pixel_store_2D_size 20
+#define default_pixel_store_3D (__glXDefaultPixelStore+0)
+#define default_pixel_store_3D_size 36
+#define default_pixel_store_4D (__glXDefaultPixelStore+0)
+#define default_pixel_store_4D_size 36
"""
for size in self.generic_sizes:
@@ -135,7 +220,10 @@ setup_vendor_request( __GLXcontext * gc, GLint code, GLint vop, GLint cmdlen )
if f.fn_offset < 0 or f.handcode or f.ignore: return
if f.glx_rop != 0 or f.vectorequiv != None:
- self.printRenderFunction(f)
+ if f.image:
+ self.printPixelFunction(f)
+ else:
+ self.printRenderFunction(f)
elif f.glx_sop != 0 or f.glx_vendorpriv != 0:
self.printSingleFunction(f)
else:
@@ -182,8 +270,38 @@ generic_%u_byte( GLint rop, const void * ptr )
return offset
- def large_emit_begin(self, indent, f):
- print '%s const GLint op = %s;' % (indent, f.opcode_real_name())
+ def pixel_emit_args(self, f, pc, indent, adjust, dim, large):
+ """Emit the arguments for a pixel function. This differs from
+ common_emit_args in that pixel functions may require padding
+ be inserted (i.e., for the missing width field for
+ TexImage1D), and they may also require a 'NULL image' flag
+ be inserted before the image data."""
+
+ offset = 0
+ for p in f.parameterIterator(1, 1):
+ self.common_emit_one_arg(p, offset, pc, indent, adjust)
+ offset += p.size()
+
+ if f.pad_after(p):
+ print '%s (void) memcpy((void *)(%s + %u), zero, 4);' % (indent, pc, offset + adjust)
+ offset += 4
+
+ if f.image.img_null_flag:
+ if large:
+ print '%s (void) memcpy((void *)(%s + %u), zero, 4);' % (indent, pc, offset + adjust)
+ else:
+ print '%s (void) memcpy((void *)(%s + %u), (void *)((%s == NULL) ? one : zero), 4);' % (indent, pc, offset + adjust, f.image.name)
+
+ offset += 4
+
+ return offset
+
+
+ def large_emit_begin(self, indent, f, op_name = None):
+ if not op_name:
+ op_name = f.opcode_real_name()
+
+ print '%s const GLint op = %s;' % (indent, op_name)
print '%s const GLuint cmdlenLarge = cmdlen + 4;' % (indent)
print '%s GLubyte * const pc = __glXFlushRenderBuffer(gc, gc->pc);' % (indent)
print '%s (void) memcpy((void *)(pc + 0), (void *)(&cmdlenLarge), 4);' % (indent)
@@ -199,9 +317,7 @@ generic_%u_byte( GLint rop, const void * ptr )
print '{'
- def common_func_print_header(self, f):
- self.common_func_print_just_header(f)
-
+ def common_func_print_just_start(self, f):
print ' __GLXcontext * const gc = __glXGetCurrentContext();'
# The only reason that single and vendor private commands need
@@ -224,6 +340,15 @@ generic_%u_byte( GLint rop, const void * ptr )
if f.count_parameters != None:
print ' const GLuint compsize = __gl%s_size(%s);' % (f.name, f.count_parameters)
+ elif f.image:
+ [dim, w, h, d, junk] = f.dimensions()
+
+ compsize = '__glImageSize(%s, %s, %s, %s, %s, %s)' % (w, h, d, f.image.img_format, f.image.img_type, f.image.img_target)
+ if not f.image.img_send_null:
+ compsize = '(%s != NULL) ? %s : 0' % (f.image.name, compsize)
+
+ print ' const GLuint compsize = %s;' % (compsize)
+
print ' const GLuint cmdlen = %s;' % (f.command_length())
@@ -241,6 +366,12 @@ generic_%u_byte( GLint rop, const void * ptr )
return 0
+ def common_func_print_header(self, f):
+ self.common_func_print_just_header(f)
+ return self.common_func_print_just_start(f)
+
+
+
def printSingleFunction(self, f):
self.common_func_print_header(f)
@@ -284,6 +415,203 @@ generic_%u_byte( GLint rop, const void * ptr )
return
+ def printPixelFunction(self, f):
+ """This function could use some major refactoring. :("""
+
+ # There is a code-space optimization that we can do here.
+ # Functions that are marked img_pad_dimensions have a version
+ # with an odd number of dimensions and an even number of
+ # dimensions. TexSubImage1D and TexSubImage2D are examples.
+ # We can emit a single function that does both, and have the
+ # real functions call the utility function with the correct
+ # parameters.
+ #
+ # The only quirk to this is that utility funcitons will be
+ # generated for 3D and 4D functions, but 4D (e.g.,
+ # GL_SGIS_texture4D) isn't typically supported. This is
+ # probably not an issue. However, it would be possible to
+ # look at the total set of functions and determine if there
+ # is another function that would actually use the utility
+ # function. If not, then fallback to the normal way of
+ # generating code.
+
+ if f.image.img_pad_dimensions:
+ # Determine the hash key and the name for the utility
+ # function that is used to implement the real
+ # function.
+
+ [h, n] = hash_pixel_function(f)
+
+
+ # If the utility function is not yet known, generate
+ # it.
+
+ if not self.pixel_stubs.has_key(h):
+ self.pixel_stubs[h] = n
+ pixel_func = glXPixelFunctionUtility(f, n)
+
+ print 'static void'
+ print '%s( unsigned opcode, unsigned dim, %s )' % (n, pixel_func.get_parameter_string())
+ print '{'
+
+ if self.common_func_print_just_start(pixel_func):
+ indent = " "
+ trailer = " }"
+ else:
+ indent = ""
+ trailer = None
+
+
+ if pixel_func.can_be_large:
+ print '%s if (cmdlen <= gc->maxSmallRenderCommandSize) {' % (indent)
+ print '%s if ( (gc->pc + cmdlen) > gc->bufEnd ) {' % (indent)
+ print '%s (void) __glXFlushRenderBuffer(gc, gc->pc);' % (indent)
+ print '%s }' % (indent)
+ indent += " "
+
+ [dim, width, height, depth, extent] = pixel_func.dimensions()
+
+ if dim < 3:
+ adjust = 20 + 4
+ else:
+ adjust = 36 + 4
+
+
+ print '%s emit_header(gc->pc, opcode, cmdlen);' % (indent)
+
+ offset = self.pixel_emit_args(pixel_func, "gc->pc", indent, adjust, dim, 0)
+
+ [s, junk] = pixel_func.command_payload_length()
+
+ pixHeaderPtr = "gc->pc + 4"
+ pcPtr = "gc->pc + %u" % (s + 4)
+
+ if pixel_func.image.img_send_null:
+ condition = '(compsize > 0) && (%s != NULL)' % (pixel_func.image.name)
+ else:
+ condition = 'compsize > 0'
+
+ print '%s if (%s) {' % (indent, condition)
+ print '%s (*gc->fillImage)(gc, dim, %s, %s, %s, %s, %s, %s, %s, %s);' % (indent, width, height, depth, pixel_func.image.img_format, pixel_func.image.img_type, pixel_func.image.name, pcPtr, pixHeaderPtr)
+ print '%s }' % (indent)
+ print '%s else {' % (indent)
+ print '%s (void) memcpy( %s, default_pixel_store_%uD, default_pixel_store_%uD_size );' % (indent, pixHeaderPtr, dim, dim)
+ print '%s }' % (indent)
+
+ print '%s gc->pc += cmdlen;' % (indent)
+ print '%s if (gc->pc > gc->limit) { (void) __glXFlushRenderBuffer(gc, gc->pc); }' % (indent)
+
+ if f.can_be_large:
+ adjust += 4
+
+ print '%s}' % (indent)
+ print '%selse {' % (indent)
+
+ self.large_emit_begin(indent, pixel_func, "opcode")
+ offset = self.pixel_emit_args(pixel_func, "pc", indent, adjust, dim, 1)
+
+ pixHeaderPtr = "pc + 8"
+ pcPtr = "pc + %u" % (s + 8)
+
+ print '%s __glXSendLargeImage(gc, compsize, dim, %s, %s, %s, %s, %s, %s, %s, %s);' % (indent, width, height, depth, f.image.img_format, f.image.img_type, f.image.name, pcPtr, pixHeaderPtr)
+
+ print '%s}' % (indent)
+
+ if trailer: print trailer
+ print '}'
+ print ''
+
+
+
+ # Generate the real function as a call to the
+ # utility function.
+
+ self.common_func_print_just_header(f)
+
+ [dim, junk, junk, junk, junk] = f.dimensions()
+
+ p_string = ""
+ for p in gl_XML.glFunction.parameterIterator(f):
+ p_string += ", " + p.name
+
+ if f.pad_after(p):
+ p_string += ", 1"
+
+ print ' %s(%s, %u%s );' % (n, f.opcode_name(), dim, p_string)
+ print '}'
+ print ''
+ return
+
+
+ if self.common_func_print_header(f):
+ indent = " "
+ trailer = " }"
+ else:
+ indent = ""
+ trailer = None
+
+
+ if f.can_be_large:
+ print '%s if (cmdlen <= gc->maxSmallRenderCommandSize) {' % (indent)
+ print '%s if ( (gc->pc + cmdlen) > gc->bufEnd ) {' % (indent)
+ print '%s (void) __glXFlushRenderBuffer(gc, gc->pc);' % (indent)
+ print '%s }' % (indent)
+ indent += " "
+
+ [dim, width, height, depth, extent] = f.dimensions()
+
+ if dim < 3:
+ adjust = 20 + 4
+ else:
+ adjust = 36 + 4
+
+
+ print '%s emit_header(gc->pc, %s, cmdlen);' % (indent, f.opcode_real_name())
+
+ offset = self.pixel_emit_args(f, "gc->pc", indent, adjust, dim, 0)
+
+ [s, junk] = f.command_payload_length()
+
+ pixHeaderPtr = "gc->pc + 4"
+ pcPtr = "gc->pc + %u" % (s + 4)
+
+ if f.image.img_send_null:
+ condition = '(compsize > 0) && (%s != NULL)' % (f.image.name)
+ else:
+ condition = 'compsize > 0'
+
+ print '%s if (%s) {' % (indent, condition)
+ print '%s (*gc->fillImage)(gc, %u, %s, %s, %s, %s, %s, %s, %s, %s);' % (indent, dim, width, height, depth, f.image.img_format, f.image.img_type, f.image.name, pcPtr, pixHeaderPtr)
+ print '%s }' % (indent)
+ print '%s else {' % (indent)
+ print '%s (void) memcpy( %s, default_pixel_store_%uD, default_pixel_store_%uD_size );' % (indent, pixHeaderPtr, dim, dim)
+ print '%s }' % (indent)
+
+ print '%s gc->pc += cmdlen;' % (indent)
+ print '%s if (gc->pc > gc->limit) { (void) __glXFlushRenderBuffer(gc, gc->pc); }' % (indent)
+
+ if f.can_be_large:
+ adjust += 4
+
+ print '%s}' % (indent)
+ print '%selse {' % (indent)
+
+ self.large_emit_begin(indent, f)
+ offset = self.pixel_emit_args(f, "pc", indent, adjust, dim, 1)
+
+ pixHeaderPtr = "pc + 8"
+ pcPtr = "pc + %u" % (s + 8)
+
+ print '%s __glXSendLargeImage(gc, compsize, %u, %s, %s, %s, %s, %s, %s, %s, %s);' % (indent, dim, width, height, depth, f.image.img_format, f.image.img_type, f.image.name, pcPtr, pixHeaderPtr)
+
+ print '%s}' % (indent)
+
+ if trailer: print trailer
+ print '}'
+ print ''
+ return
+
+
def printRenderFunction(self, f):
# There is a class of GL functions that take a single pointer
# as a parameter. This pointer points to a fixed-size chunk