浏览代码

Modified so that read-only operations will not
clobber each other if done from other threads
and provided a way to safely access the whole
buffer if only read-only access is required.
Round 1 of a fix for GeometryBatchFactory...


git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9098 75d07b2b-3a1a-0410-a2c5-0572b91ccdca

PSp..om 13 年之前
父节点
当前提交
606b676d69
共有 1 个文件被更改,包括 90 次插入18 次删除
  1. 90 18
      engine/src/core/com/jme3/scene/VertexBuffer.java

+ 90 - 18
engine/src/core/com/jme3/scene/VertexBuffer.java

@@ -374,11 +374,61 @@ public class VertexBuffer extends NativeObject implements Savable, Cloneable {
     }
     }
 
 
     /**
     /**
+     * Returns the raw internal data buffer used by this VertexBuffer.
+     * This buffer is not safe to call from multiple threads since buffers
+     * have their own internal position state that cannot be shared.
+     * Call getData().duplicate(), getData().asReadOnlyBuffer(), or 
+     * the more convenient getDataReadOnly() if the buffer may be accessed 
+     * from multiple threads.
+     * 
      * @return A native buffer, in the specified {@link Format format}.
      * @return A native buffer, in the specified {@link Format format}.
      */
      */
     public Buffer getData(){
     public Buffer getData(){
         return data;
         return data;
     }
     }
