Buffers.newDirectIntBuffer(int[]) does not set limit

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

Buffers.newDirectIntBuffer(int[]) does not set limit

jmaasing
I noticed that Buffers.newDirectIntBuffer(int[]) does not set the limit of the buffer. This causes a driver crash on OSX.

When using this form:
final IntBuffer indexBuf = Buffers.newDirectIntBuffer(triIndexes);
This is the trace output when I upload the data to the driver:
glBindBuffer(<int> 0x8893, <int> 0x3)
glBufferData(<int> 0x8893, <long> 0, <java.nio.Buffer> java.nio.DirectIntBufferU[pos=0 lim=0 cap=89034], <int> 0x88E4)

and finally the driver crashes when it is time to render:
glDrawElements(<int> 0x4, <int> 0x15BCA, <int> 0x1405, <long> 0)#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x000000010fd4b3b0, pid=1443, tid=31031
#
# JRE version: Java(TM) SE Runtime Environment (8.0-b132) (build 1.8.0-b132)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.0-b70 mixed mode bsd-amd64 compressed oops)
# Problematic frame:
# C  [libsystem_platform.dylib+0x13b0]  _platform_memmove$VARIANT$Nehalem+0x70

But if I do this:
final IntBuffer indexBuf = Buffers.newDirectIntBuffer(triIndexes.length);
for (int triIndex : triIndexes) {
	indexBuf.put(triIndex) ;
}

The trace for uploading the buffer is this:
glBindBuffer(<int> 0x8893, <int> 0x3)
glBufferData(<int> 0x8893, <long> 356136, <java.nio.Buffer> java.nio.DirectIntBufferU[pos=0 lim=89034 cap=89034], <int> 0x88E4)

Notice the limit is set to the number of ints I put into the buffer and now the driver does not crash.

Should I write a bug report or is this expected (i.e. limit not set) when using the array version of newDirectIntBuffer?
Reply | Threaded
Open this post in threaded view
|

Re: Buffers.newDirectIntBuffer(int[]) does not set limit

Xerxes Rånby
Thank you, i think it is wise to file a bug-report.

I took a quick look and wrote a proposed "fix". By replacing the use of NIO Buffer rewind with clear.
gluegen-rewind-to-clear.patch
Please test!

http://docs.oracle.com/javase/7/docs/api/java/nio/Buffer.html#clear%28%29
"clear

    public final Buffer clear()

    Clears this buffer. The position is set to zero, the limit is set to the capacity, and the mark is discarded.

    Invoke this method before using a sequence of channel-read or put operations to fill this buffer. For example:

         buf.clear();     // Prepare buffer for reading
         in.read(buf);    // Read data

    This method does not actually erase the data in the buffer, but it is named as if it did because it will most often be used in situations in which that might as well be the case."
Reply | Threaded
Open this post in threaded view
|

Re: Buffers.newDirectIntBuffer(int[]) does not set limit

jmaasing
OMG I'm sorry I left out a piece of code that I use. The 'working' case is this:

final IntBuffer indexBuf = Buffers.newDirectIntBuffer(triIndexes.length);
for (int triIndex : triIndexes) {
	indexBuf.put(triIndex) ;
}
indexBuf.flip();

The flip() part is the essential thing and I think more appropriate than clear() in the Buffers class.

Sorry I do not have a build setup for gluegen where I can test the patch :-/
Reply | Threaded
Open this post in threaded view
|

Re: Buffers.newDirectIntBuffer(int[]) does not set limit

jmaasing
Reply | Threaded
Open this post in threaded view
|

Re: Buffers.newDirectIntBuffer(int[]) does not set limit

Xerxes Rånby
In reply to this post by jmaasing
jmaasing wrote
OMG I'm sorry I left out a piece of code that I use. The 'working' case is this:

final IntBuffer indexBuf = Buffers.newDirectIntBuffer(triIndexes.length);
for (int triIndex : triIndexes) {
	indexBuf.put(triIndex) ;
}
indexBuf.flip();

