diff options
author | Kenneth Russel <[email protected]> | 2006-11-26 06:02:27 +0000 |
---|---|---|
committer | Kenneth Russel <[email protected]> | 2006-11-26 06:02:27 +0000 |
commit | 3d445e164c242fb050dc6ecc8ca736731f7bcc67 (patch) | |
tree | 70b7ad77ca6090583fb6bc8a016c6b8ffaad1b40 /src/classes/com/sun/opengl/impl/GLBufferStateTracker.java | |
parent | 643849d65648411b55281ea5c87878e148dda97b (diff) |
Fixed another performance problem related to buffer objects pointed
out by John Burkey. glGetBufferParameterivARB call in glMapBuffer was
too expensive at least with Apple's multithreaded OpenGL
implementation. Now track both bound buffer state (refactored into
GLBufferStateTracker) as well as cache created buffers' sizes
(expressed in GLBufferSizeTracker) and query the cache instead of
OpenGL directly. Verified with VertexBufferObject demo that now no
glGet queries are made at run-time.
git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1003 232f8b59-042b-4e1e-8c03-345bb8c30851
Diffstat (limited to 'src/classes/com/sun/opengl/impl/GLBufferStateTracker.java')
-rwxr-xr-x | src/classes/com/sun/opengl/impl/GLBufferStateTracker.java | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/src/classes/com/sun/opengl/impl/GLBufferStateTracker.java b/src/classes/com/sun/opengl/impl/GLBufferStateTracker.java new file mode 100755 index 000000000..2c4a9963e --- /dev/null +++ b/src/classes/com/sun/opengl/impl/GLBufferStateTracker.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + * + * Sun gratefully acknowledges that this software was originally authored + * and developed by Kenneth Bradley Russell and Christopher John Kline. + */ + +package com.sun.opengl.impl; + +import java.util.*; +import javax.media.opengl.*; + +/** + * Tracks as closely as possible which OpenGL buffer object is bound + * to which binding target in the current OpenGL context. + * GLBufferStateTracker objects are allocated on a per-GLImpl basis, + * which is basically identical to a per-OpenGL-context basis + * (assuming correct usage of the GLImpl objects, which is checked by + * the DebugGL). This class is used to verify that e.g. the vertex + * buffer object extension is in use when the glVertexPointer variant + * taking a long as argument is called. <P> + * + * Note that because the enumerated value used for the binding of a + * buffer object (e.g. GL_ARRAY_BUFFER) is different than that used to + * query the binding using glGetIntegerv (e.g. + * GL_ARRAY_BUFFER_BINDING), then in the face of new binding targets + * being added to the GL (e.g. GL_TRANSFORM_FEEDBACK_BUFFER_NV) it is + * impossible to set up a query of the buffer object currently bound + * to a particular state. It turns out that for some uses, such as + * finding the size of the currently bound buffer, this doesn't + * matter, though of course without knowing the buffer object we can't + * re-associate the queried size with the buffer object ID. <P> + * + * Because the namespace of buffer objects is the unsigned integers + * with 0 reserved by the GL, and because we have to be able to return + * both 0 and other integers as valid answers from + * getBoundBufferObject(), we need a second query, which is to ask + * whether we know the state of the binding for a given target. For + * "unknown" targets such as GL_TRANSFORM_FEEDBACK_BUFFER_NV we return + * false from this, but we also clear the valid bit and later refresh + * the binding state if glPushClientAttrib / glPopClientAttrib are + * called, since we don't want the complexity of tracking stacks of + * these attributes. + * + */ + +public class GLBufferStateTracker { + private static final boolean DEBUG = Debug.debug("GLBufferStateTracker"); + + private static final Integer arrayBufferEnum = new Integer(GL.GL_ARRAY_BUFFER); + private static final Integer elementArrayBufferEnum = new Integer(GL.GL_ELEMENT_ARRAY_BUFFER); + private static final Integer pixelPackBufferEnum = new Integer(GL.GL_PIXEL_PACK_BUFFER); + private static final Integer pixelUnpackBufferEnum = new Integer(GL.GL_PIXEL_UNPACK_BUFFER); + private static final Integer zero = new Integer(0); + + // Maps binding targets to buffer objects. A null value indicates + // that the binding is unknown. A zero value indicates that it is + // known that no buffer is bound to the target. + private Map/*<Integer,Integer>*/ bindingMap = new HashMap/*<Integer,Integer>*/(); + + private int[] bufTmp = new int[1]; + + public GLBufferStateTracker() { + // Start with known unbound targets for known keys + bindingMap.put(arrayBufferEnum, zero); + bindingMap.put(elementArrayBufferEnum, zero); + bindingMap.put(pixelPackBufferEnum, zero); + bindingMap.put(pixelUnpackBufferEnum, zero); + } + + public void setBoundBufferObject(int target, int buffer) { + Integer key = box(target); + bindingMap.put(key, box(buffer)); + } + + /** Note: returns an unspecified value if the binding for the + specified target (e.g. GL_ARRAY_BUFFER) is currently unknown. + You must use isBoundBufferObjectKnown() to see whether the + return value is valid. */ + public int getBoundBufferObject(int target, GL caller) { + Integer key = box(target); + Integer value = (Integer) bindingMap.get(key); + if (value == null) { + // User probably either called glPushClientAttrib / + // glPopClientAttrib or is querying an unknown target. See + // whether we know how to fetch this state. + boolean gotQueryTarget = true; + int queryTarget = 0; + switch (target) { + case GL.GL_ARRAY_BUFFER: queryTarget = GL.GL_ARRAY_BUFFER_BINDING; break; + case GL.GL_ELEMENT_ARRAY_BUFFER: queryTarget = GL.GL_ELEMENT_ARRAY_BUFFER_BINDING; break; + case GL.GL_PIXEL_PACK_BUFFER: queryTarget = GL.GL_PIXEL_PACK_BUFFER_BINDING; break; + case GL.GL_PIXEL_UNPACK_BUFFER: queryTarget = GL.GL_PIXEL_UNPACK_BUFFER_BINDING; break; + default: gotQueryTarget = false; break; + } + if (gotQueryTarget) { + caller.glGetIntegerv(queryTarget, bufTmp, 0); + if (DEBUG) { + System.err.println("GLBufferStateTracker.getBoundBufferObject(): queried bound buffer " + + bufTmp[0] + + " for query target 0x" + Integer.toHexString(queryTarget)); + } + setBoundBufferObject(target, bufTmp[0]); + // Try once more + return getBoundBufferObject(target, caller); + } + return 0; + } + return value.intValue(); + } + + /** Indicates whether the binding state for the specified target is + currently known. Should be called after getBoundBufferObject() + because that method may change the answer for a given target. */ + public boolean isBoundBufferObjectKnown(int target) { + return (bindingMap.get(box(target)) != null); + } + + /** Clears out the known/unknown state of the various buffer object + binding states. These will be refreshed later on an as-needed + basis. This is called by the implementations of + glPushClientAttrib / glPopClientAttrib. Might want to call this + from GLContext.makeCurrent() in the future to possibly increase + the robustness of these caches in the face of external native + code manipulating OpenGL state. */ + public void clearBufferObjectState() { + bindingMap.clear(); + } + + // FIXME: could largely remove this and use Integer.valueOf() in JDK 5 + private static Integer box(int key) { + switch (key) { + case 0: return zero; + case GL.GL_ARRAY_BUFFER: return arrayBufferEnum; + case GL.GL_ELEMENT_ARRAY_BUFFER: return elementArrayBufferEnum; + case GL.GL_PIXEL_PACK_BUFFER: return pixelPackBufferEnum; + case GL.GL_PIXEL_UNPACK_BUFFER: return pixelUnpackBufferEnum; + default: return new Integer(key); + } + } +} |