Java-Gaming.org    
Featured games (79)
games approved by the League of Dukes
Games in Showcase (477)
Games in Android Showcase (107)
games submitted by our members
Games in WIP (536)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: 1 [2] 3
  ignore  |  Print  
  Programming to the cache  (Read 21671 times)
0 Members and 1 Guest are viewing this topic.
Offline erikd

JGO Ninja


Medals: 16
Projects: 4
Exp: 14 years


Maximumisness


« Reply #30 - Posted 2008-06-26 09:54:32 »

this slow array access is for me the biggest performance issue in java
absolutely!

Offline ewjordan

Junior Member





« Reply #31 - Posted 2008-06-26 11:44:22 »

this slow array access is for me the biggest performance issue in java
This is quite interesting.
It makes me wonder though why java's bounds checks seem as expensive as they are. Especially with lots of array access, it should basically be free then? It isn't though.
I would agree with you, the loop counter and array range are usually both going to be in registers, which should allow them execute while waiting for the array element to come through from the cache or memory; however, the range check always happens first, so even if the access is slower, it might not be initiated until the range check is already finished, which would be a slight waste of time.  I'm not too familiar with how this out of order stuff happens in hardware, so I could be wrong.  With decent jump prediction, I'd at least think the next bounds check should be executed while waiting for the previous access to finish...

Are we that the slowness is actually due to the bounds checks, though?  See http://weblogs.java.net/blog/kohsuke/archive/2008/03/deep_dive_into.html - the bounds checks are actually being correctly eliminated in at least some cases for the "fast" part of the loop (the JVM splits most loops of reasonable and known length into a short pre-phase, a longer fast phase, and a short post-phase so that it can safely unroll - 8x in that example - and align things nicely, as well as trim out the bounds check for the fast phase), though the example there is a bit trivial for comfort...but with constant bounds, which the JVM is checking for, it shouldn't be difficult to eliminate most bounds checks in an identical manner.  In that case only 16 checks are performed out of 256 possible, which should add a negligible amount of time to the loop, and the fast loop doesn't look much different upon a quick inspection from what you'd expect from a C compiler.  The JVM could certainly do better, as in that example there doesn't need to be a single bounds check, but 16 out of 256 isn't that bad.

Anyone up to a compare and contrast between the assembly generated from a noticeably slow Java array access loop and a fast C one so we can see exactly what the difference is?

It might also be worth pinning down what kind of code will cause the bounds check to happen every time through the loop, because that's something you'd definitely want to avoid.
Offline erikd

JGO Ninja


Medals: 16
Projects: 4
Exp: 14 years


Maximumisness


« Reply #32 - Posted 2008-06-26 12:14:39 »

Quote
however, the range check always happens first, so even if the access is slower, it might not be initiated until the range check is already finished, which would be a slight waste of time.
True, however in tight inner loops that's only really true at the first iteration.

I know that the JVM is capable of eliminating bounds checks in some trivial cases; I'm mainly referencing random array access where bounds checks always happen.
I haven't *directly* compared against C, but what I've seen is that java's speed can be comparable to C until you do lots of random array access. What I did try is disabling bounds checks in GCJ in a random array access heavy program (an emulator), which made the whole thing speed up by a really large amount (more than 2x iirc).

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Abuse

JGO Coder


Medals: 11


falling into the abyss of reality


« Reply #33 - Posted 2008-06-26 18:46:54 »

arf, as it is not 100% true that's better to get the habit to use <<1 or <<2 or etc.. you will finally use it automatically and after severals years thinking in binary you wont see any more difference between *2 and <<1 when reading a code.

I would definitely agree with ewjordan on this one - your source-code should be as verbose as possible.
If you are performing a bit-wise operation, use the shift operators - if you are doing a division or multiplication use the intended math operators.

If you want the solution to be performant, and you don't trust the VM runtime to make the obvious optimisation - then you should pass your classes through an appropriate bytecode optimiser before deployment.

I've more than once had to fix bugs caused by code authors failing to realize the relationship "n/2 == n>>1" is only valid for natural numbers.(non-negative integers)

Make Elite IV:Dangerous happen! Pledge your backing at KICKSTARTER here! https://dl.dropbox.com/u/54785909/EliteIVsmaller.png
Offline DzzD
« Reply #34 - Posted 2008-06-26 19:27:56 »