The flip() part is the essential thing and I think more appropriate than clear() in the Buffers class.

Sorry I do not have a build setup for gluegen where I can test the patch :-/
It would be good to understand the root cause why the crash can happen when lim do not match capacity.
The only reason i can think of that generates a crash is that the JVM garbage collector has decide to reclaim the memory that have been passed to the GPU.
Reply | Threaded
Open this post in threaded view
|

Re: Buffers.newDirectIntBuffer(int[]) does not set limit

jmaasing
Xerxes Rånby wrote
It would be good to understand the root cause why the crash can happen when lim do not match capacity.
The only reason i can think of that generates a crash is that the JVM garbage collector has decide to reclaim the memory that have been passed to the GPU.
Actually I think it is my code. I used the buffer limit to calculate the amount of data when uploading data to the driver. Since limit was 0 who knows what crap the driver found when it tried to render the data :-)
Reply | Threaded
Open this post in threaded view
|

Re: Buffers.newDirectIntBuffer(int[]) does not set limit

Sven Gothel
Administrator
On 07/24/2015 08:35 PM, jmaasing [via jogamp] wrote:

>     Xerxes Rånby wrote
>     It would be good to understand the root cause why the crash can happen
>     when lim do not match capacity.
>     The only reason i can think of that generates a crash is that the JVM
>     garbage collector has decide to reclaim the memory that have been passed
>     to the GPU.
>
> Actually I think it is my code. I used the buffer limit to calculate the
> amount of data when uploading data to the driver. Since limit was 0 who knows
> what crap the driver found when it tried to render the data :-)
We have added quite a few tests for this issue:
  <https://jogamp.org/bugzilla/show_bug.cgi?id=1180>

Question remains, how did it (0 limit) happen?

Please answer in related bug report and close it if proven
to be your issue.

I guess we are a bit 'crazy' about this issue,
since iff this would be an internal bug within GlueGen and/or JOGL
it is quite substantial (and would break everything).
Hence .. we are a bit concerned and tedious now :)

~Sven



signature.asc (828 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Buffers.newDirectIntBuffer(int[]) does not set limit

jmaasing
Sven Gothel wrote
Question remains, how did it (0 limit) happen?

Please answer in related bug report and close it if proven
to be your issue.

I guess we are a bit 'crazy' about this issue,
since iff this would be an internal bug within GlueGen and/or JOGL
it is quite substantial (and would break everything).
Hence .. we are a bit concerned and tedious now :)

~Sven
I had some time to investigate this, the problem is in my expectations on what the Buffers class does. You are absolutely right in that limit is correctly set by the Buffers class. The difference is actually in the position.

This test illustrates what my code did:

public class BuffersTest {
	@Test
	public void testFlipReadOnExplicitlyPutBuffer() {
		IntBuffer explicit = Buffers.newDirectIntBuffer(3);
		explicit.put(1) ;
		explicit.put(2) ;
		explicit.put(3) ;
		explicit.flip() ;
		
		assertTrue(explicit.get() == 1) ;
		assertTrue(explicit.get() == 2) ;
		assertTrue(explicit.get() == 3) ;
	}
	
	@Test
	public void testFlipReadOnArrayCreatedBuffer() {
		IntBuffer implicit = Buffers.newDirectIntBuffer(new int[] {1,2,3});
		implicit.flip() ;
		
		assertTrue(implicit.get() == 1) ;
		assertTrue(implicit.get() == 2) ;
		assertTrue(implicit.get() == 3) ;
	}
}

Notice that I 'flip()' the buffer before I read from them and this is the key problem.
In the 'implicit' case the position on the returned buffer is set to '0'. I assumed it would be set to 3 so it would be the same as in the explicit but I assumed wrong.

I do not consider this a bug, more a mistaken assumption on my part. I will close the bugzilla issue. Sorry for all the noise.