Artificial delay needed to change to Fullscreen...

I have been having issues when trying to convert my raytracer to run in fullscreen exculsive mode. It was correctly changing mode however no image was being displayed (i.e. a grey screen is displayed).

From searching these forums i came across some code which had introducted a delay after changing modes and creating the buffer strategy. I put a similar delay in and found that the image is now being updated!

My question is why is this delay needed? and surely if it necessary there must be a method to call to wait until the screen is in a appropriate state before continuing to execute the program.

This is the code I am using to change to full screen and create the bufferstrategy:



			GraphicsDevice device = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()[0];
			setUndecorated(true);
			device.setFullScreenWindow(this);
			createBufferStrategy(2);
			device.setDisplayMode(new DisplayMode(renderWidth, renderHeight, 32,DisplayMode.REFRESH_RATE_UNKNOWN));

			
			try {
				Thread.sleep(1000);
			} catch (InterruptedException ex) {
			}

To illustrate the problem i have two versions of the program:

With Delay (program works correctly)
With NO Delay (only grey screen displayed)

depending you config, delay has no effect. Both versions worked on Mac OS X 1.2 Ghz eMac. But as for my own game, the fullscreen-mode must be execute twice switched-back to window before to get the scaling operation ok on full-screen, that’s somehow a trick to change to FSmode. Anyway, some caution with FSmode has to be cared. :o

Hmm… that is quite distressing… I had assumed that it would be conistant amongst the different platforms…

I have tried putting the full screen mode change code on the EDT but that had no effect.

I also tried your suggestion of performing a fullscreen-mode->window-mode->fullscreen-mode transition but it also had no effect.

There is no problems when rendering to a normal window (i.e. not fullscreen)

I found this trick by changing manually from window to FS and back again till the second time where I found out the loading time. So here’s mine, windowed->full-screened wait for 3-6 secs->windowed resized 3-6secs again->full-screened :

