blob: f744ee2c74b9000e4f52809424b7842d08e476ea [file] [log] [blame]
/*
* Copyright (c) 2008, 2009, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package sun.awt.windows;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.Image;
import java.awt.Window;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.awt.image.VolatileImage;
import java.lang.ref.WeakReference;
import java.security.AccessController;
import sun.awt.image.BufImgSurfaceData;
import sun.java2d.DestSurfaceProvider;
import sun.java2d.InvalidPipeException;
import sun.java2d.Surface;
import sun.java2d.pipe.RenderQueue;
import sun.java2d.pipe.hw.AccelGraphicsConfig;
import sun.java2d.pipe.hw.AccelSurface;
import sun.security.action.GetPropertyAction;
import static java.awt.image.VolatileImage.*;
import static java.awt.Transparency.*;
import static sun.java2d.pipe.hw.AccelSurface.*;
import static sun.java2d.pipe.hw.ContextCapabilities.*;
/**
* This class handles the updates of the non-opaque windows.
* The window associated with the peer is updated either given an image or
* the window is repainted to an internal buffer which is then used to update
* the window.
*
* Note: this class does not attempt to be thread safe, it is expected to be
* called from a single thread (EDT).
*/
public abstract class TranslucentWindowPainter {
protected Window window;
protected WWindowPeer peer;
// REMIND: we probably would want to remove this later
private static final boolean forceOpt =
Boolean.valueOf(AccessController.doPrivileged(
new GetPropertyAction("sun.java2d.twp.forceopt", "false")));
private static final boolean forceSW =
Boolean.valueOf(AccessController.doPrivileged(
new GetPropertyAction("sun.java2d.twp.forcesw", "false")));
/**
* Creates an instance of the painter for particular peer.
*/
public static TranslucentWindowPainter createInstance(WWindowPeer peer) {
GraphicsConfiguration gc = peer.getGraphicsConfiguration();
if (!forceSW && gc instanceof AccelGraphicsConfig) {
String gcName = gc.getClass().getSimpleName();
AccelGraphicsConfig agc = (AccelGraphicsConfig)gc;
// this is a heuristic to check that we have a pcix board
// (those have higher transfer rate from gpu to cpu)
if ((agc.getContextCapabilities().getCaps() & CAPS_PS30) != 0 ||
forceOpt)
{
// we check for name to avoid loading classes unnecessarily if
// a pipeline isn't enabled
if (gcName.startsWith("D3D")) {
return new VIOptD3DWindowPainter(peer);
} else if (forceOpt && gcName.startsWith("WGL")) {
// on some boards (namely, ATI, even on pcix bus) ogl is
// very slow reading pixels back so for now it is disabled
// unless forced
return new VIOptWGLWindowPainter(peer);
}
}
}
return new BIWindowPainter(peer);
}
protected TranslucentWindowPainter(WWindowPeer peer) {
this.peer = peer;
this.window = (Window)peer.getTarget();
}
/**
* Creates (if needed), clears (if requested) and returns the buffer
* for this painter.
*/
protected abstract Image getBackBuffer(boolean clear);
/**
* Updates the the window associated with this painter with the contents
* of the passed image.
* The image can not be null, and NPE will be thrown if it is.
*/
protected abstract boolean update(Image bb);
/**
* Flushes the resources associated with the painter. They will be
* recreated as needed.
*/
public abstract void flush();
/**
* Updates the window associated with the painter.
*
* @param repaint indicates if the window should be completely repainted
* to the back buffer using {@link java.awt.Window#paintAll} before update.
*/
public void updateWindow(boolean repaint) {
boolean done = false;
Image bb = getBackBuffer(repaint);
while (!done) {
if (repaint) {
Graphics2D g = (Graphics2D)bb.getGraphics();
try {
window.paintAll(g);
} finally {
g.dispose();
}
}
done = update(bb);
if (!done) {
repaint = true;
bb = getBackBuffer(true);
}
}
}
private static final Image clearImage(Image bb) {
Graphics2D g = (Graphics2D)bb.getGraphics();
int w = bb.getWidth(null);
int h = bb.getHeight(null);
g.setComposite(AlphaComposite.Src);
g.setColor(new Color(0, 0, 0, 0));
g.fillRect(0, 0, w, h);
return bb;
}
/**
* A painter which uses BufferedImage as the internal buffer. The window
* is painted into this buffer, and the contents then are uploaded
* into the layered window.
*
* This painter handles all types of images passed to its paint(Image)
* method (VI, BI, regular Images).
*/
private static class BIWindowPainter extends TranslucentWindowPainter {
private BufferedImage backBuffer;
protected BIWindowPainter(WWindowPeer peer) {
super(peer);
}
@Override
protected Image getBackBuffer(boolean clear) {
int w = window.getWidth();
int h = window.getHeight();
if (backBuffer == null ||
backBuffer.getWidth() != w ||
backBuffer.getHeight() != h)
{
flush();
backBuffer = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB_PRE);
}
return clear ? (BufferedImage)clearImage(backBuffer) : backBuffer;
}
@Override
protected boolean update(Image bb) {
VolatileImage viBB = null;
if (bb instanceof BufferedImage) {
BufferedImage bi = (BufferedImage)bb;
int data[] =
((DataBufferInt)bi.getRaster().getDataBuffer()).getData();
peer.updateWindowImpl(data, bi.getWidth(), bi.getHeight());
return true;
} else if (bb instanceof VolatileImage) {
viBB = (VolatileImage)bb;
if (bb instanceof DestSurfaceProvider) {
Surface s = ((DestSurfaceProvider)bb).getDestSurface();
if (s instanceof BufImgSurfaceData) {
// the image is probably lost, upload the data from the
// backup surface to avoid creating another heap-based
// image (the parent's buffer)
int w = viBB.getWidth();
int h = viBB.getHeight();
BufImgSurfaceData bisd = (BufImgSurfaceData)s;
int data[] = ((DataBufferInt)bisd.getRaster(0,0,w,h).
getDataBuffer()).getData();
peer.updateWindowImpl(data, w, h);
return true;
}
}
}
// copy the passed image into our own buffer, then upload
BufferedImage bi = (BufferedImage)clearImage(backBuffer);
int data[] =
((DataBufferInt)bi.getRaster().getDataBuffer()).getData();
peer.updateWindowImpl(data, bi.getWidth(), bi.getHeight());
return (viBB != null ? !viBB.contentsLost() : true);
}
public void flush() {
if (backBuffer != null) {
backBuffer.flush();
backBuffer = null;
}
}
}
/**
* A version of the painter which uses VolatileImage as the internal buffer.
* The window is painted into this VI and then copied into the parent's
* Java heap-based buffer (which is then uploaded to the layered window)
*/
private static class VIWindowPainter extends BIWindowPainter {
private VolatileImage viBB;
protected VIWindowPainter(WWindowPeer peer) {
super(peer);
}
@Override
protected Image getBackBuffer(boolean clear) {
int w = window.getWidth();
int h = window.getHeight();
GraphicsConfiguration gc = peer.getGraphicsConfiguration();
if (viBB == null || viBB.getWidth() != w || viBB.getHeight() != h ||
viBB.validate(gc) == IMAGE_INCOMPATIBLE)
{
flush();
if (gc instanceof AccelGraphicsConfig) {
AccelGraphicsConfig agc = ((AccelGraphicsConfig)gc);
viBB = agc.createCompatibleVolatileImage(w, h,
TRANSLUCENT,
RT_PLAIN);
}
if (viBB == null) {
viBB = gc.createCompatibleVolatileImage(w, h, TRANSLUCENT);
}
viBB.validate(gc);
}
return clear ? clearImage(viBB) : viBB;
}
@Override
public void flush() {
if (viBB != null) {
viBB.flush();
viBB = null;
}
}
}
/**
* Optimized version of hw painter. Uses VolatileImages for the
* buffer, and uses an optimized path to pull the data from those into
* the layered window, bypassing Java heap-based image.
*/
private abstract static class VIOptWindowPainter extends VIWindowPainter {
protected VIOptWindowPainter(WWindowPeer peer) {
super(peer);
}
protected abstract boolean updateWindowAccel(long psdops, int w, int h);
@Override
protected boolean update(Image bb) {
if (bb instanceof DestSurfaceProvider) {
Surface s = ((DestSurfaceProvider)bb).getDestSurface();
if (s instanceof AccelSurface) {
final int w = bb.getWidth(null);
final int h = bb.getHeight(null);
final boolean arr[] = { false };
final AccelSurface as = (AccelSurface)s;
RenderQueue rq = as.getContext().getRenderQueue();
rq.lock();
try {
as.getContext().validateContext(as);
rq.flushAndInvokeNow(new Runnable() {
public void run() {
long psdops = as.getNativeOps();
arr[0] = updateWindowAccel(psdops, w, h);
}
});
} catch (InvalidPipeException e) {
// ignore, false will be returned
} finally {
rq.unlock();
}
return arr[0];
}
}
return super.update(bb);
}
}
private static class VIOptD3DWindowPainter extends VIOptWindowPainter {
protected VIOptD3DWindowPainter(WWindowPeer peer) {
super(peer);
}
@Override
protected boolean updateWindowAccel(long psdops, int w, int h) {
// note: this method is executed on the toolkit thread, no sync is
// necessary at the native level, and a pointer to peer can be used
return sun.java2d.d3d.D3DSurfaceData.
updateWindowAccelImpl(psdops, peer.getData(), w, h);
}
}
private static class VIOptWGLWindowPainter extends VIOptWindowPainter {
protected VIOptWGLWindowPainter(WWindowPeer peer) {
super(peer);
}
@Override
protected boolean updateWindowAccel(long psdops, int w, int h) {
// note: part of this method which deals with GDI will be on the
// toolkit thread
return sun.java2d.opengl.WGLSurfaceData.
updateWindowAccelImpl(psdops, peer, w, h);
}
}
}