2008-07-18 10:48:44 -07:00
|
|
|
/*
|
2010-05-25 15:58:33 -07:00
|
|
|
* Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved.
|
2008-07-18 10:48:44 -07:00
|
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
|
|
*
|
|
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
|
|
* published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
|
|
* accompanied this code).
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License version
|
|
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
*
|
2010-05-25 15:58:33 -07:00
|
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
|
|
* questions.
|
2008-07-18 10:48:44 -07:00
|
|
|
*/
|
|
|
|
/*
|
|
|
|
* @test
|
|
|
|
* @bug 6678218 6681745 6691737
|
|
|
|
* @summary Tests that v-synced BufferStrategies works (if vsync is supported)
|
|
|
|
* @author Dmitri.Trembovetski@sun.com: area=Graphics
|
|
|
|
* @compile -XDignore.symbol.file=true VSyncedBufferStrategyTest.java
|
|
|
|
* @run main/manual/othervm VSyncedBufferStrategyTest
|
|
|
|
* @run main/manual/othervm -Dsun.java2d.opengl=True VSyncedBufferStrategyTest
|
|
|
|
*/
|
|
|
|
|
|
|
|
import java.awt.AWTException;
|
|
|
|
import java.awt.BufferCapabilities;
|
|
|
|
import java.awt.BufferCapabilities.FlipContents;
|
|
|
|
import java.awt.Button;
|
|
|
|
import java.awt.Canvas;
|
|
|
|
import java.awt.Color;
|
|
|
|
import java.awt.Dimension;
|
|
|
|
import java.awt.EventQueue;
|
|
|
|
import java.awt.FlowLayout;
|
|
|
|
import java.awt.Font;
|
|
|
|
import java.awt.Frame;
|
|
|
|
import java.awt.Graphics;
|
|
|
|
import java.awt.HeadlessException;
|
|
|
|
import java.awt.ImageCapabilities;
|
|
|
|
import java.awt.Panel;
|
|
|
|
import java.awt.event.ActionEvent;
|
|
|
|
import java.awt.event.ActionListener;
|
|
|
|
import java.awt.event.WindowAdapter;
|
|
|
|
import java.awt.event.WindowEvent;
|
|
|
|
import java.awt.image.BufferStrategy;
|
|
|
|
import java.util.concurrent.CountDownLatch;
|
|
|
|
import javax.swing.JButton;
|
|
|
|
import javax.swing.JFrame;
|
|
|
|
import javax.swing.JPanel;
|
|
|
|
import javax.swing.JScrollPane;
|
|
|
|
import javax.swing.JTextArea;
|
|
|
|
|
|
|
|
public class VSyncedBufferStrategyTest extends Canvas implements Runnable {
|
|
|
|
|
|
|
|
private static final int BLOCK_W = 50;
|
|
|
|
private static final int BLOCK_H = 200;
|
|
|
|
|
|
|
|
BufferStrategy bs;
|
|
|
|
Thread renderThread;
|
|
|
|
|
|
|
|
int blockX = 10;
|
|
|
|
int blockY = 10;
|
|
|
|
|
|
|
|
private volatile boolean done = false;
|
|
|
|
private volatile boolean requestVSync;
|
|
|
|
private boolean currentBSVSynced;
|
|
|
|
|
|
|
|
public VSyncedBufferStrategyTest(boolean requestVSync) {
|
|
|
|
this.requestVSync = requestVSync;
|
|
|
|
this.currentBSVSynced = !requestVSync;
|
|
|
|
renderThread = new Thread(this);
|
|
|
|
renderThread.start();
|
|
|
|
}
|
|
|
|
|
|
|
|
private static final BufferCapabilities defaultBC =
|
|
|
|
new BufferCapabilities(
|
|
|
|
new ImageCapabilities(true),
|
|
|
|
new ImageCapabilities(true),
|
|
|
|
null);
|
|
|
|
|
|
|
|
private void createBS(boolean requestVSync) {
|
|
|
|
if (bs != null && requestVSync == currentBSVSynced) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
BufferCapabilities bc = defaultBC;
|
|
|
|
if (requestVSync) {
|
|
|
|
bc = new sun.java2d.pipe.hw.ExtendedBufferCapabilities(
|
|
|
|
new ImageCapabilities(true),
|
|
|
|
new ImageCapabilities(true),
|
|
|
|
FlipContents.COPIED,
|
|
|
|
sun.java2d.pipe.hw.ExtendedBufferCapabilities.VSyncType.VSYNC_ON);
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
createBufferStrategy(2, bc);
|
|
|
|
} catch (AWTException e) {
|
|
|
|
System.err.println("Warning: cap is not supported: "+bc);
|
|
|
|
e.printStackTrace();
|
|
|
|
createBufferStrategy(2);
|
|
|
|
}
|
|
|
|
currentBSVSynced = requestVSync;
|
|
|
|
bs = getBufferStrategy();
|
|
|
|
String s =
|
|
|
|
getParent() instanceof Frame ?
|
|
|
|
((Frame)getParent()).getTitle() : "parent";
|
|
|
|
System.out.println("Created BS for \"" + s + "\" frame, bs="+bs);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void paint(Graphics g) {
|
|
|
|
}
|
|
|
|
@Override
|
|
|
|
public void update(Graphics g) {
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
while (!isShowing()) {
|
|
|
|
try { Thread.sleep(5); } catch (InterruptedException e) {}
|
|
|
|
}
|
|
|
|
try { Thread.sleep(2000); } catch (InterruptedException e) {}
|
|
|
|
|
|
|
|
try {
|
|
|
|
while (!done && isShowing()) {
|
|
|
|
createBS(requestVSync);
|
|
|
|
do {
|
|
|
|
step();
|
|
|
|
Graphics g = bs.getDrawGraphics();
|
|
|
|
render(g);
|
|
|
|
if (!bs.contentsRestored()) {
|
|
|
|
bs.show();
|
|
|
|
}
|
|
|
|
} while (bs.contentsLost());
|
|
|
|
Thread.yield();
|
|
|
|
}
|
|
|
|
} catch (Throwable e) {
|
|
|
|
// since we're not bothering with proper synchronization, exceptions
|
|
|
|
// may be thrown when the frame is closed
|
|
|
|
if (isShowing()) {
|
|
|
|
throw new RuntimeException(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int inc = 5;
|
|
|
|
private void step() {
|
|
|
|
blockX += inc;
|
|
|
|
if (blockX > getWidth() - BLOCK_W - 10) {
|
|
|
|
inc = -inc;
|
|
|
|
blockX += inc;
|
|
|
|
}
|
|
|
|
if (blockX < 10) {
|
|
|
|
inc = -inc;
|
|
|
|
blockX += inc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void render(Graphics g) {
|
|
|
|
g.setColor(Color.white);
|
|
|
|
g.fillRect(0, 0, getWidth(), getHeight());
|
|
|
|
|
|
|
|
g.setColor(Color.black);
|
|
|
|
g.fillRect(blockX, blockY, BLOCK_W, BLOCK_H);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void setRequestVSync(boolean reqVSync) {
|
|
|
|
requestVSync = reqVSync;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Dimension getPreferredSize() {
|
|
|
|
return new Dimension(BLOCK_W*10+20, BLOCK_H+20);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static int frameNum = 0;
|
|
|
|
private static Frame createAndShowBSFrame() {
|
|
|
|
final Frame f = new Frame("Not V-Synced");
|
|
|
|
|
|
|
|
int myNum;
|
|
|
|
synchronized (VSyncedBufferStrategyTest.class) {
|
|
|
|
myNum = frameNum++;
|
|
|
|
}
|
|
|
|
|
|
|
|
final VSyncedBufferStrategyTest component =
|
|
|
|
new VSyncedBufferStrategyTest(false);
|
|
|
|
f.setIgnoreRepaint(true);
|
|
|
|
f.add("Center", component);
|
|
|
|
|
|
|
|
Panel p = new Panel();
|
|
|
|
|
|
|
|
Button b = new Button("Request VSync");
|
|
|
|
b.addActionListener(new ActionListener() {
|
|
|
|
public void actionPerformed(ActionEvent e) {
|
|
|
|
f.setTitle("Possibly V-Synced");
|
|
|
|
component.setRequestVSync(true);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
p.add(b);
|
|
|
|
|
|
|
|
b = new Button("Relinquish VSync");
|
|
|
|
b.addActionListener(new ActionListener() {
|
|
|
|
int inc = 1;
|
|
|
|
public void actionPerformed(ActionEvent e) {
|
|
|
|
f.setTitle("Not V-Synced");
|
|
|
|
component.setRequestVSync(false);
|
|
|
|
f.setSize(f.getWidth()+inc, f.getHeight());
|
|
|
|
inc = -inc;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
p.add(b);
|
|
|
|
|
|
|
|
f.add("South", p);
|
|
|
|
|
|
|
|
f.pack();
|
|
|
|
f.setLocation(10, myNum * f.getHeight());
|
|
|
|
f.setVisible(true);
|
|
|
|
f.addWindowListener(new WindowAdapter() {
|
|
|
|
@Override
|
|
|
|
public void windowClosing(WindowEvent e) {
|
|
|
|
component.done = true;
|
|
|
|
f.dispose();
|
|
|
|
}
|
|
|
|
@Override
|
|
|
|
public void windowClosed(WindowEvent e) {
|
|
|
|
component.done = true;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static final String description =
|
|
|
|
"Tests that v-synced BufferStrategy works. Note that it in some\n" +
|
|
|
|
"cases the v-sync can not be enabled, and it is accepted.\n" +
|
|
|
|
"The following however is true: only one buffer strategy at a time can\n"+
|
|
|
|
"be created v-synced. In order for other BS to become v-synced, the one\n"+
|
|
|
|
"that currently is v-synched (or its window) needs to be disposed.\n" +
|
|
|
|
"Try the following scenarios:\n" +
|
|
|
|
" - click the \"Request VSync\" button in one of the frames. If the\n"+
|
|
|
|
" behavior of the animation changes - the animation becomes smooth\n" +
|
|
|
|
" it had successfully created a v-synced BS. Note that the animation\n" +
|
|
|
|
" in other frames may also become smoother - this is a side-effect\n"+
|
|
|
|
" of one of the BS-es becoming v-synched\n" +
|
|
|
|
" - click the \"Relinquish VSync\" button on the same frame. If the\n"+
|
|
|
|
" behavior changes to the original (tearing)- it had successfully\n" +
|
|
|
|
" created a non-vsynced strategy.\n" +
|
|
|
|
" - next, try making another one v-synced. It should succeed.\n" +
|
|
|
|
" - next, try making another one v-synced - while there's already\n" +
|
|
|
|
" a v-synced frame. It should not succeed - meaning, it shouldn't\n" +
|
|
|
|
" appear to become smoother, and the behavior of the current v-synced\n" +
|
|
|
|
" frame shouldn't change.\n" +
|
|
|
|
"\n" +
|
|
|
|
"If there aren't any BufferStrategy-related exceptions or other\n" +
|
|
|
|
"issues, and the scenarios worked, the test passed, otherwise it\n"+
|
|
|
|
"failed.\n";
|
|
|
|
|
|
|
|
private static void createAndShowDescGUI(final Frame f3, final Frame f1,
|
|
|
|
final Frame f2)
|
|
|
|
throws HeadlessException, RuntimeException
|
|
|
|
{
|
|
|
|
final JFrame desc =
|
|
|
|
new JFrame("VSyncedBufferStrategyTest - Description");
|
|
|
|
desc.addWindowListener(new WindowAdapter() {
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void windowClosing(WindowEvent e) {
|
|
|
|
f1.dispose();
|
|
|
|
f2.dispose();
|
|
|
|
f3.dispose();
|
|
|
|
l.countDown();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
JPanel p = new JPanel();
|
|
|
|
JButton bPassed = new JButton("Passed");
|
|
|
|
bPassed.addActionListener(new ActionListener() {
|
|
|
|
public void actionPerformed(ActionEvent e) {
|
|
|
|
desc.dispose();
|
|
|
|
f1.dispose();
|
|
|
|
f2.dispose();
|
|
|
|
f3.dispose();
|
|
|
|
l.countDown();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
JButton bFailed = new JButton("Failed");
|
|
|
|
bFailed.addActionListener(new ActionListener() {
|
|
|
|
public void actionPerformed(ActionEvent e) {
|
|
|
|
failed = true;
|
|
|
|
desc.dispose();
|
|
|
|
f1.dispose();
|
|
|
|
f2.dispose();
|
|
|
|
f3.dispose();
|
|
|
|
l.countDown();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
p.setLayout(new FlowLayout());
|
|
|
|
p.add(bPassed);
|
|
|
|
p.add(bFailed);
|
|
|
|
JTextArea ta = new JTextArea(24, 75);
|
|
|
|
ta.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
|
|
|
|
ta.setEditable(false);
|
|
|
|
ta.setText(description);
|
|
|
|
desc.add("Center", new JScrollPane(ta));
|
|
|
|
desc.add("South", p);
|
|
|
|
desc.pack();
|
|
|
|
desc.setLocation(BLOCK_W*10+50, 0);
|
|
|
|
desc.setVisible(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void createTestFrames() {
|
|
|
|
Frame f1 = createAndShowBSFrame();
|
|
|
|
Frame f2 = createAndShowBSFrame();
|
|
|
|
Frame f3 = createAndShowBSFrame();
|
|
|
|
createAndShowDescGUI(f1, f2, f3);
|
|
|
|
}
|
|
|
|
|
|
|
|
static boolean failed = false;
|
|
|
|
static CountDownLatch l = new CountDownLatch(1);
|
|
|
|
public static void main(String[] args) throws Exception {
|
|
|
|
EventQueue.invokeLater(new Runnable() {
|
|
|
|
public void run() {
|
|
|
|
createTestFrames();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
l.await();
|
|
|
|
if (failed) {
|
|
|
|
throw new RuntimeException("Test FAILED");
|
|
|
|
}
|
|
|
|
System.out.println("Test PASSED");
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|