You can subscribe to this list here.
| 2002 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
(134) |
Sep
(52) |
Oct
(13) |
Nov
(342) |
Dec
(163) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2003 |
Jan
(44) |
Feb
(62) |
Mar
(158) |
Apr
(38) |
May
(70) |
Jun
(58) |
Jul
(104) |
Aug
(207) |
Sep
(83) |
Oct
(122) |
Nov
(23) |
Dec
(49) |
| 2004 |
Jan
(119) |
Feb
(132) |
Mar
(192) |
Apr
(140) |
May
(77) |
Jun
(74) |
Jul
(201) |
Aug
(63) |
Sep
(102) |
Oct
(70) |
Nov
(173) |
Dec
(78) |
| 2005 |
Jan
(174) |
Feb
(197) |
Mar
(105) |
Apr
(59) |
May
(77) |
Jun
(43) |
Jul
(21) |
Aug
(18) |
Sep
(47) |
Oct
(37) |
Nov
(74) |
Dec
(50) |
| 2006 |
Jan
(44) |
Feb
(19) |
Mar
(32) |
Apr
(24) |
May
(31) |
Jun
(55) |
Jul
(138) |
Aug
(28) |
Sep
(12) |
Oct
(41) |
Nov
(58) |
Dec
(24) |
| 2007 |
Jan
(28) |
Feb
(14) |
Mar
(10) |
Apr
(68) |
May
(30) |
Jun
(26) |
Jul
(18) |
Aug
(63) |
Sep
(19) |
Oct
(29) |
Nov
(20) |
Dec
(10) |
| 2008 |
Jan
(38) |
Feb
(7) |
Mar
(37) |
Apr
(120) |
May
(41) |
Jun
(36) |
Jul
(39) |
Aug
(24) |
Sep
(28) |
Oct
(30) |
Nov
(36) |
Dec
(75) |
| 2009 |
Jan
(46) |
Feb
(22) |
Mar
(50) |
Apr
(70) |
May
(134) |
Jun
(105) |
Jul
(75) |
Aug
(34) |
Sep
(38) |
Oct
(34) |
Nov
(19) |
Dec
(20) |
| 2010 |
Jan
(11) |
Feb
(20) |
Mar
(65) |
Apr
(83) |
May
(104) |
Jun
(73) |
Jul
(78) |
Aug
(57) |
Sep
(43) |
Oct
(35) |
Nov
(9) |
Dec
(4) |
| 2011 |
Jan
(21) |
Feb
(11) |
Mar
(18) |
Apr
(10) |
May
(18) |
Jun
(15) |
Jul
(48) |
Aug
(25) |
Sep
(17) |
Oct
(45) |
Nov
(15) |
Dec
(12) |
| 2012 |
Jan
(21) |
Feb
(9) |
Mar
(12) |
Apr
(9) |
May
(9) |
Jun
(5) |
Jul
(1) |
Aug
(10) |
Sep
(12) |
Oct
(1) |
Nov
(28) |
Dec
(5) |
| 2013 |
Jan
(4) |
Feb
(1) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
| 2014 |
Jan
|
Feb
(1) |
Mar
(1) |
Apr
|
May
(2) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(1) |
Nov
|
Dec
|
| 2015 |
Jan
(1) |
Feb
|
Mar
|
Apr
|
May
|
Jun
(1) |
Jul
|
Aug
|
Sep
|
Oct
(2) |
Nov
|
Dec
|
| 2016 |
Jan
(2) |
Feb
(1) |
Mar
(1) |
Apr
(1) |
May
(2) |
Jun
|
Jul
(1) |
Aug
(2) |
Sep
|
Oct
|
Nov
(1) |
Dec
|
| 2017 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(1) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
|
|
|
|
|
|
1
|
2
(1) |
|
3
|
4
|
5
|
6
|
7
|
8
(1) |
9
(2) |
|
10
(8) |
11
(3) |
12
(13) |
13
(4) |
14
(2) |
15
|
16
(6) |
|
17
(1) |
18
|
19
|
20
|
21
(1) |
22
(2) |
23
(2) |
|
24
(1) |
25
|
26
|
27
|
28
|
29
(1) |
30
|
|
31
|
|
|
|
|
|
|
|
From: <sp...@us...> - 2011-07-22 20:09:08
|
Revision: 3598
http://java-game-lib.svn.sourceforge.net/java-game-lib/?rev=3598&view=rev
Author: spasi
Date: 2011-07-22 20:09:01 +0000 (Fri, 22 Jul 2011)
Log Message:
-----------
Converted sizeof and align to methods.
Override more methods in MappedObject subclasses, foreach is now 4 times faster.
Modified Paths:
--------------
trunk/LWJGL/src/java/org/lwjgl/test/mapped/MappedObjectTests1.java
trunk/LWJGL/src/java/org/lwjgl/test/mapped/MappedObjectTests2.java
trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedForeach.java
trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedHelper.java
trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedObject.java
trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedObjectClassLoader.java
trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedObjectTransformer.java
trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedSet2.java
trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedSet3.java
trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedSet4.java
Modified: trunk/LWJGL/src/java/org/lwjgl/test/mapped/MappedObjectTests1.java
===================================================================
--- trunk/LWJGL/src/java/org/lwjgl/test/mapped/MappedObjectTests1.java 2011-07-22 02:01:56 UTC (rev 3597)
+++ trunk/LWJGL/src/java/org/lwjgl/test/mapped/MappedObjectTests1.java 2011-07-22 20:09:01 UTC (rev 3598)
@@ -60,8 +60,8 @@
{
MappedFloat vecs1 = MappedFloat.malloc(1234);
- assert (vecs1.sizeof == MappedFloat.SIZEOF);
- assert (vecs1.sizeof * 1234 == vecs1.backingByteBuffer().capacity());
+ assert (vecs1.getSizeof() == MappedFloat.SIZEOF);
+ assert (vecs1.getSizeof() * 1234 == vecs1.backingByteBuffer().capacity());
assert (MappedFloat.SIZEOF * 1234 == vecs1.backingByteBuffer().capacity());
}
Modified: trunk/LWJGL/src/java/org/lwjgl/test/mapped/MappedObjectTests2.java
===================================================================
--- trunk/LWJGL/src/java/org/lwjgl/test/mapped/MappedObjectTests2.java 2011-07-22 02:01:56 UTC (rev 3597)
+++ trunk/LWJGL/src/java/org/lwjgl/test/mapped/MappedObjectTests2.java 2011-07-22 20:09:01 UTC (rev 3598)
@@ -44,7 +44,7 @@
System.out.println(vecs.viewAddress); // test read-access
- System.out.println(vecs.align); // test read-access
+ System.out.println(vecs.getAlign()); // test read-access
System.out.println(MappedVec3.SIZEOF); // test read-access
}
@@ -91,7 +91,7 @@
vecs.view = 1;
long a2 = vecs.viewAddress;
assert (a2 - a1 == MappedVec3.SIZEOF);
- assert (a2 - a1 == vecs.sizeof);
+ assert (a2 - a1 == vecs.getSizeof());
vecs.view = 0;
}
}
Modified: trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedForeach.java
===================================================================
--- trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedForeach.java 2011-07-22 02:01:56 UTC (rev 3597)
+++ trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedForeach.java 2011-07-22 20:09:01 UTC (rev 3598)
@@ -58,7 +58,7 @@
}
public T next() {
- MappedHelper.put_view(mapped, this.index++, mapped.sizeof);
+ mapped.setViewAddress(mapped.getViewAddress(this.index++));
return mapped;
}
Modified: trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedHelper.java
===================================================================
--- trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedHelper.java 2011-07-22 02:01:56 UTC (rev 3597)
+++ trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedHelper.java 2011-07-22 20:09:01 UTC (rev 3598)
@@ -55,11 +55,9 @@
if ( LWJGLUtil.CHECKS && align <= 0 )
throw new IllegalArgumentException("invalid alignment");
- mo.align = align;
if ( LWJGLUtil.CHECKS && (sizeof <= 0 || sizeof % align != 0) )
throw new IllegalStateException("sizeof not a multiple of alignment");
- mo.sizeof = sizeof;
long addr = MemoryUtil.getAddress(buffer);
if ( LWJGLUtil.CHECKS && addr % align != 0 )
@@ -107,8 +105,6 @@
public static MappedObject dup(MappedObject src, MappedObject dst) {
dst.baseAddress = src.baseAddress;
dst.viewAddress = src.viewAddress;
- dst.align = src.align;
- dst.sizeof = src.sizeof;
dst.preventGC = src.preventGC;
return dst;
}
@@ -116,8 +112,6 @@
public static MappedObject slice(MappedObject src, MappedObject dst) {
dst.baseAddress = src.viewAddress; // !
dst.viewAddress = src.viewAddress;
- dst.align = src.align;
- dst.sizeof = src.sizeof;
dst.preventGC = src.preventGC;
return dst;
}
Modified: trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedObject.java
===================================================================
--- trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedObject.java 2011-07-22 02:01:56 UTC (rev 3597)
+++ trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedObject.java 2011-07-22 20:09:01 UTC (rev 3598)
@@ -50,11 +50,11 @@
*
* @author Riven
*/
-public class MappedObject {
+public abstract class MappedObject {
static final boolean CHECKS = LWJGLUtil.getPrivilegedBoolean("org.lwjgl.util.mapped.Checks");
- public MappedObject() {
+ protected MappedObject() {
//
}
@@ -64,12 +64,9 @@
/** The mapped object view memory address, in bytes. Read-only. */
public long viewAddress;
- /** The mapped object memory alignment, in bytes. Read-only. */
- public int align;
+ /** The mapped buffer. */
+ ByteBuffer preventGC;
- /** The mapped object memory sizeof, in bytes. Read-only. */
- public int sizeof;
-
/**
* Holds the value of sizeof of the sub-type of this MappedObject<br>
* <br>
@@ -87,6 +84,12 @@
*/
public int view;
+ protected final long getViewAddress(final int view) {
+ // No call-site modification for this, we override in every subclass instead,
+ // so that we can use it in MappedForeach.
+ throw new InternalError("type not registered");
+ }
+
public final void setViewAddress(final long address) {
if ( CHECKS )
checkAddress(address);
@@ -96,8 +99,8 @@
final void checkAddress(final long address) {
final long base = MemoryUtil.getAddress0(preventGC);
final int offset = (int)(address - base);
- if ( address < base || preventGC.capacity() < (offset + this.sizeof) )
- throw new IndexOutOfBoundsException(Integer.toString(offset / sizeof));
+ if ( address < base || preventGC.capacity() < (offset + getSizeof()) )
+ throw new IndexOutOfBoundsException(Integer.toString(offset / getSizeof()));
}
final void checkRange(final int bytes) {
@@ -108,7 +111,28 @@
throw new BufferOverflowException();
}
+ /** The mapped object memory alignment, in bytes. Read-only. */
/**
+ * Returns the mapped object memory alignment, in bytes.
+ *
+ * @return the memory alignment
+ */
+ public final int getAlign() {
+ // No call-site modification for this, we override in every subclass instead.
+ throw new InternalError("type not registered");
+ }
+
+ /**
+ * Returns the mapped object memory sizeof, in bytes.
+ *
+ * @return the sizeof value
+ */
+ public final int getSizeof() {
+ // No call-site modification for this, we override in every subclass instead.
+ throw new InternalError("type not registered");
+ }
+
+ /**
* Creates a MappedObject instance, mapping the memory region of the specified direct ByteBuffer.
* <p/>
* The behavior of this (transformed) method does not follow the normal Java behavior.<br>
@@ -178,22 +202,18 @@
* Any code in the default constructor will not run automatically. This method
* can be used to run execute that code on the current view.
*/
- public final <T extends MappedObject> void runViewConstructor() {
+ public final void runViewConstructor() {
// any method that calls this method will have its call-site modified
throw new InternalError("type not registered");
}
/** Moves the current view to the next element. */
public final void next() {
- // any method that calls this method will have its call-site modified
+ // No call-site modification for this, we override in every subclass instead,
+ // so that we can use it in MappedSetX.
throw new InternalError("type not registered");
}
- /** Moves the current view to the next element. Non-transformed implementation for MappedSets. */
- final void nextSet() {
- setViewAddress(viewAddress + sizeof);
- }
-
/**
* Copies and amount of <code>SIZEOF</code> bytes, from the current
* mapped object, to the specified mapped object.
@@ -232,14 +252,12 @@
throw new InternalError("type not registered");
}
- ByteBuffer preventGC;
-
/**
* Returns the {@link java.nio.ByteBuffer} that backs this mapped object.
*
* @return the backing buffer
*/
- public ByteBuffer backingByteBuffer() {
+ public final ByteBuffer backingByteBuffer() {
return this.preventGC;
}
Modified: trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedObjectClassLoader.java
===================================================================
--- trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedObjectClassLoader.java 2011-07-22 02:01:56 UTC (rev 3597)
+++ trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedObjectClassLoader.java 2011-07-22 20:09:01 UTC (rev 3598)
@@ -73,7 +73,9 @@
FORKED = true;
try {
- URLClassLoader loader = new MappedObjectClassLoader(mainClass);
+ MappedObjectClassLoader loader = new MappedObjectClassLoader(mainClass);
+ loader.loadMappedObject();
+
Class<?> replacedMainClass = loader.loadClass(mainClass.getName());
Method mainMethod = replacedMainClass.getMethod("main", String[].class);
mainMethod.invoke(null, new Object[] { args });
@@ -90,6 +92,28 @@
super(((URLClassLoader)mainClass.getClassLoader()).getURLs());
}
+ protected synchronized Class<?> loadMappedObject() throws ClassNotFoundException {
+ final String name = MappedObject.class.getName();
+ String className = name.replace('.', '/');
+
+ if ( MappedObjectTransformer.PRINT_ACTIVITY )
+ LWJGLUtil.log(MappedObjectClassLoader.class.getSimpleName() + ": " + className);
+
+ byte[] bytecode = readStream(this.getResourceAsStream(className.concat(".class")));
+
+ long t0 = System.nanoTime();
+ bytecode = MappedObjectTransformer.transformMappedObject(bytecode);
+ long t1 = System.nanoTime();
+ total_time_transforming += (t1 - t0);
+
+ if ( MappedObjectTransformer.PRINT_TIMING )
+ LWJGLUtil.log("transforming " + className + " took " + (t1 - t0) / 1000 + " micros (total: " + (total_time_transforming / 1000 / 1000) + "ms)");
+
+ Class<?> clazz = super.defineClass(name, bytecode, 0, bytecode.length);
+ resolveClass(clazz);
+ return clazz;
+ }
+
private static long total_time_transforming;
@Override
@@ -104,10 +128,8 @@
if ( name.startsWith("sunw.") )
return super.loadClass(name, resolve);
- // never transform classes in this very package, sub-packages should be transformed
- if ( name.startsWith(MAPPEDOBJECT_PACKAGE_PREFIX) )
- if ( name.substring(MAPPEDOBJECT_PACKAGE_PREFIX.length()).indexOf('.') == -1 )
- return super.loadClass(name, resolve);
+ if ( name.equals(MappedObjectClassLoader.class.getName()) )
+ return super.loadClass(name, resolve);
String className = name.replace('.', '/');
@@ -116,13 +138,16 @@
byte[] bytecode = readStream(this.getResourceAsStream(className.concat(".class")));
- long t0 = System.nanoTime();
- bytecode = MappedObjectTransformer.transformMappedAPI(className, bytecode);
- long t1 = System.nanoTime();
- total_time_transforming += (t1 - t0);
+ // Classes in this package do not get transformed, but need to go through here because we have transformed MappedObject.
+ if ( !(name.startsWith(MAPPEDOBJECT_PACKAGE_PREFIX) && name.substring(MAPPEDOBJECT_PACKAGE_PREFIX.length()).indexOf('.') == -1) ) {
+ long t0 = System.nanoTime();
+ bytecode = MappedObjectTransformer.transformMappedAPI(className, bytecode);
+ long t1 = System.nanoTime();
- if ( MappedObjectTransformer.PRINT_TIMING )
- LWJGLUtil.log("transforming " + className + " took " + (t1 - t0) / 1000 + " micros (total: " + (total_time_transforming / 1000 / 1000) + "ms)");
+ total_time_transforming += (t1 - t0);
+ if ( MappedObjectTransformer.PRINT_TIMING )
+ LWJGLUtil.log("transforming " + className + " took " + (t1 - t0) / 1000 + " micros (total: " + (total_time_transforming / 1000 / 1000) + "ms)");
+ }
Class<?> clazz = super.defineClass(name, bytecode, 0, bytecode.length);
if ( resolve )
Modified: trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedObjectTransformer.java
===================================================================
--- trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedObjectTransformer.java 2011-07-22 02:01:56 UTC (rev 3597)
+++ trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedObjectTransformer.java 2011-07-22 20:09:01 UTC (rev 3598)
@@ -35,6 +35,7 @@
import org.objectweb.asm.*;
import org.objectweb.asm.tree.*;
import org.objectweb.asm.tree.analysis.*;
+import org.objectweb.asm.tree.analysis.Frame;
import org.objectweb.asm.util.TraceClassVisitor;
import java.io.PrintWriter;
@@ -76,10 +77,16 @@
static final String MAPPED_SET3_JVM = jvmClassName(MappedSet3.class);
static final String MAPPED_SET4_JVM = jvmClassName(MappedSet4.class);
- static final String LENGTH_METHOD_NAME = "length$LWJGL";
- static final String VIEWADDRESS_METHOD_NAME = "getViewAddress$LWJGL";
- static final String VIEW_CONSTRUCTOR_NAME = "constructView$LWJGL";
+ // Public methods
+ static final String VIEWADDRESS_METHOD_NAME = "getViewAddress";
+ static final String NEXT_METHOD_NAME = "next";
+ static final String ALIGN_METHOD_NAME = "getAlign";
+ static final String SIZEOF_METHOD_NAME = "getSizeof";
+ // Internal methods
+ static final String LENGTH_METHOD_NAME = "length$LWJGL"; // Used for .asArray().length
+ static final String VIEW_CONSTRUCTOR_NAME = "constructView$LWJGL"; // Used by runViewConstructor
+
static final Map<Integer, String> OPCODE_TO_NAME = new HashMap<Integer, String>();
static final Map<Integer, String> INSNTYPE_TO_NAME = new HashMap<Integer, String>();
@@ -122,9 +129,6 @@
* @param type the mapped object class.
*/
public static void register(Class<?> type) {
- if ( MappedObjectClassLoader.FORKED )
- return;
-
final MappedType mapped = type.getAnnotation(MappedType.class);
if ( mapped == null )
throw new InternalError("missing " + MappedType.class.getName() + " annotation");
@@ -185,6 +189,34 @@
return (int)byteLength;
}
+ /** Removes final from methods that will be overriden by subclasses. */
+ static byte[] transformMappedObject(byte[] bytecode) {
+ final ClassWriter cw = new ClassWriter(0);
+
+ ClassVisitor cv = new ClassAdapter(cw) {
+
+ private final String[] DEFINALIZE_LIST = {
+ VIEWADDRESS_METHOD_NAME,
+ NEXT_METHOD_NAME,
+ ALIGN_METHOD_NAME,
+ SIZEOF_METHOD_NAME,
+ };
+
+ public MethodVisitor visitMethod(int access, final String name, final String desc, final String signature, final String[] exceptions) {
+ for ( String method : DEFINALIZE_LIST ) {
+ if ( name.equals(method) ) {
+ access &= ~ACC_FINAL;
+ break;
+ }
+ }
+ return super.visitMethod(access, name, desc, signature, exceptions);
+ }
+ };
+
+ new ClassReader(bytecode).accept(cv, 0);
+ return cw.toByteArray();
+ }
+
static byte[] transformMappedAPI(final String className, byte[] bytecode) {
final ClassWriter cw = new ClassWriter(COMPUTE_FRAMES) {
@@ -203,8 +235,7 @@
if ( className_to_subtype.containsKey(className) ) // Do a first pass to generate address getters
cv = getMethodGenAdapter(className, cv);
- //cr.accept(cv, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
- new ClassReader(bytecode).accept(cv, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
+ new ClassReader(bytecode).accept(cv, ClassReader.SKIP_FRAMES);
bytecode = cw.toByteArray();
if ( PRINT_BYTECODE )
@@ -218,11 +249,14 @@
@Override
public void visitEnd() {
+ final MappedSubtypeInfo mappedSubtype = className_to_subtype.get(className);
+
generateViewAddressGetter();
generateLengthGetter();
+ generateAlignGetter(mappedSubtype);
+ generateSizeofGetter();
+ generateNext();
- final MappedSubtypeInfo mappedSubtype = className_to_subtype.get(className);
-
for ( String fieldName : mappedSubtype.fieldToOffset.keySet() ) {
final Type type = mappedSubtype.fieldToType.get(fieldName);
@@ -238,7 +272,7 @@
}
private void generateViewAddressGetter() {
- MethodVisitor mv = super.visitMethod(ACC_PUBLIC | ACC_STATIC, VIEWADDRESS_METHOD_NAME, "(L" + className + ";I)J", null, null);
+ MethodVisitor mv = super.visitMethod(ACC_PUBLIC, VIEWADDRESS_METHOD_NAME, "(I)J", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, MAPPED_OBJECT_JVM, "baseAddress", "J");
@@ -266,7 +300,7 @@
MethodVisitor mv = super.visitMethod(ACC_PUBLIC | ACC_STATIC, LENGTH_METHOD_NAME, "(L" + className + ";)I", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
- mv.visitMethodInsn(INVOKEVIRTUAL, className, "backingByteBuffer", "()L" + jvmClassName(ByteBuffer.class) + ";");
+ mv.visitMethodInsn(INVOKEVIRTUAL, MAPPED_OBJECT_JVM, "backingByteBuffer", "()L" + jvmClassName(ByteBuffer.class) + ";");
mv.visitMethodInsn(INVOKEVIRTUAL, jvmClassName(ByteBuffer.class), "capacity", "()I");
mv.visitFieldInsn(GETSTATIC, className, "SIZEOF", "I");
mv.visitInsn(IDIV);
@@ -275,12 +309,45 @@
mv.visitEnd();
}
+ private void generateAlignGetter(final MappedSubtypeInfo mappedSubtype) {
+ MethodVisitor mv = super.visitMethod(ACC_PUBLIC, ALIGN_METHOD_NAME, "()I", null, null);
+ mv.visitCode();
+ visitIntNode(mv, mappedSubtype.sizeof);
+ mv.visitInsn(IRETURN);
+ mv.visitMaxs(1, 1);
+ mv.visitEnd();
+ }
+
+ private void generateSizeofGetter() {
+ MethodVisitor mv = super.visitMethod(ACC_PUBLIC, SIZEOF_METHOD_NAME, "()I", null, null);
+ mv.visitCode();
+ mv.visitFieldInsn(GETSTATIC, className, "SIZEOF", "I");
+ mv.visitInsn(IRETURN);
+ mv.visitMaxs(1, 1);
+ mv.visitEnd();
+ }
+
+ private void generateNext() {
+ MethodVisitor mv = super.visitMethod(ACC_PUBLIC, NEXT_METHOD_NAME, "()V", null, null);
+ mv.visitCode();
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitInsn(DUP);
+ mv.visitFieldInsn(GETFIELD, MAPPED_OBJECT_JVM, "viewAddress", "J");
+ mv.visitFieldInsn(GETSTATIC, className, "SIZEOF", "I");
+ mv.visitInsn(I2L);
+ mv.visitInsn(LADD);
+ mv.visitMethodInsn(INVOKEVIRTUAL, className, "setViewAddress", "(J)V");
+ mv.visitInsn(RETURN);
+ mv.visitMaxs(3, 1);
+ mv.visitEnd();
+ }
+
private void generateByteBufferGetter(final MappedSubtypeInfo mappedSubtype, final String fieldName, final Type type) {
MethodVisitor mv = super.visitMethod(ACC_PUBLIC | ACC_STATIC, getterName(fieldName), "(L" + className + ";I)" + type.getDescriptor(), null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ILOAD, 1);
- mv.visitMethodInsn(INVOKESTATIC, className, VIEWADDRESS_METHOD_NAME, "(L" + className + ";I)J");
+ mv.visitMethodInsn(INVOKEVIRTUAL, className, VIEWADDRESS_METHOD_NAME, "(I)J");
visitIntNode(mv, mappedSubtype.fieldToOffset.get(fieldName).intValue());
mv.visitInsn(I2L);
mv.visitInsn(LADD);
@@ -296,13 +363,13 @@
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ILOAD, 1);
- mv.visitMethodInsn(INVOKESTATIC, className, VIEWADDRESS_METHOD_NAME, "(L" + className + ";I)J");
+ mv.visitMethodInsn(INVOKEVIRTUAL, className, VIEWADDRESS_METHOD_NAME, "(I)J");
visitIntNode(mv, mappedSubtype.fieldToOffset.get(fieldName).intValue());
mv.visitInsn(I2L);
mv.visitInsn(LADD);
mv.visitMethodInsn(INVOKESTATIC, MAPPED_HELPER_JVM, type.getDescriptor().toLowerCase() + "get", "(J)" + type.getDescriptor());
mv.visitInsn(type.getOpcode(IRETURN));
- mv.visitMaxs(2, 2);
+ mv.visitMaxs(3, 2);
mv.visitEnd();
}
@@ -331,13 +398,13 @@
mv.visitVarInsn(load, 2);
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ILOAD, 1);
- mv.visitMethodInsn(INVOKESTATIC, className, VIEWADDRESS_METHOD_NAME, "(L" + className + ";I)J");
+ mv.visitMethodInsn(INVOKEVIRTUAL, className, VIEWADDRESS_METHOD_NAME, "(I)J");
visitIntNode(mv, mappedSubtype.fieldToOffset.get(fieldName).intValue());
mv.visitInsn(I2L);
mv.visitInsn(LADD);
mv.visitMethodInsn(INVOKESTATIC, MAPPED_HELPER_JVM, type.getDescriptor().toLowerCase() + "put", "(" + type.getDescriptor() + "J)V");
mv.visitInsn(RETURN);
- mv.visitMaxs(3, 3);
+ mv.visitMaxs(4, 3);
mv.visitEnd();
}
@@ -415,12 +482,14 @@
@Override
public void visitEnd() {
- if ( needsTransformation ) // Early-out for methods that do not touch a mapped object.
+ if ( needsTransformation ) { // Early-out for methods that do not touch a mapped object.
+ //System.err.println("\nTRANSFORMING: " + className + "." + name + desc);
try {
transformMethod(analyse());
} catch (Exception e) {
throw new RuntimeException(e);
}
+ }
// Pass the instruction stream to the adapter's MethodVisitor
accept(mv);
@@ -433,8 +502,6 @@
}
private void transformMethod(final Frame<BasicValue>[] frames) {
- //System.err.println("\nTRANSFORMING: " + className + " - " + name + desc);
-
final InsnList instructions = this.instructions;
final Map<Integer, MappedSubtypeInfo> arrayVars = new HashMap<Integer, MappedSubtypeInfo>();
@@ -540,10 +607,6 @@
break;
}
- if ( "next".equals(methodInsn.name) && "()V".equals(methodInsn.desc) ) {
- i = replace(instructions, i, methodInsn, generateNextInstructions(mappedType));
- break;
- }
break;
case INVOKESPECIAL:
// super() in VIEW_CONSTRUCTOR_NAME, remove
@@ -567,18 +630,6 @@
return i;
}
- private static InsnList generateNextInstructions(final MappedSubtypeInfo mappedType) {
- final InsnList list = new InsnList();
-
- // stack: this
- list.add(getIntNode(mappedType.sizeof));
- // stack: sizeof, this
- list.add(new MethodInsnNode(INVOKESTATIC, MAPPED_HELPER_JVM, "put_view_next", "(L" + MAPPED_OBJECT_JVM + ";I)V"));
- // stack: -
-
- return list;
- }
-
private static InsnList generateCopyRangeInstructions(final MappedSubtypeInfo mappedType) {
final InsnList list = new InsnList();
@@ -705,9 +756,6 @@
if ( "view".equals(fieldInsn.name) )
return generateViewInstructions(fieldInsn, mappedSubtype);
- if ( "align".equals(fieldInsn.name) || "sizeof".equals(fieldInsn.name) )
- return generateAlignSizeofInstructions(fieldInsn, mappedSubtype);
-
if ( "baseAddress".equals(fieldInsn.name) || "viewAddress".equals(fieldInsn.name) ) {
return generateAddressInstructions(fieldInsn);
}
@@ -806,29 +854,6 @@
throw new InternalError();
}
- private static InsnList generateAlignSizeofInstructions(final FieldInsnNode fieldInsn, final MappedSubtypeInfo mappedSubtype) {
- if ( !"I".equals(fieldInsn.desc) )
- throw new InternalError();
-
- if ( fieldInsn.getOpcode() == GETFIELD ) {
- final InsnList list = new InsnList();
-
- // stack: instance
- list.add(new InsnNode(POP));
- // stack: -
- if ( "sizeof".equals(fieldInsn.name) )
- list.add(getIntNode(mappedSubtype.sizeof));
- else if ( "align".equals(fieldInsn.name) )
- list.add(getIntNode(mappedSubtype.align));
- // stack: int
- return list;
- }
-
- if ( fieldInsn.getOpcode() == PUTFIELD )
- throwAccessErrorOnReadOnlyField(fieldInsn.owner, fieldInsn.name);
- throw new InternalError();
- }
-
private static InsnList generateAddressInstructions(final FieldInsnNode fieldInsn) {
if ( !"J".equals(fieldInsn.desc) )
throw new IllegalStateException();
@@ -961,7 +986,7 @@
nextInsn = getter;
continue;
} else if ( stackSize < loadStackSize )
- throw new ClassFormatError("Invalid .asArray() usage detected: " + getOpcodeName(nextInsn));
+ throw new ClassFormatError("Invalid " + mappedSubtype.className + " view array usage detected: " + getOpcodeName(nextInsn));
}
instructions.remove(aaLoadInsn);
Modified: trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedSet2.java
===================================================================
--- trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedSet2.java 2011-07-22 02:01:56 UTC (rev 3597)
+++ trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedSet2.java 2011-07-22 20:09:01 UTC (rev 3598)
@@ -44,13 +44,13 @@
public int view;
void view(int view) {
- MappedHelper.put_view(this.a, view, this.a.sizeof);
- MappedHelper.put_view(this.b, view, this.b.sizeof);
+ a.setViewAddress(a.getViewAddress(view));
+ b.setViewAddress(b.getViewAddress(view));
}
public void next() {
- this.a.nextSet();
- this.b.nextSet();
+ this.a.next();
+ this.b.next();
}
}
\ No newline at end of file
Modified: trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedSet3.java
===================================================================
--- trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedSet3.java 2011-07-22 02:01:56 UTC (rev 3597)
+++ trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedSet3.java 2011-07-22 20:09:01 UTC (rev 3598)
@@ -45,15 +45,15 @@
public int view;
void view(int view) {
- MappedHelper.put_view(this.a, view, this.a.sizeof);
- MappedHelper.put_view(this.b, view, this.b.sizeof);
- MappedHelper.put_view(this.c, view, this.c.sizeof);
+ a.setViewAddress(a.getViewAddress(view));
+ b.setViewAddress(b.getViewAddress(view));
+ c.setViewAddress(c.getViewAddress(view));
}
public void next() {
- this.a.nextSet();
- this.b.nextSet();
- this.c.nextSet();
+ this.a.next();
+ this.b.next();
+ this.c.next();
}
}
\ No newline at end of file
Modified: trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedSet4.java
===================================================================
--- trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedSet4.java 2011-07-22 02:01:56 UTC (rev 3597)
+++ trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedSet4.java 2011-07-22 20:09:01 UTC (rev 3598)
@@ -46,16 +46,16 @@
public int view;
void view(int view) {
- MappedHelper.put_view(this.a, view, this.a.sizeof);
- MappedHelper.put_view(this.b, view, this.b.sizeof);
- MappedHelper.put_view(this.c, view, this.c.sizeof);
- MappedHelper.put_view(this.d, view, this.d.sizeof);
+ a.setViewAddress(a.getViewAddress(view));
+ b.setViewAddress(b.getViewAddress(view));
+ c.setViewAddress(c.getViewAddress(view));
+ d.setViewAddress(d.getViewAddress(view));
}
public void next() {
- this.a.nextSet();
- this.b.nextSet();
- this.c.nextSet();
- this.d.nextSet();
+ this.a.next();
+ this.b.next();
+ this.c.next();
+ this.d.next();
}
}
\ No newline at end of file
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <sp...@us...> - 2011-07-22 02:02:05
|
Revision: 3597
http://java-game-lib.svn.sourceforge.net/java-game-lib/?rev=3597&view=rev
Author: spasi
Date: 2011-07-22 02:01:56 +0000 (Fri, 22 Jul 2011)
Log Message:
-----------
Added support for array access to mapped objects.
Added SpriteShootout test that uses mapped objects.
Modified Paths:
--------------
trunk/LWJGL/build.xml
trunk/LWJGL/src/java/org/lwjgl/test/mapped/MappedObjectBench.java
trunk/LWJGL/src/java/org/lwjgl/test/mapped/MappedObjectTests1.java
trunk/LWJGL/src/java/org/lwjgl/test/mapped/MappedObjectTests3.java
trunk/LWJGL/src/java/org/lwjgl/test/mapped/TestMappedObject.java
trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedHelper.java
trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedObject.java
trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedObjectClassLoader.java
trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedObjectTransformer.java
trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedObjectUnsafe.java
trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedSet2.java
trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedSet3.java
trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedSet4.java
Added Paths:
-----------
trunk/LWJGL/libs/asm-debug-all.jar
trunk/LWJGL/src/java/org/lwjgl/test/mapped/MappedObjectTests4.java
trunk/LWJGL/src/java/org/lwjgl/test/opengl/sprites/SpriteShootoutMapped.java
Removed Paths:
-------------
trunk/LWJGL/libs/asm-util.jar
trunk/LWJGL/libs/asm.jar
Modified: trunk/LWJGL/build.xml
===================================================================
--- trunk/LWJGL/build.xml 2011-07-21 22:52:16 UTC (rev 3596)
+++ trunk/LWJGL/build.xml 2011-07-22 02:01:56 UTC (rev 3597)
@@ -410,7 +410,7 @@
<!-- Compiles the Java source code -->
<target name="compile" description="Compiles the java source code" depends="-initialize">
- <javac debug="yes" destdir="${lwjgl.bin}" source="1.5" target="1.5" classpath="${lwjgl.lib}/jinput.jar:${lwjgl.lib}/AppleJavaExtensions.jar;${lwjgl.lib}/asm.jar;${lwjgl.lib}/asm-util.jar" taskname="core">
+ <javac debug="yes" destdir="${lwjgl.bin}" source="1.5" target="1.5" classpath="${lwjgl.lib}/jinput.jar:${lwjgl.lib}/AppleJavaExtensions.jar:${lwjgl.lib}/asm-debug-all.jar" taskname="core">
<!--<compilerarg value="-Xlint:unchecked"/>-->
<src path="${lwjgl.src}/java/"/>
<src path="${lwjgl.src}/generated/"/>
Added: trunk/LWJGL/libs/asm-debug-all.jar
===================================================================
(Binary files differ)
Property changes on: trunk/LWJGL/libs/asm-debug-all.jar
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Deleted: trunk/LWJGL/libs/asm-util.jar
===================================================================
(Binary files differ)
Deleted: trunk/LWJGL/libs/asm.jar
===================================================================
(Binary files differ)
Modified: trunk/LWJGL/src/java/org/lwjgl/test/mapped/MappedObjectBench.java
===================================================================
--- trunk/LWJGL/src/java/org/lwjgl/test/mapped/MappedObjectBench.java 2011-07-21 22:52:16 UTC (rev 3596)
+++ trunk/LWJGL/src/java/org/lwjgl/test/mapped/MappedObjectBench.java 2011-07-22 02:01:56 UTC (rev 3597)
@@ -31,6 +31,7 @@
*/
package org.lwjgl.test.mapped;
+import org.lwjgl.MemoryUtil;
import org.lwjgl.util.mapped.MappedObjectUnsafe;
import java.nio.ByteBuffer;
@@ -212,7 +213,7 @@
final int iterations = 64 * 1024;
ByteBuffer bb = ByteBuffer.allocateDirect(200);
- long addr = MappedObjectUnsafe.getBufferBaseAddress(bb);
+ long addr = MemoryUtil.getAddress(bb);
long[] took = new long[runs];
for ( int run = 0; run < runs; run++ ) {
Modified: trunk/LWJGL/src/java/org/lwjgl/test/mapped/MappedObjectTests1.java
===================================================================
--- trunk/LWJGL/src/java/org/lwjgl/test/mapped/MappedObjectTests1.java 2011-07-21 22:52:16 UTC (rev 3596)
+++ trunk/LWJGL/src/java/org/lwjgl/test/mapped/MappedObjectTests1.java 2011-07-22 02:01:56 UTC (rev 3597)
@@ -31,6 +31,7 @@
*/
package org.lwjgl.test.mapped;
+import org.lwjgl.MemoryUtil;
import org.lwjgl.util.mapped.MappedHelper;
import org.lwjgl.util.mapped.MappedObjectUnsafe;
@@ -143,9 +144,9 @@
// test newBuffer
{
- long addr1 = MappedObjectUnsafe.getBufferBaseAddress(bb);
+ long addr1 = MemoryUtil.getAddress(bb);
ByteBuffer bb2 = MappedHelper.newBuffer(addr1, bb.capacity());
- long addr2 = MappedObjectUnsafe.getBufferBaseAddress(bb);
+ long addr2 = MemoryUtil.getAddress(bb);
System.out.println(bb);
System.out.println(bb2);
Modified: trunk/LWJGL/src/java/org/lwjgl/test/mapped/MappedObjectTests3.java
===================================================================
--- trunk/LWJGL/src/java/org/lwjgl/test/mapped/MappedObjectTests3.java 2011-07-21 22:52:16 UTC (rev 3596)
+++ trunk/LWJGL/src/java/org/lwjgl/test/mapped/MappedObjectTests3.java 2011-07-22 02:01:56 UTC (rev 3597)
@@ -31,7 +31,11 @@
*/
package org.lwjgl.test.mapped;
-import org.lwjgl.util.mapped.*;
+import org.lwjgl.MemoryUtil;
+import org.lwjgl.util.mapped.MappedObject;
+import org.lwjgl.util.mapped.MappedSet;
+import org.lwjgl.util.mapped.MappedSet2;
+import org.lwjgl.util.mapped.MappedType;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@@ -49,10 +53,10 @@
assert (some.data != some.data);
- long addr1 = MappedObjectUnsafe.getBufferBaseAddress(some.backingByteBuffer());
+ long addr1 = MemoryUtil.getAddress(some.backingByteBuffer());
ByteBuffer mapped = some.data; // creates new ByteBuffer instance
- long addr2 = MappedObjectUnsafe.getBufferBaseAddress(mapped);
+ long addr2 = MemoryUtil.getAddress(mapped);
assert (addr2 - addr1 == 4);
assert (mapped.capacity() == MappedSomething.SIZEOF - 4);
@@ -60,7 +64,7 @@
some.view++;
mapped = some.data; // creates new ByteBuffer instance
- long addr3 = MappedObjectUnsafe.getBufferBaseAddress(mapped);
+ long addr3 = MemoryUtil.getAddress(mapped);
assert (addr3 - addr1 == 4 + MappedSomething.SIZEOF);
assert (addr3 - addr2 == 0 + MappedSomething.SIZEOF);
assert (mapped.capacity() == MappedSomething.SIZEOF - 4);
@@ -87,7 +91,7 @@
static void testConstructor() {
int capacity = 1024;
ByteBuffer bb = ByteBuffer.allocateDirect(capacity).order(ByteOrder.nativeOrder());
- long address = MappedObjectUnsafe.getBufferBaseAddress(bb);
+ long address = MemoryUtil.getAddress(bb);
MappedFloat mf = MappedFloat.map(address, capacity);
Added: trunk/LWJGL/src/java/org/lwjgl/test/mapped/MappedObjectTests4.java
===================================================================
--- trunk/LWJGL/src/java/org/lwjgl/test/mapped/MappedObjectTests4.java (rev 0)
+++ trunk/LWJGL/src/java/org/lwjgl/test/mapped/MappedObjectTests4.java 2011-07-22 02:01:56 UTC (rev 3597)
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2002-2011 LWJGL Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * 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.
+ *
+ * * Neither the name of 'LWJGL' nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT OWNER 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.
+ */
+package org.lwjgl.test.mapped;
+
+import org.lwjgl.MemoryUtil;
+import org.lwjgl.opengl.Display;
+
+import java.io.File;
+import java.nio.ByteBuffer;
+
+/** @author Riven */
+@SuppressWarnings("static-access")
+public class MappedObjectTests4 {
+
+ public static void testLWJGL() throws Exception {
+ System.out.println(new File(System.getProperty("java.library.path")).getCanonicalPath());
+ Display.create();
+ }
+
+ public static void testLocalView() {
+ MappedFloat mapped1 = MappedFloat.malloc(5);
+ MappedFloat mapped2 = MappedFloat.malloc(5);
+
+ testLocalView(mapped1);
+ testLocalView(mapped1, mapped2);
+
+ MappedSomething some = MappedSomething.malloc(5);
+ testLocalView(some);
+ }
+
+ private static void testLocalView(MappedFloat mapped1) {
+ final MappedFloat[] array = mapped1.asArray();
+
+ assert (array.length == 5);
+
+ int l = 10 * array.length;
+ for ( int localView1 = 0; localView1 < 5; localView1++ ) {
+ array[localView1].value = localView1 * 5;
+ array[localView1].value *= 2.0f;
+ }
+ System.out.println();
+ float x = 0.0f;
+ for ( int localView1 = 0; localView1 < 5; localView1++ ) {
+ System.out.println("[" + localView1 + "] =>" + array[localView1].value);
+ x += array[localView1].value;
+ }
+ System.out.println("x = " + x);
+ }
+
+ private static void testLocalView(MappedFloat mo1, MappedFloat mo2) {
+ final MappedFloat[] array1 = mo1.<MappedFloat>asArray();
+ for ( int v1 = 0; v1 < 5; v1++ ) {
+ array1[v1].value = (float)Math.random();
+ array1[v1].value *= 2.0f;
+ }
+ final MappedFloat[] array2 = mo2.<MappedFloat>asArray();
+ for ( int v2 = 0; v2 < 5; v2++ ) {
+ array2[v2].value = (float)Math.random();
+ array2[v2].value *= 2.0f;
+ }
+
+ System.out.println();
+
+ for ( int v1 = 0; v1 < 5; v1++ ) {
+ System.out.println("[" + v1 + "] =>" + array1[v1].value);
+ }
+ for ( int v2 = 0; v2 < 5; v2++ ) {
+ System.out.println("[" + v2 + "] =>" + array2[v2].value);
+ }
+ }
+
+ private static void testLocalView(MappedSomething some) {
+ final MappedSomething[] array = some.asArray();
+
+ assert (array.length == 5);
+
+ final long baseAddress = MemoryUtil.getAddress(some.backingByteBuffer());
+ for ( int i = 0; i < array.length; i++ ) {
+ ByteBuffer data = array[i].data;
+
+ assert (data.capacity() == (64 - 4));
+ assert (MemoryUtil.getAddress(data) == baseAddress + i * MappedSomething.SIZEOF + 4);
+ }
+ }
+
+}
\ No newline at end of file
Modified: trunk/LWJGL/src/java/org/lwjgl/test/mapped/TestMappedObject.java
===================================================================
--- trunk/LWJGL/src/java/org/lwjgl/test/mapped/TestMappedObject.java 2011-07-21 22:52:16 UTC (rev 3596)
+++ trunk/LWJGL/src/java/org/lwjgl/test/mapped/TestMappedObject.java 2011-07-22 02:01:56 UTC (rev 3597)
@@ -71,6 +71,11 @@
MappedObjectTests3.testConstructor();
MappedObjectTests3.testMappedSet();
+ MappedObjectTests4.testLocalView();
+
+ //MappedObjectTests4.testLWJGL();
+
+
System.out.println("done");
}
Added: trunk/LWJGL/src/java/org/lwjgl/test/opengl/sprites/SpriteShootoutMapped.java
===================================================================
--- trunk/LWJGL/src/java/org/lwjgl/test/opengl/sprites/SpriteShootoutMapped.java (rev 0)
+++ trunk/LWJGL/src/java/org/lwjgl/test/opengl/sprites/SpriteShootoutMapped.java 2011-07-22 02:01:56 UTC (rev 3597)
@@ -0,0 +1,831 @@
+/*
+ * Copyright (c) 2002-2011 LWJGL Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * 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.
+ *
+ * * Neither the name of 'LWJGL' nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT OWNER 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.
+ */
+package org.lwjgl.test.opengl.sprites;
+
+import org.lwjgl.BufferUtils;
+import org.lwjgl.LWJGLException;
+import org.lwjgl.Sys;
+import org.lwjgl.input.Keyboard;
+import org.lwjgl.input.Mouse;
+import org.lwjgl.opengl.*;
+import org.lwjgl.util.mapped.MappedObject;
+import org.lwjgl.util.mapped.MappedObjectClassLoader;
+import org.lwjgl.util.mapped.MappedObjectTransformer;
+import org.lwjgl.util.mapped.MappedType;
+
+import java.awt.image.BufferedImage;
+import java.awt.image.Raster;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Random;
+import javax.imageio.ImageIO;
+
+import static org.lwjgl.opengl.EXTTransformFeedback.*;
+import static org.lwjgl.opengl.GL11.*;
+import static org.lwjgl.opengl.GL12.*;
+import static org.lwjgl.opengl.GL15.*;
+import static org.lwjgl.opengl.GL20.*;
+import static org.lwjgl.opengl.GL30.*;
+
+/**
+ * Sprite rendering demo. Three implementations are supported:
+ * a) CPU animation + BufferData VBO update.
+ * b) CPU animation + MapBufferRange VBO update.
+ * c) GPU animation using transform feedback with a vertex shader.
+ *
+ * @author Spasi
+ * @since 18/3/2011
+ */
+public final class SpriteShootoutMapped {
+
+ static final int SCREEN_WIDTH = 800;
+ static final int SCREEN_HEIGHT = 600;
+
+ private static final int ANIMATION_TICKS = 60;
+
+ private boolean run = true;
+ private boolean render = true;
+ private boolean colorMask = true;
+ private boolean animate = true;
+ private boolean smooth;
+ private boolean vsync;
+
+ int ballSize = 42;
+ int ballCount = 100 * 1000;
+
+ private SpriteRenderer renderer;
+
+ // OpenGL stuff
+ private int texID;
+ private int texBigID;
+ private int texSmallID;
+
+ private SpriteShootoutMapped() {
+ }
+
+ public static void main(String[] args) {
+ MappedObjectTransformer.register(Pixel4b.class);
+ MappedObjectTransformer.register(Pixel3b.class);
+ MappedObjectTransformer.register(Sprite.class);
+ MappedObjectTransformer.register(SpriteRender.class);
+
+ if ( MappedObjectClassLoader.fork(SpriteShootoutMapped.class, args) )
+ return;
+
+ try {
+ new SpriteShootoutMapped().start();
+ } catch (LWJGLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void start() throws LWJGLException {
+ try {
+ initGL();
+
+ final ContextCapabilities caps = GLContext.getCapabilities();
+ if ( !true && (caps.OpenGL30 || caps.GL_EXT_transform_feedback) )
+ renderer = new SpriteRendererTF();
+ else if ( true && caps.GL_ARB_map_buffer_range )
+ renderer = new SpriteRendererMapped();
+ else
+ renderer = new SpriteRendererPlain();
+
+ updateBalls(ballCount);
+ run();
+ } catch (Throwable t) {
+ t.printStackTrace();
+ } finally {
+ destroy();
+ }
+ }
+
+ private void initGL() throws LWJGLException {
+ Display.setLocation((Display.getDisplayMode().getWidth() - SCREEN_WIDTH) / 2,
+ (Display.getDisplayMode().getHeight() - SCREEN_HEIGHT) / 2);
+ Display.setDisplayMode(new DisplayMode(SCREEN_WIDTH, SCREEN_HEIGHT));
+ Display.setTitle("Sprite Shootout");
+ Display.create();
+ //Display.create(new PixelFormat(), new ContextAttribs(4, 1).withProfileCompatibility(true).withDebug(true));
+ //AMDDebugOutput.glDebugMessageCallbackAMD(new AMDDebugOutputCallback());
+
+ if ( !GLContext.getCapabilities().OpenGL20 )
+ throw new RuntimeException("OpenGL 2.0 is required for this demo.");
+
+ // Setup viewport
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0, SCREEN_WIDTH, 0, SCREEN_HEIGHT, -1.0, 1.0);
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+
+ glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
+
+ // Create textures
+
+ try {
+ texSmallID = createTexture("res/ball_sm.png");
+ texBigID = createTexture("res/ball.png");
+ } catch (IOException e) {
+ e.printStackTrace();
+ System.exit(-1);
+ }
+ texID = texBigID;
+
+ // Setup rendering state
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+
+ glEnable(GL_ALPHA_TEST);
+ glAlphaFunc(GL_GREATER, 0.0f);
+
+ glColorMask(colorMask, colorMask, colorMask, false);
+ glDepthMask(false);
+ glDisable(GL_DEPTH_TEST);
+
+ // Setup geometry
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+ Util.checkGLError();
+ }
+
+ private static int createTexture(final String path) throws IOException {
+ final BufferedImage img = ImageIO.read(SpriteShootoutMapped.class.getClassLoader().getResource(path));
+
+ final int w = img.getWidth();
+ final int h = img.getHeight();
+
+ final ByteBuffer buffer = readImage(img);
+
+ final int texID = glGenTextures();
+
+ glBindTexture(GL_TEXTURE_2D, texID);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, buffer);
+
+ return texID;
+ }
+
+ @MappedType(sizeof = 4)
+ public static class Pixel4b extends MappedObject {
+
+ public byte r, g, b, a;
+
+ }
+
+ @MappedType(sizeof = 3, align = 3)
+ public static class Pixel3b extends MappedObject {
+
+ public byte r, g, b;
+
+ }
+
+ private static ByteBuffer readImage(final BufferedImage img) throws IOException {
+ final Raster raster = img.getRaster();
+
+ final int bands = raster.getNumBands();
+
+ final int w = img.getWidth();
+ final int h = img.getHeight();
+
+ final int count = w * h;
+
+ final byte[] pixels = new byte[count * bands];
+ raster.getDataElements(0, 0, w, h, pixels);
+
+ if ( bands == 4 ) {
+ Pixel4b p = Pixel4b.malloc(count);
+
+ int b = 0;
+ for ( int i = 0; i < count; i++, b += 4 ) {
+ // Pre-multiply alpha
+ final float a = unpackUByte01(pixels[b + 3]);
+
+ p.view = i;
+ p.r = packUByte01(unpackUByte01(pixels[b + 2]) * a);
+ p.g = packUByte01(unpackUByte01(pixels[b + 1]) * a);
+ p.b = packUByte01(unpackUByte01(pixels[b + 0]) * a);
+ p.a = pixels[b + 3];
+ }
+
+ return p.backingByteBuffer();
+ } else if ( bands == 3 ) {
+ Pixel3b p = Pixel3b.malloc(count);
+
+ int b = 0;
+ for ( int i = 0; i < count; i++, b += 3 ) {
+ p.view = i;
+ p.r = pixels[b + 2];
+ p.g = pixels[b + 1];
+ p.b = pixels[b + 0];
+ }
+
+ return p.backingByteBuffer();
+ } else {
+ ByteBuffer p = BufferUtils.createByteBuffer(count * bands);
+ p.put(pixels, 0, p.capacity());
+ p.flip();
+ return p;
+ }
+
+ }
+
+ private static float unpackUByte01(final byte x) {
+ return (x & 0xFF) / 255.0f;
+ }
+
+ private static byte packUByte01(final float x) {
+ return (byte)(x * 255.0f);
+ }
+
+ private void updateBalls(final int count) {
+ System.out.println("NUMBER OF BALLS: " + count);
+ renderer.updateBalls(ballCount);
+ }
+
+ private void run() {
+ long startTime = System.currentTimeMillis() + 5000;
+ long fps = 0;
+
+ long time = Sys.getTime();
+ final int ticksPerUpdate = (int)(Sys.getTimerResolution() / ANIMATION_TICKS);
+
+ renderer.render(false, true, 0);
+
+ while ( run ) {
+ Display.processMessages();
+ handleInput();
+
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ final long currTime = Sys.getTime();
+ final int delta = (int)(currTime - time);
+ if ( smooth || delta >= ticksPerUpdate ) {
+ renderer.render(render, animate, delta);
+ time = currTime;
+ } else
+ renderer.render(render, false, 0);
+
+ Display.update(false);
+ //Display.sync(60);
+
+ if ( startTime > System.currentTimeMillis() ) {
+ fps++;
+ } else {
+ long timeUsed = 5000 + (startTime - System.currentTimeMillis());
+ startTime = System.currentTimeMillis() + 5000;
+ System.out.println("FPS: " + (Math.round(fps / (timeUsed / 1000.0) * 10) / 10.0) + ", Balls: " + ballCount);
+ fps = 0;
+ }
+ }
+ }
+
+ private void handleInput() {
+ if ( Display.isCloseRequested() )
+ run = false;
+
+ while ( Keyboard.next() ) {
+ if ( Keyboard.getEventKeyState() )
+ continue;
+
+ switch ( Keyboard.getEventKey() ) {
+ case Keyboard.KEY_1:
+ case Keyboard.KEY_2:
+ case Keyboard.KEY_3:
+ case Keyboard.KEY_4:
+ case Keyboard.KEY_5:
+ case Keyboard.KEY_6:
+ case Keyboard.KEY_7:
+ case Keyboard.KEY_8:
+ case Keyboard.KEY_9:
+ case Keyboard.KEY_0:
+ ballCount = 1 << (Keyboard.getEventKey() - Keyboard.KEY_1);
+ updateBalls(ballCount);
+ break;
+ case Keyboard.KEY_ADD:
+ case Keyboard.KEY_SUBTRACT:
+ int mult;
+ if ( Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_RSHIFT) )
+ mult = 1000;
+ else if ( Keyboard.isKeyDown(Keyboard.KEY_LMENU) || Keyboard.isKeyDown(Keyboard.KEY_RMENU) )
+ mult = 100;
+ else if ( Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) || Keyboard.isKeyDown(Keyboard.KEY_RCONTROL) )
+ mult = 10;
+ else
+ mult = 1;
+ if ( Keyboard.getEventKey() == Keyboard.KEY_SUBTRACT )
+ mult = -mult;
+ ballCount += mult * 100;
+ if ( ballCount <= 0 )
+ ballCount = 1;
+ updateBalls(ballCount);
+ break;
+ case Keyboard.KEY_ESCAPE:
+ run = false;
+ break;
+ case Keyboard.KEY_A:
+ animate = !animate;
+ System.out.println("Animation is now " + (animate ? "on" : "off") + ".");
+ break;
+ case Keyboard.KEY_C:
+ colorMask = !colorMask;
+ glColorMask(colorMask, colorMask, colorMask, false);
+ System.out.println("Color mask is now " + (colorMask ? "on" : "off") + ".");
+ // Disable alpha test when color mask is off, else we get no benefit.
+ if ( colorMask ) {
+ glEnable(GL_BLEND);
+ glEnable(GL_ALPHA_TEST);
+ } else {
+ glDisable(GL_BLEND);
+ glDisable(GL_ALPHA_TEST);
+ }
+ break;
+ case Keyboard.KEY_R:
+ render = !render;
+ System.out.println("Rendering is now " + (render ? "on" : "off") + ".");
+ break;
+ case Keyboard.KEY_S:
+ smooth = !smooth;
+ System.out.println("Smooth animation is now " + (smooth ? "on" : "off") + ".");
+ break;
+ case Keyboard.KEY_T:
+ if ( texID == texBigID ) {
+ texID = texSmallID;
+ ballSize = 16;
+ } else {
+ texID = texBigID;
+ ballSize = 42;
+ }
+ renderer.updateBallSize();
+ glBindTexture(GL_TEXTURE_2D, texID);
+ System.out.println("Now using the " + (texID == texBigID ? "big" : "small") + " texture.");
+ break;
+ case Keyboard.KEY_V:
+ vsync = !vsync;
+ Display.setVSyncEnabled(vsync);
+ System.out.println("VSYNC is now " + (vsync ? "enabled" : "disabled") + ".");
+ break;
+ }
+ }
+
+ while ( Mouse.next() ) ;
+ }
+
+ private void destroy() {
+ Display.destroy();
+ }
+
+ @MappedType(sizeof = 4 * 4)
+ public static class Sprite extends MappedObject {
+
+ public float x, y;
+ public float dx, dy;
+
+ }
+
+ @MappedType(sizeof = 2 * 4)
+ public static class SpriteRender extends MappedObject {
+
+ public float x, y;
+
+ }
+
+ private abstract class SpriteRenderer {
+
+ protected Sprite sprites;
+
+ protected int spriteCount;
+
+ protected int vshID;
+ protected int progID;
+
+ protected void createProgram() {
+ final int fshID = glCreateShader(GL_FRAGMENT_SHADER);
+ glShaderSource(fshID, "uniform sampler2D COLOR_MAP;\n" +
+ "void main(void) {\n" +
+ " gl_FragColor = texture2D(COLOR_MAP, gl_PointCoord);\n" +
+ "}");
+ glCompileShader(fshID);
+ if ( glGetShader(fshID, GL_COMPILE_STATUS) == GL_FALSE ) {
+ System.out.println(glGetShaderInfoLog(fshID, glGetShader(fshID, GL_INFO_LOG_LENGTH)));
+ throw new RuntimeException("Failed to compile fragment shader.");
+ }
+
+ progID = glCreateProgram();
+ glAttachShader(progID, vshID);
+ glAttachShader(progID, fshID);
+ glLinkProgram(progID);
+ if ( glGetProgram(progID, GL_LINK_STATUS) == GL_FALSE ) {
+ System.out.println(glGetProgramInfoLog(progID, glGetProgram(progID, GL_INFO_LOG_LENGTH)));
+ throw new RuntimeException("Failed to link shader program.");
+ }
+
+ glUseProgram(progID);
+ glUniform1i(glGetUniformLocation(progID, "COLOR_MAP"), 0);
+
+ updateBallSize();
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ }
+
+ public void updateBallSize() {
+ glPointSize(ballSize);
+ }
+
+ public abstract void updateBalls(int count);
+
+ protected abstract void render(boolean render, boolean animate, int delta);
+
+ }
+
+ private abstract class SpriteRendererBatched extends SpriteRenderer {
+
+ protected static final int BALLS_PER_BATCH = 10 * 1000;
+
+ SpriteRendererBatched() {
+ vshID = glCreateShader(GL_VERTEX_SHADER);
+ glShaderSource(vshID, "void main(void) {\n" +
+ " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n" +
+ "}");
+ glCompileShader(vshID);
+ if ( glGetShader(vshID, GL_COMPILE_STATUS) == GL_FALSE ) {
+ System.out.println(glGetShaderInfoLog(vshID, glGetShader(vshID, GL_INFO_LOG_LENGTH)));
+ throw new RuntimeException("Failed to compile vertex shader.");
+ }
+
+ createProgram();
+ }
+
+ public void updateBalls(final int count) {
+ final Random random = new Random();
+
+ final Sprite newSprites = Sprite.malloc(count);
+ if ( sprites != null ) {
+ sprites.view = 0;
+ sprites.copyRange(newSprites, Math.min(count, spriteCount));
+ }
+
+ if ( count > spriteCount ) {
+ for ( int i = spriteCount; i < count; i++ ) {
+ newSprites.view = i;
+
+ newSprites.x = (int)(random.nextFloat() * (SCREEN_WIDTH - ballSize) + ballSize * 0.5f);
+ newSprites.y = (int)(random.nextFloat() * (SCREEN_HEIGHT - ballSize) + ballSize * 0.5f);
+ newSprites.dx = random.nextFloat() * 0.4f - 0.2f;
+ newSprites.dy = random.nextFloat() * 0.4f - 0.2f;
+ }
+ }
+
+ sprites = newSprites;
+ spriteCount = count;
+ }
+
+ protected void animate(
+ final Sprite sprite,
+ final SpriteRender spriteRender,
+ final int ballSize, final int ballIndex, final int batchSize, final int delta
+ ) {
+ final float ballRadius = ballSize * 0.5f;
+ final float boundW = SCREEN_WIDTH - ballRadius;
+ final float boundH = SCREEN_HEIGHT - ballRadius;
+
+ final Sprite[] sprites = sprite.asArray();
+ final SpriteRender[] spritesRender = spriteRender.asArray();
+ for ( int b = ballIndex, r = 0, len = (ballIndex + batchSize); b < len; b++, r++ ) {
+ float x = sprites[b].x;
+ float dx = sprites[b].dx;
+
+ x += dx * delta;
+ if ( x < ballRadius ) {
+ x = ballRadius;
+ sprites[b].dx = -dx;
+ } else if ( x > boundW ) {
+ x = boundW;
+ sprites[b].dx = -dx;
+ }
+ sprites[b].x = x;
+
+ float y = sprites[b].y;
+ float dy = sprites[b].dy;
+
+ y += dy * delta;
+ if ( y < ballRadius ) {
+ y = ballRadius;
+ sprites[b].dy = -dy;
+ } else if ( y > boundH ) {
+ y = boundH;
+ sprites[b].dy = -dy;
+ }
+ sprites[b].y = y;
+
+ spritesRender[r].x = x;
+ spritesRender[r].y = y;
+ }
+ }
+
+ }
+
+ private class SpriteRendererPlain extends SpriteRendererBatched {
+
+ private final int DATA_PER_BATCH = BALLS_PER_BATCH * 2 * 4; // balls * 2 floats * 4 bytes
+
+ protected int[] animVBO;
+
+ private SpriteRender spritesRender;
+
+ SpriteRendererPlain() {
+ System.out.println("Shootout Implementation: CPU animation & BufferData");
+ spritesRender = SpriteRender.malloc(BALLS_PER_BATCH);
+ }
+
+ public void updateBalls(final int count) {
+ super.updateBalls(count);
+
+ final int batchCount = count / BALLS_PER_BATCH + (count % BALLS_PER_BATCH == 0 ? 0 : 1);
+ if ( animVBO != null && batchCount == animVBO.length )
+ return;
+
+ final int[] newAnimVBO = new int[batchCount];
+ if ( animVBO != null ) {
+ System.arraycopy(animVBO, 0, newAnimVBO, 0, Math.min(animVBO.length, newAnimVBO.length));
+ for ( int i = newAnimVBO.length; i < animVBO.length; i++ )
+ glDeleteBuffers(animVBO[i]);
+ }
+ for ( int i = animVBO == null ? 0 : animVBO.length; i < newAnimVBO.length; i++ ) {
+ newAnimVBO[i] = glGenBuffers();
+ glBindBuffer(GL_ARRAY_BUFFER, newAnimVBO[i]);
+ }
+
+ animVBO = newAnimVBO;
+ }
+
+ public void render(final boolean render, final boolean animate, final int delta) {
+ int batchSize = Math.min(ballCount, BALLS_PER_BATCH);
+ int ballIndex = 0;
+ int batchIndex = 0;
+ while ( ballIndex < ballCount ) {
+ glBindBuffer(GL_ARRAY_BUFFER, animVBO[batchIndex]);
+
+ if ( animate )
+ animate(ballIndex, batchSize, delta);
+
+ if ( render ) {
+ glVertexPointer(2, GL_FLOAT, 0, 0);
+ glDrawArrays(GL_POINTS, 0, batchSize);
+ }
+
+ ballIndex += batchSize;
+ batchSize = Math.min(ballCount - ballIndex, BALLS_PER_BATCH);
+ batchIndex++;
+ }
+ }
+
+ private void animate(final int ballIndex, final int batchSize, final int delta) {
+ animate(
+ sprites, spritesRender,
+ ballSize, ballIndex, batchSize, delta
+ );
+
+ glBufferData(GL_ARRAY_BUFFER, DATA_PER_BATCH, GL_STREAM_DRAW);
+ glBufferSubData(GL_ARRAY_BUFFER, 0, spritesRender.backingByteBuffer());
+ }
+
+ }
+
+ private class SpriteRendererMapped extends SpriteRendererBatched {
+
+ private StreamVBO animVBO;
+
+ SpriteRendererMapped() {
+ System.out.println("Shootout Implementation: CPU animation & MapBufferRange");
+ }
+
+ public void updateBalls(final int count) {
+ super.updateBalls(count);
+
+ if ( animVBO != null )
+ animVBO.destroy();
+
+ animVBO = new StreamVBO(GL_ARRAY_BUFFER, ballCount * (2 * 4));
+ }
+
+ public void render(final boolean render, final boolean animate, final int delta) {
+ int batchSize = Math.min(ballCount, BALLS_PER_BATCH);
+ int ballIndex = 0;
+ while ( ballIndex < ballCount ) {
+ if ( animate ) {
+ final ByteBuffer buffer = animVBO.map(batchSize * (2 * 4));
+
+ animate(sprites, SpriteRender.<SpriteRender>map(buffer), ballSize, ballIndex, batchSize, delta);
+
+ animVBO.unmap();
+ }
+
+ if ( render ) {
+ glVertexPointer(2, GL_FLOAT, 0, ballIndex * (2 * 4));
+ glDrawArrays(GL_POINTS, 0, batchSize);
+ }
+
+ ballIndex += batchSize;
+ batchSize = Math.min(ballCount - ballIndex, BALLS_PER_BATCH);
+ }
+ }
+
+ }
+
+ private class SpriteRendererTF extends SpriteRenderer {
+
+ private int progIDTF;
+ private int ballSizeLoc;
+ private int deltaLoc;
+
+ private int[] tfVBO = new int[2];
+ private int currVBO;
+
+ SpriteRendererTF() {
+ System.out.println("Shootout Implementation: TF GPU animation");
+
+ // Transform-feedback program
+
+ final int vshID = glCreateShader(GL_VERTEX_SHADER);
+ glShaderSource(vshID, "#version 130\n" +
+ "const float WIDTH = " + SCREEN_WIDTH + ";\n" +
+ "const float HEIGHT = " + SCREEN_HEIGHT + ";\n" +
+ "uniform float ballSize;\n" + // ballSize / 2
+ "uniform float delta;\n" +
+ "void main(void) {\n" +
+ " vec4 anim = gl_Vertex;\n" +
+ " anim.xy = anim.xy + anim.zw * delta;\n" +
+ " vec2 animC = clamp(anim.xy, vec2(ballSize), vec2(WIDTH - ballSize, HEIGHT - ballSize));\n" +
+ " if ( anim.x != animC.x ) anim.z = -anim.z;\n" +
+ " if ( anim.y != animC.y ) anim.w = -anim.w;\n" +
+ " gl_Position = vec4(animC, anim.zw);\n" +
+ "}");
+ glCompileShader(vshID);
+ if ( glGetShader(vshID, GL_COMPILE_STATUS) == GL_FALSE ) {
+ System.out.println(glGetShaderInfoLog(vshID, glGetShader(vshID, GL_INFO_LOG_LENGTH)));
+ throw new RuntimeException("Failed to compile vertex shader.");
+ }
+
+ progIDTF = glCreateProgram();
+ glAttachShader(progIDTF, vshID);
+ glTransformFeedbackVaryings(progIDTF, new CharSequence[] { "gl_Position" }, GL_SEPARATE_ATTRIBS);
+ glLinkProgram(progIDTF);
+ if ( glGetProgram(progIDTF, GL_LINK_STATUS) == GL_FALSE ) {
+ System.out.println(glGetProgramInfoLog(progIDTF, glGetProgram(progIDTF, GL_INFO_LOG_LENGTH)));
+ throw new RuntimeException("Failed to link shader program.");
+ }
+
+ glUseProgram(progIDTF);
+
+ ballSizeLoc = glGetUniformLocation(progIDTF, "ballSize");
+ deltaLoc = glGetUniformLocation(progIDTF, "delta");
+
+ glUniform1f(ballSizeLoc, ballSize * 0.5f);
+
+ // -----------------
+
+ this.vshID = glCreateShader(GL_VERTEX_SHADER);
+ glShaderSource(this.vshID, "void main(void) {\n" +
+ " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n" +
+ "}");
+ glCompileShader(this.vshID);
+ if ( glGetShader(this.vshID, GL_COMPILE_STATUS) == GL_FALSE ) {
+ System.out.println(glGetShaderInfoLog(this.vshID, glGetShader(this.vshID, GL_INFO_LOG_LENGTH)));
+ throw new RuntimeException("Failed to compile vertex shader.");
+ }
+
+ createProgram();
+ }
+
+ public void updateBallSize() {
+ glUseProgram(progIDTF);
+ glUniform1f(ballSizeLoc, ballSize * 0.5f);
+
+ glUseProgram(progID);
+ super.updateBallSize();
+ }
+
+ private void doUpdateBalls(final int count) {
+ final Random random = new Random();
+
+ final Sprite newSprites = Sprite.malloc(count);
+ if ( sprites != null ) {
+ sprites.view = 0;
+ sprites.copyRange(newSprites, Math.min(count, spriteCount));
+ }
+
+ if ( count > spriteCount ) {
+ for ( int i = spriteCount; i < count; i++ ) {
+ newSprites.view = i;
+
+ newSprites.x = (int)(random.nextFloat() * (SCREEN_WIDTH - ballSize) + ballSize * 0.5f);
+ newSprites.y = (int)(random.nextFloat() * (SCREEN_HEIGHT - ballSize) + ballSize * 0.5f);
+ newSprites.dx = random.nextFloat() * 0.4f - 0.2f;
+ newSprites.dy = random.nextFloat() * 0.4f - 0.2f;
+ }
+ }
+
+ sprites = newSprites;
+ spriteCount = count;
+ }
+
+ public void updateBalls(final int count) {
+ if ( tfVBO[0] != 0 ) {
+ // Fetch current animation state
+ glGetBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sprites.backingByteBuffer());
+ }
+
+ doUpdateBalls(count);
+
+ if ( tfVBO[0] != 0 ) {
+ for ( int i = 0; i < tfVBO.length; i++ )
+ glDeleteBuffers(tfVBO[i]);
+ }
+
+ for ( int i = 0; i < tfVBO.length; i++ ) {
+ tfVBO[i] = glGenBuffers();
+ glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, tfVBO[i]);
+ glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sprites.backingByteBuffer(), GL_STATIC_DRAW);
+ }
+
+ glBindBuffer(GL_ARRAY_BUFFER, tfVBO[0]);
+ glVertexPointer(2, GL_FLOAT, (4 * 4), 0);
+ }
+
+ public void render(final boolean render, final boolean animate, final int delta) {
+ if ( animate ) {
+ glUseProgram(progIDTF);
+ glUniform1f(deltaLoc, delta);
+
+ final int vbo = currVBO;
+ currVBO = 1 - currVBO;
+
+ glBindBuffer(GL_ARRAY_BUFFER, tfVBO[vbo]);
+ glVertexPointer(4, GL_FLOAT, 0, 0);
+
+ glEnable(GL_RASTERIZER_DISCARD);
+ if ( GLContext.getCapabilities().OpenGL30 ) {
+ glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tfVBO[1 - vbo]);
+
+ glBeginTransformFeedback(GL_POINTS);
+ glDrawArrays(GL_POINTS, 0, ballCount);
+ glEndTransformFeedback();
+ } else {
+ glBindBufferBaseEXT(GL_TRANSFORM_FEEDBACK_BUFFER_EXT, 0, tfVBO[1 - vbo]);
+
+ glBeginTransformFeedbackEXT(GL_POINTS);
+ glDrawArrays(GL_POINTS, 0, ballCount);
+ glEndTransformFeedbackEXT();
+ }
+ glDisable(GL_RASTERIZER_DISCARD);
+
+ glUseProgram(progID);
+ glVertexPointer(2, GL_FLOAT, (4 * 4), 0);
+ }
+
+ if ( render )
+ glDrawArrays(GL_POINTS, 0, ballCount);
+ }
+
+ }
+
+}
\ No newline at end of file
Modified: trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedHelper.java
===================================================================
--- trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedHelper.java 2011-07-21 22:52:16 UTC (rev 3596)
+++ trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedHelper.java 2011-07-22 02:01:56 UTC (rev 3597)
@@ -31,6 +31,9 @@
*/
package org.lwjgl.util.mapped;
+import org.lwjgl.LWJGLUtil;
+import org.lwjgl.MemoryUtil;
+
import java.nio.ByteBuffer;
/**
@@ -43,30 +46,32 @@
public class MappedHelper {
public static void setup(MappedObject mo, ByteBuffer buffer, int align, int sizeof) {
- if ( mo.baseAddress != 0L )
+ if ( LWJGLUtil.CHECKS && mo.baseAddress != 0L )
throw new IllegalStateException("this method should not be called by user-code");
- if ( buffer == null )
- throw new NullPointerException("buffer");
- if ( !buffer.isDirect() )
+ if ( LWJGLUtil.CHECKS && !buffer.isDirect() )
throw new IllegalArgumentException("bytebuffer must be direct");
mo.preventGC = buffer;
- if ( align <= 0 )
+ if ( LWJGLUtil.CHECKS && align <= 0 )
throw new IllegalArgumentException("invalid alignment");
mo.align = align;
- if ( sizeof % align != 0 )
+ if ( LWJGLUtil.CHECKS && (sizeof <= 0 || sizeof % align != 0) )
throw new IllegalStateException("sizeof not a multiple of alignment");
mo.sizeof = sizeof;
- long addr = MappedObjectUnsafe.getBufferBaseAddress(buffer) + buffer.position();
- if ( addr % align != 0 )
+ long addr = MemoryUtil.getAddress(buffer);
+ if ( LWJGLUtil.CHECKS && addr % align != 0 )
throw new IllegalStateException("buffer address not aligned on " + align + " bytes");
mo.baseAddress = mo.viewAddress = addr;
}
+ public static void checkAddress(MappedObject mapped, long viewAddress) {
+ mapped.checkAddress(viewAddress);
+ }
+
public static void put_views(MappedSet2 set, int view) {
set.view(view);
}
@@ -87,6 +92,14 @@
return (int)(mapped.viewAddress - mapped.baseAddress) / sizeof;
}
+ public static void put_view_shift(MappedObject mapped, int view, int sizeof_shift) {
+ mapped.setViewAddress(mapped.baseAddress + (view << sizeof_shift));
+ }
+
+ public static int get_view_shift(MappedObject mapped, int sizeof_shift) {
+ return ((int)(mapped.viewAddress - mapped.baseAddress)) >> sizeof_shift;
+ }
+
public static void put_view_next(MappedObject mapped, int sizeof) {
mapped.setViewAddress(mapped.viewAddress + sizeof);
}
@@ -130,68 +143,124 @@
MappedObjectUnsafe.INSTANCE.putByte(addr, value);
}
+ public static void bput(MappedObject mapped, byte value, int fieldOffset) {
+ MappedObjectUnsafe.INSTANCE.putByte(mapped.viewAddress + fieldOffset, value);
+ }
+
public static byte bget(long addr) {
return MappedObjectUnsafe.INSTANCE.getByte(addr);
}
+ public static byte bget(MappedObject mapped, int fieldOffset) {
+ return MappedObjectUnsafe.INSTANCE.getByte(mapped.viewAddress + fieldOffset);
+ }
+
// short
public static void sput(short value, long addr) {
MappedObjectUnsafe.INSTANCE.putShort(addr, value);
}
+ public static void sput(MappedObject mapped, short value, int fieldOffset) {
+ MappedObjectUnsafe.INSTANCE.putShort(mapped.viewAddress + fieldOffset, value);
+ }
+
public static short sget(long addr) {
return MappedObjectUnsafe.INSTANCE.getShort(addr);
}
+ public static short sget(MappedObject mapped, int fieldOffset) {
+ return MappedObjectUnsafe.INSTANCE.getShort(mapped.viewAddress + fieldOffset);
+ }
+
// char
public static void cput(char value, long addr) {
MappedObjectUnsafe.INSTANCE.putChar(addr, value);
}
+ public static void cput(MappedObject mapped, char value, int fieldOffset) {
+ MappedObjectUnsafe.INSTANCE.putChar(mapped.viewAddress + fieldOffset, value);
+ }
+
public static char cget(long addr) {
return MappedObjectUnsafe.INSTANCE.getChar(addr);
}
+ public static char cget(MappedObject mapped, int fieldOffset) {
+ return MappedObjectUnsafe.INSTANCE.getChar(mapped.viewAddress + fieldOffset);
+ }
+
// int
public static void iput(int value, long addr) {
MappedObjectUnsafe.INSTANCE.putInt(addr, value);
}
- public static int iget(long addr) {
- return MappedObjectUnsafe.INSTANCE.getInt(addr);
+ public static void iput(MappedObject mapped, int value, int fieldOffset) {
+ MappedObjectUnsafe.INSTANCE.putInt(mapped.viewAddress + fieldOffset, value);
}
+ public static int iget(long address) {
+ return MappedObjectUnsafe.INSTANCE.getInt(address);
+ }
+
+ public static int iget(MappedObject mapped, int fieldOffset) {
+ return MappedObjectUnsafe.INSTANCE.getInt(mapped.viewAddress + fieldOffset);
+ }
+
// float
public static void fput(float value, long addr) {
MappedObjectUnsafe.INSTANCE.putFloat(addr, value);
}
+ public static void fput(MappedObject mapped, float value, int fieldOffset) {
+ MappedObjectUnsafe.INSTANCE.putFloat(mapped.viewAddress + fieldOffset, value);
+ }
+
public static float fget(long addr) {
return MappedObjectUnsafe.INSTANCE.getFloat(addr);
}
+ public static float fget(MappedObject mapped, int fieldOffset) {
+ return MappedObjectUnsafe.INSTANCE.getFloat(mapped.viewAddress + fieldOffset);
+ }
+
// long
public static void jput(long value, long addr) {
MappedObjectUnsafe.INSTANCE.putLong(addr, value);
}
+ public static void jput(MappedObject mapped, long value, int fieldOffset) {
+ MappedObjectUnsafe.INSTANCE.putLong(mapped.viewAddress + fieldOffset, value);
+ }
+
public static long jget(long addr) {
return MappedObjectUnsafe.INSTANCE.getLong(addr);
}
+ public static long lget(MappedObject mapped, int fieldOffset) {
+ return MappedObjectUnsafe.INSTANCE.getLong(mapped.viewAddress + fieldOffset);
+ }
+
// double
public static void dput(double value, long addr) {
MappedObjectUnsafe.INSTANCE.putDouble(addr, value);
}
+ public static void dput(MappedObject mapped, double value, int fieldOffset) {
+ MappedObjectUnsafe.INSTANCE.putDouble(mapped.viewAddress + fieldOffset, value);
+ }
+
public static double dget(long addr) {
return MappedObjectUnsafe.INSTANCE.getDouble(addr);
}
+ public static double dget(MappedObject mapped, int fieldOffset) {
+ return MappedObjectUnsafe.INSTANCE.getDouble(mapped.viewAddress + fieldOffset);
+ }
+
}
\ No newline at end of file
Modified: trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedObject.java
===================================================================
--- trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedObject.java 2011-07-21 22:52:16 UTC (rev 3596)
+++ trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedObject.java 2011-07-22 02:01:56 UTC (rev 3597)
@@ -32,6 +32,7 @@
package org.lwjgl.util.mapped;
import org.lwjgl.LWJGLUtil;
+import org.lwjgl.MemoryUtil;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
@@ -93,7 +94,7 @@
}
final void checkAddress(final long address) {
- final long base = MappedObjectUnsafe.getBufferBaseAddress(preventGC);
+ final long base = MemoryUtil.getAddress0(preventGC);
final int offset = (int)(address - base);
if ( address < base || preventGC.capacity() < (offset + this.sizeof) )
throw new IndexOutOfBoundsException(Integer.toString(offset / sizeof));
@@ -103,7 +104,7 @@
if ( bytes < 0 )
throw new IllegalArgumentException();
- if ( preventGC.capacity() < (viewAddress - MappedObjectUnsafe.getBufferBaseAddress(preventGC) + bytes) )
+ if ( preventGC.capacity() < (viewAddress - MemoryUtil.getAddress0(preventGC) + bytes) )
throw new BufferOverflowException();
}
@@ -155,7 +156,7 @@
/**
* Creates an identical new MappedObject instance, comparable to the
- * contract of {@link ByteBuffer#duplicate}. This is useful when more than one
+ * contract of {@link java.nio.ByteBuffer#duplicate}. This is useful when more than one
* views of the mapped object are required at the same time, e.g. in
* multithreaded access.
*/
@@ -166,7 +167,7 @@
/**
* Creates a new MappedObject instance, with a base offset equal to
- * the offset of the current view, comparable to the contract of {@link ByteBuffer#slice}.
+ * the offset of the current view, comparable to the contract of {@link java.nio.ByteBuffer#slice}.
*/
public final <T extends MappedObject> T slice() {
// any method that calls this method will have its call-site modified
@@ -188,6 +189,11 @@
throw new InternalError("type not registered");
}
+ /** Moves the current view to the next element. Non-transformed implementation for MappedSets. */
+ final void nextSet() {
+ setViewAddress(viewAddress + sizeof);
+ }
+
/**
* Copies and amount of <code>SIZEOF</code> bytes, from the current
* mapped object, to the specified mapped object.
@@ -220,10 +226,16 @@
return new MappedForeach<T>(mapped, elementCount);
}
+ @SuppressWarnings("unused")
+ public final <T extends MappedObject> T[] asArray() {
+ // any method that calls this method will have its call-site modified
+ throw new InternalError("type not registered");
+ }
+
ByteBuffer preventGC;
/**
- * Returns the {@link ByteBuffer} that backs this mapped object.
+ * Returns the {@link java.nio.ByteBuffer} that backs this mapped object.
*
* @return the backing buffer
*/
Modified: trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedObjectClassLoader.java
===================================================================
--- trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedObjectClassLoader.java 2011-07-21 22:52:16 UTC (rev 3596)
+++ trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedObjectClassLoader.java 2011-07-22 02:01:56 UTC (rev 3597)
@@ -117,7 +117,7 @@
byte[] bytecode = readStream(this.getResourceAsStream(className.concat(".class")));
long t0 = System.nanoTime();
- bytecode = MappedObjectTransformer.transformFieldAccess(className, bytecode);
+ bytecode = MappedObjectTransformer.transformMappedAPI(className, bytecode);
long t1 = System.nanoTime();
total_time_transforming += (t1 - t0);
Modified: trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedObjectTransformer.java
===================================================================
--- trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedObjectTransformer.java 2011-07-21 22:52:16 UTC (rev 3596)
+++ trunk/LWJGL/src/java/org/lwjgl/util/mapped/MappedObjectTransformer.java 2011-07-22 02:01:56 UTC (rev 3597)
@@ -1,21 +1,51 @@
/*
- * Created on Jun 23, 2011
+ * Copyright (c) 2002-2011 LWJGL Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * 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.
+ *
+ * * Neither the name of 'LWJGL' nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT OWNER 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.
*/
-
package org.lwjgl.util.mapped;
import org.lwjgl.LWJGLUtil;
import org.objectweb.asm.*;
+import org.objectweb.asm.tree.*;
+import org.objectweb.asm.tree.analysis.*;
import org.objectweb.asm.util.TraceClassVisitor;
-import java.io.*;
+import java.io.PrintWriter;
+import java.io.StringWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
-import java.util.StringTokenizer;
+import static org.objectweb.asm.ClassWriter.*;
import static org.objectweb.asm.Opcodes.*;
/**
@@ -25,7 +55,7 @@
* The transformer supports some debugging tools, enabled through JVM system properties:<br/>
* org.lwjgl.util.mapped.PrintTiming=true, prints timing information for the transformation step.<br/>
* org.lwjgl.util.mapped.PrintActivity=true, prints activity information.<br/>
- * org.lwjgl.util.mapped.PrintBytecode=true, prints the transformed bytecode. [not working atm]<br/>
+ * org.lwjgl.util.mapped.PrintBytecode=true, prints the transformed bytecode.<br/>
* org.lwjgl.util.Debug must also be set to true for the above to work.
*
* @author Riven
@@ -41,7 +71,24 @@
static final String MAPPED_OBJECT_JVM = jvmClassName(MappedObject.class);
static final String MAPPED_HELPER_JVM = jvmClassName(MappedHelper.class);
+ static final String MAPPEDSET_PREFIX = jvmClassName(MappedSet.class);
+ static final String MAPPED_SET2_JVM = jvmClassName(MappedSet2.class);
+ static final String MAPPED_SET3_JVM = jvmClassName(MappedSet3.class);
+ static final String MAPPED_SET4_JVM = jvmClassName(MappedSet4.class);
+
+ static final String LENGTH_METHOD_NAME = "length$LWJGL";
+ static final String VIEWADDRESS_METHOD_NAME = "getViewAddress$LWJGL";
+ static final String VIEW_CONSTRUCTOR_NAME = "constructView$LWJGL";
+
+ static final Map<Integer, String> OPCODE_TO_NAME = new HashMap<Integer, String>();
+ static final Map<Integer, String> INSNTYPE_TO_NAME = new HashMap<Integer, String>();
+
+ static boolean is_currently_computing_frames;
+
static {
+ getClassEnums(Opcodes.class, OPCODE_TO_NAME, "V1_", "ACC_", "T_", "F_", "MH_");
+ getClassEnums(AbstractInsnNode.class, INSNTYPE_TO_NAME);
+
className_to_subtype = new HashMap<String, MappedSubtypeInfo>();
{
@@ -59,11 +106,10 @@
// => IADD
// => PUTFIELD MyMappedType.view
//
- MappedSubtypeInfo info = new MappedSubtypeInfo(MAPPED_OBJECT_JVM, -1, -1);
- className_to_subtype.put(info.className, info);
+ className_to_subtype.put(MAPPED_OBJECT_JVM, new MappedSubtypeInfo(MAPPED_OBJECT_JVM, -1, -1));
}
- String vmName = System.getProperty("java.vm.name");
+ final String vmName = System.getProperty("java.vm.name");
if ( vmName != null && !vmName.contains("Server") ) {
System.err.println("Warning: " + MappedObject.class.getSimpleName() + "s have inferiour performance on Client VMs, please consider switching to a Server VM.");
}
@@ -71,7 +117,7 @@
/**
* Registers a class as a mapped object.
- * The class must extend {@link MappedObject} and be annotated with {@link MappedField}.
+ * The class must extend {@link org.lwjgl.util.mapped.MappedObject} and be annotated with {@link org.lwjgl.util.mapped.MappedField}.
*
* @param type the mapped object class.
*/
@@ -79,585 +125,992 @@
if ( MappedObjectClassLoader.FORKED )
return;
- MappedType mapped = type.getAnnotation(MappedType.class);
+ final MappedType mapped = type.getAnnotation(MappedType.class);
if ( mapped == null )
throw new InternalError("missing " + MappedType.class.getName() + " annotation");
if ( type.getEnclosingClass() != null && !Modifier.isStatic(type.getModifiers()) )
throw new InternalError("only top-level or static inner classes are allowed");
- String className = jvmClassName(type);
+ final MappedSubtypeInfo mappedType = new MappedSubtypeInfo(jvmClassName(type), mapped.sizeof(), mapped.align());
- MappedSubtypeInfo mappedType = new MappedSubtypeInfo(className, mapped.sizeof(), mapped.align());
-
int advancingOffset = 0;
+ for ( Field field : type.getDeclaredFields() )
+ advancingOffset += registerField(mapped, mappedType.className, mappedType, advancingOffset, field);
- for ( Field field : type.getDeclaredFields() ) {
- // static fields are never mapped
- if ( Modifier.isStatic(field.getModifiers()) )
- continue;
+ if ( className_to_subtype.put(mappedType.className, mappedType) != null )
+ throw new InternalError("duplicate mapped type: " + mappedType.className);
+ }
- // we only support primitives and ByteBuffers
- if ( !field.getType().isPrimitive() && field.getType() != ByteBuffer.class )
- throw new InternalError("field '" + className + "." + field.getName() + "' not supported: " + field.getType());
+ private static int registerField(final MappedType mapped, final String className, final MappedSubtypeInfo mappedType, int advancingOffset, final Field field) {
+ if ( Modifier.isStatic(field.getModifiers()) ) // static fields are never mapped
+ return 0;
- MappedField meta = field.getAnnotation(MappedField.class);
- if ( meta == null && !mapped.autoGenerateOffsets() )
- throw new InternalError("field '" + className + "." + field.getName() + "' missing annotation " + MappedField.class.getName() + ": " + className);
+ // we only support primitives and ByteBuffers
+ if ( !field.getType().isPrimitive() && field.getType() != ByteBuffer.class )
+ throw new InternalError("field '" + className + "." + field.getName() + "' not supported: " + field.getType());
- // quick hack
- long byteOffset = meta == null ? advancingOffset : meta.byteOffset();
- long byteLength;
- if ( field.getType() == long.class || field.getType() == double.class )
- byteLength = 8;
- else if ( field.getType() == int.class || field.getType() == float.class )
- byteLength = 4;
- else if ( field.getType() == char.class || field.getType() == short.class )
- byteLength = 2;
- else if ( field.getType() == byte.class )
- byteLength = 1;
- else if ( field.getType() == ByteBuffer.class ) {
- byteLength = meta.byteLength();
- if ( byteLength < 0 )
- throw new IllegalStateException("invalid byte length for mapped ByteBuffer field: " + className + "." + field.getName() + " [length=" + byteLength + "]");
- } else
- throw new IllegalStateException(field.getType().getName());
+ MappedField meta = field.getAnnotation(MappedField.class);
+ if ( meta == null && !mapped.autoGenerateOffsets() )
+ throw new InternalError("field '" + className + "." + field.getName() + "' missing annotation " + MappedField.class.getName() + ": " + className);
- if ( field.getType() != ByteBuffer.class )
- if ( (advancingOffset % byteLength) != 0 )
- throw new IllegalStateException("misaligned mapped type: " + className + "." + field.getName());
+ // quick hack
+ long byteOffset = meta == null ? advancingOffset : meta.byteOffset();
+ long byteLength;
+ if ( field.getType() == long.class || field.getType() == double.class )
+ byteLength = 8;
+ else if ( field.getType() == int.class || field.getType() == float.class )
+ byteLength = 4;
+ else if ( field.getType() == char.class || field.getType() == short.class )
+ byteLength = 2;
+ else if ( field.getType() == byte.class )
+ byteLength = 1;
+ else if ( field.getType() == ByteBuffer.class ) {
+ byteLength = meta.byteLength();
+ if ( byteLength < 0 )
+ throw new IllegalStateException("invalid byte length for mapped ByteBuffer field: " + className + "." + field.getName() + " [length=" + byteLength + "]");
+ } else
+ throw new InternalError(field.getType().getName());
- if ( PRINT_ACTIVITY )
- LWJGLUtil.log(MappedObjectTransformer.class.getSimpleName() + ": " + className + "." + field.getName() + " [type=" + field.getType().getSimpleName() + ", offset=" + byteOffset + "]");
+ if ( field.getType() != ByteBuffer.class && (advancingOffset % byteLength) != 0 )
+ throw new IllegalStateException("misaligned mapped type: " + className + "." + field.getName());
- mappedType.fieldToOffset.put(field.getName(), byteOffset);
- mappedType.fieldToLength.put(field.getName(), byteLength);
+ if ( PRINT_ACTIVITY )
+ LWJGLUtil.log(MappedObjectTransformer.class.getSimpleName() + ": " + className + "." + field.getName() + " [type=" + field.getType().getSimpleName() + ", offset=" + byteOffset + "]");
- advancingOffset += byteLength;
- }
+ mappedType.fieldToOffset.put(field.getName(), byteOffset);
+ mappedType.fieldToLength.put(field.getName(), byteLength);
+ mappedType.fieldToType.put(field.getName(), Type.getType(field.getType()));
- if ( className_to_subtype.put(className, mappedType) != null ) {
- throw new InternalError("duplicate mapped type: " + className);
- }
+ return (int)byteLength;
}
- static boolean is_currently_computing_frames = false;
- static final String view_constructor_method = "_construct_view_";
+ static byte[] transformMappedAPI(final String className, byte[] bytecode) {
+ final ClassWriter cw = new ClassWriter(COMPUTE_FRAMES) {
- static byte[] transformFieldAccess(final String className, byte[] bytecode) {
- int flags = ClassWriter.COMPUTE_FRAMES;
-
- ClassWriter writer = new ClassWriter(flags) {
- // HACK: prevent user-code static-initialization-blocks to be executed
-
@Override
protected String getCommonSuperClass(String a, String b) {
- if ( is_currently_computing_frames )
- if ( !a.startsWith("java/") || !b.startsWith("java/") )
- return "java/lang/Object";
+ // HACK: prevent user-code static-initialization-blocks to be executed
+ if ( is_currently_computing_frames && !a.startsWith("java/") || !b.startsWith("java/") )
+ return "java/lang/Object";
+
return super.getCommonSuperClass(a, b);
}
+
};
- ClassAdapter adapter = new ClassAdapter(writer) {
+ ClassVisitor cv = getTransformationAdapter(className, cw);
+ if ( className_to_subtype.containsKey(className) ) // Do a first pass to generate address getters
+ cv = getMethodGenAdapter(className, cv);
+
+ //cr.accept(cv, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
+ new ClassReader(bytecode).accept(cv, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
+ bytecode = cw.toByteArray();
+
+ if ( PRINT_BYTECODE )
+ printBytecode(bytecode);
+
+ return bytecode;
+ }
+
+ private static ClassAdapter getMethodGenAdapter(final String className, final ClassVisitor cv) {
+ return new ClassAdapter(cv) {
+
@Override
- public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
- {
- MappedSubtypeInfo mappedSubtype = className_to_subtype.get(className);
+ public void visitEnd() {
+ generateViewAddressGetter();
+ generateLengthGetter();
- if ( mappedSubtype != null && !mappedSubtype.className.equals(MAPPED_OBJECT_JVM) ) {
- if ( "<init>".equals(name) ) {
- if ( !"()V".equals(desc) )
- throw new IllegalStateException(className + " can only have a default constructor, found: " + desc);
+ final MappedSubtypeInfo mappedSubtype = className_to_subtype.get(className);
- MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
- mv.visitCode(...
[truncated message content] |