Thread: [PyOpenGL-Devel] On pointer locks...
Brought to you by:
mcfletch
From: Mike C. F. <mcf...@ro...> - 2004-12-31 06:31:30
|
So this evening I've decided I need to figure out why we have this (to me) rather byzantine pointer lock mechanism in PyOpenGL. This is because we both have a bug somewhere in there and because I've been asked in email to explain it. This email is going to serve as a trace of my explorations as I try to figure them out... First, the reason: AFAICS, the purpose for a pointer "lock" is to keep track of how many internal OpenGL pointers are reliant on a given void*. The pointers are not actually tracking PyObject's, they're tracking void * pointers and using PyMem* operations on them to delete memory. They wind up with their own refcount mechanism as a result :( . Haven't yet figured out why the code is decrementing the values before various array-using calls, really seems as though the array-using calls should have no effect on the array-tracking calls... ah, looks as though "acquire" is incrementing the values. Question for myself: Why aren't we just tracking which PyObject is associated with a given pointer? That is, create a struct that holds a PyObject * and a "result pointer" for each array type. When we get a set (or even a get) pointer operation, check to see if the current pointer value (as returned from OpenGL) matches result pointer. If not, then we decrement the old PyObject (actually, we always decrement for set, but we can even do it on get if we want to release a Python-set value ASAP when C sets a value). When we do a getXPointer on a pointer value we didn't set through PyOpenGL we'd want to return something intelligent... don't know what yet... it's an unsized pointer, after all, don't want to be doing much with it if at all possible... maybe an opaque token that can only be passed back to PyOpenGL? But what about writing extensions that want to pass that pointer to something else (e.g. a multimedia library, for streaming). This is probably out-of-scope for now? When we do a getXPointer where we *did* set the value, of course, we want to return the PyObject. This all probably needs to be done on a per-context basis? Seems like it should be. Current code appears to just keep growing a list of pointer locks regardless of which context is involved. Works, but how does it know to clean up when the context goes away? For that matter, does the context *ever* go away (doesn't look like the code deals with the destruction of a context... how should it anyway, AFAIK we don't get notification from the C side for context destruction... hmm, may be no solution for that...)? Plan pseudo-code: class HolderRecord: PyObject * holder; void * pointer; context.arrayMapping = { #GL_ENUM: HolderRecord } def notePointer( enumerant, PyObject * holder, void * pointer ): currentContext.arrayMapping[ enumerant ] = HolderRecord( holder, pointer ) Now, if I'm figuring this correctly, by calling notePointer for every set method (after the actual set is completed, to avoid race conditions where the GL trys to access the old pointer which we just GC'd), with the explicit contract that holding a pointer to "holder" must keep "pointer" alive (and that deleting holder must delete pointer), should handle all of the cases the current code handles, while allowing for arbitrary new pointer types (e.g. from extensions) and hopefully simplifying the code somewhat. About that explicit contract. It should definitely be true for Python strings. Is it true for Numpy arrays (i.e. can the internal buffer location *change* for a given array (buffer can definitely resize, but that's not the issue at the moment, if you resize, you'll have to re-set the pointer (and we'll get a contiguous copy at that point)))? What will we do for cases where there's no natural holder object (e.g. when the user passes us a list or tuple of values). I'm tempted to say that we'll construct an appropriate Numpy array and store it internally, but wonder if creating an explicit buffer type would be better. IIRC there are data-types not available in Numpy which have GL types, which might mean we require a special type anyway (or we could hack it using same-sized data-values, I suppose, but that's un-lovely). I'm tempted to add a "size" to the HolderRecord and record the array size from the PyObject in order to allow for checking sizes in array-dependent operations... but then what do we do when something non-Pythonic sets the pointer (just ignore the lack of a known size I suppose). Punt that for now. Anyway, don't think I'm going to get this re-implemented tonight, so I guess I'll post this in case anyone feels like discussing it. I'm going to *try* to get some PyOpenGL and OpenGLContext time this weekend, btw. Have fun, Mike ________________________________________________ Mike C. Fletcher Designer, VR Plumber, Coder http://www.vrplumber.com http://blog.vrplumber.com |