Quote
I've more than once had to fix bugs caused by code authors failing to realize the relationship "n/2 == n>>1" is only valid for natural numbers.(non-negative integers)
I did this error too...

of course readability is good, just said that >>1 does not seem less readable than /2.

EDIT: but it seems that java use the right decal op (not >>>)  to make it work even with negative  , do I am wrong ?


Offline Abuse

JGO Coder


Medals: 11


falling into the abyss of reality


« Reply #35 - Posted 2008-06-26 20:32:26 »

I did this error too...

of course readability is good, just said that >>1 does not seem less readable than /2.

EDIT: but it seems that java use the right decal op (not >>>)  to make it work even with negative  , do I am wrong ?



I'm referring to the difference in rounding behaviour.

right shift rounds toward negative infinity.
division rounds toward 0.

e.g.

-3/2 = -1
-3>>1 = -2

Make Elite IV:Dangerous happen! Pledge your backing at KICKSTARTER here! https://dl.dropbox.com/u/54785909/EliteIVsmaller.png
Offline ewjordan

Junior Member





« Reply #36 - Posted 2008-06-26 20:44:55 »

I haven't *directly* compared against C, but what I've seen is that java's speed can be comparable to C until you do lots of random array access. What I did try is disabling bounds checks in GCJ in a random array access heavy program (an emulator), which made the whole thing speed up by a really large amount (more than 2x iirc).
Ok, that's definitely one way to prove that the bounds checks are actually having an effect!  The irony here is that random access is the one area where Java should be able to really shine over non-GCed languages because it could be arranging things well in memory; if it's just throwing all that away due to bounds checks, that's really a shame.

One thing that I've noticed while browsing the source - HotSpot is able to prove certain facts about some of your variables to itself, for instance:
1  
2  
3  
4  
5  
6  
7  
8  
int[] myArray = new int[200];

if (x > 5) {
  if (x < 100) {
    //Hotspot knows that x is between 5 and 100 here, so in theory could skip the bounds check (I haven't verified that it does)
   myArray[x] += 1;
  }
}

