chrstfer / blacken

Not mine, just a clone automatically exported from the now defunct google code.
https://code.google.com/archive/p/blacken/
3 stars 0 forks source link

Screen flickers with content for a moment then goes totally grey in OSX. #50

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
Scren flickers with content for a moment then goes totally grey in OSX.  Moving 
the mouse off the window and back will show content for one frame then back to 
grey

What steps will reproduce the problem?
1. run any of the examples
2. wait a fraction of a second

Attached is a screenshot

Original issue reported on code.google.com by jgmath2...@gmail.com on 15 Sep 2012 at 3:36

Attachments:

GoogleCodeExporter commented 9 years ago
I'm also getting a flood of this error:

ERROR [AWT-EventQueue-0] (BlackenPanel.java:290) - Dropped an paintComponent 
update -- didn't come through refresh()

Original comment by jgmath2...@gmail.com on 15 Sep 2012 at 6:08

GoogleCodeExporter commented 9 years ago
I know what's going on.

An ancestor element is displaying itself with the expectation that the UI will 
refresh itself.

I don't understand _why_, though. It really sounds like Swing is refusing to 
double-buffer. Since Swing is supposed to double-buffer by default, that would 
be severely broken on a number of levels.

Is this with Oracle's Java 7 or with the Apple's Java that ships with Mac OS X? 
I thought I'd heard that Apple hadn't yet switched to Java 7.

Original comment by yam...@gmail.com on 21 Sep 2012 at 4:41

GoogleCodeExporter commented 9 years ago

Original comment by yam...@gmail.com on 21 Sep 2012 at 5:01

GoogleCodeExporter commented 9 years ago
I think I have fixed this issue.

Can you try out the version I have attached? (It's the "stumble" example.)

Thanks!
Steven Black

Original comment by yam...@gmail.com on 21 Sep 2012 at 6:01

Attachments:

GoogleCodeExporter commented 9 years ago
I ran the jar you made and the problem is still there.  If I out of the window 
and back I see the game for a moment then it goes back to grey.

I'm using Oracle's java 7 for OS X.  It's not part of an OS X system update but 
you can download it from Oracle.

I noticed that putting  refresh_all=true;  as the first line of 
paintComponent(...) in BlackenPanel.java fixes the problem, but I'm assuming 
there are performance implications there.

Original comment by jgmath2...@gmail.com on 21 Sep 2012 at 6:37

GoogleCodeExporter commented 9 years ago
The example I included should display _something_, but it may be a little 
"glitchy". I'll include another attachment when I have the last of the issues 
worked out.

Original comment by yam...@gmail.com on 21 Sep 2012 at 6:50

GoogleCodeExporter commented 9 years ago
Here's what your example looks like:

Original comment by jgmath2...@gmail.com on 21 Sep 2012 at 10:49

Attachments:

GoogleCodeExporter commented 9 years ago

Original comment by yam...@gmail.com on 21 Sep 2012 at 1:51

GoogleCodeExporter commented 9 years ago
The new example should not be putting out the "Dropped an paintComponent update 
-- didn't come through refresh()" messages -- can you confirm that? Is it 
throwing an exception now?

What is the exact output of (in a Terminal window):

    which java ; java -version

The punctuation is first a semicolon (";") and then a single dash ("-").

Thanks!
Steven Black

Original comment by yam...@gmail.com on 21 Sep 2012 at 1:57

GoogleCodeExporter commented 9 years ago
In OS/X you set which java to use by going through java preferences, then the 
OS sets up the symbolic links.

Here's the info:

jgauci-macbookpro:stumble-1.2-2012-09-21 jgauci$ which java
/usr/bin/java
jgauci-macbookpro:stumble-1.2-2012-09-21 jgauci$ java -version
java version "1.7.0_10-ea"
Java(TM) SE Runtime Environment (build 1.7.0_10-ea-b07)
Java HotSpot(TM) 64-Bit Server VM (build 23.6-b02, mixed mode)

Here's what the console prints when I run it:

jgauci-macbookpro:stumble-1.2-2012-09-21 jgauci$ java -jar 
stumble-1.2-SNAPSHOT.jar 
DEBUG [main] (SwingTerminal.java:751) - Setting font to null
 INFO [AWT-EventQueue-0] (BlackenPanel.java:463) - Panel update speed: 93 ms / Average: 93 ms
 INFO [AWT-EventQueue-0] (BlackenPanel.java:463) - Panel update speed: 1 ms / Average: 47 ms
 INFO [AWT-EventQueue-0] (BlackenPanel.java:463) - Panel update speed: 62 ms / Average: 54 ms
 INFO [AWT-EventQueue-0] (BlackenPanel.java:463) - Panel update speed: 35 ms / Average: 44 ms
 INFO [AWT-EventQueue-0] (BlackenPanel.java:463) - Panel update speed: 71 ms / Average: 57 ms
 INFO [AWT-EventQueue-0] (BlackenPanel.java:463) - Panel update speed: 0 ms / Average: 28 ms
DEBUG [AWT-EventQueue-0] (EventListener.java:300) - Undefined Key: 
java.awt.event.KeyEvent[KEY_PRESSED,keyCode=157,keyText=Meta,keyChar=Undefined 
keyChar,modifiers=Meta,extModifiers=Meta,keyLocation=KEY_LOCATION_LEFT,rawCode=0
,primaryLevelUnicode=0,scancode=0,extendedKeyCode=0x0] on 
com.googlecode.blacken.swing.BlackenPanel[,0,0,1176x694,layout=java.awt.FlowLayo
ut,alignmentX=0.0,alignmentY=0.0,border=,flags=9,maximumSize=,minimumSize=,prefe
rredSize=]
 INFO [AWT-EventQueue-0] (BlackenPanel.java:463) - Panel update speed: 38 ms / Average: 33 ms
 INFO [AWT-EventQueue-0] (BlackenPanel.java:463) - Panel update speed: 51 ms / Average: 42 ms
 INFO [AWT-EventQueue-0] (BlackenPanel.java:463) - Panel update speed: 23 ms / Average: 32 ms
 INFO [AWT-EventQueue-0] (BlackenPanel.java:463) - Panel update speed: 11 ms / Average: 21 ms
 INFO [AWT-EventQueue-0] (BlackenPanel.java:463) - Panel update speed: 10 ms / Average: 15 ms
 INFO [AWT-EventQueue-0] (BlackenPanel.java:463) - Panel update speed: 0 ms / Average: 7 ms
 INFO [AWT-EventQueue-0] (BlackenPanel.java:463) - Panel update speed: 15 ms / Average: 11 ms
 INFO [AWT-EventQueue-0] (BlackenPanel.java:463) - Panel update speed: 6 ms / Average: 8 ms
 INFO [AWT-EventQueue-0] (BlackenPanel.java:463) - Panel update speed: 13 ms / Average: 10 ms
 INFO [AWT-EventQueue-0] (BlackenPanel.java:463) - Panel update speed: 0 ms / Average: 5 ms

I did some digging on my own and it looks like OS/X is clearing the panel each 
frame before paintComponent is called.  Maybe double buffering isn't supported 
on macs?  As I mentioned before, forcing refresh_all to true fixes it.

Original comment by jgmath2...@gmail.com on 21 Sep 2012 at 3:35

GoogleCodeExporter commented 9 years ago
Yes, actually you cannot prevent the OS from clearing your component before a 
repaint in a cross-platform way.  Look at this stackoverflow for more info:

http://stackoverflow.com/questions/3289336/swing-active-rendering-efficiency-or-
how-to-combine-active-rendering-with-gui-wi

Original comment by jgmath2...@gmail.com on 21 Sep 2012 at 3:46

GoogleCodeExporter commented 9 years ago
Sorry, somehow I missed your comment saying that refresh_all=true solved the 
issue yesterday.

I've seen some other comments that point that perhaps double-buffering isn't 
supported in Mac OS X -- Mac OS X compensates by being "accelerated."

With the refresh_all fix in place, are you generally getting a "Panel update 
speed" that jumps between 0 and ~15 ms? (After start up.) Toward the end it 
looks like that's what it is doing.

If that's the case then we're not seeing any slowdown. I can special-case Mac 
OS X until I can track down the proper cross-platform way to tell if I need to 
use this approach or not.

I'm already special-casing a Windows 7 vertical maximize bug. (It also shows up 
with NetBeans.) I don't have the Windows-specific check in the version you're 
using -- this is why the window contents flickers on mouse entry. (I'm going to 
see if I can remove the flicker even in Windows as that flicker only started 
showing up when I made a change for this bug.)

Good old Java, right once and test everywhere... :/

Original comment by yam...@gmail.com on 21 Sep 2012 at 10:31

GoogleCodeExporter commented 9 years ago
Actually I think a better approach would be to draw to an offscreen buffer and 
in paintComponent just paint that buffer like they do in that stackoverflow 
link I sent you. Basically you will end up implementing your own double 
buffering, but then the OS is free to redraw the window when someone maximizes 
it, shrinks it, etc. without paying a huge performance hit.

Original comment by jgmath2...@gmail.com on 22 Sep 2012 at 4:31

GoogleCodeExporter commented 9 years ago
Manual double-buffering like that is _super_ slow. Like 50 to 100x as slow. 
(Instead of updates of 0-15ms it was ~0.3 seconds per frame.) The Blacken 1.0 
line used manual double-buffering like that and only the fact that I totally 
ignored refresh requests caused it to feel remotely responsive. Seriously.