/***/
    private transient Thread T_switchFullScreen;
    
    /** swichtes to fullscreen-mode */
    private void switchFullScreen(boolean init) {
        if (!activeRendering) {
            new UIMessage(true, "full-screen not allowed w/ soft rendering, switch to hardware accelerated [F12] !", frame, UIMessage.ERROR_TYPE);
            return;
        }
        if (fullscreen) {
            try {
                if (device.isFullScreenSupported()) {
                    device.setDisplayMode(initialDisplayMode);
                }
            } catch (IllegalArgumentException ex) {
                ex.printStackTrace();
                String msg = "";
                for (StackTraceElement se : ex.getStackTrace()) {
                    msg += se.toString() + "\n";
                }
                new UIMessage(false, ex.getMessage() + "\r\n" + msg, frame, UIMessage.ERROR_TYPE);
            } finally {
                stop();
                device.setFullScreenWindow(null);
                frame.setResizable(true);
                setPreferredSize(defaultSize);
                frame.setSize(defaultSize);
                frame.pack();
                removeActionAfter(getRefreshAction(FULLSCREEN_MODE));
                addActionAfter(getRefreshAction(WINDOWED_MODE));
                fullscreen = false;
                start();
            }
        } else {
            stop();
            if (init) {
                DisplayModeWrapper[] dms = new DisplayModeWrapper[device.getDisplayModes().length];
                int i = 0;
                for (DisplayMode dm : device.getDisplayModes()) {
                    dms[i++] = new DisplayModeWrapper(dm);
                }
                displayMode = ((DisplayModeWrapper) UIMessage.showSelectDialog(this, "What display mode should I use?", "Fullscreen mode", dms, new DisplayModeWrapper(displayMode))).getDM();
            }
            removeActionAfter(getRefreshAction(WINDOWED_MODE));
            addActionAfter(getRefreshAction(FULLSCREEN_MODE));
            if (frame instanceof JFrame) {
                if (!frame.isDisplayable()) {
                    frame = new JFrame(getGraphicsConfiguration());
                }
            } else {
                frame = new JFrame(getGraphicsConfiguration());
            }
            if (!frame.isDisplayable()) {
                frame.setUndecorated(true);
            }
            fullscreen = true;
            defaultSize = new Dimension(getWidth(), getHeight());
            frame.getContentPane().removeAll();
            frame.getContentPane().add(this);
            device.setFullScreenWindow(frame);
            try {
                device.setDisplayMode(displayMode);
            } catch (IllegalArgumentException ex) {
                ex.printStackTrace();
                new UIMessage(true, ex, null);
            } finally {
                // fix for mac os x
                setPreferredSize(new Dimension(displayMode.getWidth(), displayMode.getHeight()));
                frame.setSize(displayMode.getWidth(), displayMode.getHeight());
                frame.setResizable(false);
                frame.pack();
                start();
                if (init) {
                    if (T_switchFullScreen instanceof Thread) {
                        if (T_switchFullScreen.isAlive()) {
                            return;
                        }
                    }
                    Thread t = T_switchFullScreen = new Thread(new Runnable() {
                        
                        public void run() {
                            JFrame wait = UIMessage.displayWaiting("switching to full-screen " + new DisplayModeWrapper(displayMode).toString(), RenderingScene.this);
                            try {
                                Thread.currentThread().sleep(3000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            } finally {
                                switchFullScreen(false);
                                try {
                                    Thread.currentThread().sleep(3000);
                                } catch (InterruptedException ex) {
                                    ex.printStackTrace();
                                } finally {
                                    switchFullScreen(false);
                                    wait.dispose();
                                }
                            }
                        }
                    }, "T-switchFullScreen-initloop");
                    t.start();
                }
            }
        }
    }

I remember when I was working from KJGP that when addNotify or something was wrong there would be an error. This would happen when the graphics was created before the JFrame was created completely or something like that. Normally the JFrame gets created quick enough so the error doesn’t occur. I suspect your problem has something to do with the Graphics being created before the FSEM has fully started. On a slow pc this (probably) won’t happen and the graphics will take a bit longer than the FSEM to start.

Could you maybe show all the code for the class you showed here?

I remember having a very similar problem a while ago. I got the gray screen 10% of the time, so the timing theory seems quite valid. I whacked around in the code and what I have right now is something like:


	protected static JFrame mainFrame = null;
	protected static GraphicsDevice device = null;
	protected static BufferStrategy bufferStrategy;
	protected static Graphics g;
	protected static Canvas canvas = new Canvas();

					mainFrame = new JFrame("Game");
					GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
					device = env.getDefaultScreenDevice();

					if (device.isDisplayChangeSupported())
					{
						device.setDisplayMode(new DisplayMode(800, 600, 32, 0));
					}else{
						log.info("Display change is not supported!");
					}
					int w = device.getDisplayMode().getWidth();
					int h = device.getDisplayMode().getWidth();

					mainFrame.setUndecorated(true);
					JPanel panel = (JPanel) mainFrame.getContentPane();
					canvas.setBounds(0,0,w,h);
					panel.setPreferredSize(new Dimension(w,h));
					panel.setLayout(null);
					panel.add(canvas);

					mainFrame.setBounds(0,0,w,h);
					mainFrame.setVisible(true);
					mainFrame.setResizable(false);
					mainFrame.setLayout(null);
					mainFrame.setIgnoreRepaint(true);
					
					log.info("About to set buffer strategy");
					canvas.createBufferStrategy(2);      //It used to gets stuck here
					log.fine("Buffer strategy set");
					bufferStrategy = canvas.getBufferStrategy();
					canvas.requestFocus();
					g = bufferStrategy.getDrawGraphics();


Quickly changed to remove my specific code, so might not work right of the bat… This is probably borrowed from a few places, so cred/blame goes out to whomever wrote the parts first :slight_smile: Not sure what really made it work for me, just happy that it does! It could be that the JFrame-JPanel voodoo was the trick. Might be extra code in there not needed, but no sleep or anything like that needed for me.

Here the entire class:



package org.moogiesoft.JRTRT;

import java.awt.Color;
import java.awt.DisplayMode;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Insets;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;

import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class RTFrame extends JFrame implements RenderedImageUpdated
{
	private final boolean isFullScreen;
	private final int topInset;
	private final int leftInset;
	private final int rightInset;
	private final int bottomInset;
	private double frameCount;
	private int warmUpCount;
	private final BufferStrategy strategy;
	private final Graphics graphics;
	
	private long time;
	private double avgFPS;
	private RTFrame frame;
	
	public RTFrame(boolean isFullScreen, final int renderWidth, final int renderHeight)
	{
		this.frame=this;
		int leftInset=0;
		int topInset=0;
		int rightInset=0;
		int bottomInset=0;
		this.isFullScreen=isFullScreen;
		
        // Full-screen mode
		if (isFullScreen)
		{

			GraphicsDevice device = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()[0];
			setUndecorated(true);
			device.setFullScreenWindow(this);
			createBufferStrategy(2);
			device.setDisplayMode(new DisplayMode(renderWidth, renderHeight, 32,DisplayMode.REFRESH_RATE_UNKNOWN));

			try {
				Thread.sleep(1000);
			} catch (InterruptedException ex) {
			}
		}
		else
		{
			setResizable(false);
			setDefaultCloseOperation(EXIT_ON_CLOSE);
			addNotify();

			Insets insets=getInsets();
			leftInset=insets.left;
			topInset=insets.top;
			rightInset=insets.right;
			bottomInset=insets.bottom;
			
    		setSize(renderWidth+leftInset+rightInset,renderHeight+topInset+bottomInset);
    		setLocationRelativeTo(null);
    		setVisible(true);
    		
    		// create the buffering strategy which will allow AWT
    		// to manage our accelerated graphics
    	    createBufferStrategy(2);
		}

		this.leftInset=leftInset;
		this.topInset=topInset;
		this.rightInset=rightInset;
		this.bottomInset=bottomInset;
		

		

	    time=System.currentTimeMillis();
	    frameCount=0;
	    strategy=getBufferStrategy();
	    graphics=strategy.getDrawGraphics();
	    
	}
	
	final public void update(final BufferedImage image)
	{
		frameCount++;

		
		final long currTime=System.currentTimeMillis();
		final long timeLaped=currTime-time;
		if (timeLaped>1000)
		{
			if (warmUpCount<3)
			{
				warmUpCount++;
				avgFPS=frameCount*1000/(timeLaped);
			}
			else
			{
				avgFPS=(avgFPS*2+frameCount*1000/(timeLaped))/3;
			}
			setTitle(Double.toString(avgFPS));
			frameCount=0;
			time=currTime;
		}
		
	   	graphics.drawImage(image,leftInset,topInset,null);
	   	strategy.show();
	}
}

Thanks to jojoh and broumbroum, i will try using your suggestions to see if i can change to fullscreen consistantly.

Check out Killer Game Programming in Java, Chapter 3. Full-Screen Worms, Section 3.2. Setting up Full-Screen Exclusive Mode:

Changing your code to


try{
  EventQueue.invokeAndWait(new Runnable(){
    public void run(){
      createBufferStrategy(2);
    }
  });
}catch(Exception e){
  System.out.println("Error while creating buffer strategy");
  System.exit(0);
}

seems to be working.

You’ll notice the initial grey screen in your desktop’s resolution remains a bit longer now. The grey screen in the smaller resolution will appear briefly and go away. After the first run the grey screens appear a lot quicker or not at all.

Thanks malberts! That has seem to have done the trick!

I had tried eariler to put an invoke and wait around the change in display mode. As i thought that it was asynchronous call… i was unaware that createBufferStrategy was asynchronous and so i never did attempt to put it in a invoke and wait block.