aboutsummaryrefslogtreecommitdiffstats
path: root/src/jogl/classes/jogamp/opengl/GLBufferSizeTracker.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/jogl/classes/jogamp/opengl/GLBufferSizeTracker.java')
-rw-r--r--src/jogl/classes/jogamp/opengl/GLBufferSizeTracker.java200
1 files changed, 200 insertions, 0 deletions
diff --git a/src/jogl/classes/jogamp/opengl/GLBufferSizeTracker.java b/src/jogl/classes/jogamp/opengl/GLBufferSizeTracker.java
new file mode 100644
index 000000000..fa05902d5
--- /dev/null
+++ b/src/jogl/classes/jogamp/opengl/GLBufferSizeTracker.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright (c) 2010 JogAmp Community. 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 jogamp.opengl;
+
+import javax.media.opengl.*;
+import com.jogamp.common.util.IntLongHashMap;
+
+/**
+ * Tracks as closely as possible the sizes of allocated OpenGL buffer
+ * objects. When glMapBuffer or glMapBufferARB is called, in order to
+ * turn the resulting base address into a java.nio.ByteBuffer, we need
+ * to know the size in bytes of the allocated OpenGL buffer object.
+ * Previously we would compute this size by using
+ * glGetBufferParameterivARB with a pname of GL_BUFFER_SIZE, but
+ * it appears doing so each time glMapBuffer is called is too costly
+ * on at least Apple's new multithreaded OpenGL implementation. <P>
+ *
+ * Instead we now try to track the sizes of allocated buffer objects.
+ * We watch calls to glBindBuffer to see which buffer is bound to
+ * which target and to glBufferData to see how large the buffer's
+ * allocated size is. When glMapBuffer is called, we consult our table
+ * of buffer sizes to see if we can return an answer without a glGet
+ * call. <P>
+ *
+ * We share the GLBufferSizeTracker objects among all GLContexts for
+ * which sharing is enabled, because the namespace for buffer objects
+ * is the same for these contexts. <P>
+ *
+ * Tracking the state of which buffer objects are bound is done in the
+ * GLBufferStateTracker and is not completely trivial. In the face of
+ * calls to glPushClientAttrib / glPopClientAttrib we currently punt
+ * and re-fetch the bound buffer object for the state in question;
+ * see, for example, glVertexPointer and the calls down to
+ * GLBufferStateTracker.getBoundBufferObject(). Note that we currently
+ * ignore new binding targets such as GL_TRANSFORM_FEEDBACK_BUFFER_NV;
+ * the fact that new binding targets may be added in the future makes
+ * it impossible to cache state for these new targets. <P>
+ *
+ * Ignoring new binding targets, the primary situation in which we may
+ * not be able to return a cached answer is in the case of an error,
+ * where glBindBuffer may not have been called before trying to call
+ * glBufferData. Also, if external native code modifies a buffer
+ * object, we may return an incorrect answer. (FIXME: this case
+ * requires more thought, and perhaps stochastic and
+ * exponential-fallback checking. However, note that it can only occur
+ * in the face of external native code which requires that the
+ * application be signed anyway, so there is no security risk in this
+ * area.)
+ */
+
+public class GLBufferSizeTracker {
+ protected static final boolean DEBUG;
+
+ static {
+ Debug.initSingleton();
+ DEBUG = Debug.isPropertyDefined("jogl.debug.GLBufferSizeTracker", true);
+ }
+
+ // Map from buffer names to sizes.
+ // Note: should probably have some way of shrinking this map, but
+ // can't just make it a WeakHashMap because nobody holds on to the
+ // keys; would have to always track creation and deletion of buffer
+ // objects, which is probably sub-optimal. The expected usage
+ // pattern of buffer objects indicates that the fact that this map
+ // never shrinks is probably not that bad.
+ private final IntLongHashMap bufferSizeMap;
+ private final long keyNotFount = 0xFFFFFFFFFFFFFFFFL;
+
+ public GLBufferSizeTracker() {
+ bufferSizeMap = new IntLongHashMap();
+ bufferSizeMap.setKeyNotFoundValue(keyNotFount);
+ }
+
+ public final void setBufferSize(GLBufferStateTracker bufferStateTracker,
+ int target, GL caller, long size) {
+ // Need to do some similar queries to getBufferSize below
+ int buffer = bufferStateTracker.getBoundBufferObject(target, caller);
+ if (buffer != 0) {
+ setDirectStateBufferSize(buffer, caller, size);
+ }
+ // We don't know the current buffer state. Note that the buffer
+ // state tracker will have made the appropriate OpenGL query if it
+ // didn't know what was going on, so at this point we have nothing
+ // left to do except drop this piece of information on the floor.
+ }
+
+ public final void setDirectStateBufferSize(int buffer, GL caller, long size) {
+ bufferSizeMap.put(buffer, size);
+ }
+
+ public final long getBufferSize(GLBufferStateTracker bufferStateTracker,
+ int target,
+ GL caller) {
+ // See whether we know what buffer is currently bound to the given
+ // state
+ final int buffer = bufferStateTracker.getBoundBufferObject(target, caller);
+ if (0 != buffer) {
+ return getBufferSizeImpl(target, buffer, caller);
+ }
+ // We don't know what's going on in this case; query the GL for an answer
+ // FIXME: both functions return 'int' types, which is not suitable,
+ // since buffer lenght is 64bit ?
+ int[] tmp = new int[1];
+ caller.glGetBufferParameteriv(target, GL.GL_BUFFER_SIZE, tmp, 0);
+ if (DEBUG) {
+ System.err.println("GLBufferSizeTracker.getBufferSize(): no cached buffer information");
+ }
+ return tmp[0];
+ }
+
+ public final long getDirectStateBufferSize(int buffer, GL caller) {
+ return getBufferSizeImpl(0, buffer, caller);
+ }
+
+ private final long getBufferSizeImpl(int target, int buffer, GL caller) {
+ // See whether we know the size of this buffer object; at this
+ // point we almost certainly should if the application is
+ // written correctly
+ long sz = bufferSizeMap.get(buffer);
+ if (keyNotFount == sz) {
+ // For robustness, try to query this value from the GL as we used to
+ // FIXME: both functions return 'int' types, which is not suitable,
+ // since buffer lenght is 64bit ?
+ int[] tmp = new int[1];
+ if(0==target) {
+ // DirectState ..
+ if(caller.isFunctionAvailable("glGetNamedBufferParameterivEXT")) {
+ caller.getGL2().glGetNamedBufferParameterivEXT(buffer, GL.GL_BUFFER_SIZE, tmp, 0);
+ } else {
+ throw new GLException("Error: getDirectStateBufferSize called with unknown state and GL function 'glGetNamedBufferParameterivEXT' n/a to query size");
+ }
+ } else {
+ caller.glGetBufferParameteriv(target, GL.GL_BUFFER_SIZE, tmp, 0);
+ }
+ if (tmp[0] == 0) {
+ // Assume something is wrong rather than silently going along
+ throw new GLException("Error: buffer size returned by "+
+ ((0==target)?"glGetNamedBufferParameterivEXT":"glGetBufferParameteriv")+
+ " was zero; probably application error");
+ }
+ // Assume we just don't know what's happening
+ sz = tmp[0];
+ bufferSizeMap.put(buffer, sz);
+ if (DEBUG) {
+ System.err.println("GLBufferSizeTracker.getBufferSize(): made slow query to cache size " +
+ sz +
+ " for buffer " +
+ buffer);
+ }
+ }
+ return sz;
+ }
+
+ // This should be called on any major event where we might start
+ // producing wrong answers, such as OpenGL context creation and
+ // destruction if we don't know whether there are other currently-
+ // created contexts that might be keeping the buffer objects alive
+ // that we're dealing with
+ public final void clearCachedBufferSizes() {
+ bufferSizeMap.clear();
+ }
+}