Once again! fast MappedObjects implementation

CLMem mem = clCreateBuffer(clContext, CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, nodes * Matrix4f.SIZEOF, errorCode);
ByteBuffer data = MappedObjectUnsafe.newBuffer(mem.getInfoLong(CL_MEM_HOST_PTR), (int)mem.getInfoSize(CL_MEM_SIZE));
Matrix4f matrices = Matrix4f.map(data);
Matrix4f.setIdentity(matrices, nodes);

Mapped access to CPU addressable PCIe memory? Check. :wink:

More requests:

  • A getter for the mapped buffer in MappedObject will be useful. Itā€™s one less reference to keep around when user code needs to pass the buffer to GL/CL.

  • A .map(address, capacity) could be added, that would do the equivalent of lines 2-3 in the code above. MappedObjectUnsafe could be made package-private as well.

Interesting to see how you put my lib to use :slight_smile:

What youā€™re doing, is rather dangerous at the moment. Once the GC deems the manipulated ByteBuffer collectable, it will free the address itā€™s pointing to, which is probably an illegal action, because that memory is not supposed to made available again through malloc(ā€¦) and last but not least might also be freed by the driver.

At least, thatā€™s what little I (think I) know of what happens within ByteBuffer and how memory gets reused.

I think the best solution would be to never release the buffers, by storing them in some hidden collection, forever, maybe adding a method to release them.

Nope, itā€™s safe because of .duplicate(). It uses a different constructor that doesnā€™t set a Deallocator, so Unsafeā€™s freeMemory wonā€™t be called when the object gets garbage collected. Itā€™s the same with JNIā€™s NewDirectByteBuffer.

[quote=ā€œRiven,post:62,topic:31992ā€]
Tbh, I would have created something like this on my own eventually. Iā€™m currently doing research for an upcoming project that kinda requires fast buffer access. It was very fortunate that you started working on this now, saves me time and Iā€™d never have thought about field access with bytecode transformation, so itā€™s a double win for me. Thatā€™s why Iā€™m trying to contribute as much as I can, I need this to be as robust and complete as possible. Iā€™m also pretty sure itā€™s not only me and Princec that are really happy about this library being available.

Keep in mind that the buffer is not necessarily linked to the baseAddress field, which might be very confusing.

Okay, but it would still need a reference to its ā€˜parentā€™ buffer, to prevent its memory region from being freed.

I should probably look into the sourcecode to see whatā€™s happening there.

[quote=ā€œSpasi,post:65,topic:31992ā€]

Your ā€˜contributionsā€™ are basically the only reason I keep updating the lib. It seems like nobody else cares, and I donā€™t really plan on using this lib myself :slight_smile:

[quote=ā€œRiven,post:66,topic:31992ā€]
I guess you mean when thereā€™s an offset involved? I can live with that.

[quote=ā€œRiven,post:66,topic:31992ā€]
Indeed, thereā€™s a ā€œviewedBufferā€ reference.

Iā€™m watching it carefully for the dust to settle so I can go and have a poke around it! My sprite engine is annoyingly much slower than it should be thanks to the relative slowness of filling data up in the buffers, so Iā€™m interested to see how much faster (and nicer looking!) it can be made to be with this.

Cas :slight_smile:

Iā€™m following this closely too.

me three :slight_smile:

me too, but only for interrest on the technical part, not really for using it.

well, youā€™d need to license it for your games then - CC-NCā€¦

That doesnā€™t mean that Iā€™d charge everybody for a commercial licenseā€¦ poor indies make an excellent exception :slight_smile:

Bit OT, but I hate that Non-Commercial clause. Itā€™s so misunderstood and ill-defined both generally and legally - just look at all the research and discussions around it when being ported to different jurisdictions. If thatā€™s what you want, why not GPL + commercial? Worked for MySQL (getting bought up and bolloxed up by Oracle is an optional extra! ;D )

I might change it soon, after some research. Letā€™s not derail this thread into a license discussion. :slight_smile:

I coded mapped ByteBuffers by turning the GETFIELD into bytecode that creates a new ByteBuffer, located at the proper memory region:

@MappedType(sizeof = 64)
public class MappedSomething extends MappedObject
{
   @MappedField(byteOffset = 0)
   public int        used;

   @MappedField(byteOffset = 4, byteLength = 64 - 4)
   public ByteBuffer data;

   @Override
   public String toString()
   {
      return "MappedSomething[" + used + "]";
   }
}

      MappedSomething some = MappedSomething.malloc(4);

      if (some.data == some.data)
         throw new IllegalStateException("should be two distinct ByteBuffers");

      ByteBuffer buf = some.data;  // creates new ByteBuffer instance, it will always point to view #0

      some.view++;

      buf = some.data;  // creates new ByteBuffer instance, it will always point to view #1

Itā€™s quite convenient this way, but the creation of the ByteBuffer adds some overhead. :emo:

Also, for traversing N mapped objects, use:


for(int i=0; i<N; i++)
{
    mapped.view = i;

    // stuff
}

not:


for(int mapped.view=0; mapped.view<N; mapped.view++)
{
    // stuff
}

maybe I will add an Iterator/Iterable for the convenient for-each loop.

Could you drop .duplicate() from .backingByteBuffer()? The library doesnā€™t depend on the ByteBuffer state so I donā€™t think thereā€™s a reason for the extra allocation there.

Fair enough. I updated it under version 0.6, as itā€™s a rather minor update.

Further, I added support for enhanced-for:


      for (MappedSomething item: foreach(mapped, viewCount))
      {
         System.out.println("item.view=" + item.view);
      }

which is a static import of MappedObject.foreach

Note that mapped==item, if you want an independant view, use dup()
Regardless of the initial value of ā€˜viewā€™, you will iterate: [0ā€¦viewCount>
After the foreach, the view of ā€˜mappedā€™ == ā€˜viewCount-1ā€™ (the last valid view, basically to prevent a native crash, when accessed after the loop!)

If anybody knows how to get this working with an instance-method, let me know. :point:

I also added MO.slice() which is identical to MO.dup(), except it does:
dst.baseAddress=src.viewAddress
which means is has similar characteristics as ByteBuffer.slice()

Bugfix in 0.6:

  • copy/paste bug in jput(..) and iput(..)

@Spasi: sent you a PM.

So uh, I still donā€™t get what the point of this library is :stuck_out_tongue: