/*
* Copyright (c) 2007, 2008, 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.java2d.d3d;
import java.awt.Component;
import java.awt.GraphicsConfiguration;
import java.awt.Image;
import java.awt.Transparency;
import java.awt.image.ColorModel;
import sun.awt.Win32GraphicsConfig;
import sun.awt.image.SunVolatileImage;
import sun.awt.image.SurfaceManager;
import sun.awt.image.VolatileSurfaceManager;
import sun.awt.windows.WComponentPeer;
import sun.java2d.InvalidPipeException;
import sun.java2d.SurfaceData;
import static sun.java2d.pipe.hw.AccelSurface.*;
import static sun.java2d.d3d.D3DContext.D3DContextCaps.*;
import sun.java2d.windows.GDIWindowSurfaceData;
public class D3DVolatileSurfaceManager
extends VolatileSurfaceManager
{
private boolean accelerationEnabled;
private int restoreCountdown;
public D3DVolatileSurfaceManager(SunVolatileImage vImg, Object context) {
super(vImg, context);
/*
* We will attempt to accelerate this image only under the
* following conditions:
* - the image is opaque OR
* - the image is translucent AND
* - the GraphicsConfig supports the FBO extension OR
* - the GraphicsConfig has a stored alpha channel
*/
int transparency = vImg.getTransparency();
D3DGraphicsDevice gd = (D3DGraphicsDevice)
vImg.getGraphicsConfig().getDevice();
accelerationEnabled =
(transparency == Transparency.OPAQUE) ||
(transparency == Transparency.TRANSLUCENT &&
(gd.isCapPresent(CAPS_RT_PLAIN_ALPHA) ||
gd.isCapPresent(CAPS_RT_TEXTURE_ALPHA)));
}
protected boolean isAccelerationEnabled() {
return accelerationEnabled;
}
public void setAccelerationEnabled(boolean accelerationEnabled) {
this.accelerationEnabled = accelerationEnabled;
}
/**
* Create a pbuffer-based SurfaceData object (or init the backbuffer
* of an existing window if this is a double buffered GraphicsConfig).
*/
protected SurfaceData initAcceleratedSurface() {
SurfaceData sData;
Component comp = vImg.getComponent();
WComponentPeer peer =
(comp != null) ? (WComponentPeer)comp.getPeer() : null;
try {
boolean forceback = false;
if (context instanceof Boolean) {
forceback = ((Boolean)context).booleanValue();
}
if (forceback) {
// peer must be non-null in this case
sData = D3DSurfaceData.createData(peer, vImg);
} else {
D3DGraphicsConfig gc =
(D3DGraphicsConfig)vImg.getGraphicsConfig();
ColorModel cm = gc.getColorModel(vImg.getTransparency());
int type = vImg.getForcedAccelSurfaceType();
// if acceleration type is forced (type != UNDEFINED) then
// use the forced type, otherwise use RT_TEXTURE
if (type == UNDEFINED) {
type = RT_TEXTURE;
}
sData = D3DSurfaceData.createData(gc,
vImg.getWidth(),
vImg.getHeight(),
cm, vImg,
type);
}
} catch (NullPointerException ex) {
sData = null;
} catch (OutOfMemoryError er) {
sData = null;
} catch (InvalidPipeException ipe) {
sData = null;
}
return sData;
}
protected boolean isConfigValid(GraphicsConfiguration gc) {
return ((gc == null) || (gc == vImg.getGraphicsConfig()));
}
/**
* Set the number of iterations for restoreAcceleratedSurface to fail
* before attempting to restore the accelerated surface.
*
* @see #restoreAcceleratedSurface
* @see #handleVItoScreenOp
*/
private synchronized void setRestoreCountdown(int count) {
restoreCountdown = count;
}
/**
* Note that we create a new surface instead of restoring
* an old one. This will help with D3DContext revalidation.
*/
@Override
protected void restoreAcceleratedSurface() {
synchronized (this) {
if (restoreCountdown > 0) {
restoreCountdown--;
throw new
InvalidPipeException("Will attempt to restore surface " +
" in " + restoreCountdown);
}
}
SurfaceData sData = initAcceleratedSurface();
if (sData != null) {
sdAccel = sData;
} else {
throw new InvalidPipeException("could not restore surface");
// REMIND: alternatively, we could try this:
// ((D3DSurfaceData)sdAccel).restoreSurface();
}
}
/**
* We're asked to restore contents by the accelerated surface, which means
* that it had been lost.
*/
@Override
public SurfaceData restoreContents() {
acceleratedSurfaceLost();
return super.restoreContents();
}
/**
* If the destination surface's peer can potentially handle accelerated
* on-screen rendering then it is likely that the condition which resulted
* in VI to Screen operation is temporary, so this method sets the
* restore countdown in hope that the on-screen accelerated rendering will
* resume. In the meantime the backup surface of the VISM will be used.
*
* The countdown is needed because otherwise we may never break out
* of "do { vi.validate()..} while(vi.lost)" loop since validate() could
* restore the source surface every time and it will get lost again on the
* next copy attempt, and we would never get a chance to use the backup
* surface. By using the countdown we allow the backup surface to be used
* while the screen surface gets sorted out, or if it for some reason can
* never be restored.
*
* If the destination surface's peer could never do accelerated onscreen
* rendering then the acceleration for the SurfaceManager associated with
* the source surface is disabled forever.
*/
static void handleVItoScreenOp(SurfaceData src, SurfaceData dst) {
if (src instanceof D3DSurfaceData &&
dst instanceof GDIWindowSurfaceData)
{
D3DSurfaceData d3dsd = (D3DSurfaceData)src;
SurfaceManager mgr =
SurfaceManager.getManager((Image)d3dsd.getDestination());
if (mgr instanceof D3DVolatileSurfaceManager) {
D3DVolatileSurfaceManager vsm = (D3DVolatileSurfaceManager)mgr;
if (vsm != null) {
d3dsd.setSurfaceLost(true);
GDIWindowSurfaceData wsd = (GDIWindowSurfaceData)dst;
WComponentPeer p = wsd.getPeer();
if (D3DScreenUpdateManager.canUseD3DOnScreen(p,
(Win32GraphicsConfig)p.getGraphicsConfiguration(),
p.getBackBuffersNum()))
{
// 10 is only chosen to be greater than the number of
// times a sane person would call validate() inside
// a validation loop, and to reduce thrashing between
// accelerated and backup surfaces
vsm.setRestoreCountdown(10);
} else {
vsm.setAccelerationEnabled(false);
}
}
}
}
}
@Override
public void initContents() {
if (vImg.getForcedAccelSurfaceType() != TEXTURE) {
super.initContents();
}
}
}