[PATCH 8/9] optionally track the GL state manually
Imre Deak
imre.deak at intel.com
Wed Apr 11 08:19:38 PDT 2012
At the moment apitrace uses GL/GLES calls to querry the current GL status.
This might not work if the underlying implementation doesn't support
these calls. This is the case at least with the Android software GL
implementation, where the following calls/arguments are not implemented:
- glGetIntegerv with the following pname parameters, with for example
GL_VERTEX_ARRAY_BUFFER_BINDING and in general any GL_*_ARRAY_BUFFER_BINDING
pname parameter.
- glEnabled with several cap parameters.
Also glGetBufferSubData is not supported by GLES, so we need to track
buffer contents, at least in some cases.
This patch won't provide tracking for the full state, only for those
parts that are essential for tracing GLES applications on Android. For
the rest fall back to calling the the platform's GL function as it's
used to be.
Signed-off-by: Imre Deak <imre.deak at intel.com>
---
glsize.hpp | 14 +++-
gltrace.hpp | 13 +++-
gltrace.py | 258 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
3 files changed, 272 insertions(+), 13 deletions(-)
diff --git a/glsize.hpp b/glsize.hpp
index d81cdf1..9c2f0c7 100644
--- a/glsize.hpp
+++ b/glsize.hpp
@@ -309,6 +309,14 @@ __glDrawArrays_maxindex(GLint first, GLsizei count)
#define __glDrawArraysEXT_maxindex __glDrawArrays_maxindex
+/* Forward declarations for definitions in gltrace.py */
+void
+__apitrace_glGetIntegerv(GLenum pname, GLint *params);
+
+void
+__apitrace_glGetBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size,
+ GLvoid *data);
+
static inline GLuint
__glDrawElementsBaseVertex_maxindex(GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex)
{
@@ -319,7 +327,8 @@ __glDrawElementsBaseVertex_maxindex(GLsizei count, GLenum type, const GLvoid *in
return 0;
}
- __glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &__element_array_buffer);
+ __apitrace_glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING,
+ &__element_array_buffer);
if (__element_array_buffer) {
// Read indices from index buffer object
GLintptr offset = (GLintptr)indices;
@@ -329,7 +338,8 @@ __glDrawElementsBaseVertex_maxindex(GLsizei count, GLenum type, const GLvoid *in
return 0;
}
memset(temp, 0, size);
- __glGetBufferSubData(GL_ELEMENT_ARRAY_BUFFER, offset, size, temp);
+ __apitrace_glGetBufferSubData(GL_ELEMENT_ARRAY_BUFFER, offset,
+ size, temp);
indices = temp;
} else {
if (!indices) {
diff --git a/gltrace.hpp b/gltrace.hpp
index e4fefc3..992b2d6 100644
--- a/gltrace.hpp
+++ b/gltrace.hpp
@@ -26,7 +26,8 @@
#ifndef _GLTRACE_HPP_
#define _GLTRACE_HPP_
-
+#include <map>
+#include <set>
#include "glimports.hpp"
@@ -39,11 +40,21 @@ enum Profile {
PROFILE_ES2,
};
+struct gl_buffer {
+ size_t size;
+ void *data;
+};
+
struct Context {
enum Profile profile;
bool user_arrays;
bool user_arrays_arb;
bool user_arrays_nv;
+ std::map <GLuint, GLuint> bindings;
+ std::map <GLuint, struct gl_buffer *> buffers;
+ std::set <GLenum> enabled_caps;
+ std::map <GLenum, const GLvoid *> pointers;
+ std::map <GLenum, GLuint> integers;
};
Context *
diff --git a/gltrace.py b/gltrace.py
index 6fc456c..24b560f 100644
--- a/gltrace.py
+++ b/gltrace.py
@@ -89,6 +89,23 @@ class TypeGetter(stdapi.Visitor):
def visitOpaque(self, pointer):
return self.prefix + 'Pointerv' + self.ext_suffix, 'GLvoid *'
+class TypeGetterManualTracking(TypeGetter):
+ def manualTrackingFunctionName(self, function_name):
+ return 'apitrace_' + function_name
+
+ def visitAlias(self, alias):
+ function_name, arg_type = TypeGetter.visitAlias(self, alias)
+ # We don't support yet the rest of the types
+ if alias.expr in ('GLint', 'GLuint', 'GLsizei'):
+ function_name = self.manualTrackingFunctionName(function_name)
+
+ return function_name, arg_type
+
+ def visitOpaque(self, pointer):
+ function_name, arg_type = TypeGetter.visitOpaque(self, pointer)
+ function_name = self.manualTrackingFunctionName(function_name)
+
+ return function_name, arg_type
class GlTracer(Tracer):
@@ -124,7 +141,7 @@ class GlTracer(Tracer):
print 'gltrace::getContext(void)'
print '{'
print ' // TODO return the context set by other APIs (GLX, EGL, and etc.)'
- print ' static gltrace::Context __ctx = { gltrace::PROFILE_COMPAT, false, false, false };'
+ print ' static gltrace::Context __ctx = { gltrace::PROFILE_COMPAT, };'
print ' return &__ctx;'
print '}'
print
@@ -148,6 +165,8 @@ class GlTracer(Tracer):
print '}'
print
+ self.defineManualTrackingHelpers()
+
# Whether we need user arrays
print 'static inline bool __need_user_arrays(void)'
print '{'
@@ -169,9 +188,9 @@ class GlTracer(Tracer):
print ' // %s' % function_name
print ' if (%s) {' % profile_check
self.array_prolog(api, uppercase_name)
- print ' if (__glIsEnabled(%s)) {' % enable_name
+ print ' if (__apitrace_glIsEnabled(%s)) {' % enable_name
print ' GLint __binding = 0;'
- print ' __glGetIntegerv(%s, &__binding);' % binding_name
+ print ' __apitrace_glGetIntegerv(%s, &__binding);' % binding_name
print ' if (!__binding) {'
self.array_cleanup(api, uppercase_name)
print ' return true;'
@@ -324,6 +343,224 @@ class GlTracer(Tracer):
print '}'
print
+ def manualTracking(self):
+ return False
+
+ def defineManualTrackingHelpers(self):
+ print 'void __apitrace_glGetIntegerv(GLenum pname, GLint *params)'
+ print '{'
+ if self.manualTracking():
+ print ' gltrace::Context *ctx = gltrace::getContext();'
+ print
+ print ' if (ctx->integers.find(pname) != ctx->integers.end())'
+ print ' *params = ctx->integers[pname];'
+ print ' else if (pname == GL_CLIENT_ACTIVE_TEXTURE)'
+ print ' *params = GL_TEXTURE0;'
+ print ' else'
+ print ' __glGetIntegerv(pname, params);'
+ else:
+ print ' __glGetIntegerv(pname, params);'
+ print '}'
+ print
+
+ print 'static GLboolean __apitrace_glIsEnabled(GLenum cap)'
+ print '{'
+ if self.manualTracking():
+ print ' gltrace::Context *ctx = gltrace::getContext();'
+ print ' std::set <GLenum> *caps = &ctx->enabled_caps;'
+ print
+ print ' if (caps->find(cap) != caps->end())'
+ print ' return true;'
+ print ' else'
+ print ' return __glIsEnabled(cap);'
+ else:
+ print ' return __glIsEnabled(cap);'
+ print '}'
+ print
+
+ print 'static void __apitrace_glGetPointerv(GLenum pname, GLvoid **params)'
+ print '{'
+ print ' gltrace::Context *ctx = gltrace::getContext();'
+ print ' *params = (void *)ctx->pointers[pname];'
+ print '}'
+ print
+
+ print 'void __apitrace_glGetBufferSubData(GLenum target,'
+ print ' GLintptr offset,'
+ print ' GLsizeiptr size,'
+ print ' GLvoid *data)'
+ print '{'
+ if self.manualTracking():
+ print ' if (target != GL_ELEMENT_ARRAY_BUFFER_BINDING) {'
+ print ' glGetBufferSubData(target, offset, size, data);'
+ print ' return;'
+ print ' }'
+ print ' struct gltrace::Context *ctx = gltrace::getContext();'
+ print ' struct gltrace::gl_buffer *buf;'
+ print ' GLint buf_id;'
+ print
+ print ' __apitrace_glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING,'
+ print ' &buf_id);'
+ print ' assert(buf_id == ctx->bindings[GL_ELEMENT_ARRAY_BUFFER]);'
+ print ' buf = ctx->buffers[buf_id];'
+ print ' assert(size + offset <= buf->size);'
+ print ' memcpy(data, (uint8_t *)buf->data + offset, size);'
+ else:
+ print ' glGetBufferSubData(target, offset, size, data);'
+ print '}'
+ print
+
+ def manualTrackingProlog(self, function):
+ if function.name == 'glBindBuffer':
+ print ' gltrace::Context *ctx = gltrace::getContext();'
+ print ' ctx->bindings[target] = buffer;'
+ print ' switch (target) {'
+ print ' case GL_ARRAY_BUFFER:'
+ print ' ctx->integers[GL_ARRAY_BUFFER_BINDING] = buffer;'
+ print ' break;'
+ print ' case GL_ELEMENT_ARRAY_BUFFER:'
+ print ' ctx->integers[GL_ELEMENT_ARRAY_BUFFER_BINDING] = buffer;'
+ print ' break;'
+ print ' case GL_PIXEL_UNPACK_BUFFER:'
+ print ' ctx->integers[GL_PIXEL_UNPACK_BUFFER_BINDING] = buffer;'
+ print ' break;'
+ print ' }'
+ print
+
+ if function.name == 'glBufferData':
+ print ' if (target == GL_ELEMENT_ARRAY_BUFFER) {'
+ print ' gltrace::Context *ctx = gltrace::getContext();'
+ print ' unsigned long buf_id = ctx->bindings[target];'
+ print ' struct gltrace::gl_buffer *buf;'
+ print ' if (ctx->buffers.find(buf_id) != ctx->buffers.end()) {'
+ print ' buf = ctx->buffers[buf_id];'
+ print ' } else {'
+ print ' buf = (struct gltrace::gl_buffer *)calloc(1, sizeof(*buf));'
+ print ' ctx->buffers[buf_id] = buf;'
+ print ' }'
+ print ' if (data) {'
+ print ' buf->data = realloc(buf->data, size);'
+ print ' buf->size = size;'
+ print ' memcpy(buf->data, data, size);'
+ print ' } else {'
+ print ' buf->size = 0;'
+ print ' free(buf->data);'
+ print ' buf->data = NULL;'
+ print ' }'
+ print ' }'
+ print
+
+ if function.name == 'glBufferSubData':
+ print ' if (target == GL_ELEMENT_ARRAY_BUFFER) {'
+ print ' gltrace::Context *ctx = gltrace::getContext();'
+ print ' struct gltrace::gl_buffer *buf;'
+ print ' unsigned long buf_id = ctx->bindings[target];'
+ print ' buf = ctx->buffers[buf_id];'
+ print ' memcpy((uint8_t *)buf->data + offset, data, size);'
+ print ' }'
+ print
+
+ if function.name == 'glDeleteBuffers':
+ print ' gltrace::Context *ctx = gltrace::getContext();'
+ print
+ print ' while (n) {'
+ print ' unsigned long buf_id;'
+ print ' struct gltrace::gl_buffer *buf;'
+ print ' n--;'
+ print ' buf_id = buffer[n];'
+ print ' buf = ctx->buffers[buf_id];'
+ print ' if (buf) {'
+ print ' free(buf->data);'
+ print ' free(buf);'
+ print ' ctx->buffers.erase(buf_id);'
+ print ' std::map <GLuint, GLuint>::iterator b;'
+ print
+ print ' b = ctx->bindings.begin();'
+ print ' while (b != ctx->bindings.end()) {'
+ print ' if (b->second != buf_id) {'
+ print ' b++;'
+ print ' continue;'
+ print ' }'
+ print ' ctx->bindings.erase(b++);'
+ print ' std::map <GLenum, GLuint>::iterator i;'
+ print ' i = ctx->integers.begin();'
+ print ' while (i != ctx->integers.end()) {'
+ print ' if (i->second != buf_id) {'
+ print ' i++;'
+ print ' continue;'
+ print ' }'
+ print
+ print ' switch (i->first) {'
+ for i in ['', 'ELEMENT_', 'VERTEX_', 'NORMAL_', 'COLOR_', 'INDEX_', 'TEXTURE_COORD_', 'EDGE_FLAG_', 'FOG_COORD_', 'SECONDARY_COLOR_']:
+ print ' case GL_%sARRAY_BUFFER_BINDING:' % i
+ print ' ctx->integers.erase(i++);'
+ print ' break;'
+ print ' }'
+ print ' }'
+ print ' }'
+ print ' }'
+ print ' }'
+
+ if function.name == 'glEnable':
+ print ' gltrace::Context *ctx = gltrace::getContext();'
+ print ' std::set <GLenum> *caps = &ctx->enabled_caps;'
+ print
+ # We don't care if the cap is valid here. We anyway use our own
+ # set of enabled caps for known-good values only. The traced
+ # application itself will use the native glIsEnabled instead (if
+ # it's supported.
+ print ' caps->insert(cap);'
+
+ if function.name == 'glEnableClientState':
+ print ' gltrace::Context *ctx = gltrace::getContext();'
+ print ' std::set <GLenum> *caps = &ctx->enabled_caps;'
+ print
+ # We don't care if the cap is valid here. We anyway use our own
+ # set of enabled caps for known-good values only. The traced
+ # application itself will use the native glIsEnabled instead (if
+ # it's supported.
+ print ' caps->insert(array);'
+
+ if function.name == 'glDisable':
+ print ' gltrace::Context *ctx = gltrace::getContext();'
+ print ' std::set <GLenum> *caps = &ctx->enabled_caps;'
+ print
+ print ' caps->erase(cap);'
+
+ if function.name == 'glDisableClientState':
+ print ' gltrace::Context *ctx = gltrace::getContext();'
+ print ' std::set <GLenum> *caps = &ctx->enabled_caps;'
+ print
+ print ' caps->erase(array);'
+
+ if function.name == 'glClientActiveTexture':
+ print ' gltrace::Context *ctx = gltrace::getContext();'
+ print
+ print ' ctx->integers[GL_CLIENT_ACTIVE_TEXTURE] = texture;'
+
+ pointer_functions = {
+ 'glVertexPointer': 'GL_VERTEX_ARRAY',
+ 'glTexCoordPointer': 'GL_TEXTURE_COORD_ARRAY',
+ 'glNormalPointer': 'GL_NORMAL_ARRAY',
+ 'glColorPointer': 'GL_COLOR_ARRAY',
+ }
+
+ if function.name in pointer_functions:
+ print ' gltrace::Context *ctx = gltrace::getContext();'
+ print ' GLuint binding;'
+ array_name = pointer_functions[function.name]
+ if function.name != 'glNormalPointer':
+ print ' ctx->integers[%s_SIZE] = size;' % array_name
+ print ' ctx->integers[%s_STRIDE] = stride;' % array_name
+ print ' ctx->integers[%s_TYPE] = type;' % array_name
+ print ' ctx->pointers[%s_POINTER] = pointer;' % array_name
+ print ' if (ctx->bindings.find(GL_ARRAY_BUFFER) != '
+ print ' ctx->bindings.end())'
+ print ' binding = ctx->bindings[GL_ARRAY_BUFFER];'
+ print ' else'
+ print ' binding = 0;'
+ print ' ctx->integers[%s_BUFFER_BINDING] = binding;' % array_name
+
array_pointer_function_names = set((
"glVertexPointer",
"glNormalPointer",
@@ -407,7 +644,7 @@ class GlTracer(Tracer):
# Defer tracing of user array pointers...
if function.name in self.array_pointer_function_names:
print ' GLint __array_buffer = 0;'
- print ' __glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &__array_buffer);'
+ print ' __apitrace_glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &__array_buffer);'
print ' if (!__array_buffer) {'
print ' gltrace::Context *ctx = gltrace::getContext();'
print ' ctx->user_arrays = true;'
@@ -607,6 +844,7 @@ class GlTracer(Tracer):
print ' }'
print ' }'
+ self.manualTrackingProlog(function)
Tracer.traceFunctionImplBody(self, function)
marker_functions = [
@@ -746,7 +984,7 @@ class GlTracer(Tracer):
def serializeArgValue(self, function, arg):
if function.name in self.draw_function_names and arg.name == 'indices':
print ' GLint __element_array_buffer = 0;'
- print ' __glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &__element_array_buffer);'
+ print ' __apitrace_glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &__element_array_buffer);'
print ' if (!__element_array_buffer) {'
if isinstance(arg.type, stdapi.Array):
print ' trace::localWriter.beginArray(%s);' % arg.type.length
@@ -772,7 +1010,7 @@ class GlTracer(Tracer):
print ' gltrace::Context *ctx = gltrace::getContext();'
print ' GLint __unpack_buffer = 0;'
print ' if (ctx->profile == gltrace::PROFILE_COMPAT)'
- print ' __glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &__unpack_buffer);'
+ print ' __apitrace_glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &__unpack_buffer);'
print ' if (__unpack_buffer) {'
print ' trace::localWriter.writeOpaque(%s);' % arg.name
print ' } else {'
@@ -822,15 +1060,15 @@ class GlTracer(Tracer):
print ' if (%s) {' % profile_check
self.array_trace_prolog(api, uppercase_name)
self.array_prolog(api, uppercase_name)
- print ' if (__glIsEnabled(%s)) {' % enable_name
+ print ' if (__apitrace_glIsEnabled(%s)) {' % enable_name
print ' GLint __binding = 0;'
- print ' __glGetIntegerv(%s, &__binding);' % binding_name
+ print ' __apitrace_glGetIntegerv(%s, &__binding);' % binding_name
print ' if (!__binding) {'
# Get the arguments via glGet*
for arg in function.args:
arg_get_enum = 'GL_%s_ARRAY_%s' % (uppercase_name, arg.name.upper())
- arg_get_function, arg_type = TypeGetter().visit(arg.type)
+ arg_get_function, arg_type = TypeGetterManualTracking().visit(arg.type)
print ' %s %s = 0;' % (arg_type, arg.name)
print ' __%s(%s, &%s);' % (arg_get_function, arg_get_enum, arg.name)
@@ -947,7 +1185,7 @@ class GlTracer(Tracer):
def array_prolog(self, api, uppercase_name):
if uppercase_name == 'TEXTURE_COORD':
print ' GLint client_active_texture = 0;'
- print ' __glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
+ print ' __apitrace_glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE, &client_active_texture);'
print ' GLint max_texture_coords = 0;'
print ' if (ctx->profile == gltrace::PROFILE_COMPAT)'
print ' __glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
--
1.7.5.4
More information about the apitrace
mailing list