+    
+    /** 
+     * Returns a safe read-only version of this VertexBuffer's data.  The
+     * contents of the buffer will reflect whatever changes are made on
+     * other threads (eventually) but these should not be used in that way.
+     * This method provides a read-only buffer that is safe to _read_ from
+     * a separate thread since it has its own book-keeping state (position, limit, etc.)
+     *
+     * @return A rewound native buffer in the specified {@link Format format}
+     *         that is safe to read from a separate thread from other readers. 
+     */
+    public Buffer getDataReadOnly() {
+    
+        if (data == null) {
+            return null;
+        }
+        
+        // Create a read-only duplicate().  Note: this does not copy
+        // the underlying memory, it just creates a new read-only wrapper
+        // with its own buffer position state.
+        
+        // Unfortunately, this is not 100% straight forward since Buffer
+        // does not have an asReadOnlyBuffer() method.
+        Buffer result;
+        if( data instanceof ByteBuffer ) {
+            result = ((ByteBuffer)data).asReadOnlyBuffer();
+        } else if( data instanceof FloatBuffer ) {
+            result = ((FloatBuffer)data).asReadOnlyBuffer();
+        } else if( data instanceof ShortBuffer ) {
+            result = ((ShortBuffer)data).asReadOnlyBuffer();
+        } else if( data instanceof IntBuffer ) {
+            result = ((IntBuffer)data).asReadOnlyBuffer();
+        } else {
+            throw new UnsupportedOperationException( "Cannot get read-only view of buffer type:" + data );
+        }
+        
+        // Make sure the caller gets a consistent view since we may
+        // have grabbed this buffer while another thread was reading
+        // the raw data.
+        result.rewind();
+        
+        return result;
+    }
 
 
     /**
     /**
      * @return The usage of this buffer. See {@link Usage} for more
      * @return The usage of this buffer. See {@link Usage} for more
@@ -470,6 +520,9 @@ public class VertexBuffer extends NativeObject implements Savable, Cloneable {
         if (usage == null || format == null || data == null)
         if (usage == null || format == null || data == null)
             throw new IllegalArgumentException("None of the arguments can be null");
             throw new IllegalArgumentException("None of the arguments can be null");
             
             
+        if (data.isReadOnly()) 
+            throw new IllegalArgumentException( "VertexBuffer data cannot be read-only." );
+
         if (components < 1 || components > 4)
         if (components < 1 || components > 4)
             throw new IllegalArgumentException("components must be between 1 and 4");
             throw new IllegalArgumentException("components must be between 1 and 4");
 
 
@@ -499,6 +552,12 @@ public class VertexBuffer extends NativeObject implements Savable, Cloneable {
             // request to update data is okay
             // request to update data is okay
         }
         }
 
 
+        // Check if the data buffer is read-only which is a sign
+        // of a bug on the part of the caller
+        if (data != null && data.isReadOnly()) {
+            throw new IllegalArgumentException( "VertexBuffer data cannot be read-only." );
+        }
+
         // will force renderer to call glBufferData again
         // will force renderer to call glBufferData again
         if (data != null && (this.data.getClass() != data.getClass() || data.limit() != lastLimit)){
         if (data != null && (this.data.getClass() != data.getClass() || data.limit() != lastLimit)){
             dataSizeChanged = true;
             dataSizeChanged = true;
@@ -669,24 +728,24 @@ public class VertexBuffer extends NativeObject implements Savable, Cloneable {
             elementPos *= 2;
             elementPos *= 2;
         }
         }
 
 
-        data.clear();
+        Buffer srcData = getDataReadOnly();
 
 
         switch (format){
         switch (format){
             case Byte:
             case Byte:
             case UnsignedByte:
             case UnsignedByte:
             case Half:
             case Half:
-                ByteBuffer bin = (ByteBuffer) data;
+                ByteBuffer bin = (ByteBuffer) srcData;
                 return bin.get(inPos + elementPos);
                 return bin.get(inPos + elementPos);
             case Short:
             case Short:
             case UnsignedShort:
             case UnsignedShort:
-                ShortBuffer sin = (ShortBuffer) data;
+                ShortBuffer sin = (ShortBuffer) srcData;
                 return sin.get(inPos + elementPos);
                 return sin.get(inPos + elementPos);
             case Int:
             case Int:
             case UnsignedInt:
             case UnsignedInt:
-                IntBuffer iin = (IntBuffer) data;
+                IntBuffer iin = (IntBuffer) srcData;
                 return iin.get(inPos + elementPos);
                 return iin.get(inPos + elementPos);
             case Float:
             case Float:
-                FloatBuffer fin = (FloatBuffer) data;
+                FloatBuffer fin = (FloatBuffer) srcData;
                 return fin.get(inPos + elementPos);
                 return fin.get(inPos + elementPos);
             default:
             default:
                 throw new UnsupportedOperationException("Unrecognized buffer format: "+format);
                 throw new UnsupportedOperationException("Unrecognized buffer format: "+format);
@@ -718,14 +777,17 @@ public class VertexBuffer extends NativeObject implements Savable, Cloneable {
             elementSz *= 2;
             elementSz *= 2;
         }
         }
 
 
-        data.clear();
+        // Make sure to grab a read-only copy in case some other
+        // thread is also accessing the buffer and messing with its
+        // position()
+        Buffer srcData = getDataReadOnly();
         outVb.data.clear();
         outVb.data.clear();
 
 
         switch (format){
         switch (format){
             case Byte:
             case Byte:
             case UnsignedByte:
             case UnsignedByte:
             case Half:
             case Half:
-                ByteBuffer bin = (ByteBuffer) data;
+                ByteBuffer bin = (ByteBuffer) srcData;
                 ByteBuffer bout = (ByteBuffer) outVb.data;
                 ByteBuffer bout = (ByteBuffer) outVb.data;
                 bin.position(inPos).limit(inPos + elementSz);
                 bin.position(inPos).limit(inPos + elementSz);
                 bout.position(outPos).limit(outPos + elementSz);
                 bout.position(outPos).limit(outPos + elementSz);
@@ -733,7 +795,7 @@ public class VertexBuffer extends NativeObject implements Savable, Cloneable {
                 break;
                 break;
             case Short:
             case Short:
             case UnsignedShort:
             case UnsignedShort:
-                ShortBuffer sin = (ShortBuffer) data;
+                ShortBuffer sin = (ShortBuffer) srcData;
                 ShortBuffer sout = (ShortBuffer) outVb.data;
                 ShortBuffer sout = (ShortBuffer) outVb.data;
                 sin.position(inPos).limit(inPos + elementSz);
                 sin.position(inPos).limit(inPos + elementSz);
                 sout.position(outPos).limit(outPos + elementSz);
                 sout.position(outPos).limit(outPos + elementSz);
@@ -741,14 +803,14 @@ public class VertexBuffer extends NativeObject implements Savable, Cloneable {
                 break;
                 break;
             case Int:
             case Int:
             case UnsignedInt:
             case UnsignedInt:
-                IntBuffer iin = (IntBuffer) data;
+                IntBuffer iin = (IntBuffer) srcData;
                 IntBuffer iout = (IntBuffer) outVb.data;
                 IntBuffer iout = (IntBuffer) outVb.data;
                 iin.position(inPos).limit(inPos + elementSz);
                 iin.position(inPos).limit(inPos + elementSz);
                 iout.position(outPos).limit(outPos + elementSz);
                 iout.position(outPos).limit(outPos + elementSz);
                 iout.put(iin);
                 iout.put(iin);
                 break;
                 break;
             case Float:
             case Float:
-                FloatBuffer fin = (FloatBuffer) data;
+                FloatBuffer fin = (FloatBuffer) srcData;
                 FloatBuffer fout = (FloatBuffer) outVb.data;
                 FloatBuffer fout = (FloatBuffer) outVb.data;
                 fin.position(inPos).limit(inPos + elementSz);
                 fin.position(inPos).limit(inPos + elementSz);
                 fout.position(outPos).limit(outPos + elementSz);
                 fout.position(outPos).limit(outPos + elementSz);
@@ -758,7 +820,6 @@ public class VertexBuffer extends NativeObject implements Savable, Cloneable {
                 throw new UnsupportedOperationException("Unrecognized buffer format: "+format);
                 throw new UnsupportedOperationException("Unrecognized buffer format: "+format);
         }
         }
 
 
-        data.clear();
         outVb.data.clear();
         outVb.data.clear();
     }
     }
 
 
@@ -807,8 +868,13 @@ public class VertexBuffer extends NativeObject implements Savable, Cloneable {
         VertexBuffer vb = (VertexBuffer) super.clone();
         VertexBuffer vb = (VertexBuffer) super.clone();
         vb.handleRef = new Object();
         vb.handleRef = new Object();
         vb.id = -1;
         vb.id = -1;
-        if (data != null)
-            vb.updateData(BufferUtils.clone(data));
+        if (data != null) {
+            // Make sure to pass a read-only buffer to clone so that
+            // the position information doesn't get clobbered by another
+            // reading thread during cloning (and vice versa) since this is
+            // a purely read-only operation.
+            vb.updateData(BufferUtils.clone(getDataReadOnly()));
+        }
         
         
         return vb;
         return vb;
     }
     }
@@ -824,7 +890,12 @@ public class VertexBuffer extends NativeObject implements Savable, Cloneable {
         VertexBuffer vb = new VertexBuffer(overrideType);
         VertexBuffer vb = new VertexBuffer(overrideType);
         vb.components = components;
         vb.components = components;
         vb.componentsLength = componentsLength;
         vb.componentsLength = componentsLength;
-        vb.data = BufferUtils.clone(data);
+        
+        // Make sure to pass a read-only buffer to clone so that
+        // the position information doesn't get clobbered by another
+        // reading thread during cloning (and vice versa) since this is
+        // a purely read-only operation.
+        vb.data = BufferUtils.clone(getDataReadOnly());
         vb.format = format;
         vb.format = format;
         vb.handleRef = new Object();
         vb.handleRef = new Object();
         vb.id = -1;
         vb.id = -1;
@@ -876,22 +947,23 @@ public class VertexBuffer extends NativeObject implements Savable, Cloneable {
         oc.write(stride, "stride", 0);
         oc.write(stride, "stride", 0);
 
 
         String dataName = "data" + format.name();
         String dataName = "data" + format.name();
+        Buffer roData = getDataReadOnly();
         switch (format){
         switch (format){
             case Float:
             case Float:
-                oc.write((FloatBuffer) data, dataName, null);
+                oc.write((FloatBuffer) roData, dataName, null);
                 break;
                 break;
             case Short:
             case Short:
             case UnsignedShort:
             case UnsignedShort:
-                oc.write((ShortBuffer) data, dataName, null);
+                oc.write((ShortBuffer) roData, dataName, null);
                 break;
                 break;
             case UnsignedByte:
             case UnsignedByte:
             case Byte:
             case Byte:
             case Half:
             case Half:
-                oc.write((ByteBuffer) data, dataName, null);
+                oc.write((ByteBuffer) roData, dataName, null);
                 break;
                 break;
             case Int:
             case Int:
             case UnsignedInt:
             case UnsignedInt:
-                oc.write((IntBuffer) data, dataName, null);
+                oc.write((IntBuffer) roData, dataName, null);
                 break;
                 break;
             default:
             default:
                 throw new IOException("Unsupported export buffer format: "+format);
                 throw new IOException("Unsupported export buffer format: "+format);