And that's on Windows where they actualy normally do double-buffering. Even the 
standard Mac OS X double-buffering is super slow in comparison -- they 
recommend against any double-buffering and instead writing directly to the 
screen. (Different Stack Overflow thread.)

It would be a massive step backward that would only (potentially) help the Mac 
OS X space -- and if you're getting speeds of 0-15 ms I don't even know that it 
would actually help that space. The whole reason they don't do double-buffering 
by default in Mac OS X is that you're not supposed to need it. Why manually 
implement something I'm not supposed to need?

With Blacken the OS isn't "free" to redraw the screen when it's resized anyway. 
The screen is always refreshed completely on a resize -- because the font 
and/or the number of rows or columns change. This means you just double the 
performance impact of these operations because instead of doing it once, you're 
doing it once and blitting the result.

That article you mentioned doesn't actually relate, as that's about combining 
active rendering with widgets -- Blacken doesn't use any widgets. To further 
highlight the issues with the buffer approach, that very article you mention 
says, "The Mac implementation doesn't seem to support hardware acceleration 
properly, which makes repainting the background image to the output window a 
tedious task, depending of course on the size of the window."

With active rendering the rendering speed is nearly constant with the number of 
cells on screen. Rendering in a very large window as fast as it is in a very 
small window. This is something that is _not_ true once you start using a 
manual buffer and blitting the results. (I was seeing a blit-size penalty when 
I used the manual double-buffer approach.)

This is further backed up by Java gaming-related articles that also advocate 
active rendering as being the only solution to good performance.

I've seen active rendering speeds average under 5 ms a frame. Okay, 15 ms is 
three times that, but it is still better than manual double-buffering any day 
of the week.

I'm going to make a new archive and I want you to try it and tell me the speeds.

Actually, I'm going to implement this first (the author is wrong about the need 
to use BufferStrategy with Swing, but this bit looks useful):

http://jamesgames.org/resources/double_buffer/double_buffering_and_active_render
ing.html#OverridingRepaintManager

Original comment by yam...@gmail.com on 23 Sep 2012 at 2:45

GoogleCodeExporter commented 9 years ago
Well, overriding the repaint manager is definitely the way to stop refreshing 
the window in a cross-platform manner.

A roguelike is sort of a poor fit of a totally actively rendered approach. I 
looked at it, but in the end I think the partial active rendering I'm doing is 
a better fit.

I get ~5 ms of slowdown copying the precomputed data so I can handle redraws 
that are not triggered by the main game logic. (Regardless of window size.) 
This gets me support for all of the rendering requests that are still passed 
through when "setIgnoreRepaint(true)" is enabled -- in fact I don't know that 
ignoring any repaint requests gain us anything anymore. (You saw these 
"ignored" in the initial version.) 

I may be able to cut some of that overhead but that's not enough to be a 
priority right now.

Original comment by yam...@gmail.com on 23 Sep 2012 at 3:30

Attachments:

GoogleCodeExporter commented 9 years ago
Yeah, I was able to entirely remove the 5-6 ms overhead I had just added 
working on this ticket.

Original comment by yam...@gmail.com on 23 Sep 2012 at 4:01

GoogleCodeExporter commented 9 years ago
I'm attaching what I'm about to check in.

It appears to be faster than before I started working on this ticket.

The Mac OS X fix is in place -- but only for Mac OS X. (Though when in place on 
Windows it only decreased the speed by ~1-2 ms on the long cycles. -- Still 
under 10 ms on average for me.)

The Windows 7 fix has also been set to only apply to Windows 7 and it has been 
fixed so it doesn't visibly flicker the font as much.

Part of this fix included responding to more update events. What I'm checking 
in now doesn't ignore any repaint requests. This should clear up some edge 
conditions that were annoying.

Original comment by yam...@gmail.com on 23 Sep 2012 at 7:51

Attachments:

GoogleCodeExporter commented 9 years ago
There were some things that shook loose from the fixes around this ticket. I 
had created some minor display issues that I wanted to resolve.

I'm attaching the current results of my work. With a full repaint it is now 
averaging 5 ms.

More interestingly, I have a bug in the logic which only repaints a part of the 
window, so even in Windows it is currently doing a full repaint.

How does it work for you? I have it marked "fixed" because I _think_ it is 
fixed, but I'd love to mark it "verified" because it is confirmed that the 
solution works well.

Cheers,
Steven Black

Original comment by yam...@gmail.com on 24 Sep 2012 at 7:11

Attachments:

GoogleCodeExporter commented 9 years ago
Nice! it looks like this version works fine.

Original comment by jgmath2...@gmail.com on 24 Sep 2012 at 5:12

GoogleCodeExporter commented 9 years ago
Fantastic!

Thanks again for helping me with this issue.

Original comment by yam...@gmail.com on 25 Sep 2012 at 8:34