The problem is, in a lot of random access cases the proof that you're not going outside the range is a lot more complicated than some nested ifs, and I'm not sure how deeply things get analyzed and how far variable ranges propagate - not very far, I'm sure.  Also, from what I can tell most of the JVM's optimization is purely per-function (please correct me if I'm wrong on this!), so any range restrictions that might be present globally will not be factored in.  To some extent this is unavoidable, since knowing whether we're going outside the bounds of an array in general is equivalent to the halting problem, but I'm sure a lot more could be done here...

The more I think about this, the more I'm wondering whether what we really should be pushing for at this point is a more powerful optimization mode than -server.  To me it seems that while in theory the idea of having a quick and dirty compile phase is great and all, the balance (even with -server) is quite a bit too far in favor of reducing pauses due to compilation at the expense of the ultimate speed of the program; furthermore, nobody really uses Java for any of the light, quick starting things that would have their overall performance impacted at all by a few stutters at first.  Let's be honest, nobody was ever happy with the client JVM, despite its supposed benefits over the server one.  Is anyone actually irritated by (or does anyone even notice, for that matter) the time taken to compile?  I know when I turn on the compilation print statements, I'm almost always annoyed at how quickly things stop happening, especially when I know there's so much more that could be done...
Offline jezek2
« Reply #37 - Posted 2008-06-26 21:22:05 »

Let's be honest, nobody was ever happy with the client JVM, despite its supposed benefits over the server one.  Is anyone actually irritated by (or does anyone even notice, for that matter) the time taken to compile?  I know when I turn on the compilation print statements, I'm almost always annoyed at how quickly things stop happening, especially when I know there's so much more that could be done...

I'm 'happy' with the client JVM on my machine (single core P4 northwood 2.4ghz), because the server VM has irregular pauses due to compiles over a long time span. I think this is due to reaching compilation treshold slowly on not so often called methods.

I'm really looking forward to the tiered approach, hoping it will be without these pauses (that are not much acceptable for GUI/game apps).
Offline DzzD
« Reply #38 - Posted 2008-06-26 21:26:03 »

Quote
-3/2 = -1
-3>>1 = -2
ok


Quote
Ok, that's definitely one way to prove that the bounds checks are actually having an effect!

yup that's really annoying, enable manual disabling on that would be great, but not really java like Sad





Offline arm

Senior Newbie




Java games rock!


« Reply #39 - Posted 2008-06-27 09:01:29 »


There are already available some improvements to hotspot (6up6) that work on 64bits OS.

http://java.sun.com/javase/technologies/performance.jsp]]http://java.sun.com/javase/technologies/performance.jsp

According to Sun site:

"These performance enhancements will be included in an upcoming standard release of the Java SE platform."

These improvements will probably include (http://www.ssw.uni-linz.ac.at/Research/Papers/Ko08/):

Scalar replacement: If an object does not escape the creating method, its
fields can be replaced by scalar variables.

Stack allocation: An object that is accessed only by one method and its callees
can be allocated on the stack instead of the heap.

Automatic Object Colocation and Inlining: Two objects, where one containing (by reference)
the other, will be stored in memory as one object.
It reduces the access costs of fields and arrays by improving
the cache behavior and by eliminating unnecessary field loads.

The same applies to objects containing an array of size known at creation time (String object included)
http://www.ssw.uni-linz.ac.at/Research/Papers/Wimmer08/
http://www.ssw.uni-linz.ac.at/Research/Papers/Haeubl08Master/

Regards

Angelo


Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline swpalmer

JGO Coder




Where's the Kaboom?


« Reply #40 - Posted 2008-06-29 02:33:19 »


Java Results (Apple JVM 1.6, -server - I'll check this on a Sun VM pretty soon, too)
...
...
@jezek2: on the Mac, the -server mode in 1.6 doesn't do very much, I think it just changes the way the heap sizing operates, which is irrelevant for these tests.  I tried in 1.5, though, and got the following:

Apple 1.5 without -server:
Normal FPS:      7530.917239361543
Interleaved FPS:   7536.807696165959
Object FPS:      6943.34652777474

Apple 1.5 with -server:
Normal FPS:      22029.56632155148
Interleaved FPS:   21603.01266973487
Object FPS:      18347.889937613505
Local FPS:      13744.841045723999

So at least on OS X, 1.5 should DEFINITELY be used with the -server flag.  I included that "Local FPS" entry in the last one because that shows that at least Apple's 1.5 -server has a speed problem passing arrays as local variables, I'm not sure why - I omitted that from all the other tests because it never differed.

On a Mac Java 6 is only implemented as a 64-bit server VM... -server does nothing.  There is no Java 6 client VM on a Mac. As I understand it Apple decided to implement only a 64-bit JVM since they are heading towards 64-bit throughout OS X.  The only 64-bit VM that was available to port was the server VM.
Conversely there is no server VM for Java 1.5 on a Mac.  But the -server flag is used to adjust some VM parameters to things more suitable for a server (like compile thresholds and heap settings) but it is still running on the 1.5 client VM.  Also Java 1.5 on a Mac is using a 32-bit VM.  I'm surprised at the large difference you saw with the -server option on the Mac.

Scott

Offline erikd

JGO Ninja


Medals: 16
Projects: 4
Exp: 14 years


Maximumisness


« Reply #41 - Posted 2008-06-30 10:34:31 »

yup that's really annoying, enable manual disabling on that would be great, but not really java like Sad

Disabling bounds checks is out of the question I suppose  Smiley

Sometimes it would have been nice to have some known cases where bounds checks for random array access are eliminated.
For example a case:
* length of the array is power of 2
* the array is declared as final (power of 2 and final just to make the check for bounds check elimination quicker).
* the index into the array is AND masked with array.length - 1
The AND operation would be cheaper than a bounds check, right?
1  
2  
3  
4  
5  
final int[] myArray = new int[0x1000];

public int getMyValue(int index) {
   return myArray[index & 0xfff];
}


This currently doesn't work unfortunately, and adding the '& 0xfff' just makes it slower.

Offline Markus_Persson

JGO Wizard


Medals: 14
Projects: 19


Mojang Specifications


« Reply #42 - Posted 2008-06-30 15:16:21 »

How about

1  
2  
3  
Object[] myArray = new Object[65536];
char i = 12;
myArray[i] = new Object();


 Grin

Play Minecraft!
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 744
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #43 - Posted 2008-06-30 18:31:54 »

I guess that should have been: new Object[65535] Tongue


Anyway, do not overestimate the overhead of array bound checks.

With sun.misc.Unsafe you (can) have array-access without bound checks, and it's hardly faster, if at all!!



Some people forget that there is a null-check for every reference that is followed, even for arrays. So that silly value[p] involves both a bounds check and a null-check!

In most cases, the JVM just removes all those silly checks, even for non-trivial array access. For true random-access (still 'random' after the JVM recursively inlined it, where it can find 'limits' of your 'random' variable, which it will use to remove the checks), yes, true random access, you'll have that slow loop... and sun.misc.Unsafe or JNI to the rescue!

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline erikd

JGO Ninja


Medals: 16
Projects: 4
Exp: 14 years


Maximumisness


« Reply #44 - Posted 2008-06-30 19:23:07 »

I guess that should have been: new Object[65535] Tongue

I guess not  Tongue
1  
2  
3  
new Object[65535];
char i = 65535;
myArray[i] = new Object();

barfs an ArrayOutOfBoundsException

Quote
With sun.misc.Unsafe you (can) have array-access without bound checks, and it's hardly faster, if at all!!
IIRC the thing with Unsafe is that the indices are byte offsets, which is a bit of a pain when retrieving ints or something.
I've done tests with JEmu2 and when using Unsafe it definitely is noticably faster but I had to rewrite a lot of the algorithms in order to get the most from Unsafe, avoiding offset<<=2 and such to convert from int to byte offsets and keeping track of just one pointer instead of a pointer and an index etc.
In the end I disabled the 'Unsafe' code, because of the non-standard nature of it. It's too hacky and who knows it's going to be there in all JVM implementations, working exactly the same way.

Offline krausest

Junior Member


Exp: 15 years


I love YaBB 1G - SP1!


« Reply #45 - Posted 2008-07-01 20:39:15 »

Last, your have that giant method that runs all the benchmarks. The JIT stops moptimising methods that are longer than a certain amount of instructions. That 'magic amount' is rather low, and your method will certainly not be turned into the most efficient native code. You can take a look at the output of the Debug VMs (release candidates with debug commandline options, IIRC) from Sun, which will tell you when the JIT gives up.
Can you tell more about that? Is there a -XX switch to adjust that limit? What options have to be set in the debug commandline  (Does -XX:PrintCompilation also show that effect)?
Offline erikd

JGO Ninja


Medals: 16
Projects: 4
Exp: 14 years


Maximumisness


« Reply #46 - Posted 2008-07-16 15:35:51 »

Quote
Let's look at this loop:
Code:

long[] data = new long[1024];
long xor = 0;
for(int i=0; i<data.length; i++)
   xor ^= data;

It's obvious that this loop basicly waits a lot of the time. You can do quite a bit meanwhile, in the same thread.

it's actually so bad, that you can do this, in exactly the same time:
Code:

long[] data = new long[1024];
long xor = 0;
for(int i=0; i<data.length; i++)
   xor ^= swap64(data);

   public static final long swap64(long val)
   {
      long swapped = 0;
      swapped |= (val & 0x00000000000000FFL) << 56;
      swapped |= (val & 0x000000000000FF00L) << 40;
      swapped |= (val & 0x0000000000FF0000L) << 24;
      swapped |= (val & 0x00000000FF000000L) << 8;
      swapped |= (val & 0x000000FF00000000L) >> 8;
      swapped |= (val & 0x0000FF0000000000L) >> 24;
      swapped |= (val & 0x00FF000000000000L) >> 40;
      swapped |= (val & 0xFF00000000000000L) >>> 56;
      return swapped;
   }


We're adding maybe 32 instructions per loop-iteration, and we have no speed-penalty at all.

Hmm, I actually just tested this, but I'm seeing something else:
The code with 'swap64' is about 15 times as slow on my PC (which I call quite a speed penalty Tongue), on both -client and -server (java 1.6.0 update 7) running on a 32bit dual core Intel.
I could imagine things like this might vary a lot between CPUs and/or RAM speeds and such. Riven, on what CPU and java version did you test this?

Offline Riven
« League of Dukes »

JGO Overlord


Medals: 744
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #47 - Posted 2008-07-16 21:16:27 »

64 bit OS (Vista)
64 bit JVM (1.6, Sun, server vm)



I bet you get really poor performance on long primitives in 32 bit JREs.


You might want to create an example that works with ints, and a swap32 method

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline erikd

JGO Ninja


Medals: 16
Projects: 4
Exp: 14 years


Maximumisness


« Reply #48 - Posted 2008-07-16 22:26:24 »

You might want to create an example that works with ints, and a swap32 method
Yes, that's what I tried at first but that gave a similar result. The difference was less severe than with 64 bit, but it was still significantly slower...

Quote
Anyway, do not overestimate the overhead of array bound checks.
One thing I did in JEmu2 in the Sega Y-Board driver that really gave me nice performance boost was to load the sprite roms into long[] arrays. Because sprite pattern data is stored in 8 byte blocks (for 16 pixels), I only had to do one array access to retrieve 16 pixels and shift-mask the pixels out of the long value. That really made a big difference (>10% overall increase in FPS).
TBH I'm not 100% sure it is entirely accountable to less bounds checks due to array access though, but less bounds checks were the reason for packing the data into long[]  Smiley

Offline Riven
« League of Dukes »

JGO Overlord


Medals: 744
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #49 - Posted 2008-07-16 22:35:30 »

I'll try to see if I can make a small benchmark that shows the behaviour I described before.


But well, you know how it is... you only have to bump your PC case and the JVM takes another optimalisation path Wink

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline DzzD
« Reply #50 - Posted 2008-07-17 19:47:51 »

Quote
...64 bit OS (Vista)
64 bit JVM (1.6, Sun, server vm)...


Quote
...running on a 32bit dual core Intel...

I think that the difference in performance come form  the use of long they are slow on 32bit and as fast as int on 64bit cpu, that's why you see a performance penality, replacing the whole includind the array with int should do the job. Riven sample only rquiere trivial ops on register when there size fit the OS (int/long 32/64) and it should be a lot faster than array acces wich requiere bounds+memory acces.



Offline Riven
« League of Dukes »

JGO Overlord


Medals: 744
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #51 - Posted 2008-07-17 22:27:43 »

Have you read the last 3 posts? Wink

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline DzzD
« Reply #52 - Posted 2008-07-18 01:56:37 »

oups...   Roll Eyes


... forgot to read the end of your post
Quote
I bet you get really poor performance on long primitives in 32 bit JREs.

Offline erikd

JGO Ninja


Medals: 16
Projects: 4
Exp: 14 years


Maximumisness


« Reply #53 - Posted 2008-07-18 10:25:17 »

Just reran the 32 version of the test, but with swap32(int) made the test about 9 times as slow as without.
So yeah, using long on a 32bit cpu skewed the results somewhat, but the result is still that I'm not seeing what Riven described.

Offline Riven
« League of Dukes »

JGO Overlord


Medals: 744
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #54 - Posted 2008-07-18 19:08:37 »

I'm really busy these days. Excuse me for the delay - I'll post a benchmark (for review) ASAP.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline Mr_Light

Senior Member




shiny.


« Reply #55 - Posted 2008-08-13 18:32:11 »

One thing that I've noticed while browsing the source - HotSpot is able to prove certain facts about some of your variables to itself, for instance:
1  
2  
3  
4  
5  
6  
7  
8  
int[] myArray = new int[200];

if (x > 5) {
  if (x < 100) {
    //Hotspot knows that x is between 5 and 100 here, so in theory could skip the bounds check (I haven't verified that it does)
   myArray[x] += 1;
  }
}

The problem is, in a lot of random access cases the proof that you're not going outside the range is a lot more complicated than some nested ifs, and I'm not sure how deeply things get analyzed and how far variable ranges propagate - not very far, I'm sure.  Also, from what I can tell most of the JVM's optimization is purely per-function (please correct me if I'm wrong on this!), so any range restrictions that might be present globally will not be factored in.  To some extent this is unavoidable, since knowing whether we're going outside the bounds of an array in general is equivalent to the halting problem, but I'm sure a lot more could be done here..
You also need to prove that x doesn't escapes. As for 'not very far'/'per function'  as the 'restricting' code is further away it is harder to guaranty that it doesn't escape.

Also it is not till Java 6-7 that escape analysis was really added (and enabled by default) or completed. Undoubtedly as that analysis evolves, it can more often give guaranties, which in turn can be used to improve other optimisations. Given those entanglements and the correlated 'lock-step' evolution, it is perhaps not that weird how some optimisations work and others don't.

Adding that it's programmed in c/c++ they sure get my pitty. Maxine seems to be pretty sweet with respect to that.

ps. to do the thing raven talked about; see the output have a look here: http://weblogs.java.net/blog/kohsuke/archive/2008/03/deep_dive_into.html

It's harder to read code than to write it. - it's even harder to write readable code.

The gospel of brother Riven: "The guarantee that all bugs are in *your* code is worth gold." Amen brother a-m-e-n.
Offline Jack9C

Junior Newbie





« Reply #56 - Posted 2008-08-16 05:38:17 »

Quote
My impression is that the JVM specs guarantee literally nothing about any sort of contiguous allocation - by my reading, an array of floats could very well be scattered all across the heap.  Apparently even the stack is usually not contiguous in Sun's VMs.

I'm pretty sure java.nio.MappedByteBuffer is contiguous. I use it for volatile ringbuffers.
Offline ewjordan

Junior Member





« Reply #57 - Posted 2008-08-16 09:09:03 »

You also need to prove that x doesn't escapes. As for 'not very far'/'per function'  as the 'restricting' code is further away it is harder to guaranty that it doesn't escape.
True, though in that example, since x is a float, it's a bit easier since it's bound to its declared scope and can't escape via a function call or reference stored away somewhere.  That's what's so nice about having objects with value semantics in a language, it is dead simple to allocate them to the stack instead of the heap.

Quote
Also it is not till Java 6-7 that escape analysis was really added (and enabled by default) or completed. Undoubtedly as that analysis evolves, it can more often give guaranties, which in turn can be used to improve other optimisations. Given those entanglements and the correlated 'lock-step' evolution, it is perhaps not that weird how some optimisations work and others don't.
Right on - I've been screaming bloody murder about how desperately we could use escape analysis for quite a while now, and I'm really hoping that they decide to turn it on by default and actually use it to optimize compiled code (well, that is, assuming that all of the other (better, IMO) options for dealing with these things are discarded on the basis that they would require language changes, such as, say, value semantics, as mentioned above).  As far as I am aware, none of the current JVM builds use escape analysis for stack allocation or inlining, which is a shame.  Supposedly they are used for lock coarsening, but based on that link even that seems to be hit or miss, only helping in fairly trivial situations.  Hopefully sometime over the next few versions things will improve...
Offline blahblahblahh

JGO Coder


Medals: 1


http://t-machine.org


« Reply #58 - Posted 2008-09-24 09:35:49 »

also x*2 is much slower than x<<1

I know I'm late coming to this thread, but: Wha...? Since when? Proof?

malloc will be first against the wall when the revolution comes...
Offline zammbi

JGO Coder


Medals: 4



« Reply #59 - Posted 2008-09-24 09:55:36 »

Not really proof but for a piece of code I had, I replaced x*2 with x<<1 and it decreased the cpu usage a noticeable amount. Something like 10-15%.

Current project - Rename and Sort
Pages: 1 [2] 3
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

Riven (12 views)
2014-07-29 18:09:19

Riven (9 views)
2014-07-29 18:08:52

Dwinin (9 views)
2014-07-29 10:59:34

E.R. Fleming (26 views)
2014-07-29 03:07:13

E.R. Fleming (10 views)
2014-07-29 03:06:25

pw (40 views)
2014-07-24 01:59:36

Riven (39 views)
2014-07-23 21:16:32

Riven (27 views)
2014-07-23 21:07:15

Riven (28 views)
2014-07-23 20:56:16

ctomni231 (59 views)
2014-07-18 06:55:21
HotSpot Options
by dleskov
2014-07-08 03:59:08

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:58:24

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:47:22

How do I start Java Game Development?
by ra4king
2014-05-17 11:13:37

HotSpot Options
by Roquen
2014-05-15 09:59:54

HotSpot Options
by Roquen
2014-05-06 15:03:10

Escape Analysis
by Roquen
2014-04-29 22:16:43

Experimental Toys
by Roquen
2014-04-28 13:24:22
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!