e5870cf002
Reviewed-by: prr
304 lines
12 KiB
Java
304 lines
12 KiB
Java
/*
|
|
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
|
|
* 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.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
import java.awt.Color;
|
|
import java.awt.Component;
|
|
import java.awt.DisplayMode;
|
|
import java.awt.Frame;
|
|
import java.awt.Graphics;
|
|
import java.awt.GraphicsConfiguration;
|
|
import java.awt.GraphicsDevice;
|
|
import java.awt.GraphicsEnvironment;
|
|
import java.awt.Image;
|
|
import java.awt.Rectangle;
|
|
import java.awt.Robot;
|
|
import java.awt.Transparency;
|
|
import java.awt.Window;
|
|
import java.awt.event.KeyEvent;
|
|
import java.awt.event.KeyListener;
|
|
import java.awt.image.BufferedImage;
|
|
import java.util.ArrayList;
|
|
|
|
/**
|
|
* @test
|
|
* @bug 4836241 6364134 8232200 8252133
|
|
* @key headful
|
|
* @summary verify that images are restored correctly after display mode
|
|
* switches and that no other rendering or crash problems occur
|
|
* @run main/timeout=500 CycleDMImage
|
|
*/
|
|
public class CycleDMImage extends Component implements Runnable, KeyListener {
|
|
/**
|
|
* This test cycles through all available display modes, waiting after
|
|
* each call to setDisplayMode() to ensure that the new one is active
|
|
* before proceeding on to the next one. The Component is filled with
|
|
* a green background color and then compatible images of all 3
|
|
* Transparency types are copied to the screen. The results of these
|
|
* operations are checked (using Robot) and the test fails if any of the
|
|
* rendering is wrong in any of the DisplayModes. The purpose of this
|
|
* test is to ensure that display mode switches do not cause problems
|
|
* with image restoration (or other rendering operations).
|
|
*/
|
|
boolean painted = false;
|
|
boolean earlyExit = false;
|
|
Image rImage = null, wImage = null, bImage = null;
|
|
int imgSize = 10;
|
|
static Robot robot = null;
|
|
volatile static boolean done = false;
|
|
static String errorMessage = null;
|
|
|
|
public synchronized void paint(Graphics g) {
|
|
if (!painted) {
|
|
painted = true;
|
|
(new Thread(this)).start();
|
|
}
|
|
if (rImage == null) {
|
|
GraphicsConfiguration gc = getGraphicsConfiguration();
|
|
rImage = gc.createCompatibleImage(imgSize, imgSize);
|
|
wImage = gc.createCompatibleImage(imgSize, imgSize,
|
|
Transparency.BITMASK);
|
|
bImage = gc.createCompatibleImage(imgSize, imgSize,
|
|
Transparency.TRANSLUCENT);
|
|
Graphics imgGraphics = rImage.getGraphics();
|
|
imgGraphics.setColor(Color.red);
|
|
imgGraphics.fillRect(0, 0, imgSize, imgSize);
|
|
imgGraphics = wImage.getGraphics();
|
|
imgGraphics.setColor(Color.white);
|
|
imgGraphics.fillRect(0, 0, imgSize, imgSize);
|
|
imgGraphics = bImage.getGraphics();
|
|
imgGraphics.setColor(Color.blue);
|
|
imgGraphics.fillRect(0, 0, imgSize, imgSize);
|
|
}
|
|
g.setColor(Color.green);
|
|
g.fillRect(0, 0, getWidth(), getHeight());
|
|
g.drawImage(rImage, 0, 0, this);
|
|
g.drawImage(wImage, imgSize, 0, this);
|
|
g.drawImage(bImage, imgSize*2, 0, this);
|
|
g.drawImage(rImage, 0, getHeight()-imgSize, null);
|
|
g.drawImage(rImage, getWidth()-imgSize, getHeight()-imgSize, null);
|
|
g.drawImage(rImage, getWidth()-imgSize, 0, null);
|
|
}
|
|
|
|
static void delay(long ms) {
|
|
try {
|
|
Thread.sleep(ms);
|
|
} catch (Exception e) {}
|
|
}
|
|
|
|
public boolean checkResult(DisplayMode dm) {
|
|
Rectangle bounds = getGraphicsConfiguration().getBounds();
|
|
int pixels[] = new int[imgSize * 4];
|
|
BufferedImage clientPixels =
|
|
robot.createScreenCapture(new Rectangle(bounds.x, bounds.y,
|
|
imgSize*4, 1));
|
|
clientPixels.getRGB(0, 0, imgSize * 4, 1, pixels, 0, getWidth());
|
|
// Now check the results. We expect: imgSize blocks of r/w/b/g
|
|
int colors[] = {0xffff0000, 0xffffffff, 0xff0000ff, 0xff00ff00};
|
|
for (int color = 0; color < 4; ++color) {
|
|
for (int i = 0; i < imgSize; ++i) {
|
|
int pixelIndex = imgSize * color + i;
|
|
if (pixels[pixelIndex] != colors[color]) {
|
|
errorMessage = "\n DisplayMode(" +
|
|
dm.getWidth() + " x " +
|
|
dm.getHeight() + " x " +
|
|
dm.getBitDepth() + "bpp x " +
|
|
dm.getRefreshRate() +
|
|
")\n Pixel " + i +
|
|
": Expected " +
|
|
Integer.toHexString(colors[color]) +
|
|
", got " +
|
|
Integer.toHexString(pixels[pixelIndex]) +
|
|
" at " + i;
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
boolean displayModesEqual(DisplayMode dm1, DisplayMode dm2) {
|
|
if (dm1.equals(dm2)) {
|
|
return true;
|
|
}
|
|
// not enough - check whether the modes are equal except for
|
|
// refreshRate, if either mode has REFRESH_RATE_UNKNOWN
|
|
// value for this parameter
|
|
if (dm1.getWidth() != dm2.getWidth() ||
|
|
dm1.getHeight() != dm2.getHeight() ||
|
|
dm1.getBitDepth() != dm2.getBitDepth())
|
|
{
|
|
// core parameters must match
|
|
return false;
|
|
}
|
|
// Now we know that w1 == w2, h1 == h2, and d1 == d2; must be the
|
|
// case that the refresh rates do not match.
|
|
// Is either one REFRESH_RATE_UNKNOWN?
|
|
if (dm1.getRefreshRate() == DisplayMode.REFRESH_RATE_UNKNOWN ||
|
|
dm2.getRefreshRate() == DisplayMode.REFRESH_RATE_UNKNOWN)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public void run() {
|
|
GraphicsDevice gd = getGraphicsConfiguration().getDevice();
|
|
gd.setFullScreenWindow((Window) getParent());
|
|
// First, delay a bit just to let the fullscreen window
|
|
// settle down before switching display modes
|
|
robot.waitForIdle();
|
|
delay(1000);
|
|
|
|
if (!gd.isDisplayChangeSupported()) {
|
|
System.err.println("Display change is not supported,"+
|
|
" the test is considered passed.");
|
|
finished();
|
|
return;
|
|
}
|
|
|
|
// We are really only interested in unique w/h/d resolutions
|
|
// and it would be nice to skip the myriad of refresh rate
|
|
// varations, so let us construct a subset that contains
|
|
// only those DisplayModes with unique w/h/d values
|
|
// Also, due to a current bug (4837228), we should skip the
|
|
// 24-bit depths since attempting to create bitmask-transparent
|
|
// ddraw images can cause the test to crash (we should change this
|
|
// test to include that depth when the bug is fixed).
|
|
ArrayList<DisplayMode> dmSubset = new ArrayList<>();
|
|
for (final DisplayMode dm : gd.getDisplayModes()) {
|
|
boolean skip = false;
|
|
for (final DisplayMode dmUnique : dmSubset) {
|
|
int bitDepth = dm.getBitDepth();
|
|
int width = dm.getWidth();
|
|
int height = dm.getHeight();
|
|
if (bitDepth == 24 || width <= 800 || height <= 600 ||
|
|
(dmUnique.getWidth() == width &&
|
|
dmUnique.getHeight() == height &&
|
|
dmUnique.getBitDepth() == bitDepth)) {
|
|
skip = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!skip) {
|
|
dmSubset.add(dm);
|
|
}
|
|
}
|
|
|
|
// Now, cycle through the display modes one-by-one. For
|
|
// each new display mode, delay until we detect that the
|
|
// new mode == the current mode. Then delay an additional
|
|
// second (to allow any repaints to occur)
|
|
|
|
for (DisplayMode newDM : dmSubset) {
|
|
gd.setDisplayMode(newDM);
|
|
while (!displayModesEqual(newDM, gd.getDisplayMode())) {
|
|
delay(100);
|
|
}
|
|
// Delay another few seconds after the new display mode is active
|
|
delay(4000);
|
|
|
|
// Check the rendering results
|
|
if (!checkResult(newDM)) {
|
|
finished();
|
|
return;
|
|
}
|
|
|
|
// Escape out if requested by the user
|
|
if (earlyExit) {
|
|
System.out.println("Exiting test early, by request");
|
|
System.exit(0);
|
|
}
|
|
}
|
|
|
|
// Done with test; if we got here, we passed
|
|
System.out.println("Passed");
|
|
finished();
|
|
}
|
|
|
|
public static void finished() {
|
|
synchronized (CycleDMImage.class) {
|
|
done = true;
|
|
CycleDMImage.class.notify();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* KeyListener methods; these provide a way for a user to escape out of
|
|
* a potentially lengthy test.
|
|
*/
|
|
|
|
public void keyTyped(KeyEvent e) {
|
|
}
|
|
|
|
public void keyPressed(KeyEvent e) {
|
|
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
|
|
earlyExit = true;
|
|
}
|
|
}
|
|
|
|
public void keyReleased(KeyEvent e) {
|
|
}
|
|
|
|
public static void main(String args[]) throws Exception {
|
|
robot = new Robot();
|
|
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
|
|
for (final GraphicsDevice gd: ge.getScreenDevices()) {
|
|
if (!gd.isFullScreenSupported()) {
|
|
System.err.println("FullScreen mode is not supported,"+
|
|
" the test is considered passed.");
|
|
continue;
|
|
}
|
|
done = false;
|
|
DisplayMode currentDM = gd.getDisplayMode();
|
|
Frame frame = new Frame(gd.getDefaultConfiguration());
|
|
try {
|
|
frame.setSize(400, 400);
|
|
frame.setUndecorated(true);
|
|
CycleDMImage comp = new CycleDMImage();
|
|
frame.addKeyListener(comp);
|
|
frame.add(comp);
|
|
frame.setVisible(true);
|
|
// Sleep awaiting frame disposal
|
|
synchronized (CycleDMImage.class) {
|
|
while (!done) {
|
|
try {
|
|
CycleDMImage.class.wait(100);
|
|
} catch (InterruptedException e) {
|
|
}
|
|
}
|
|
}
|
|
} finally {
|
|
gd.setDisplayMode(currentDM);
|
|
gd.setFullScreenWindow(null);
|
|
frame.dispose();
|
|
}
|
|
if (errorMessage != null) {
|
|
throw new RuntimeException(errorMessage);
|
|
}
|
|
// delay a bit just to let the fullscreen window disposing complete
|
|
// before switching to next display
|
|
delay(10000);
|
|
}
|
|
}
|
|
}
|