1 /* 2 * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 /* 24 * @test 25 * @bug 6678218 6681745 6691737 26 * @summary Tests that v-synced BufferStrategies works (if vsync is supported) 27 * @author Dmitri.Trembovetski@sun.com: area=Graphics 28 * @compile -XDignore.symbol.file=true VSyncedBufferStrategyTest.java 29 * @run main/manual/othervm VSyncedBufferStrategyTest 30 * @run main/manual/othervm -Dsun.java2d.opengl=True VSyncedBufferStrategyTest 31 */ 32 33 import java.awt.AWTException; 34 import java.awt.BufferCapabilities; 35 import java.awt.BufferCapabilities.FlipContents; 36 import java.awt.Button; 37 import java.awt.Canvas; 38 import java.awt.Color; 39 import java.awt.Dimension; 40 import java.awt.EventQueue; 41 import java.awt.FlowLayout; 42 import java.awt.Font; 43 import java.awt.Frame; 44 import java.awt.Graphics; 45 import java.awt.HeadlessException; 46 import java.awt.ImageCapabilities; 47 import java.awt.Panel; 48 import java.awt.event.ActionEvent; 49 import java.awt.event.ActionListener; 50 import java.awt.event.WindowAdapter; 51 import java.awt.event.WindowEvent; 52 import java.awt.image.BufferStrategy; 53 import java.util.concurrent.CountDownLatch; 54 import javax.swing.JButton; 55 import javax.swing.JFrame; 56 import javax.swing.JPanel; 57 import javax.swing.JScrollPane; 58 import javax.swing.JTextArea; 59 60 public class VSyncedBufferStrategyTest extends Canvas implements Runnable { 61 62 private static final int BLOCK_W = 50; 63 private static final int BLOCK_H = 200; 64 65 BufferStrategy bs; 66 Thread renderThread; 67 68 int blockX = 10; 69 int blockY = 10; 70 71 private volatile boolean done = false; 72 private volatile boolean requestVSync; 73 private boolean currentBSVSynced; 74 75 public VSyncedBufferStrategyTest(boolean requestVSync) { 76 this.requestVSync = requestVSync; 77 this.currentBSVSynced = !requestVSync; 78 renderThread = new Thread(this); 79 renderThread.start(); 80 } 81 82 private static final BufferCapabilities defaultBC = 83 new BufferCapabilities( 84 new ImageCapabilities(true), 85 new ImageCapabilities(true), 86 null); 87 88 private void createBS(boolean requestVSync) { 89 if (bs != null && requestVSync == currentBSVSynced) { 90 return; 91 } 92 93 BufferCapabilities bc = defaultBC; 94 if (requestVSync) { 95 bc = new sun.java2d.pipe.hw.ExtendedBufferCapabilities( 96 new ImageCapabilities(true), 97 new ImageCapabilities(true), 98 FlipContents.COPIED, 99 sun.java2d.pipe.hw.ExtendedBufferCapabilities.VSyncType.VSYNC_ON); 100 } 101 try { 102 createBufferStrategy(2, bc); 103 } catch (AWTException e) { 104 System.err.println("Warning: cap is not supported: "+bc); 105 e.printStackTrace(); 106 createBufferStrategy(2); 107 } 108 currentBSVSynced = requestVSync; 109 bs = getBufferStrategy(); 110 String s = 111 getParent() instanceof Frame ? 112 ((Frame)getParent()).getTitle() : "parent"; 113 System.out.println("Created BS for \"" + s + "\" frame, bs="+bs); 114 } 115 116 @Override 117 public void paint(Graphics g) { 118 } 119 @Override 120 public void update(Graphics g) { 121 } 122 123 @Override 124 public void run() { 125 while (!isShowing()) { 126 try { Thread.sleep(5); } catch (InterruptedException e) {} 127 } 128 try { Thread.sleep(2000); } catch (InterruptedException e) {} 129 130 try { 131 while (!done && isShowing()) { 132 createBS(requestVSync); 133 do { 134 step(); 135 Graphics g = bs.getDrawGraphics(); 136 render(g); 137 if (!bs.contentsRestored()) { 138 bs.show(); 139 } 140 } while (bs.contentsLost()); 141 Thread.yield(); 142 } 143 } catch (Throwable e) { 144 // since we're not bothering with proper synchronization, exceptions 145 // may be thrown when the frame is closed 146 if (isShowing()) { 147 throw new RuntimeException(e); 148 } 149 } 150 } 151 152 int inc = 5; 153 private void step() { 154 blockX += inc; 155 if (blockX > getWidth() - BLOCK_W - 10) { 156 inc = -inc; 157 blockX += inc; 158 } 159 if (blockX < 10) { 160 inc = -inc; 161 blockX += inc; 162 } 163 } 164 165 private void render(Graphics g) { 166 g.setColor(Color.white); 167 g.fillRect(0, 0, getWidth(), getHeight()); 168 169 g.setColor(Color.black); 170 g.fillRect(blockX, blockY, BLOCK_W, BLOCK_H); 171 } 172 173 private void setRequestVSync(boolean reqVSync) { 174 requestVSync = reqVSync; 175 } 176 177 @Override 178 public Dimension getPreferredSize() { 179 return new Dimension(BLOCK_W*10+20, BLOCK_H+20); 180 } 181 182 private static int frameNum = 0; 183 private static Frame createAndShowBSFrame() { 184 final Frame f = new Frame("Not V-Synced"); 185 186 int myNum; 187 synchronized (VSyncedBufferStrategyTest.class) { 188 myNum = frameNum++; 189 } 190 191 final VSyncedBufferStrategyTest component = 192 new VSyncedBufferStrategyTest(false); 193 f.setIgnoreRepaint(true); 194 f.add("Center", component); 195 196 Panel p = new Panel(); 197 198 Button b = new Button("Request VSync"); 199 b.addActionListener(new ActionListener() { 200 public void actionPerformed(ActionEvent e) { 201 f.setTitle("Possibly V-Synced"); 202 component.setRequestVSync(true); 203 } 204 }); 205 p.add(b); 206 207 b = new Button("Relinquish VSync"); 208 b.addActionListener(new ActionListener() { 209 int inc = 1; 210 public void actionPerformed(ActionEvent e) { 211 f.setTitle("Not V-Synced"); 212 component.setRequestVSync(false); 213 f.setSize(f.getWidth()+inc, f.getHeight()); 214 inc = -inc; 215 } 216 }); 217 p.add(b); 218 219 f.add("South", p); 220 221 f.pack(); 222 f.setLocation(10, myNum * f.getHeight()); 223 f.setVisible(true); 224 f.addWindowListener(new WindowAdapter() { 225 @Override 226 public void windowClosing(WindowEvent e) { 227 component.done = true; 228 f.dispose(); 229 } 230 @Override 231 public void windowClosed(WindowEvent e) { 232 component.done = true; 233 } 234 }); 235 236 return f; 237 } 238 239 private static final String description = 240 "Tests that v-synced BufferStrategy works. Note that it in some\n" + 241 "cases the v-sync can not be enabled, and it is accepted.\n" + 242 "The following however is true: only one buffer strategy at a time can\n"+ 243 "be created v-synced. In order for other BS to become v-synced, the one\n"+ 244 "that currently is v-synched (or its window) needs to be disposed.\n" + 245 "Try the following scenarios:\n" + 246 " - click the \"Request VSync\" button in one of the frames. If the\n"+ 247 " behavior of the animation changes - the animation becomes smooth\n" + 248 " it had successfully created a v-synced BS. Note that the animation\n" + 249 " in other frames may also become smoother - this is a side-effect\n"+ 250 " of one of the BS-es becoming v-synched\n" + 251 " - click the \"Relinquish VSync\" button on the same frame. If the\n"+ 252 " behavior changes to the original (tearing)- it had successfully\n" + 253 " created a non-vsynced strategy.\n" + 254 " - next, try making another one v-synced. It should succeed.\n" + 255 " - next, try making another one v-synced - while there's already\n" + 256 " a v-synced frame. It should not succeed - meaning, it shouldn't\n" + 257 " appear to become smoother, and the behavior of the current v-synced\n" + 258 " frame shouldn't change.\n" + 259 "\n" + 260 "If there aren't any BufferStrategy-related exceptions or other\n" + 261 "issues, and the scenarios worked, the test passed, otherwise it\n"+ 262 "failed.\n"; 263 264 private static void createAndShowDescGUI(final Frame f3, final Frame f1, 265 final Frame f2) 266 throws HeadlessException, RuntimeException 267 { 268 final JFrame desc = 269 new JFrame("VSyncedBufferStrategyTest - Description"); 270 desc.addWindowListener(new WindowAdapter() { 271 272 @Override 273 public void windowClosing(WindowEvent e) { 274 f1.dispose(); 275 f2.dispose(); 276 f3.dispose(); 277 l.countDown(); 278 } 279 }); 280 JPanel p = new JPanel(); 281 JButton bPassed = new JButton("Passed"); 282 bPassed.addActionListener(new ActionListener() { 283 public void actionPerformed(ActionEvent e) { 284 desc.dispose(); 285 f1.dispose(); 286 f2.dispose(); 287 f3.dispose(); 288 l.countDown(); 289 } 290 }); 291 JButton bFailed = new JButton("Failed"); 292 bFailed.addActionListener(new ActionListener() { 293 public void actionPerformed(ActionEvent e) { 294 failed = true; 295 desc.dispose(); 296 f1.dispose(); 297 f2.dispose(); 298 f3.dispose(); 299 l.countDown(); 300 } 301 }); 302 p.setLayout(new FlowLayout()); 303 p.add(bPassed); 304 p.add(bFailed); 305 JTextArea ta = new JTextArea(24, 75); 306 ta.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12)); 307 ta.setEditable(false); 308 ta.setText(description); 309 desc.add("Center", new JScrollPane(ta)); 310 desc.add("South", p); 311 desc.pack(); 312 desc.setLocation(BLOCK_W*10+50, 0); 313 desc.setVisible(true); 314 } 315 316 private static void createTestFrames() { 317 Frame f1 = createAndShowBSFrame(); 318 Frame f2 = createAndShowBSFrame(); 319 Frame f3 = createAndShowBSFrame(); 320 createAndShowDescGUI(f1, f2, f3); 321 } 322 323 static boolean failed = false; 324 static CountDownLatch l = new CountDownLatch(1); 325 public static void main(String[] args) throws Exception { 326 EventQueue.invokeLater(new Runnable() { 327 public void run() { 328 createTestFrames(); 329 } 330 }); 331 l.await(); 332 if (failed) { 333 throw new RuntimeException("Test FAILED"); 334 } 335 System.out.println("Test PASSED"); 336 } 337 338 }