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