From d1a03d19398960d6e34232f29a30f1d569fba2a7 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Sat, 6 Nov 2010 06:26:56 +0100 Subject: Fix buffer size: 64bit GLBufferSizeTracker, hash over addr+size, save fail-fast hash cache, .. Relates to GlueGen 6b6b9b3b81cdc85b7260664ebec547756a6be5d7, branch sgothel_wip_fixes01. Memory object size is ptrdiff_t, hence long (64bit). The hash value must include size as well, otherwise boundaries cannot be verified. (security) Double check hash collisions while adding a new MemoryObject. --- .../jogamp/opengl/impl/GLBufferSizeTracker.java | 27 ++-- .../com/jogamp/opengl/impl/MemoryObject.java | 142 +++++++++++++++++++++ 2 files changed, 158 insertions(+), 11 deletions(-) create mode 100644 src/jogl/classes/com/jogamp/opengl/impl/MemoryObject.java (limited to 'src/jogl/classes/com') diff --git a/src/jogl/classes/com/jogamp/opengl/impl/GLBufferSizeTracker.java b/src/jogl/classes/com/jogamp/opengl/impl/GLBufferSizeTracker.java index ceabd3910..6ebda222b 100644 --- a/src/jogl/classes/com/jogamp/opengl/impl/GLBufferSizeTracker.java +++ b/src/jogl/classes/com/jogamp/opengl/impl/GLBufferSizeTracker.java @@ -1,5 +1,6 @@ /* * 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 @@ -40,7 +41,7 @@ package com.jogamp.opengl.impl; import javax.media.opengl.*; -import com.jogamp.common.util.IntIntHashMap; +import com.jogamp.common.util.IntLongHashMap; /** * Tracks as closely as possible the sizes of allocated OpenGL buffer @@ -93,17 +94,17 @@ public class GLBufferSizeTracker { // 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 IntIntHashMap bufferSizeMap; + private IntLongHashMap bufferSizeMap; protected static final boolean DEBUG = Debug.debug("GLStatusTracker"); public GLBufferSizeTracker() { - bufferSizeMap = new IntIntHashMap(); + bufferSizeMap = new IntLongHashMap(); bufferSizeMap.setKeyNotFoundValue(-1); } public void setBufferSize(GLBufferStateTracker bufferStateTracker, - int target, GL caller, int size) { + int target, GL caller, long size) { // Need to do some similar queries to getBufferSize below int buffer = bufferStateTracker.getBoundBufferObject(target, caller); boolean valid = bufferStateTracker.isBoundBufferObjectKnown(target); @@ -125,11 +126,11 @@ public class GLBufferSizeTracker { // left to do except drop this piece of information on the floor. } - public void setDirectStateBufferSize(int buffer, GL caller, int size) { + public void setDirectStateBufferSize(int buffer, GL caller, long size) { bufferSizeMap.put(buffer, size); } - public int getBufferSize(GLBufferStateTracker bufferStateTracker, + public long getBufferSize(GLBufferStateTracker bufferStateTracker, int target, GL caller) { // See whether we know what buffer is currently bound to the given @@ -149,25 +150,29 @@ public class GLBufferSizeTracker { 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]; + return (long) tmp[0]; } - public int getDirectStateBufferSize(int buffer, GL caller) { + public long getDirectStateBufferSize(int buffer, GL caller) { return getBufferSizeImpl(0, buffer, caller); } - private int getBufferSizeImpl(int target, int buffer, GL caller) { + private 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 - int sz = bufferSizeMap.get(buffer); + long sz = bufferSizeMap.get(buffer); if (0 > 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 .. @@ -186,7 +191,7 @@ public class GLBufferSizeTracker { " was zero; probably application error"); } // Assume we just don't know what's happening - sz = tmp[0]; + sz = (long) tmp[0]; bufferSizeMap.put(buffer, sz); if (DEBUG) { System.err.println("GLBufferSizeTracker.getBufferSize(): made slow query to cache size " + diff --git a/src/jogl/classes/com/jogamp/opengl/impl/MemoryObject.java b/src/jogl/classes/com/jogamp/opengl/impl/MemoryObject.java new file mode 100644 index 000000000..a691a6156 --- /dev/null +++ b/src/jogl/classes/com/jogamp/opengl/impl/MemoryObject.java @@ -0,0 +1,142 @@ +/** + * Copyright 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: + * + * 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 com.jogamp.opengl.impl; + +import java.nio.ByteBuffer; +import java.util.HashMap; + +/** + * + */ +public class MemoryObject { + private long addr; + private long size; + private int hash32; + private ByteBuffer buffer=null; + + public MemoryObject(long addr, long size) { + this.addr = addr; + this.size = size; + this.hash32 = getHash32(addr, size); + } + + public void setBuffer(ByteBuffer buffer) { + this.buffer = buffer; + } + + public ByteBuffer getBuffer() { + return this.buffer; + } + + /** + * @return the 32bit hash value generated via {@link #getHash32(long, long)} + */ + public int hashCode() { + return hash32; + } + + /** + * Ignores the optional attached ByteBuffer intentionally.
+ * + * @return true of reference is equal or obj is of type MemoryObject + * and addr and size is equal.
+ */ + public boolean equals(Object obj) { + if(this == obj) { return true; } + if(obj instanceof MemoryObject) { + MemoryObject m = (MemoryObject) obj; + return addr == m.addr && size == m.size ; + } + return false; + } + + /** + * Generates a 32bit hash value by addr and size.
+ * Ignores the optional attached ByteBuffer intentionally.
+ */ + public static int getHash32(long addr, long size) { + // avoid xor collisions of eg low/high parts + // 31 * x == (x << 5) - x + int hash = 31 + (int) addr ; // lo addr + hash = ((hash << 5) - hash) + (int) ( addr >>> 32 ) ; // hi addr + hash = ((hash << 5) - hash) + (int) size ; // lo size + hash = ((hash << 5) - hash) + (int) ( size >>> 32 ) ; // hi size + + return hash; + } + + /** + * Generates a 64bit hash value by addr and size.
+ * Ignores the optional attached ByteBuffer intentionally.
+ */ + public static long getHash64(long addr, long size) { + // 31 * x == (x << 5) - x + final long hash = 31 + addr; + return ((hash << 5) - hash) + size; + } + + public String toString() { + return "MemoryObject[addr 0x"+Long.toHexString(addr)+", size 0x"+Long.toHexString(size)+", hash32: 0x"+Integer.toHexString(hash32)+"]"; + } + + /** + * Verifies the hash map operation, ie + * + * In case the above verification fails, a RuntimeException is thrown.
+ * In such case the calculation of the hash value should either be tuned,
+ * or we just cannot use hash mapping.
+ * + * @param map the identity HashMap mapping MemoryObject to MemoryObject + * @param obj0 the MemoryObject to get or add in the map + * @return either the already mapped one where obj0 != return, + * or the added obj0 == return. + * @throws RuntimeException if hash collision occurs + */ + public static MemoryObject getOrAddSafe(HashMap/**/ map, MemoryObject obj0) { + MemoryObject obj1 = (MemoryObject) map.get(obj0); // get identity (fast) + if(null == obj1) { + // verify hash collision (slow) + if( map.values().contains(obj0) ) { + throw new RuntimeException("Hash collision, hash !exist, but in values: "+obj0); + } + map.put(obj0, obj0); + obj1 = obj0; + } else { + // verify hash collision (ok) + if( !obj1.equals(obj0) ) { + throw new RuntimeException("Hash collision, hash equals, but objects not: query "+obj0+" != contained "+obj1); + } + } + return obj1; + } + +} \ No newline at end of file -- cgit v1.2.3