/*
* This file is modified by Ivan Maidanski <ivmai@ivmaisoft.com>
* Project name: JCGO-SUNAWT (http://www.ivmaisoft.com/jcgo/)
*/
/*
* @(#)Win32OffScreenSurfaceData.java 1.42 03/01/30
*
* Copyright 2003 Sun Microsystems, Inc. All rights reserved.
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
package sun.awt.windows;
import java.awt.Color;
import java.awt.GraphicsConfiguration;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Transparency;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.DirectColorModel;
import java.awt.image.IndexColorModel;
import java.awt.image.Raster;
import sun.awt.SunHints;
import sun.java2d.SunGraphics2D;
import sun.java2d.SurfaceData;
import sun.java2d.pipe.PixelToShapeConverter;
import sun.java2d.loops.GraphicsPrimitive;
import sun.java2d.loops.SurfaceType;
import sun.java2d.loops.RenderLoops;
import sun.awt.Win32ColorModel24;
import sun.awt.Win32GraphicsDevice;
import sun.awt.Win32GraphicsConfig;
/**
* Win32OffScreenSurfaceData
*
* This class implements a hardware-accelerated video memory surface. It uses
* a custom renderer (Win32DDRenderer) to render via DirectDraw into the
* surface and uses a custom Blit loop (Win32BlitLoops) to copy between
* two hardware-accelerated surfaces (including the screen).
*/
public class Win32OffScreenSurfaceData extends SurfaceData {
int width;
int height;
int transparency;
private GraphicsConfiguration graphicsConfig;
private Image image;
private static boolean forceDDVram;
private RenderLoops solidloops;
private static boolean d3dEnabled = true;
private boolean localD3dEnabled = true;
protected boolean d3dClippingEnabled = false;
private static boolean ddScaleEnabled = false;
private boolean ddSurfacePunted = false;
private static native void initDDraw(boolean sharing);
private static native boolean enableD3D(boolean forceD3D);
private static native void initIDs();
private static int textureBpp = 32;
static boolean directXInitialized = false;
public static void initD3D() {
if (!directXInitialized) {
boolean forceD3D = false;
directXInitialized = true;
String d3dProp = (String) java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("sun.java2d.d3d"));
String d3dTexBppProp = (String) java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("sun.java2d.d3dtexbpp"));
if (d3dProp != null) {
if (d3dProp.equals("true") || d3dProp.equals("t")) {
forceD3D = true;
d3dEnabled = true;
} else if (d3dProp.equals("false") || d3dProp.equals("f")) {
d3dEnabled = false;
}
}
if (d3dTexBppProp != null) {
try {
int parsed = Integer.parseInt(d3dTexBppProp);
if (parsed == 32 || parsed == 16) {
textureBpp = parsed;
System.out.println("Texture bpp is set to " + textureBpp);
}
} catch (NumberFormatException e) {}
}
if (d3dEnabled) {
d3dEnabled = enableD3D(forceD3D);
if (d3dEnabled) {
D3DBlitLoops.register();
}
}
}
}
static {
initIDs();
String noddraw = (String) java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("sun.java2d.noddraw"));
String ddoffscreenProp = (String) java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("sun.java2d.ddoffscreen"));
String ddForceVramProp = (String) java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("sun.java2d.ddforcevram"));
String ddBlitProp = (String) java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("sun.java2d.ddblit"));
String ddScaleProp = (String) java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("sun.java2d.ddscale"));
String offscreenSharingProp = (String) java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("sun.java2d.offscreenSharing"));
boolean ddoffscreenDisable = (ddoffscreenProp != null &&
(ddoffscreenProp.equals("false") ||
ddoffscreenProp.equals("f")));
forceDDVram = (ddForceVramProp != null &&
(ddForceVramProp.equals("true") ||
ddForceVramProp.equals("t")));
boolean ddBlitDisable = (ddBlitProp != null &&
(ddBlitProp.equals("false") ||
ddBlitProp.equals("f")));
boolean ddScaleDisable = (ddScaleProp == null ||
(ddScaleProp.equals("false") ||
ddScaleProp.equals("f")));
boolean offscreenSharing = ((offscreenSharingProp != null) &&
!(offscreenSharingProp.equals("false") ||
offscreenSharingProp.equals("f")));
if (offscreenSharing) {
System.out.println("Warning: offscreenSharing has been enabled. " +
"The use of this capability will change in future " +
"releases and applications that depend on it " +
"may not work correctly");
}
initD3D();
// REMIND: This isn't really thought-out; if the user doesn't have or
// doesn't want ddraw then we should not even have this surface type
// in the loop
if (noddraw == null && !ddoffscreenDisable) {
String magPresent = (String)java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("javax.accessibility.screen_magnifier_present"));
if (magPresent == null || !magPresent.equals("true")) {
if ("false".equals(magPresent) || getOsMajorVer() < 6)
initDDraw(offscreenSharing);
if (!ddBlitDisable) {
// Register out hardware-accelerated Blit loops
Win32BlitLoops.register();
} else {
System.out.println("DirectDraw Blits disabled");
}
if (!ddScaleDisable) {
Win32ScaleLoops.register();
ddScaleEnabled = true;
System.out.println("DirectDraw Scaling enabled");
}
if (forceDDVram) {
System.out.println("DirectDraw surfaces constrained to use vram");
}
}
}
}
private static int getOsMajorVer() {
try {
String ver = System.getProperty("os.version");
int pos;
if (ver != null && (pos = ver.indexOf('.')) > 0)
return Integer.parseInt(ver.substring(0, pos));
}
catch (SecurityException e) {
}
catch (NumberFormatException e) {
}
return -1;
}
public static SurfaceType getSurfaceType(ColorModel cm, int transparency) {
// REMIND: If ddraw not available, set sType to non-ddraw surface type
if (transparency == Transparency.TRANSLUCENT) {
if (cm.getPixelSize() == 16) {
return Win32SurfaceData.Ushort4444ArgbD3D;
} else {
return Win32SurfaceData.IntArgbD3D;
}
}
boolean transparent = (transparency == Transparency.BITMASK);
switch (cm.getPixelSize()) {
case 32:
case 24:
if (cm instanceof DirectColorModel) {
if (((DirectColorModel)cm).getRedMask() == 0xff0000) {
return transparent ? Win32SurfaceData.IntRgbDD_BM :
Win32SurfaceData.IntRgbDD;
} else {
return transparent ? Win32SurfaceData.IntRgbxDD_BM :
Win32SurfaceData.IntRgbxDD;
}
} else {
return transparent ? Win32SurfaceData.ThreeByteBgrDD_BM :
Win32SurfaceData.ThreeByteBgrDD;
}
case 15:
return transparent ? Win32SurfaceData.Ushort555RgbDD_BM :
Win32SurfaceData.Ushort555RgbDD;
case 16:
if ((cm instanceof DirectColorModel) &&
(((DirectColorModel)cm).getBlueMask() == 0x3e))
{
return transparent ? Win32SurfaceData.Ushort555RgbxDD_BM :
Win32SurfaceData.Ushort555RgbxDD;
} else {
return transparent ? Win32SurfaceData.Ushort565RgbDD_BM :
Win32SurfaceData.Ushort565RgbDD;
}
case 8:
if (cm.getColorSpace().getType() == ColorSpace.TYPE_GRAY &&
cm instanceof ComponentColorModel) {
return transparent ? Win32SurfaceData.ByteGrayDD_BM :
Win32SurfaceData.ByteGrayDD;
} else if (cm instanceof IndexColorModel &&
isOpaqueGray((IndexColorModel)cm)) {
return transparent ? Win32SurfaceData.Index8GrayDD_BM :
Win32SurfaceData.Index8GrayDD;
} else {
return transparent ? Win32SurfaceData.ByteIndexedDD_BM :
Win32SurfaceData.ByteIndexedOpaqueDD;
}
default:
throw new sun.java2d.InvalidPipeException("Unsupported bit " +
"depth: " +
cm.getPixelSize());
}
}
public static Win32OffScreenSurfaceData createData(int width, int height,
ColorModel cm, GraphicsConfiguration graphicsConfig,
Image image, int transparency) {
if (!((Win32GraphicsDevice)graphicsConfig.getDevice()).
isOffscreenAccelerationEnabled()) {
// If acceleration is disabled on this device, don't create
// a surface of this type
return null;
}
// need to use device color model for textures
if (transparency == Transparency.TRANSLUCENT) {
cm = ((Win32PeerlessImage)image).getDeviceColorModel();
}
Win32OffScreenSurfaceData ret = new Win32OffScreenSurfaceData(width,
height, getSurfaceType(cm, transparency),
cm, graphicsConfig, image, transparency);
Win32GraphicsDevice gd =
(Win32GraphicsDevice)graphicsConfig.getDevice();
ret.initSurface(cm.getPixelSize(), width, height, gd.getScreen(),
(image instanceof WVolatileImage), transparency, forceDDVram);
// d3dClippingEnabled is set during the call to initSurface
if (ret.d3dClippingEnabled) {
ret.d3dPipe = d3dClipPipe;
ret.d3dTxPipe = d3dTxClipPipe;
} else {
ret.d3dPipe = d3dNoClipPipe;
ret.d3dTxPipe = d3dTxNoClipPipe;
}
return ret;
}
protected static Win32D3DRenderer d3dNoClipPipe;
protected static Win32D3DRenderer d3dClipPipe;
protected static Win32DDRenderer ddPipe;
protected static PixelToShapeConverter d3dTxNoClipPipe;
protected static PixelToShapeConverter d3dTxClipPipe;
protected static PixelToShapeConverter ddTxPipe;
// The next 2 instance variables are set if d3dEnabled during
// construction, depending on whether d3d can handle clipping
// or not
protected Win32D3DRenderer d3dPipe = null;
protected PixelToShapeConverter d3dTxPipe = null;
static {
d3dNoClipPipe = new Win32D3DRenderer(false);
d3dClipPipe = new Win32D3DRenderer(true);
ddPipe = new Win32DDRenderer();
if (GraphicsPrimitive.tracingEnabled()) {
d3dNoClipPipe = d3dNoClipPipe.traceWrapD3D();
d3dClipPipe = d3dClipPipe.traceWrapD3D();
ddPipe = ddPipe.traceWrapDD();
}
d3dTxNoClipPipe = new PixelToShapeConverter(d3dNoClipPipe);
d3dTxClipPipe = new PixelToShapeConverter(d3dClipPipe);
ddTxPipe = new PixelToShapeConverter(ddPipe);
}
public void validatePipe(SunGraphics2D sg2d) {
if (sg2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON &&
sg2d.paintState == sg2d.PAINT_SOLIDCOLOR &&
sg2d.compositeState == sg2d.COMP_ISCOPY &&
sg2d.clipState != sg2d.CLIP_SHAPE)
{
PixelToShapeConverter txPipe;
Win32DDRenderer nontxPipe;
if (d3dEnabled && localD3dEnabled) {
txPipe = d3dTxPipe;
nontxPipe = d3dPipe;
} else {
txPipe = ddTxPipe;
nontxPipe = ddPipe;
}
sg2d.imagepipe = imagepipe;
if (sg2d.transformState > sg2d.TRANSFORM_TRANSLATEONLY) {
sg2d.drawpipe = txPipe;
sg2d.fillpipe = txPipe;
} else if (sg2d.strokeState != sg2d.STROKE_THIN){
sg2d.drawpipe = txPipe;
sg2d.fillpipe = nontxPipe;
} else {
sg2d.drawpipe = nontxPipe;
sg2d.fillpipe = nontxPipe;
}
sg2d.shapepipe = nontxPipe;
if (sg2d.textAntialiasHint == SunHints.INTVAL_TEXT_ANTIALIAS_ON) {
sg2d.textpipe = aaTextRenderer;
} else {
sg2d.textpipe = solidTextRenderer;
}
// This is needed for AA text.
// Note that even a SolidTextRenderer can dispatch AA text
// if a GlyphVector overrides the AA setting.
sg2d.loops = solidloops;
} else {
super.validatePipe(sg2d);
}
}
/**
* Disables D3D on this surfaceData object. This can happen
* when we encounter an error in rendering a D3D primitive
* (for example, if we were unable to create a D3D device).
* Upon next validation, this renderer will then choose a
* non-D3D pipe.
*/
public void disableD3D() {
localD3dEnabled = false;
}
public static boolean isDDScaleEnabled() {
return ddScaleEnabled;
}
public Raster getRaster(int x, int y, int w, int h) {
throw new InternalError("not implemented yet");
}
public void lock() {
// REMIND: Do we need this call here? Who calls the Java method?
}
public void unlock() {
// REMIND: Do we need this call here? Who calls the Java method?
}
public RenderLoops getRenderLoops(SunGraphics2D sg2d) {
if (sg2d.paintState == sg2d.PAINT_SOLIDCOLOR &&
sg2d.compositeState == sg2d.COMP_ISCOPY)
{
return solidloops;
}
return super.getRenderLoops(sg2d);
}
public GraphicsConfiguration getDeviceConfiguration() {
return graphicsConfig;
}
/**
* Initializes the native Ops pointer.
*/
private native void initOps(int depth, int transparency);
/**
* This native method creates the offscreen surface in video memory and
* (if necessary) initializes DirectDraw
*/
public native void initSurface(int depth, int width, int height,
int screen,
boolean isVolatile,
int transparency,
boolean disablePunts);
public native void restoreSurface();
/**
* Protected constructor. Use createData() to create an object.
*/
protected Win32OffScreenSurfaceData(int width, int height,
SurfaceType sType, ColorModel cm,
GraphicsConfiguration graphicsConfig,
Image image, int transparency)
{
super(sType, cm);
this.width = width;
this.height = height;
this.graphicsConfig = graphicsConfig;
this.image = image;
initOps(cm.getPixelSize(), transparency);
this.transparency = transparency;
this.solidloops =
((Win32GraphicsConfig)graphicsConfig).getSolidLoops(sType);
}
/**
* Need this since the surface data is created with
* the color model of the target GC, which is always
* opaque. But in SunGraphics2D.blitSD we choose loops
* based on the transparency on the source SD, so
* we could choose wrong loop (blit instead of blitbg,
* for example, which will cause problems in transparent
* case).
*/
public int getTransparency() {
return transparency;
}
public static int getTextureBpp() {
return textureBpp;
}
public SurfaceData getReplacement() {
// When someone asks for a new surface data, we punt to our
// container image which will attempt to restore the contents
// of this surface or, failing that, will return null
if (image instanceof Win32OffScreenImage) {
// Only this type of image has auto-restore
// REMIND: don't like this hack - we should just generically
// punt to our parent image and let it decide without having
// to figure out what our parent is.
return ((Win32OffScreenImage)image).restoreContents();
} else if (image instanceof WVolatileImage) {
return ((WVolatileImage)image).restoreContents();
} else {
throw new InternalError();
}
}
public Rectangle getBounds() {
return new Rectangle(width, height);
}
private native void nativeInvalidate();
public void invalidate() {
if (isValid()) {
nativeInvalidate();
super.invalidate();
}
}
public native void setTransparentPixel(int pixel);
public native void flush();
/**
* Returns true if the native representation of this image has been
* moved into ddraw system memory. This happens when many reads
* or read-modify-write operations are requested of that surface.
* If we have moved that surface into system memory, we should note that
* here so that someone wanting to copy something to this surface will
* take that into account during that copy.
*/
public boolean surfacePunted() {
return ddSurfacePunted;
}
}