Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

gltrace: Handle GL_EXT_compiled_vertex_array correctly.

Quake3 puts some vertices in its array buffer that it never renders.
This happens for clouds rendering as well as flares. (In other words, it
creates a vertex buffer with V vertices, and an index buffer that
reference indices substantially lower than V, max(I) < V).

It uses compiled vertex arrays, and will LockArrays(V) - more elements
than it actually references. This is legal because Quake3's arrays have
a static size, much bigger than however many vertices it puts in there,
so the driver can safely read the whole locked area even though half of
it is never referenced.

With Apitrace, however, the situation changes a bit, because Apitrace's
calculation for the length of a user pointer is based on max(draw
element indices).

Below is an example of Quake3's sky rendering:

  3466977 glLockArraysEXT(first = 0, count = 110)
  3466978 glEnableClientState(array = GL_TEXTURE_COORD_ARRAY)
  3466979 glEnableClientState(array = GL_COLOR_ARRAY)
  3466980 glEnableClientState(array = GL_COLOR_ARRAY)
  3466981 glBindTexture(target = GL_TEXTURE_2D, texture = 1132)
  3466982 glTexCoordPointer(size = 2, type = GL_FLOAT, stride = 0, pointer = blob(440))
  3466983 glClientActiveTexture(texture = GL_TEXTURE1)
  3466984 glTexCoordPointer(size = 2, type = GL_FLOAT, stride = 0, pointer = blob(440))
  3466985 glClientActiveTexture(texture = GL_TEXTURE0)
  3466986 glColorPointer(size = 4, type = GL_UNSIGNED_BYTE, stride = 0, pointer = blob(220))
  3466987 glVertexPointer(size = 3, type = GL_FLOAT, stride = 16, pointer = blob(876))
  3466988 glDrawElements(mode = GL_TRIANGLES, count = 192, type = GL_UNSIGNED_INT, indices = blob(768))

The glDrawElements only references indices from 0 to 54.

Under Apitrace, the trace only copies the 55 vertices, instead of the
110 locked values. When replaying, the driver, which may want to read
the whole locked area, will read past the 55 vertices. This doesn't
always crash because we're lucky, but on the NVIDIA driver this crashes
fairly reliably. According to the compiled array spec, the driver is
allowed to read all of the locked memory.

The fix is to change the array tracing so that its count is based on
max(drawelements_count, locked_count).

Thanks to Arthur Huillet for diagnosing the problem, the above
description, suggesting the fix, and testing it.

Tested-by: Arthur Huillet <arthur.huillet@free.fr>
  • Loading branch information...
commit 707630df1b4270eae3dd49b7344c645f32c1b5f4 1 parent 26be8f9
@jrfonseca jrfonseca authored
Showing with 15 additions and 0 deletions.
  1. +15 −0 wrappers/gltrace.py
View
15 wrappers/gltrace.py
@@ -111,6 +111,8 @@ class GlTracer(Tracer):
def header(self, api):
Tracer.header(self, api)
+ print '#include <algorithm>'
+ print
print '#include "gltrace.hpp"'
print
@@ -230,6 +232,10 @@ def header(self, api):
print 'static void _trace_user_arrays(GLuint count);'
print
+ print '// whether glLockArraysEXT() has ever been called'
+ print 'static bool _checkLockArraysEXT = false;'
+ print
+
# Buffer mappings
print '// whether glMapBufferRange(GL_MAP_WRITE_BIT) has ever been called'
print 'static bool _checkBufferMapRange = false;'
@@ -542,8 +548,17 @@ def traceFunctionImplBody(self, function):
print ' if (_need_user_arrays()) {'
arg_names = ', '.join([arg.name for arg in function.args[1:]])
print ' GLuint _count = _%s_count(%s);' % (function.name, arg_names)
+ # Some apps, in particular Quake3, can tell the driver to lock more
+ # vertices than those actually required for the draw call.
+ print ' if (_checkLockArraysEXT) {'
+ print ' GLuint _locked_count = _glGetInteger(GL_ARRAY_ELEMENT_LOCK_FIRST_EXT)'
+ print ' + _glGetInteger(GL_ARRAY_ELEMENT_LOCK_COUNT_EXT);'
+ print ' _count = std::max(_count, _locked_count);'
+ print ' }'
print ' _trace_user_arrays(_count);'
print ' }'
+ if function.name == 'glLockArraysEXT':
+ print ' _checkLockArraysEXT = true;'
# Emit a fake memcpy on buffer uploads
if function.name == 'glBufferParameteriAPPLE':
Please sign in to comment.
Something went wrong with that request. Please try again.