diff options
Diffstat (limited to 'src')
10 files changed, 899 insertions, 286 deletions
diff --git a/src/jogl/classes/com/jogamp/gluegen/opengl/BuildComposablePipeline.java b/src/jogl/classes/com/jogamp/gluegen/opengl/BuildComposablePipeline.java index df60d2f73..023913d7b 100644 --- a/src/jogl/classes/com/jogamp/gluegen/opengl/BuildComposablePipeline.java +++ b/src/jogl/classes/com/jogamp/gluegen/opengl/BuildComposablePipeline.java @@ -41,6 +41,7 @@ package com.jogamp.gluegen.opengl; import com.jogamp.gluegen.CodeGenUtils; import com.jogamp.gluegen.JavaType; + import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; @@ -50,6 +51,7 @@ import java.lang.reflect.Method; import java.nio.Buffer; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -82,6 +84,16 @@ public class BuildComposablePipeline { */ public static final int GEN_GL_IDENTITY_BY_ASSIGNABLE_CLASS = 1 << 4; + private static final HashMap<String, String> addedGLHooks = new HashMap<String, String>(); + private static final String[] addedGLHookMethodNames = new String[] { + "mapBuffer", "mapBufferRange", + "mapNamedBuffer", "mapNamedBufferRange" }; + static { + for(int i=0; i<addedGLHookMethodNames.length; i++) { + addedGLHooks.put(addedGLHookMethodNames[i], addedGLHookMethodNames[i]); + } + } + int mode; private final String outputDir; private final String outputPackage; @@ -200,8 +212,11 @@ public class BuildComposablePipeline { // Don't hook methods which aren't real GL methods, // such as the synthetic "isGL2ES2" "getGL2ES2" final String name = method.getName(); - boolean runHooks = name.startsWith("gl"); - if ( !name.startsWith("getGL") && !name.startsWith("isGL") && !name.equals("getDownstreamGL") && !name.equals("toString") ) { + if ( !name.startsWith("getGL") && + !name.startsWith("isGL") && + !name.equals("getDownstreamGL") && + !name.equals("toString") ) { + final boolean runHooks = name.startsWith("gl") || addedGLHooks.containsKey(name); publicMethodsPlain.add(new PlainMethod(method, runHooks)); } } diff --git a/src/jogl/classes/javax/media/opengl/GLBase.java b/src/jogl/classes/javax/media/opengl/GLBase.java index a19a99196..3ac12f0a1 100644 --- a/src/jogl/classes/javax/media/opengl/GLBase.java +++ b/src/jogl/classes/javax/media/opengl/GLBase.java @@ -505,26 +505,97 @@ public interface GLBase { public void glDepthRange(double zNear, double zFar); /** - * @param target a GL buffer (VBO) target as used in {@link GL#glBindBuffer(int, int)}, ie {@link GL#GL_ELEMENT_ARRAY_BUFFER}, {@link GL#GL_ARRAY_BUFFER}, .. - * @return the GL buffer (VBO) name bound to a target via {@link GL#glBindBuffer(int, int)} or 0 if unbound. + * @deprecated Avoid original GL API namespace conflict. Use {@link #getBoundBuffer(int)} */ public int glGetBoundBuffer(int target); + /** + * @param target a GL buffer (VBO) target as used in {@link GL#glBindBuffer(int, int)}, ie {@link GL#GL_ELEMENT_ARRAY_BUFFER}, {@link GL#GL_ARRAY_BUFFER}, .. + * @return the GL buffer name bound to a target via {@link GL#glBindBuffer(int, int)} or 0 if unbound. + * @see #getBufferStorage(int) + */ + public int getBoundBuffer(int target); /** - * @param buffer a GL buffer name, generated with {@link GL#glGenBuffers(int, int[], int)} and used in {@link GL#glBindBuffer(int, int)}, {@link GL#glBufferData(int, long, java.nio.Buffer, int)} or {@link GL2#glNamedBufferDataEXT(int, long, java.nio.Buffer, int)} for example. - * @return the size of the given GL buffer + * @deprecated Use {@link #getBufferStorage(int)}. */ - public long glGetBufferSize(int buffer); + public long glGetBufferSize(int bufferName); + /** + * @param bufferName a GL buffer name, generated with e.g. {@link GL#glGenBuffers(int, int[], int)} and used in {@link GL#glBindBuffer(int, int)}, {@link GL#glBufferData(int, long, java.nio.Buffer, int)} or {@link GL2#glNamedBufferDataEXT(int, long, java.nio.Buffer, int)}. + * @return the size of the given GL buffer storage, see {@link GLBufferStorage} + * @see #getBoundBuffer(int) + */ + public GLBufferStorage getBufferStorage(int bufferName); /** - * @return true if a VBO is bound to {@link GL#GL_ARRAY_BUFFER} via {@link GL#glBindBuffer(int, int)}, otherwise false + * Returns the {@link GLBufferStorage} instance as mapped via OpenGL's native {@link GL#glMapBuffer(int, int) glMapBuffer(..)} implementation. + * <p> + * Throws a {@link GLException} if GL-function constraints are not met. + * </p> + * <p> + * {@link GL#glMapBuffer(int, int)} wrapper calls this method and returns {@link GLBufferStorage#getMappedBuffer()}. + * </p> + * <p> + * A zero {@link GLBufferStorage#getSize()} will avoid a native call and returns the unmapped {@link GLBufferStorage}. + * </p> + * <p> + * A null native mapping result indicating an error will + * not cause a GLException but returns the unmapped {@link GLBufferStorage}. + * This allows the user to handle this case. + * </p> + * @param target denotes the buffer via it's bound target + * @param access the mapping access mode + * @throws GLException if buffer is not bound to target + * @throws GLException if buffer is not tracked + * @throws GLException if buffer is already mapped + * @throws GLException if buffer has invalid store size, i.e. less-than zero + */ + public GLBufferStorage mapBuffer(int target, int access) throws GLException; + + /** + * Returns the {@link GLBufferStorage} instance as mapped via OpenGL's native {@link GL#glMapBufferRange(int, long, long, int) glMapBufferRange(..)} implementation. + * <p> + * Throws a {@link GLException} if GL-function constraints are not met. + * </p> + * <p> + * {@link GL#glMapBufferRange(int, long, long, int)} wrapper calls this method and returns {@link GLBufferStorage#getMappedBuffer()}. + * </p> + * <p> + * A zero {@link GLBufferStorage#getSize()} will avoid a native call and returns the unmapped {@link GLBufferStorage}. + * </p> + * <p> + * A null native mapping result indicating an error will + * not cause a GLException but returns the unmapped {@link GLBufferStorage}. + * This allows the user to handle this case. + * </p> + * @param target denotes the buffer via it's bound target + * @param offset offset of the mapped buffer's storage + * @param length length of the mapped buffer's storage + * @param access the mapping access mode + * @throws GLException if buffer is not bound to target + * @throws GLException if buffer is not tracked + * @throws GLException if buffer is already mapped + * @throws GLException if buffer has invalid store size, i.e. less-than zero + * @throws GLException if buffer mapping range does not fit, incl. offset + */ + public GLBufferStorage mapBufferRange(final int target, final long offset, final long length, final int access) throws GLException; + + /** + * @deprecated Avoid original GL API namespace conflict. Use {@link #isVBOArrayBound()} */ public boolean glIsVBOArrayBound(); + /** + * @return true if a VBO is bound to {@link GL#GL_ARRAY_BUFFER} via {@link GL#glBindBuffer(int, int)}, otherwise false + */ + public boolean isVBOArrayBound(); /** - * @return true if a VBO is bound to {@link GL#GL_ELEMENT_ARRAY_BUFFER} via {@link GL#glBindBuffer(int, int)}, otherwise false + * @deprecated Avoid original GL API namespace conflict. Use {@link #isVBOElementArrayBound()} */ public boolean glIsVBOElementArrayBound(); + /** + * @return true if a VBO is bound to {@link GL#GL_ELEMENT_ARRAY_BUFFER} via {@link GL#glBindBuffer(int, int)}, otherwise false + */ + public boolean isVBOElementArrayBound(); /** * Return the framebuffer name bound to this context, diff --git a/src/jogl/classes/javax/media/opengl/GLBufferStorage.java b/src/jogl/classes/javax/media/opengl/GLBufferStorage.java new file mode 100644 index 000000000..929ecf60a --- /dev/null +++ b/src/jogl/classes/javax/media/opengl/GLBufferStorage.java @@ -0,0 +1,150 @@ +/** + * Copyright 2014 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: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package javax.media.opengl; + +import java.nio.ByteBuffer; +import java.nio.IntBuffer; + +/** + * OpenGL buffer storage object reflecting it's + * <ul> + * <li>storage size</li> + * <li>storage memory if mapped</li> + * <li>mutable usage or immutable flags</li> + * </ul> + * <p> + * Buffer storage is created via: + * <ul> + * <li><code>glBufferStorage</code> - storage creation with target</li> + * <li>{@link GL#glBufferData(int, long, java.nio.Buffer, int)} - storage recreation with target</li> + * <li>{@link GL2#glNamedBufferDataEXT(int, long, java.nio.Buffer, int)} - storage recreation, direct</li> + * </ul> + * Note that storage <i>recreation</i> as mentioned above also invalidate a previous storage instance, + * i.e. disposed the buffer's current storage if exist and attaches a new storage instance. + * </p> + * <p> + * Buffer storage is disposed via: + * <ul> + * <li>{@link GL#glDeleteBuffers(int, IntBuffer)} - explicit, direct, via {@link #notifyBuffersDeleted(int, IntBuffer)} or {@link #notifyBuffersDeleted(int, int[], int)}</li> + * <li>{@link GL#glBufferData(int, long, java.nio.Buffer, int)} - storage recreation via target</li> + * <li>{@link GL2#glNamedBufferDataEXT(int, long, java.nio.Buffer, int)} - storage recreation, direct</li> + * </ul> + * </p> + * <p> + * GL buffer storage is mapped via + * <ul> + * + * <li>{@link GL#mapBuffer(int, int)}</li> + * <li>{@link GL#mapBufferRange(int, long, long, int)}</li> + * <li>{@link GL2#mapNamedBuffer(int, int)}</li> + * <li>{@link GL2#mapNamedBufferRange(int, long, long, int)}</li> + * </ul> + * </p> + * <p> + * GL buffer storage is unmapped via + * <ul> + * <li>{@link GL#glUnmapBuffer(int)} - explicit via target</li> + * <li>{@link GL2#glUnmapNamedBufferEXT(int)} - explicit direct</li> + * <li>{@link GL#glBufferData(int, long, java.nio.Buffer, int)} - storage recreation via target</li> + * <li>{@link GL2#glNamedBufferDataEXT(int, long, java.nio.Buffer, int)} - storage recreation, direct</li> + * <li>{@link GL#glDeleteBuffers(int, IntBuffer)} - buffer deletion</li> + * </ul> + * </p> + */ +public abstract class GLBufferStorage { + private final int name; + private final long size; + private final int mutableUsage; + private final int immutableFlags; + protected ByteBuffer mappedBuffer; + + protected GLBufferStorage(final int name, final long size, final int mutableUsage, final int immutableFlags) { + this.name = name; + this.size = size; + this.mutableUsage = mutableUsage; + this.immutableFlags = immutableFlags; + this.mappedBuffer = null; + } + + /** Return the buffer name */ + public final int getName() { return name; } + + /** Return the buffer's storage size. */ + public final long getSize() { return size; } + + /** + * Returns <code>true</code> if buffer's storage is mutable, i.e. + * created via {@link GL#glBufferData(int, long, java.nio.Buffer, int)}. + * <p> + * Returns <code>false</code> if buffer's storage is immutable, i.e. + * created via <code>glBufferStorage</code>. FIXME: Add GL 4.4 support! + * </p> + * @return + */ + public final boolean isMutableStorage() { return 0 != mutableUsage; } + + /** + * Returns the mutable storage usage or 0 if storage is not {@link #isMutableStorage() mutable}. + */ + public final int getMutableUsage() { return mutableUsage; } + + /** + * Returns the immutable storage flags, invalid if storage is {@link #isMutableStorage() mutable}. + */ + public final int getImmutableFlags() { return immutableFlags; } + + /** + * Returns the mapped ByteBuffer, or null if not mapped. + * Mapping may occur via: + * <ul> + * <li>{@link GL#glMapBuffer(int, int)}</li> + * <li>{@link GL#glMapBufferRange(int, long, long, int)}</li> + * <li>{@link GL2#glMapNamedBufferEXT(int, int)}</li> + * <li>{@link GL2#glMapNamedBufferRangeEXT(int, long, long, int)} + * </ul> + */ + public final ByteBuffer getMappedBuffer() { return mappedBuffer; } + + public final String toString() { + return toString(false); + } + public final String toString(final boolean skipMappedBuffer) { + final String s0; + if( isMutableStorage() ) { + s0 = String.format("%s[name %s, size %d, mutable usage 0x%X", msgClazzName, name, size, mutableUsage); + } else { + s0 = String.format("%s[name %s, size %d, immutable flags 0x%X", msgClazzName, name, size, immutableFlags); + } + if(skipMappedBuffer) { + return s0+"]"; + } else { + return s0+", mapped "+mappedBuffer+"]"; + } + } + private final String msgClazzName = "GLBufferStorage"; +} diff --git a/src/jogl/classes/javax/media/opengl/GLContext.java b/src/jogl/classes/javax/media/opengl/GLContext.java index bec62c30d..0b0ed8e0d 100644 --- a/src/jogl/classes/javax/media/opengl/GLContext.java +++ b/src/jogl/classes/javax/media/opengl/GLContext.java @@ -1622,8 +1622,8 @@ public abstract class GLContext { final Integer valI = deviceVersionAvailable.get(key); if(null != valI) { final int bits32 = valI.intValue(); - final int major = ( bits32 & 0xFF000000 ) >> 24 ; - final int minor = ( bits32 & 0x00FF0000 ) >> 16 ; + final int major = ( bits32 & 0xFF000000 ) >>> 24 ; + final int minor = ( bits32 & 0x00FF0000 ) >>> 16 ; final int ctp = ( bits32 & 0x0000FFFF ) ; sb.append(GLContext.getGLVersion(major, minor, ctp, null)); } else { @@ -1668,10 +1668,10 @@ public abstract class GLContext { final int bits32 = valI.intValue(); if(null!=major) { - major[0] = ( bits32 & 0xFF000000 ) >> 24 ; + major[0] = ( bits32 & 0xFF000000 ) >>> 24 ; } if(null!=minor) { - minor[0] = ( bits32 & 0x00FF0000 ) >> 16 ; + minor[0] = ( bits32 & 0x00FF0000 ) >>> 16 ; } if(null!=ctp) { ctp[0] = ( bits32 & 0x0000FFFF ) ; diff --git a/src/jogl/classes/jogamp/opengl/GLBufferObjectTracker.java b/src/jogl/classes/jogamp/opengl/GLBufferObjectTracker.java new file mode 100644 index 000000000..289884b5c --- /dev/null +++ b/src/jogl/classes/jogamp/opengl/GLBufferObjectTracker.java @@ -0,0 +1,532 @@ +/* + * 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 java.nio.Buffer; +import java.nio.ByteBuffer; +import java.nio.IntBuffer; + +import javax.media.opengl.*; + +import com.jogamp.common.nio.Buffers; +import com.jogamp.common.util.IntObjectHashMap; + +/** + * Tracking of {@link GLBufferStorage} instances via GL API callbacks. + * <p> + * See {@link GLBufferStorage} for generic details. + * </p> + * <p> + * Buffer storage is created via + * <ul> + * <li><code>glBufferStorage</code> - storage creation with target via {@link #createBufferStorage(GLBufferStateTracker, GL, int, long, Buffer, int, int, CreateStorageDispatch, long)}</li> + * <li>{@link GL#glBufferData(int, long, java.nio.Buffer, int)} - storage recreation with target via {@link #createBufferStorage(GLBufferStateTracker, GL, int, long, Buffer, int, int, CreateStorageDispatch, long)}</li> + * <li>{@link GL2#glNamedBufferDataEXT(int, long, java.nio.Buffer, int)} - storage recreation, direct, via {@link #createBufferStorage(GL, int, long, Buffer, int, CreateStorageDispatch, long)}</li> + * </ul> + * Note that storage <i>recreation</i> as mentioned above also invalidate a previous storage instance, + * i.e. disposed the buffer's current storage if exist and attaches a new storage instance. + * </p> + * <p> + * Buffers storage is disposed via + * <ul> + * <li>{@link GL#glDeleteBuffers(int, IntBuffer)} - explicit, direct, via {@link #notifyBuffersDeleted(int, IntBuffer)} or {@link #notifyBuffersDeleted(int, int[], int)}</li> + * <li>{@link GL#glBufferData(int, long, java.nio.Buffer, int)} - storage recreation via target</li> + * <li>{@link GL2#glNamedBufferDataEXT(int, long, java.nio.Buffer, int)} - storage recreation, direct</li> + * </ul> + * </p> + * + * <p> + * Implementation throws a {@link GLException} in all <i>construction</i> methods as listed below, + * if GL-function constraints are not met. <code>createBufferStorage</code> also throws an exception + * if the native GL-function fails. + * <ul> + * <li>{@link #createBufferStorage(GLBufferStateTracker, GL, int, long, Buffer, int, int, CreateStorageDispatch, long)}, etc ..</li> + * <li>{@link #mapBuffer(GLBufferStateTracker, GL, int, int, MapBufferAllDispatch, long)}, etc ..</li> + * </ul> + * In <i>destruction</i> and informal methods, i.e. all others, implementation only issues a WARNING debug message, if enabled. + * </p> + * + * <p> + * Buffer mapping methods like {@link GL#mapBuffer(int, int)} ..., + * require knowledge of the buffer's storage size as determined via it's creation with + * {@link GL#glBufferData(int, long, java.nio.Buffer, int)} .... + * </p> + * <p> + * Hence we track the OpenGL buffer's {@link GLBufferStorage} to be able to + * access the buffer's storage size. The tracked {@link GLBufferStorage} instances + * also allow users to conveniently access details of their created and maybe mapped buffer storage. + * </p> + * <p> + * The {@link GLBufferObjectTracker} and it's tracked {@link GLBufferStorage} instances + * maybe shared across multiple OpenGL context, hence this class is thread safe and employs synchronization. + * </p> + * <p> + * Implementation requires and utilizes a local {@link GLBufferStateTracker} + * to resolve the actual buffer-name bound to the given target. + * </p> + * <p> + * Note: This tracker requires to be notified about all OpenGL buffer storage operations, + * as well as the local {@link GLBufferStateTracker} to be notified about all + * OpenGL buffer binding operations. + * Hence buffer storage cannot be accessed properly if managed via native code. + * </p> + */ +public class GLBufferObjectTracker { + protected static final boolean DEBUG; + + static { + Debug.initSingleton(); + DEBUG = Debug.isPropertyDefined("jogl.debug.GLBufferObjectTracker", true); + } + + static final class GLBufferStorageImpl extends GLBufferStorage { + GLBufferStorageImpl(final int name, final long size, final int mutableUsage, final int immutableFlags) { + super(name, size, mutableUsage, immutableFlags); + } + final void setMappedBuffer(final ByteBuffer bb) { + if (DEBUG) { + System.err.printf("%s.GLBufferStorage.setMappedBuffer: %s: %s -> %s%n", msgClazzName, toString(true), mappedBuffer, bb); + } + mappedBuffer = bb; + } + } + + /** + * Map from buffer names to GLBufferObject. + */ + private final IntObjectHashMap bufferName2StorageMap; + + public GLBufferObjectTracker() { + bufferName2StorageMap = new IntObjectHashMap(); + bufferName2StorageMap.setKeyNotFoundValue(null); + } + + public static interface CreateStorageDispatch { + void create(final int targetOrBufferName, final long size, final Buffer data, final int mutableUsageOrImmutableFlags, final long glProcAddress); + } + + /** + * Must be called when [re]creating the GL buffer object via <code>glBufferStorage</code> and {@link GL#glBufferData(int, long, java.nio.Buffer, int)}, + * i.e. implies destruction of the buffer. + * + * @param bufferStateTracker + * @param caller + * @param target + * @param size + * @param mutableUsage <code>glBufferData</code>, <code>glNamedBufferDataEXT</code> usage + * @param immutableFlags <code>glBufferStorage</code> flags + * @throws GLException if buffer is not bound to target + * @throws GLException if size is less-or-eqaul zero for <code>glBufferStorage</code>, or size is less-than zero otherwise + * @throws GLException if a native GL-Error occurs + */ + public synchronized final void createBufferStorage(final GLBufferStateTracker bufferStateTracker, final GL caller, + final int target, final long size, final Buffer data, int mutableUsage, int immutableFlags, + final CreateStorageDispatch dispatch, final long glProcAddress) throws GLException { + final int glerrPre = caller.glGetError(); // clear + if (DEBUG && GL.GL_NO_ERROR != glerrPre) { + System.err.printf("%s.%s glerr-pre 0x%X%n", msgClazzName, msgCreateBound, glerrPre); + } + final int bufferName = bufferStateTracker.getBoundBufferObject(target, caller); + if ( 0 == bufferName ) { + throw new GLException(String.format("%s: Buffer for target 0x%X not bound", GL_INVALID_OPERATION, target)); + } + final boolean mutableBuffer = 0 != mutableUsage; + final boolean invalidSize = ( mutableBuffer && 0 > size ) // glBufferData, glNamedBufferDataEXT + || ( !mutableBuffer && 0 >= size ); // glBufferStorage + if( invalidSize ) { + throw new GLException(String.format("%s: Invalid size %d for buffer %d on target 0x%X", GL_INVALID_VALUE, size, bufferName, target)); + } + + dispatch.create(target, size, data, mutableBuffer ? mutableUsage : immutableFlags, glProcAddress); + final int glerrPost = caller.glGetError(); // be safe, catch failure! + if(GL.GL_NO_ERROR != glerrPost) { + throw new GLException(String.format("GL-Error 0x%X while creating %s storage for target 0x%X -> buffer %d of size %d with data %s", + glerrPost, mutableBuffer ? "mutable" : "immutable", target, bufferName, size, data)); + } + final GLBufferStorageImpl objNew = new GLBufferStorageImpl(bufferName, size, mutableUsage, immutableFlags); + final GLBufferStorageImpl objOld = (GLBufferStorageImpl) bufferName2StorageMap.put(bufferName, objNew); + if (DEBUG) { + System.err.printf("%s.%s target: 0x%X -> %d: %s -> %s%n", msgClazzName, msgCreateBound, target, bufferName, objOld, objNew); + } + if( null != objOld ) { + objOld.setMappedBuffer(null); + } + } + + /** + * Must be called when [re]creating the GL buffer object via {@link GL2#glNamedBufferDataEXT(int, long, java.nio.Buffer, int)}, + * i.e. implies destruction of the buffer. + * + * @param bufferName + * @param size + * @param mutableUsage + * @throws GLException if size is less-than zero + * @throws GLException if a native GL-Error occurs + */ + public synchronized final void createBufferStorage(final GL caller, + final int bufferName, final long size, final Buffer data, final int mutableUsage, int immutableFlags, + final CreateStorageDispatch dispatch, final long glProcAddress) throws GLException { + final int glerrPre = caller.glGetError(); // clear + if (DEBUG && GL.GL_NO_ERROR != glerrPre) { + System.err.printf("%s.%s glerr-pre 0x%X%n", msgClazzName, msgCreateNamed, glerrPre); + } + if ( 0 > size ) { // glBufferData, glNamedBufferDataEXT + throw new GLException(String.format("%s: Invalid size %d for buffer %d", GL_INVALID_VALUE, size, bufferName)); + } + final boolean mutableBuffer = 0 != mutableUsage; + if( !mutableBuffer ) { + throw new InternalError("Immutable glNamedBufferStorageEXT not supported yet"); + } + dispatch.create(bufferName, size, data, mutableUsage, glProcAddress); + final int glerrPost = caller.glGetError(); // be safe, catch failure! + if(GL.GL_NO_ERROR != glerrPost) { + throw new GLException(String.format("GL-Error 0x%X while creating %s storage for buffer %d of size %d with data %s", + glerrPost, "mutable", bufferName, size, data)); + } + final GLBufferStorageImpl objNew = new GLBufferStorageImpl(bufferName, size, mutableUsage, 0 /* immutableFlags */); + final GLBufferStorageImpl objOld = (GLBufferStorageImpl) bufferName2StorageMap.put(bufferName, objNew); + if (DEBUG) { + System.err.printf("%s.%s direct: %d: %s -> %s%n", msgClazzName, msgCreateNamed, bufferName, objOld, objNew); + } + if( null != objOld ) { + objOld.setMappedBuffer(null); + } + } + + /** + * Must be called when deleting GL buffer objects vis <code>glDeleteBuffers</code>. + * @param count + * @param bufferNames + * @param offset + */ + public synchronized final void notifyBuffersDeleted(final int count, final int[] bufferNames, final int offset) { + for(int i=0; i<count; i++) { + notifyBufferDeleted(bufferNames[i+offset], i, count); + } + } + /** + * Must be called when deleting GL buffer objects vis <code>glDeleteBuffers</code>. + * @param n + * @param bufferNames + */ + public synchronized final void notifyBuffersDeleted(final int n, final IntBuffer bufferNames) { + final int offset = bufferNames.position(); + for(int i=0; i<n; i++) { + notifyBufferDeleted(bufferNames.get(i+offset), i, n); + } + } + /** + * Must be called when deleting GL buffer objects vis {@link GL#glDeleteBuffers(int, IntBuffer)}. + * @param bufferName + * @param i + * @param count + */ + private synchronized final void notifyBufferDeleted(final int bufferName, final int i, final int count) { + final GLBufferStorageImpl objOld = (GLBufferStorageImpl) bufferName2StorageMap.put(bufferName, null); + if (DEBUG) { + System.err.printf("%s.notifyBuffersDeleted()[%d/%d]: %d: %s -> null%n", msgClazzName, i+1, count, bufferName, objOld); + } + if( null == objOld ) { + if (DEBUG) { + System.err.printf("%s: %s.notifyBuffersDeleted()[%d/%d]: Buffer %d not tracked%n", warning, msgClazzName, i+1, count, bufferName); + Thread.dumpStack(); + } + return; + } + objOld.setMappedBuffer(null); + } + + public static interface MapBufferDispatch { + ByteBuffer allocNioByteBuffer(final long addr, final long length); + } + public static interface MapBufferRangeDispatch extends MapBufferDispatch { + long mapBuffer(final int targetOrBufferName, final long offset, final long length, final int access, final long glProcAddress); + } + public static interface MapBufferAllDispatch extends MapBufferDispatch { + long mapBuffer(final int targetOrBufferName, final int access, final long glProcAddress); + } + + private static final String GL_INVALID_OPERATION = "GL_INVALID_OPERATION"; + private static final String GL_INVALID_VALUE = "GL_INVALID_VALUE"; + + /** + * Must be called when mapping GL buffer objects via {@link GL#mapBuffer(int, int)}. + * @throws GLException if buffer is not bound to target + * @throws GLException if buffer is not tracked + * @throws GLException if buffer is already mapped + * @throws GLException if buffer has invalid store size, i.e. less-than zero + */ + public synchronized final GLBufferStorage mapBuffer(final GLBufferStateTracker bufferStateTracker, + final GL caller, final int target, final int access, + final MapBufferAllDispatch dispatch, final long glProcAddress) throws GLException { + return this.mapBufferImpl(bufferStateTracker, caller, target, false /* useRange */, 0 /* offset */, 0 /* length */, access, dispatch, glProcAddress); + } + /** + * Must be called when mapping GL buffer objects via {@link GL#mapBufferRange(int, long, long, int)}. + * @throws GLException if buffer is not bound to target + * @throws GLException if buffer is not tracked + * @throws GLException if buffer is already mapped + * @throws GLException if buffer has invalid store size, i.e. less-than zero + * @throws GLException if buffer mapping range does not fit, incl. offset + */ + public synchronized final GLBufferStorage mapBuffer(final GLBufferStateTracker bufferStateTracker, + final GL caller, final int target, final long offset, final long length, final int access, + final MapBufferRangeDispatch dispatch, final long glProcAddress) throws GLException { + return this.mapBufferImpl(bufferStateTracker, caller, target, true /* useRange */, length, access, access, dispatch, glProcAddress); + } + /** + * Must be called when mapping GL buffer objects via {@link GL2#mapNamedBuffer(int, int)}. + * @throws GLException if buffer is not tracked + * @throws GLException if buffer is already mapped + * @throws GLException if buffer has invalid store size, i.e. less-than zero + */ + public synchronized final GLBufferStorage mapBuffer(final int bufferName, final int access, final MapBufferAllDispatch dispatch, + final long glProcAddress) throws GLException { + return this.mapBufferImpl(0 /* target */, bufferName, true /* isNamedBuffer */, false /* useRange */, 0 /* offset */, 0 /* length */, access, dispatch, glProcAddress); + } + /** + * Must be called when mapping GL buffer objects via {@link GL2#mapNamedBufferRange(int, long, long, int)}. + * @throws GLException if buffer is not tracked + * @throws GLException if buffer is already mapped + * @throws GLException if buffer has invalid store size, i.e. less-than zero + * @throws GLException if buffer mapping range does not fit, incl. offset + */ + public synchronized final GLBufferStorage mapBuffer(final int bufferName, final long offset, final long length, final int access, final MapBufferRangeDispatch dispatch, + final long glProcAddress) throws GLException { + return this.mapBufferImpl(0 /* target */, bufferName, true /* isNamedBuffer */, false /* useRange */, 0 /* offset */, 0 /* length */, access, dispatch, glProcAddress); + } + /** + * @throws GLException if buffer is not bound to target + * @throws GLException if buffer is not tracked + * @throws GLException if buffer is already mapped + * @throws GLException if buffer has invalid store size, i.e. less-than zero + * @throws GLException if buffer mapping range does not fit, incl. optional offset + */ + private synchronized final GLBufferStorage mapBufferImpl(final GLBufferStateTracker bufferStateTracker, + final GL caller, final int target, final boolean useRange, + long offset, long length, final int access, + final MapBufferDispatch dispatch, final long glProcAddress) throws GLException { + final int bufferName = bufferStateTracker.getBoundBufferObject(target, caller); + if( 0 == bufferName ) { + throw new GLException(String.format("%s.%s: %s Buffer for target 0x%X not bound", msgClazzName, msgMapBuffer, GL_INVALID_OPERATION, target)); + } + return this.mapBufferImpl(target, bufferName, false /* isNamedBuffer */, useRange, offset, length, access, dispatch, glProcAddress); + } + /** + * <p> + * A zero store size will avoid a native call and returns the unmapped {@link GLBufferStorage}. + * </p> + * <p> + * A null native mapping result indicating an error will + * not cause a GLException but returns the unmapped {@link GLBufferStorage}. + * This allows the user to handle this case. + * </p> + * @throws GLException if buffer is not tracked + * @throws GLException if buffer is already mapped + * @throws GLException if buffer has invalid store size, i.e. less-than zero + * @throws GLException if buffer mapping range does not fit, incl. optional offset + */ + private synchronized final GLBufferStorage mapBufferImpl(final int target, final int bufferName, final boolean isNamedBuffer, final boolean useRange, long offset, + long length, final int access, final MapBufferDispatch dispatch, + final long glProcAddress) throws GLException { + final GLBufferStorageImpl store = (GLBufferStorageImpl)bufferName2StorageMap.get(bufferName); + if ( null == store ) { + throw new GLException("Buffer with name "+bufferName+" not tracked"); + } + if( null != store.getMappedBuffer() ) { + throw new GLException(String.format("%s.%s: %s Buffer storage of target 0x%X -> %d: %s is already mapped", msgClazzName, msgMapBuffer, GL_INVALID_OPERATION, target, bufferName, store)); + } + final long storeSize = store.getSize(); + if ( 0 > storeSize ) { + throw new GLException(String.format("%s.%s: %s Buffer storage of target 0x%X -> %d: %s is of less-than zero", msgClazzName, msgMapBuffer, GL_INVALID_OPERATION, target, bufferName, store)); + } + if( !useRange ) { + length = storeSize; + offset = 0; + } + if( length + offset > storeSize ) { + throw new GLException(String.format("%s.%s: %s Out of range: offset %d, length %d, buffer storage of target 0x%X -> %d: %s", msgClazzName, msgMapBuffer, GL_INVALID_VALUE, offset, length, target, bufferName, store)); + } + if( 0 >= length || 0 > offset ) { + throw new GLException(String.format("%s.%s: %s Invalid values: offset %d, length %d, buffer storage of target 0x%X -> %d: %s", msgClazzName, msgMapBuffer, GL_INVALID_VALUE, offset, length, target, bufferName, store)); + } + if( 0 == storeSize ) { + return store; + } + final long addr; + if( isNamedBuffer ) { + if( useRange ) { + addr = ((MapBufferRangeDispatch)dispatch).mapBuffer(bufferName, offset, length, access, glProcAddress); + } else { + addr = ((MapBufferAllDispatch)dispatch).mapBuffer(bufferName, access, glProcAddress); + } + } else { + if( useRange ) { + addr = ((MapBufferRangeDispatch)dispatch).mapBuffer(target, offset, length, access, glProcAddress); + } else { + addr = ((MapBufferAllDispatch)dispatch).mapBuffer(target, access, glProcAddress); + } + } + // GL's map-buffer implementation always returns NULL on error, + // user shall validate the result and the corresponding getGLError() value! + if ( 0 == addr ) { + if( DEBUG ) { + System.err.printf("%s.%s: %s MapBuffer null result for target 0x%X -> %d: %s, off %d, len %d, acc 0x%X%n", msgClazzName, msgMapBuffer, warning, target, bufferName, store, offset, length, access); + Thread.dumpStack(); + } + // User shall handle the glError ! + } else { + final ByteBuffer buffer = dispatch.allocNioByteBuffer(addr, length); + Buffers.nativeOrder(buffer); + if( DEBUG ) { + System.err.printf("%s.%s: Target 0x%X -> %d: %s, off %d, len %d, acc 0x%X%n", msgClazzName, msgClazzName, target, bufferName, store.toString(false), offset, length, access); + } + store.setMappedBuffer(buffer); + } + return store; + } + + public static interface UnmapBufferDispatch { + boolean unmap(final int targetOrBufferName, final long glProcAddress); + } + + /** + * Must be called when unmapping GL buffer objects via {@link GL#glUnmapBuffer(int)}. + * <p> + * Only clear mapped buffer reference of {@link GLBufferStorage} + * if native unmapping was successful. + * </p> + */ + public synchronized final boolean unmapBuffer(final GLBufferStateTracker bufferStateTracker, final GL caller, + final int target, + final UnmapBufferDispatch dispatch, final long glProcAddress) { + final int bufferName = bufferStateTracker.getBoundBufferObject(target, caller); + final GLBufferStorageImpl store; + if( 0 == bufferName ) { + if (DEBUG) { + System.err.printf("%s: %s.%s: Buffer for target 0x%X not bound%n", warning, msgClazzName, msgUnmapped, target); + Thread.dumpStack(); + } + store = null; + } else { + store = (GLBufferStorageImpl) bufferName2StorageMap.get(bufferName); + if( DEBUG && null == store ) { + System.err.printf("%s: %s.%s: Buffer %d not tracked%n", warning, msgClazzName, msgUnmapped, bufferName); + Thread.dumpStack(); + } + } + final boolean res = dispatch.unmap(target, glProcAddress); + if( res && null != store ) { + store.setMappedBuffer(null); + } + if( DEBUG ) { + System.err.printf("%s.%s %s target: 0x%X -> %d: %s%n", msgClazzName, msgUnmapped, res ? "OK" : "Failed", target, bufferName, store.toString(false)); + if(!res) { + Thread.dumpStack(); + } + } + return res; + } + /** + * Must be called when unmapping GL buffer objects via {@link GL2#glUnmapNamedBufferEXT(int)}. + * <p> + * Only clear mapped buffer reference of {@link GLBufferStorage} + * if native unmapping was successful. + * </p> + */ + public synchronized final boolean unmapBuffer(final int bufferName, + final UnmapBufferDispatch dispatch, final long glProcAddress) { + final GLBufferStorageImpl store = (GLBufferStorageImpl) bufferName2StorageMap.get(bufferName); + if (DEBUG && null == store ) { + System.err.printf("%s: %s.%s: Buffer %d not tracked%n", warning, msgClazzName, msgUnmapped, bufferName); + Thread.dumpStack(); + } + final boolean res = dispatch.unmap(bufferName, glProcAddress); + if( res && null != store ) { + store.setMappedBuffer(null); + } + if (DEBUG) { + System.err.printf("%s.%s %s %d: %s%n", msgClazzName, msgUnmapped, res ? "OK" : "Failed", bufferName, store.toString(false)); + if(!res) { + Thread.dumpStack(); + } + } + return res; + } + + public synchronized final long getBufferSize(final int bufferName) { + final GLBufferStorageImpl store = (GLBufferStorageImpl)bufferName2StorageMap.get(bufferName); + if ( null == store ) { + if (DEBUG) { + System.err.printf("%s: %s.getBufferSize(): Buffer %d not tracked%n", warning, msgClazzName, bufferName); + Thread.dumpStack(); + } + return 0; + } + return store.getSize(); + } + + public synchronized final GLBufferStorage getBufferStorage(final int bufferName) { + return (GLBufferStorageImpl)bufferName2StorageMap.get(bufferName); + } + + /** + * Clear all tracked buffer object knowledge. + * <p> + * Shall only be called at GLContext destruction <i>iff</i> + * there are no other shared GLContext instances left. + * </p> + */ + public synchronized final void clear() { + if (DEBUG) { + System.err.printf("%s.clear() - Thread %s%n", msgClazzName, Thread.currentThread().getName()); + // Thread.dumpStack(); + } + bufferName2StorageMap.clear(); + } + + private static final String warning = "WARNING"; + private static final String msgClazzName = "GLBufferObjectTracker"; + private static final String msgUnmapped = "notifyBufferUnmapped()"; + private static final String msgCreateBound = "createBoundBufferStorage()"; + private static final String msgCreateNamed = "createNamedBufferStorage()"; + private static final String msgMapBuffer = "mapBuffer()"; +} diff --git a/src/jogl/classes/jogamp/opengl/GLBufferSizeTracker.java b/src/jogl/classes/jogamp/opengl/GLBufferSizeTracker.java deleted file mode 100644 index b6d9b5682..000000000 --- a/src/jogl/classes/jogamp/opengl/GLBufferSizeTracker.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * 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. - * <p> - * <code>glMapBuffer</code> or <code>glMapBufferRange</code> etc - * returns a <code>java.nio.ByteBuffer</code> - * instance reflecting the returned native address of respective calls - * and the actual buffer size. - * </p> - * <p> - * In case the buffer size is unknown, we need to compute this size by using - * <code>glGetBufferParameteriv</code> with a pname of <code>GL_BUFFER_SIZE</code>. - * The latter appears to be problematic due to the returned <code>int</code> value, - * where size should be of type <code>long</code>. - * Further more, this query appears to be costly for each glMapBuffer call - * at for Apple's new multithreaded OpenGL implementation. - * </p> - * <p> - * The buffer size state is shared across all shared OpenGL context, - * hence we share the GLBufferSizeTracker instance across all shared GLContexts. - * Hence utilizing this instance must be synchronized to be thread safe due to multithreading usage. - * </p> - * <p> - * We track the sizes of allocated buffer objects. - * We track calls to <code>glBindBuffer</code> etc to see which buffer is bound to - * which target and to <code>glBufferData</code> to see how large the buffer's - * allocated size is. When <code>glMapBuffer</code> is called, we consult our table - * of buffer sizes to see if we can return an answer without a glGet - * call. - * </p> - * <p> - * 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, <code>glVertexPointer</code> and the calls down to - * <code>GLBufferStateTracker.getBoundBufferObject()</code>. Note that we currently - * ignore new binding targets such as <code>GL_TRANSFORM_FEEDBACK_BUFFER_NV</code>; - * the fact that new binding targets may be added in the future makes - * it impossible to cache state for these new targets. - * </p> - * <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 <code>glBindBuffer</code> may not have been called before trying to call - * <code>glBufferData</code>. 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.) - * </p> - */ -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 sizeNotFount = 0xFFFFFFFFFFFFFFFFL; - - public GLBufferSizeTracker() { - bufferSizeMap = new IntLongHashMap(); - bufferSizeMap.setKeyNotFoundValue(sizeNotFount); - } - - 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 (sizeNotFount == 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(); - } -} diff --git a/src/jogl/classes/jogamp/opengl/GLBufferStateTracker.java b/src/jogl/classes/jogamp/opengl/GLBufferStateTracker.java index 304c8ec32..511c1b9b9 100644 --- a/src/jogl/classes/jogamp/opengl/GLBufferStateTracker.java +++ b/src/jogl/classes/jogamp/opengl/GLBufferStateTracker.java @@ -102,14 +102,92 @@ public class GLBufferStateTracker { // Start with known unbound targets for known keys // setBoundBufferObject(GL2ES3.GL_VERTEX_ARRAY_BINDING, 0); // not using default VAO (removed in GL3 core) - only explicit setBoundBufferObject(GL.GL_ARRAY_BUFFER, 0); + setBoundBufferObject(GL4.GL_DRAW_INDIRECT_BUFFER, 0); setBoundBufferObject(GL.GL_ELEMENT_ARRAY_BUFFER, 0); setBoundBufferObject(GL2.GL_PIXEL_PACK_BUFFER, 0); setBoundBufferObject(GL2.GL_PIXEL_UNPACK_BUFFER, 0); - setBoundBufferObject(GL4.GL_DRAW_INDIRECT_BUFFER, 0); } - public final void setBoundBufferObject(int target, int value) { - bindingMap.put(target, value); + + /** + * GL_ARRAY_BUFFER, + * GL_ATOMIC_COUNTER_BUFFER, + * GL_COPY_READ_BUFFER, + * GL_COPY_WRITE_BUFFER, + * GL_DRAW_INDIRECT_BUFFER, + * GL_DISPATCH_INDIRECT_BUFFER, + * GL_ELEMENT_ARRAY_BUFFER, + * GL_PIXEL_PACK_BUFFER, + * GL_PIXEL_UNPACK_BUFFER, + * GL_SHADER_STORAGE_BUFFER, + * GL_TEXTURE_BUFFER, + * GL_TRANSFORM_FEEDBACK_BUFFER or + * GL_UNIFORM_BUFFER. + * + * GL_VERTEX_ARRAY_BINDING + * + */ + private static final int getQueryName(final int target) { + switch (target) { + case GL.GL_ARRAY_BUFFER: return GL.GL_ARRAY_BUFFER_BINDING; + case GL4.GL_ATOMIC_COUNTER_BUFFER: return GL4.GL_ATOMIC_COUNTER_BUFFER_BINDING; + case GL2ES3.GL_COPY_READ_BUFFER: return GL2ES3.GL_COPY_READ_BUFFER_BINDING; + case GL2ES3.GL_COPY_WRITE_BUFFER: return GL2ES3.GL_COPY_WRITE_BUFFER_BINDING; + case GL4.GL_DRAW_INDIRECT_BUFFER: return GL4.GL_DRAW_INDIRECT_BUFFER_BINDING; + case GL4.GL_DISPATCH_INDIRECT_BUFFER: return GL4.GL_DISPATCH_INDIRECT_BUFFER_BINDING; + case GL.GL_ELEMENT_ARRAY_BUFFER: return GL.GL_ELEMENT_ARRAY_BUFFER_BINDING; + case GL2.GL_PIXEL_PACK_BUFFER: return GL2.GL_PIXEL_PACK_BUFFER_BINDING; + case GL2.GL_PIXEL_UNPACK_BUFFER: return GL2.GL_PIXEL_UNPACK_BUFFER_BINDING; + // FIXME case GL4.GL_QUERY_BUFFER: return GL4.GL_QUERY_BUFFER_BINDING; + case GL4.GL_SHADER_STORAGE_BUFFER: return GL4.GL_SHADER_STORAGE_BUFFER_BINDING; + case GL2GL3.GL_TEXTURE_BUFFER: return GL2GL3.GL_TEXTURE_BINDING_BUFFER; + case GL2ES3.GL_TRANSFORM_FEEDBACK_BUFFER: return GL2ES3.GL_TRANSFORM_FEEDBACK_BUFFER_BINDING; + case GL2ES3.GL_UNIFORM_BUFFER: return GL2ES3.GL_UNIFORM_BUFFER_BINDING; + + case GL2ES3.GL_VERTEX_ARRAY_BINDING: return GL2ES3.GL_VERTEX_ARRAY_BINDING; + + default: + throw new GLException(String.format("GL_INVALID_ENUM: Invalid binding target 0x%X", target)); + } + } + private static final void checkTargetName(final int target) { + switch (target) { + case GL.GL_ARRAY_BUFFER: + case GL4.GL_ATOMIC_COUNTER_BUFFER: + case GL2ES3.GL_COPY_READ_BUFFER: + case GL2ES3.GL_COPY_WRITE_BUFFER: + case GL4.GL_DRAW_INDIRECT_BUFFER: + case GL4.GL_DISPATCH_INDIRECT_BUFFER: + case GL.GL_ELEMENT_ARRAY_BUFFER: + case GL2.GL_PIXEL_PACK_BUFFER: + case GL2.GL_PIXEL_UNPACK_BUFFER: + // FIXME case GL4.GL_QUERY_BUFFER: + case GL4.GL_SHADER_STORAGE_BUFFER: + case GL2GL3.GL_TEXTURE_BUFFER: + case GL2ES3.GL_TRANSFORM_FEEDBACK_BUFFER: + case GL2ES3.GL_UNIFORM_BUFFER: + + case GL2ES3.GL_VERTEX_ARRAY_BINDING: + return; + + default: + throw new GLException(String.format("GL_INVALID_ENUM: Invalid binding target 0x%X", target)); + } + } + + /** + * Must be called when binding a buffer, e.g.: + * <ul> + * <li><code>glBindBuffer</code></li> + * <li><code>glBindBufferBase</code></li> + * <li><code>glBindBufferRange</code></li> + * </ul> + * @param target + * @param bufferName + */ + public final void setBoundBufferObject(int target, int bufferName) { + checkTargetName(target); + final int oldBufferName = bindingMap.put(target, bufferName); /*** * Test for clearing bound buffer states when unbinding VAO, * Bug 692 Comment 5 is invalid, i.e. <https://jogamp.org/bugzilla/show_bug.cgi?id=692#c5>. @@ -117,8 +195,8 @@ public class GLBufferStateTracker { * after unbinding a VAO w/o unbinding the VBOs resulted to no visible image. * Leaving code in here for discussion - in case I am wrong. * - final int pre = bindingMap.put(target, value); - if( GL2ES3.GL_VERTEX_ARRAY_BINDING == target && keyNotFound != pre && 0 == value ) { + final int pre = bindingMap.put(target, bufferName); + if( GL2ES3.GL_VERTEX_ARRAY_BINDING == target && keyNotFound != pre && 0 == bufferName ) { // Unbinding a previous bound VAO leads to unbinding of all buffers! bindingMap.put(GL.GL_ARRAY_BUFFER, 0); bindingMap.put(GL.GL_ELEMENT_ARRAY_BUFFER, 0); @@ -127,38 +205,12 @@ public class GLBufferStateTracker { bindingMap.put(GL4.GL_DRAW_INDIRECT_BUFFER, 0); } */ if (DEBUG) { - System.err.println("GLBufferStateTracker.setBoundBufferObject() target 0x" + - Integer.toHexString(target) + " -> mapped bound buffer 0x" + - Integer.toHexString(value)); + System.err.println("GLBufferStateTracker.setBoundBufferObject() target " + + toHexString(target) + ": " + toHexString(oldBufferName) + " -> " + toHexString(bufferName)); // Thread.dumpStack(); } } - public static final int getQueryName(final int target) { - switch (target) { - case GL.GL_ARRAY_BUFFER: return GL.GL_ARRAY_BUFFER_BINDING; - case GL.GL_ELEMENT_ARRAY_BUFFER: return GL.GL_ELEMENT_ARRAY_BUFFER_BINDING; - - case GL2ES3.GL_VERTEX_ARRAY_BINDING: return GL2ES3.GL_VERTEX_ARRAY_BINDING; - case GL2ES3.GL_COPY_READ_BUFFER: return GL2ES3.GL_COPY_READ_BUFFER_BINDING; - case GL2ES3.GL_COPY_WRITE_BUFFER: return GL2ES3.GL_COPY_WRITE_BUFFER_BINDING; - case GL2ES3.GL_TRANSFORM_FEEDBACK_BUFFER: return GL2ES3.GL_TRANSFORM_FEEDBACK_BUFFER_BINDING; - case GL2ES3.GL_UNIFORM_BUFFER: return GL2ES3.GL_UNIFORM_BUFFER_BINDING; - - case GL2GL3.GL_TEXTURE_BUFFER: return GL2GL3.GL_TEXTURE_BINDING_BUFFER; - - case GL2.GL_PIXEL_PACK_BUFFER: return GL2.GL_PIXEL_PACK_BUFFER_BINDING; - case GL2.GL_PIXEL_UNPACK_BUFFER: return GL2.GL_PIXEL_UNPACK_BUFFER_BINDING; - - case GL4.GL_DRAW_INDIRECT_BUFFER: return GL4.GL_DRAW_INDIRECT_BUFFER_BINDING; - case GL4.GL_ATOMIC_COUNTER_BUFFER: return GL4.GL_ATOMIC_COUNTER_BUFFER_BINDING; - case GL4.GL_DISPATCH_INDIRECT_BUFFER: return GL4.GL_DISPATCH_INDIRECT_BUFFER_BINDING; - case GL4.GL_SHADER_STORAGE_BUFFER: return GL4.GL_SHADER_STORAGE_BUFFER_BINDING; - // case GL4.GL_QUERY_BUFFER: return GL4.GL_QUERY_BUFFER_BINDING; - default: return 0; - } - } - /** 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 @@ -180,9 +232,9 @@ public class GLBufferStateTracker { value = 0; } if (DEBUG) { - System.err.println("GLBufferStateTracker.getBoundBufferObject() glerr[pre 0x"+Integer.toHexString(glerrPre)+", post 0x"+Integer.toHexString(glerrPost)+"], [queried value]: target 0x" + - Integer.toHexString(target) + " / query 0x"+Integer.toHexString(queryTarget)+ - " -> mapped bound buffer 0x" + Integer.toHexString(value)); + System.err.println("GLBufferStateTracker.getBoundBufferObject() glerr[pre "+toHexString(glerrPre)+", post "+toHexString(glerrPost)+"], [queried value]: target " + + toHexString(target) + " / query "+toHexString(queryTarget)+ + " -> mapped bound buffer " + toHexString(value)); } setBoundBufferObject(target, value); return value; @@ -204,11 +256,12 @@ public class GLBufferStateTracker { 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 final void clearBufferObjectState() { + public final void clear() { + if (DEBUG) { + System.err.println("GLBufferStateTracker.clear() - Thread "+Thread.currentThread().getName()); + // Thread.dumpStack(); + } bindingMap.clear(); - if (DEBUG) { - System.err.println("GLBufferStateTracker.clearBufferObjectState()"); - //Thread.dumpStack(); - } } + private final String toHexString(int i) { return Integer.toHexString(i); } } diff --git a/src/jogl/classes/jogamp/opengl/GLContextImpl.java b/src/jogl/classes/jogamp/opengl/GLContextImpl.java index 66eed9d96..ee9f315c8 100644 --- a/src/jogl/classes/jogamp/opengl/GLContextImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLContextImpl.java @@ -100,9 +100,9 @@ public abstract class GLContextImpl extends GLContext { private String glRendererLowerCase; private String glVersion; - // Tracks creation and initialization of buffer objects to avoid + // Tracks lifecycle of buffer objects to avoid // repeated glGet calls upon glMapBuffer operations - private final GLBufferSizeTracker bufferSizeTracker; + private final GLBufferObjectTracker bufferObjectTracker; private final GLBufferStateTracker bufferStateTracker; private final GLStateTracker glStateTracker = new GLStateTracker(); private GLDebugMessageHandler glDebugHandler = null; @@ -141,10 +141,10 @@ public abstract class GLContextImpl extends GLContext { bufferStateTracker = new GLBufferStateTracker(); if ( null != shareWith ) { GLContextShareSet.registerSharing(this, shareWith); - bufferSizeTracker = ((GLContextImpl)shareWith).getBufferSizeTracker(); - assert (bufferSizeTracker != null) : "shared context hash null bufferSizeTracker: "+shareWith; + bufferObjectTracker = ((GLContextImpl)shareWith).getBufferObjectTracker(); + assert (bufferObjectTracker != null) : "shared context hash null GLBufferObjectTracker: "+shareWith; } else { - bufferSizeTracker = new GLBufferSizeTracker(); + bufferObjectTracker = new GLBufferObjectTracker(); } this.drawable = drawable; @@ -155,9 +155,9 @@ public abstract class GLContextImpl extends GLContext { private final void clearStates() { if( !GLContextShareSet.hasCreatedSharedLeft(this) ) { - bufferSizeTracker.clearCachedBufferSizes(); + bufferObjectTracker.clear(); } - bufferStateTracker.clearBufferObjectState(); + bufferStateTracker.clear(); glStateTracker.setEnabled(false); glStateTracker.clearStates(); } @@ -2122,8 +2122,8 @@ public abstract class GLContextImpl extends GLContext { //---------------------------------------------------------------------- // Helpers for buffer object optimizations - public final GLBufferSizeTracker getBufferSizeTracker() { - return bufferSizeTracker; + public final GLBufferObjectTracker getBufferObjectTracker() { + return bufferObjectTracker; } public final GLBufferStateTracker getBufferStateTracker() { diff --git a/src/jogl/classes/jogamp/opengl/MemoryObject.java b/src/jogl/classes/jogamp/opengl/MemoryObject.java index ac02e0bca..6ebefc517 100644 --- a/src/jogl/classes/jogamp/opengl/MemoryObject.java +++ b/src/jogl/classes/jogamp/opengl/MemoryObject.java @@ -31,17 +31,18 @@ package jogamp.opengl; import java.nio.ByteBuffer; import java.util.HashMap; +import javax.media.opengl.GLBufferStorage; + import com.jogamp.common.util.HashUtil; /** - * + * @deprecated No more used for GL buffer storage tracking, see {@link GLBufferStorage} and {@link GLBufferObjectTracker}. */ public class MemoryObject { private final long addr; private final long size; private final int hash; private ByteBuffer buffer=null; - public MemoryObject(long addr, long size) { this.addr = addr; this.size = size; diff --git a/src/jogl/classes/jogamp/opengl/util/glsl/fixedfunc/FixedFuncHook.java b/src/jogl/classes/jogamp/opengl/util/glsl/fixedfunc/FixedFuncHook.java index c329945c4..458a9c94f 100644 --- a/src/jogl/classes/jogamp/opengl/util/glsl/fixedfunc/FixedFuncHook.java +++ b/src/jogl/classes/jogamp/opengl/util/glsl/fixedfunc/FixedFuncHook.java @@ -352,11 +352,11 @@ public class FixedFuncHook implements GLLightingFunc, GLMatrixFunc, GLPointerFun @Override public void glVertexPointer(GLArrayData array) { if(array.isVBO()) { - if(!gl.glIsVBOArrayBound()) { + if(!gl.isVBOArrayBound()) { throw new GLException("VBO array is not enabled: "+array); } } else { - if(gl.glIsVBOArrayBound()) { + if(gl.isVBOArrayBound()) { throw new GLException("VBO array is not disabled: "+array); } Buffers.rangeCheck(array.getBuffer(), 1); @@ -373,7 +373,7 @@ public class FixedFuncHook implements GLLightingFunc, GLMatrixFunc, GLPointerFun } @Override public void glVertexPointer(int size, int type, int stride, long pointer_buffer_offset) { - int vboName = gl.glGetBoundBuffer(GL.GL_ARRAY_BUFFER); + int vboName = gl.getBoundBuffer(GL.GL_ARRAY_BUFFER); if(vboName==0) { throw new GLException("no GL_ARRAY_BUFFER VBO bound"); } @@ -384,11 +384,11 @@ public class FixedFuncHook implements GLLightingFunc, GLMatrixFunc, GLPointerFun @Override public void glColorPointer(GLArrayData array) { if(array.isVBO()) { - if(!gl.glIsVBOArrayBound()) { + if(!gl.isVBOArrayBound()) { throw new GLException("VBO array is not enabled: "+array); } } else { - if(gl.glIsVBOArrayBound()) { + if(gl.isVBOArrayBound()) { throw new GLException("VBO array is not disabled: "+array); } Buffers.rangeCheck(array.getBuffer(), 1); @@ -404,7 +404,7 @@ public class FixedFuncHook implements GLLightingFunc, GLMatrixFunc, GLPointerFun } @Override public void glColorPointer(int size, int type, int stride, long pointer_buffer_offset) { - int vboName = gl.glGetBoundBuffer(GL.GL_ARRAY_BUFFER); + int vboName = gl.getBoundBuffer(GL.GL_ARRAY_BUFFER); if(vboName==0) { throw new GLException("no GL_ARRAY_BUFFER VBO bound"); } @@ -418,11 +418,11 @@ public class FixedFuncHook implements GLLightingFunc, GLMatrixFunc, GLPointerFun throw new GLException("Only 3 components per normal allowed"); } if(array.isVBO()) { - if(!gl.glIsVBOArrayBound()) { + if(!gl.isVBOArrayBound()) { throw new GLException("VBO array is not enabled: "+array); } } else { - if(gl.glIsVBOArrayBound()) { + if(gl.isVBOArrayBound()) { throw new GLException("VBO array is not disabled: "+array); } Buffers.rangeCheck(array.getBuffer(), 1); @@ -438,7 +438,7 @@ public class FixedFuncHook implements GLLightingFunc, GLMatrixFunc, GLPointerFun } @Override public void glNormalPointer(int type, int stride, long pointer_buffer_offset) { - int vboName = gl.glGetBoundBuffer(GL.GL_ARRAY_BUFFER); + int vboName = gl.getBoundBuffer(GL.GL_ARRAY_BUFFER); if(vboName==0) { throw new GLException("no GL_ARRAY_BUFFER VBO bound"); } @@ -449,11 +449,11 @@ public class FixedFuncHook implements GLLightingFunc, GLMatrixFunc, GLPointerFun @Override public void glTexCoordPointer(GLArrayData array) { if(array.isVBO()) { - if(!gl.glIsVBOArrayBound()) { + if(!gl.isVBOArrayBound()) { throw new GLException("VBO array is not enabled: "+array); } } else { - if(gl.glIsVBOArrayBound()) { + if(gl.isVBOArrayBound()) { throw new GLException("VBO array is not disabled: "+array); } Buffers.rangeCheck(array.getBuffer(), 1); @@ -470,7 +470,7 @@ public class FixedFuncHook implements GLLightingFunc, GLMatrixFunc, GLPointerFun } @Override public void glTexCoordPointer(int size, int type, int stride, long pointer_buffer_offset) { - int vboName = gl.glGetBoundBuffer(GL.GL_ARRAY_BUFFER); + int vboName = gl.getBoundBuffer(GL.GL_ARRAY_BUFFER); if(vboName==0) { throw new GLException("no GL_ARRAY_BUFFER VBO bound"); } |