diff -r 7eb22e81bb28 -r 0aab8d3fa11a jdk/src/windows/classes/sun/java2d/d3d/D3DSurfaceData.java --- a/jdk/src/windows/classes/sun/java2d/d3d/D3DSurfaceData.java Tue Jul 15 16:04:08 2008 +0400 +++ b/jdk/src/windows/classes/sun/java2d/d3d/D3DSurfaceData.java Fri Jul 18 10:48:44 2008 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2007-2008 Sun Microsystems, Inc. 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 @@ -26,432 +26,919 @@ package sun.java2d.d3d; import java.awt.AlphaComposite; +import java.awt.BufferCapabilities; +import java.awt.Component; import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; import java.awt.Image; +import java.awt.Rectangle; import java.awt.Transparency; import java.awt.image.ColorModel; +import java.awt.image.DataBuffer; import java.awt.image.DirectColorModel; +import java.awt.image.Raster; +import java.awt.image.SampleModel; +import java.awt.image.SinglePixelPackedSampleModel; import sun.awt.SunHints; -import sun.awt.Win32GraphicsConfig; -import sun.awt.Win32GraphicsDevice; +import sun.awt.image.DataBufferNative; +import sun.awt.image.PixelConverter; import sun.awt.image.SurfaceManager; +import sun.awt.image.WritableRasterNative; +import sun.awt.windows.WComponentPeer; +import sun.java2d.pipe.hw.AccelSurface; import sun.java2d.InvalidPipeException; import sun.java2d.SunGraphics2D; import sun.java2d.SurfaceData; -import sun.java2d.SurfaceDataProxy; import sun.java2d.loops.GraphicsPrimitive; +import sun.java2d.loops.MaskFill; import sun.java2d.loops.SurfaceType; -import sun.java2d.pipe.PixelToShapeConverter; +import sun.java2d.loops.CompositeType; +import sun.java2d.pipe.ParallelogramPipe; +import sun.java2d.pipe.PixelToParallelogramConverter; +import sun.java2d.pipe.RenderBuffer; import sun.java2d.pipe.TextPipe; -import sun.java2d.windows.Win32OffScreenSurfaceData; -import sun.java2d.windows.Win32SurfaceData; -import sun.java2d.windows.WinVolatileSurfaceManager; -import sun.java2d.windows.WindowsFlags; - -import static sun.java2d.windows.Win32SurfaceData.*; - -public class D3DSurfaceData extends Win32OffScreenSurfaceData { - - // properties of a surface - /** - * This property is used for a back-buffer surface - */ - public static final int D3D_ATTACHED_SURFACE = (1 << 15); - /** - * A surface with this property can be used as a Direct3D rendering - * destination. - */ - public static final int D3D_RENDER_TARGET = (1 << 16); +import static sun.java2d.pipe.BufferedOpCodes.*; +import static sun.java2d.d3d.D3DContext.D3DContextCaps.*; +import static sun.java2d.pipe.hw.ExtendedBufferCapabilities.VSyncType.*; +import sun.java2d.pipe.hw.ExtendedBufferCapabilities.VSyncType; +import java.awt.BufferCapabilities.FlipContents; +import java.awt.Window; +import sun.awt.SunToolkit; +import sun.awt.image.SunVolatileImage; +import sun.java2d.ScreenUpdateManager; +import sun.java2d.StateTracker; +import sun.java2d.SurfaceDataProxy; +import sun.java2d.pipe.hw.ExtendedBufferCapabilities; - public static final int - D3D_INVALID_SURFACE = 0; - /** - * Surface is a Direct3D plain surface (not a texture). - * Plain surface can be used as render target. - * VolatileImages typically use plain surfaces as their hardware - * accelerated surfaces. - */ - public static final int - D3D_PLAIN_SURFACE = (1 << 0) | D3D_RENDER_TARGET; - /** - * Direct3D texture. Mostly used for cached accelerated surfaces. - * Surfaces of this type can be copied from using hardware acceleration - * by using texture mapping. - */ - public static final int - D3D_TEXTURE_SURFACE = (1 << 1); - /** - * Direct3D Backbuffer surface - an attached surface. Used for - * multibuffered BufferStrategies. - */ - public static final int - D3D_BACKBUFFER_SURFACE = D3D_PLAIN_SURFACE | D3D_ATTACHED_SURFACE; - /** - * Render-to-texture. A texture which can also be a render target. - * Combines the benefits of textures (fast copies-from) and - * backbuffers or plain surfaces (hw-accelerated rendering to the surface) - */ - public static final int - D3D_RTT_SURFACE = D3D_TEXTURE_SURFACE | D3D_RENDER_TARGET; - - // supported texture pixel formats - public static final int PF_INVALID = 0; - public static final int PF_INT_ARGB = 1; - public static final int PF_INT_RGB = 2; - public static final int PF_INT_RGBX = 3; - public static final int PF_INT_BGR = 4; - public static final int PF_USHORT_565_RGB = 5; - public static final int PF_USHORT_555_RGB = 6; - public static final int PF_USHORT_555_RGBX = 7; - public static final int PF_INT_ARGB_PRE = 8; - public static final int PF_USHORT_4444_ARGB= 9; - - public static final String - DESC_INT_ARGB_D3D = "Integer ARGB D3D with translucency"; - public static final String - DESC_USHORT_4444_ARGB_D3D = "UShort 4444 ARGB D3D with translucency"; +/** + * This class describes a D3D "surface", that is, a region of pixels + * managed via D3D. An D3DSurfaceData can be tagged with one of three + * different SurfaceType objects for the purpose of registering loops, etc. + * This diagram shows the hierarchy of D3D SurfaceTypes: + * + * Any + * / \ + * D3DSurface D3DTexture + * | + * D3DSurfaceRTT + * + * D3DSurface + * This kind of surface can be rendered to using D3D APIs. It is also + * possible to copy a D3DSurface to another D3DSurface (or to itself). + * + * D3DTexture + * This kind of surface cannot be rendered to using D3D (in the same sense + * as in D3DSurface). However, it is possible to upload a region of pixels + * to a D3DTexture object via Lock/UnlockRect(). One can also copy a + * surface of type D3DTexture to a D3DSurface by binding the texture + * to a quad and then rendering it to the destination surface (this process + * is known as "texture mapping"). + * + * D3DSurfaceRTT + * This kind of surface can be thought of as a sort of hybrid between + * D3DSurface and D3DTexture, in that one can render to this kind of + * surface as if it were of type D3DSurface, but the process of copying + * this kind of surface to another is more like a D3DTexture. (Note that + * "RTT" stands for "render-to-texture".) + * + * In addition to these SurfaceType variants, we have also defined some + * constants that describe in more detail the type of underlying D3D + * surface. This table helps explain the relationships between those + * "type" constants and their corresponding SurfaceType: + * + * D3D Type Corresponding SurfaceType + * -------- ------------------------- + * RT_PLAIN D3DSurface + * TEXTURE D3DTexture + * FLIP_BACKBUFFER D3DSurface + * RT_TEXTURE D3DSurfaceRTT + */ +public class D3DSurfaceData extends SurfaceData implements AccelSurface { /** - * Surface type for texture destination. We cannot render textures to - * the screen because Direct3D is not clipped by the window's clip list, - * so we only enable the texture blit loops for copies to offscreen - * accelerated surfaces. + * To be used with getNativeResource() only. + * @see #getNativeResource() */ - public static final String - DESC_DEST_D3D = "D3D render target"; - - public static final SurfaceType D3DSurface = - SurfaceType.Any.deriveSubType("Direct3D Surface"); - public static final SurfaceType D3DTexture = - D3DSurface.deriveSubType("Direct3D Texture"); - - /** - * D3D destination surface types (derive from offscreen dd surfaces). - * Note that all of these surfaces have the same surface description; - * we do not care about the depth of the surface since texture ops - * support multiple depths. + public static final int D3D_DEVICE_RESOURCE= 100; + /* + * Surface types. + * We use these surface types when copying from a sw surface + * to a surface or texture. */ - public static final SurfaceType IntRgbD3D = - IntRgbDD.deriveSubType(DESC_DEST_D3D); - - public static final SurfaceType IntRgbxD3D = - IntRgbxDD.deriveSubType(DESC_DEST_D3D); - - public static final SurfaceType Ushort565RgbD3D = - Ushort565RgbDD.deriveSubType(DESC_DEST_D3D); + public static final int ST_INT_ARGB = 0; + public static final int ST_INT_ARGB_PRE = 1; + public static final int ST_INT_ARGB_BM = 2; + public static final int ST_INT_RGB = 3; + public static final int ST_INT_BGR = 4; + public static final int ST_USHORT_565_RGB = 5; + public static final int ST_USHORT_555_RGB = 6; + public static final int ST_BYTE_INDEXED = 7; + public static final int ST_BYTE_INDEXED_BM = 8; - public static final SurfaceType Ushort555RgbxD3D = - Ushort555RgbxDD.deriveSubType(DESC_DEST_D3D); - - public static final SurfaceType Ushort555RgbD3D = - Ushort555RgbDD.deriveSubType(DESC_DEST_D3D); - - // REMIND: Is it possible to have d3d accelerated on this type of surface? - public static final SurfaceType ThreeByteBgrD3D = - ThreeByteBgrDD.deriveSubType(DESC_DEST_D3D); - - public static final SurfaceType IntArgbD3D = - SurfaceType.IntArgb.deriveSubType(DESC_INT_ARGB_D3D); + /** Equals to D3DSWAPEFFECT_DISCARD */ + public static final int SWAP_DISCARD = 1; + /** Equals to D3DSWAPEFFECT_FLIP */ + public static final int SWAP_FLIP = 2; + /** Equals to D3DSWAPEFFECT_COPY */ + public static final int SWAP_COPY = 3; + /* + * SurfaceTypes + */ + private static final String DESC_D3D_SURFACE = "D3D Surface"; + private static final String DESC_D3D_SURFACE_RTT = + "D3D Surface (render-to-texture)"; + private static final String DESC_D3D_TEXTURE = "D3D Texture"; - public static final SurfaceType Ushort4444ArgbD3D = - SurfaceType.Ushort4444Argb.deriveSubType(DESC_USHORT_4444_ARGB_D3D); - - // Textures we can render to using d3d - public static final SurfaceType IntRgbD3D_RTT = - IntRgbD3D.deriveSubType(DESC_DEST_D3D); + // REMIND: regarding ArgbPre?? + static final SurfaceType D3DSurface = + SurfaceType.Any.deriveSubType(DESC_D3D_SURFACE, + PixelConverter.ArgbPre.instance); + static final SurfaceType D3DSurfaceRTT = + D3DSurface.deriveSubType(DESC_D3D_SURFACE_RTT); + static final SurfaceType D3DTexture = + SurfaceType.Any.deriveSubType(DESC_D3D_TEXTURE); - public static final SurfaceType IntRgbxD3D_RTT = - IntRgbxD3D.deriveSubType(DESC_DEST_D3D); - - public static final SurfaceType Ushort565RgbD3D_RTT = - Ushort565RgbD3D.deriveSubType(DESC_DEST_D3D); - - public static final SurfaceType Ushort555RgbxD3D_RTT = - Ushort555RgbxD3D.deriveSubType(DESC_DEST_D3D); - - public static final SurfaceType Ushort555RgbD3D_RTT = - Ushort555RgbD3D.deriveSubType(DESC_DEST_D3D); + private int type; + private int width, height; + // these fields are set from the native code when the surface is + // initialized + private int nativeWidth, nativeHeight; + protected WComponentPeer peer; + private Image offscreenImage; + protected D3DGraphicsDevice graphicsDevice; - public static final SurfaceType Ushort4444ArgbD3D_RTT = - Ushort4444ArgbD3D.deriveSubType(DESC_DEST_D3D); + private int swapEffect; + private VSyncType syncType; + private int backBuffersNum; - public static final SurfaceType IntArgbD3D_RTT = - IntArgbD3D.deriveSubType(DESC_DEST_D3D); - - public static final SurfaceType ThreeByteBgrD3D_RTT = - ThreeByteBgrD3D.deriveSubType(DESC_DEST_D3D); + private WritableRasterNative wrn; - // the type of this surface - texture, plain, back-buffer - protected int type; - protected int pixelFormat; - - private D3DContext d3dContext; + protected static D3DRenderer d3dRenderPipe; + protected static PixelToParallelogramConverter d3dTxRenderPipe; + protected static ParallelogramPipe d3dAAPgramPipe; + protected static D3DTextRenderer d3dTextPipe; + protected static D3DDrawImage d3dImagePipe; - protected static D3DRenderer d3dPipe; - protected static PixelToShapeConverter d3dTxPipe; - protected static D3DTextRenderer d3dTextPipe; - protected static D3DDrawImage d3dDrawImagePipe; - - private native void initOps(int depth, int transparency); + private native boolean initTexture(long pData, boolean isRTT, + boolean isOpaque); + private native boolean initFlipBackbuffer(long pData, long pPeerData, + int numbuffers, + int swapEffect, int syncType); + private native boolean initRTSurface(long pData, boolean isOpaque); + private native void initOps(int screen, int width, int height); static { - if (WindowsFlags.isD3DEnabled()) { - D3DBlitLoops.register(); - D3DMaskFill.register(); + D3DRenderQueue rq = D3DRenderQueue.getInstance(); + d3dImagePipe = new D3DDrawImage(); + d3dTextPipe = new D3DTextRenderer(rq); + d3dRenderPipe = new D3DRenderer(rq); + if (GraphicsPrimitive.tracingEnabled()) { + d3dTextPipe = d3dTextPipe.traceWrap(); + d3dRenderPipe = d3dRenderPipe.traceWrap(); + //The wrapped d3dRenderPipe will wrap the AA pipe as well... + //d3dAAPgramPipe = d3dRenderPipe.traceWrap(); } + d3dAAPgramPipe = d3dRenderPipe.getAAParallelogramPipe(); + d3dTxRenderPipe = + new PixelToParallelogramConverter(d3dRenderPipe, d3dRenderPipe, + 1.0, 0.25, true); + + D3DBlitLoops.register(); + D3DMaskFill.register(); + D3DMaskBlit.register(); + } - d3dPipe = new D3DRenderer(); - d3dTxPipe = new PixelToShapeConverter(d3dPipe); - d3dTextPipe = new D3DTextRenderer(); - d3dDrawImagePipe = new D3DDrawImage(); + protected D3DSurfaceData(WComponentPeer peer, D3DGraphicsConfig gc, + int width, int height, Image image, + ColorModel cm, int numBackBuffers, + int swapEffect, VSyncType vSyncType, + int type) + { + super(getCustomSurfaceType(type), cm); + this.graphicsDevice = gc.getD3DDevice(); + this.peer = peer; + this.type = type; + this.width = width; + this.height = height; + this.offscreenImage = image; + this.backBuffersNum = numBackBuffers; + this.swapEffect = swapEffect; + this.syncType = vSyncType; - if (GraphicsPrimitive.tracingEnabled()) { - d3dPipe = d3dPipe.traceWrapD3D(); - d3dTextPipe = d3dTextPipe.traceWrap(); + initOps(graphicsDevice.getScreen(), width, height); + if (type == WINDOW) { + // we put the surface into the "lost" + // state; it will be restored by the D3DScreenUpdateManager + // prior to rendering to it for the first time. This is done + // so that vram is not wasted for surfaces never rendered to + setSurfaceLost(true); + } else { + initSurface(); } + setBlitProxyKey(gc.getProxyKey()); } @Override public SurfaceDataProxy makeProxyFor(SurfaceData srcData) { - //D3D may be eliminated soon so no Proxy was created for it... - //return D3DSurfaceDataProxy.createProxy(srcData, graphicsConfig); - return SurfaceDataProxy.UNCACHED; + return D3DSurfaceDataProxy. + createProxy(srcData, + (D3DGraphicsConfig)graphicsDevice.getDefaultConfiguration()); + } + + /** + * Creates a SurfaceData object representing the back buffer of a + * double-buffered on-screen Window. + */ + public static D3DSurfaceData createData(WComponentPeer peer, Image image) { + D3DGraphicsConfig gc = getGC(peer); + if (gc == null || !peer.isAccelCapable()) { + return null; + } + BufferCapabilities caps = peer.getBackBufferCaps(); + VSyncType vSyncType = VSYNC_DEFAULT; + if (caps instanceof ExtendedBufferCapabilities) { + vSyncType = ((ExtendedBufferCapabilities)caps).getVSync(); + } + Rectangle r = peer.getBounds(); + BufferCapabilities.FlipContents flip = caps.getFlipContents(); + int swapEffect; + if (flip == FlipContents.COPIED) { + swapEffect = SWAP_COPY; + } else if (flip == FlipContents.PRIOR) { + swapEffect = SWAP_FLIP; + } else { // flip == FlipContents.UNDEFINED || .BACKGROUND + swapEffect = SWAP_DISCARD; + } + return new D3DSurfaceData(peer, gc, r.width, r.height, + image, peer.getColorModel(), + peer.getBackBuffersNum(), + swapEffect, vSyncType, FLIP_BACKBUFFER); } /** - * Non-public constructor. Use createData() to create an object. + * Returns a WINDOW type of surface - a + * swap chain which serves as an on-screen surface, + * handled by the D3DScreenUpdateManager. + * + * Note that the native surface is not initialized + * when the surface is created to avoid using excessive + * resources, and the surface is placed into the lost + * state. It will be restored prior to any rendering + * to it. * - * This constructor is used to house the common construction - * code shared between the creation of D3DSurfaceData objects - * and subclasses of D3DSurfaceData (such as D3DBackBufferSD). - * - * It calls the common constructor in the parent, and then - * initializes other shared D3D data. + * @param peer peer for which the onscreen surface is to be created + * @return a D3DWindowSurfaceData (flip chain) surface + */ + public static D3DSurfaceData createData(WComponentPeer peer) { + D3DGraphicsConfig gc = getGC(peer); + if (gc == null || !peer.isAccelCapable()) { + return null; + } + return new D3DWindowSurfaceData(peer, gc); + } + + /** + * Creates a SurfaceData object representing an off-screen buffer (either + * a plain surface or Texture). */ - protected D3DSurfaceData(int width, int height, - int d3dSurfaceType, - SurfaceType sType, ColorModel cm, - GraphicsConfiguration gc, - Image image, int transparency) + public static D3DSurfaceData createData(D3DGraphicsConfig gc, + int width, int height, + ColorModel cm, + Image image, int type) { - super(width, height, sType, cm, gc, image, transparency); - this.type = d3dSurfaceType; + if (type == RT_TEXTURE) { + boolean isOpaque = cm.getTransparency() == Transparency.OPAQUE; + int cap = isOpaque ? CAPS_RT_TEXTURE_OPAQUE : CAPS_RT_TEXTURE_ALPHA; + if (!gc.getD3DDevice().isCapPresent(cap)) { + type = RT_PLAIN; + } + } + D3DSurfaceData ret = null; + try { + ret = new D3DSurfaceData(null, gc, width, height, + image, cm, 0, SWAP_DISCARD, VSYNC_DEFAULT, + type); + } catch (InvalidPipeException ipe) { + // try again - we might have ran out of vram, and rt textures + // could take up more than a plain surface, so it might succeed + if (type == RT_TEXTURE) { + // If a RT_TEXTURE was requested do not attempt to create a + // plain surface. (note that RT_TEXTURE can only be requested + // from a VI so the cast is safe) + if (((SunVolatileImage)image).getForcedAccelSurfaceType() != + RT_TEXTURE) + { + type = RT_PLAIN; + ret = new D3DSurfaceData(null, gc, width, height, + image, cm, 0, SWAP_DISCARD, + VSYNC_DEFAULT, type); + } + } + } + return ret; } /** - * Private constructor. Use createData() to create an object. - * - * This constructor calls the common constructor above and then - * performs the specific initialization of the D3DSurface. + * Returns the appropriate SurfaceType corresponding to the given D3D + * surface type constant (e.g. TEXTURE -> D3DTexture). */ - private D3DSurfaceData(int width, int height, - int d3dSurfaceType, - SurfaceType sType, ColorModel cm, - GraphicsConfiguration gc, - Image image, int transparency, - int screen) - { - this(width, height, d3dSurfaceType, sType, cm, gc, image, transparency); - pixelFormat = initSurface(width, height, screen, - null /*parent SurfaceData*/); + private static SurfaceType getCustomSurfaceType(int d3dType) { + switch (d3dType) { + case TEXTURE: + return D3DTexture; + case RT_TEXTURE: + return D3DSurfaceRTT; + default: + return D3DSurface; + } } - public static D3DSurfaceData createData(int width, int height, - int d3dSurfaceType, - ColorModel cm, - GraphicsConfiguration gc, - Image image) - { - Win32GraphicsDevice gd = (Win32GraphicsDevice)gc.getDevice(); - // After a display change ddInstance may not be - // recreated yet, and in this case isD3DEnabledOnDevice will - // return false, until someone attempted to recreate the - // primary. - if (!gd.isD3DEnabledOnDevice()) { - return null; + private boolean initSurfaceNow() { + boolean isOpaque = (getTransparency() == Transparency.OPAQUE); + switch (type) { + case RT_PLAIN: + return initRTSurface(getNativeOps(), isOpaque); + case TEXTURE: + return initTexture(getNativeOps(), false/*isRTT*/, isOpaque); + case RT_TEXTURE: + return initTexture(getNativeOps(), true/*isRTT*/, isOpaque); + // REMIND: we may want to pass the exact type to the native + // level here so that we could choose the right presentation + // interval for the frontbuffer (immediate vs v-synced) + case WINDOW: + case FLIP_BACKBUFFER: + return initFlipBackbuffer(getNativeOps(), peer.getData(), + backBuffersNum, swapEffect, + syncType.id()); + default: + return false; } - - return new D3DSurfaceData(width, height, - d3dSurfaceType, - getSurfaceType(gc, cm, d3dSurfaceType), - cm, gc, image, - cm.getTransparency(), gd.getScreen()); - } - - int getPixelFormat() { - return pixelFormat; } - static SurfaceType getSurfaceType(GraphicsConfiguration gc, - ColorModel cm, - int d3dSurfaceType) - { - if (d3dSurfaceType == D3D_TEXTURE_SURFACE) { - // for non-rtt textures we have only one surface type - return D3DTexture; - } else { - int pixelSize = cm.getPixelSize(); - Win32GraphicsDevice gd = (Win32GraphicsDevice)gc.getDevice(); - int transparency = cm.getTransparency(); - - // We'll attempt to use render-to-texture if render target is - // requested, but it's not a back-buffer and we support RTT - // for this configuration. - boolean useRTT = - ((d3dSurfaceType & D3D_RENDER_TARGET) != 0) && - ((d3dSurfaceType & D3D_BACKBUFFER_SURFACE) == 0) && - gd.getD3DContext().isRTTSupported(); - - // if there's no RTT available, we can't accelerate non-opaque - // surfaces, so we return null. - if (transparency == Transparency.TRANSLUCENT || - transparency == Transparency.BITMASK) - { - if (pixelSize == 16) { - return useRTT ? Ushort4444ArgbD3D_RTT : - null/*Ushort4444ArgbD3D*/; - } else { - return useRTT ? IntArgbD3D_RTT : null/*IntArgbD3D*/; + /** + * Initializes the appropriate D3D offscreen surface based on the value + * of the type parameter. If the surface creation fails for any reason, + * an OutOfMemoryError will be thrown. + */ + protected void initSurface() { + // any time we create or restore the surface, recreate the raster + synchronized (this) { + wrn = null; + } + // REMIND: somewhere a puppy died + class Status { + boolean success = false; + }; + final Status status = new Status(); + D3DRenderQueue rq = D3DRenderQueue.getInstance(); + rq.lock(); + try { + rq.flushAndInvokeNow(new Runnable() { + public void run() { + status.success = initSurfaceNow(); } - } else { - // it's an opaque surface, either a VI or a back-buffer - switch (pixelSize) { - case 32: - case 24: - if (cm instanceof DirectColorModel) { - if (((DirectColorModel)cm).getRedMask() == 0xff0000) { - return useRTT ? IntRgbD3D_RTT : IntRgbD3D; - } else { - return useRTT ? IntRgbxD3D_RTT : IntRgbxD3D; - } - } else { - return useRTT ? ThreeByteBgrD3D_RTT : ThreeByteBgrD3D; + }); + if (!status.success) { + throw new InvalidPipeException("Error creating D3DSurface"); + } + } finally { + rq.unlock(); + } + } + + /** + * Returns the D3DContext for the GraphicsConfig associated with this + * surface. + */ + public final D3DContext getContext() { + return graphicsDevice.getContext(); + } + + /** + * Returns one of the surface type constants defined above. + */ + public final int getType() { + return type; + } + + private static native int dbGetPixelNative(long pData, int x, int y); + private static native void dbSetPixelNative(long pData, int x, int y, + int pixel); + static class D3DDataBufferNative extends DataBufferNative { + int pixel; + protected D3DDataBufferNative(SurfaceData sData, + int type, int w, int h) + { + super(sData, type, w, h); + } + + protected int getElem(final int x, final int y, + final SurfaceData sData) + { + int retPixel; + D3DRenderQueue rq = D3DRenderQueue.getInstance(); + rq.lock(); + try { + rq.flushAndInvokeNow(new Runnable() { + public void run() { + pixel = dbGetPixelNative(sData.getNativeOps(), x, y); } - case 15: - return useRTT ? Ushort555RgbD3D_RTT : Ushort555RgbD3D; - case 16: - if ((cm instanceof DirectColorModel) && - (((DirectColorModel)cm).getBlueMask() == 0x3e)) - { - return useRTT ? Ushort555RgbxD3D_RTT : Ushort555RgbxD3D; - } else { - return useRTT ? Ushort565RgbD3D_RTT : Ushort565RgbD3D; + }); + } finally { + retPixel = pixel; + rq.unlock(); + } + return retPixel; + } + + protected void setElem(final int x, final int y, final int pixel, + final SurfaceData sData) + { + D3DRenderQueue rq = D3DRenderQueue.getInstance(); + rq.lock(); + try { + rq.flushAndInvokeNow(new Runnable() { + public void run() { + dbSetPixelNative(sData.getNativeOps(), x, y, pixel); } - case 8: // not supported - default: - throw new sun.java2d.InvalidPipeException("Unsupported bit " + - "depth: " + - cm.getPixelSize()); - } + }); + sData.markDirty(); + } finally { + rq.unlock(); } } } - private native int initOffScreenSurface(long pCtx, - long pData, long parentPdata, - int width, int height, - int type, int screen); + public synchronized Raster getRaster(int x, int y, int w, int h) { + if (wrn == null) { + DirectColorModel dcm = (DirectColorModel)getColorModel(); + SampleModel smHw; + int dataType = 0; + int scanStride = width; - protected int initSurface(int width, int height, int screen, - Win32SurfaceData parentData) - { - int pFormat = PF_INVALID; - - synchronized (D3DContext.LOCK) { - long pData = getNativeOps(); - long pDataParent = 0L; - if (parentData != null) { - pDataParent = parentData.getNativeOps(); + if (dcm.getPixelSize() == 24 || dcm.getPixelSize() == 32) { + dataType = DataBuffer.TYPE_INT; + } else { + // 15, 16 + dataType = DataBuffer.TYPE_USHORT; } - D3DContext d3dContext = getContext(); - long pCtx = d3dContext.getNativeContext(); - // native context could be 0 if the context is currently invalid, - // so attempt to revalidate - if (pCtx == 0) { - d3dContext.reinitNativeContext(); - pCtx = d3dContext.getNativeContext(); + + // note that we have to use the surface width and height here, + // not the passed w,h + smHw = new SinglePixelPackedSampleModel(dataType, width, height, + scanStride, dcm.getMasks()); + DataBuffer dbn = new D3DDataBufferNative(this, dataType, + width, height); + wrn = WritableRasterNative.createNativeRaster(smHw, dbn); + } + + return wrn; + } + + /** + * For now, we can only render LCD text if: + * - the pixel shaders are available, and + * - blending is disabled, and + * - the source color is opaque + */ + public boolean canRenderLCDText(SunGraphics2D sg2d) { + return + graphicsDevice.isCapPresent(CAPS_LCD_SHADER) && + sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY && + sg2d.paintState <= SunGraphics2D.PAINT_OPAQUECOLOR; + } + + public void validatePipe(SunGraphics2D sg2d) { + TextPipe textpipe; + boolean validated = false; + + // REMIND: the D3D pipeline doesn't support XOR!, more + // fixes will be needed below + if (sg2d.compositeState >= sg2d.COMP_XOR) { + super.validatePipe(sg2d); + sg2d.imagepipe = d3dImagePipe; + return; + } + + // D3DTextRenderer handles both AA and non-AA text, but + // only works with the following modes: + // (Note: For LCD text we only enter this code path if + // canRenderLCDText() has already validated that the mode is + // CompositeType.SrcNoEa (opaque color), which will be subsumed + // by the CompositeType.SrcNoEa (any color) test below.) + + if (/* CompositeType.SrcNoEa (any color) */ + (sg2d.compositeState <= sg2d.COMP_ISCOPY && + sg2d.paintState <= sg2d.PAINT_ALPHACOLOR) || + + /* CompositeType.SrcOver (any color) */ + (sg2d.compositeState == sg2d.COMP_ALPHA && + sg2d.paintState <= sg2d.PAINT_ALPHACOLOR && + (((AlphaComposite)sg2d.composite).getRule() == + AlphaComposite.SRC_OVER)) || + + /* CompositeType.Xor (any color) */ + (sg2d.compositeState == sg2d.COMP_XOR && + sg2d.paintState <= sg2d.PAINT_ALPHACOLOR)) + { + textpipe = d3dTextPipe; + } else { + // do this to initialize textpipe correctly; we will attempt + // to override the non-text pipes below + super.validatePipe(sg2d); + textpipe = sg2d.textpipe; + validated = true; + } + + PixelToParallelogramConverter txPipe = null; + D3DRenderer nonTxPipe = null; + + if (sg2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON) { + if (sg2d.paintState <= sg2d.PAINT_ALPHACOLOR) { + if (sg2d.compositeState <= sg2d.COMP_XOR) { + txPipe = d3dTxRenderPipe; + nonTxPipe = d3dRenderPipe; + } + } else if (sg2d.compositeState <= sg2d.COMP_ALPHA) { + if (D3DPaints.isValid(sg2d)) { + txPipe = d3dTxRenderPipe; + nonTxPipe = d3dRenderPipe; + } + // custom paints handled by super.validatePipe() below } - if (pData != 0 && pCtx != 0) { - pFormat = initOffScreenSurface(pCtx, - pData, pDataParent, - width, height, type, screen); + } else { + if (sg2d.paintState <= sg2d.PAINT_ALPHACOLOR) { + if (graphicsDevice.isCapPresent(CAPS_AA_SHADER) && + (sg2d.imageComp == CompositeType.SrcOverNoEa || + sg2d.imageComp == CompositeType.SrcOver)) + { + if (!validated) { + super.validatePipe(sg2d); + validated = true; + } + PixelToParallelogramConverter aaConverter = + new PixelToParallelogramConverter(sg2d.shapepipe, + d3dAAPgramPipe, + 1.0/8.0, 0.499, + false); + sg2d.drawpipe = aaConverter; + sg2d.fillpipe = aaConverter; + sg2d.shapepipe = aaConverter; + } else if (sg2d.compositeState == sg2d.COMP_XOR) { + // install the solid pipes when AA and XOR are both enabled + txPipe = d3dTxRenderPipe; + nonTxPipe = d3dRenderPipe; + } + } + // other cases handled by super.validatePipe() below + } + + if (txPipe != null) { + if (sg2d.transformState >= sg2d.TRANSFORM_TRANSLATESCALE) { + sg2d.drawpipe = txPipe; + sg2d.fillpipe = txPipe; + } else if (sg2d.strokeState != sg2d.STROKE_THIN) { + sg2d.drawpipe = txPipe; + sg2d.fillpipe = nonTxPipe; } else { - // if the context can't be restored, give up for now. - throw new InvalidPipeException("D3DSD.initSurface: pData " + - "or pCtx is null"); + sg2d.drawpipe = nonTxPipe; + sg2d.fillpipe = nonTxPipe; + } + // Note that we use the transforming pipe here because it + // will examine the shape and possibly perform an optimized + // operation if it can be simplified. The simplifications + // will be valid for all STROKE and TRANSFORM types. + sg2d.shapepipe = txPipe; + } else { + if (!validated) { + super.validatePipe(sg2d); } } - return pFormat; + + // install the text pipe based on our earlier decision + sg2d.textpipe = textpipe; + + // always override the image pipe with the specialized D3D pipe + sg2d.imagepipe = d3dImagePipe; + } + + @Override + protected MaskFill getMaskFill(SunGraphics2D sg2d) { + if (sg2d.paintState > sg2d.PAINT_ALPHACOLOR) { + /* + * We can only accelerate non-Color MaskFill operations if + * all of the following conditions hold true: + * - there is an implementation for the given paintState + * - the current Paint can be accelerated for this destination + * - multitexturing is available (since we need to modulate + * the alpha mask texture with the paint texture) + * + * In all other cases, we return null, in which case the + * validation code will choose a more general software-based loop. + */ + if (!D3DPaints.isValid(sg2d) || + !graphicsDevice.isCapPresent(CAPS_MULTITEXTURE)) + { + return null; + } + } + return super.getMaskFill(sg2d); + } + + @Override + public boolean copyArea(SunGraphics2D sg2d, + int x, int y, int w, int h, int dx, int dy) + { + if (sg2d.transformState < sg2d.TRANSFORM_TRANSLATESCALE && + sg2d.compositeState < sg2d.COMP_XOR) + { + x += sg2d.transX; + y += sg2d.transY; + + d3dRenderPipe.copyArea(sg2d, x, y, w, h, dx, dy); + + return true; + } + return false; } @Override - public void validatePipe(SunGraphics2D sg2d) { - // we don't support COMP_XOR yet.. - if (sg2d.compositeState < sg2d.COMP_XOR) { - TextPipe textpipe; - boolean validated = false; + public void flush() { + D3DRenderQueue rq = D3DRenderQueue.getInstance(); + rq.lock(); + try { + RenderBuffer buf = rq.getBuffer(); + rq.ensureCapacityAndAlignment(12, 4); + buf.putInt(FLUSH_SURFACE); + buf.putLong(getNativeOps()); + + // this call is expected to complete synchronously, so flush now + rq.flushNow(); + } finally { + rq.unlock(); + } + } + + /** + * Disposes the native resources associated with the given D3DSurfaceData + * (referenced by the pData parameter). This method is invoked from + * the native Dispose() method from the Disposer thread when the + * Java-level D3DSurfaceData object is about to go away. + */ + static void dispose(long pData) { + D3DRenderQueue rq = D3DRenderQueue.getInstance(); + rq.lock(); + try { + RenderBuffer buf = rq.getBuffer(); + rq.ensureCapacityAndAlignment(12, 4); + buf.putInt(DISPOSE_SURFACE); + buf.putLong(pData); + + // this call is expected to complete synchronously, so flush now + rq.flushNow(); + } finally { + rq.unlock(); + } + } - if (((sg2d.compositeState <= sg2d.COMP_ISCOPY && - sg2d.paintState <= sg2d.PAINT_ALPHACOLOR) || - (sg2d.compositeState == sg2d.COMP_ALPHA && - sg2d.paintState <= sg2d.PAINT_ALPHACOLOR && - (((AlphaComposite)sg2d.composite).getRule() == - AlphaComposite.SRC_OVER))) && - sg2d.textAntialiasHint <= SunHints.INTVAL_TEXT_ANTIALIAS_GASP) - { - // D3DTextRenderer handles both AA and non-AA text, but - // only works if composite is SrcNoEa or SrcOver - textpipe = d3dTextPipe; - } else { - // do this to initialize textpipe correctly; we will attempt - // to override the non-text pipes below - super.validatePipe(sg2d); - textpipe = sg2d.textpipe; - validated = true; + static void swapBuffers(D3DSurfaceData sd, + final int x1, final int y1, + final int x2, final int y2) + { + long pData = sd.getNativeOps(); + D3DRenderQueue rq = D3DRenderQueue.getInstance(); + // swapBuffers can be called from the toolkit thread by swing, we + // should detect this and prevent the deadlocks + if (rq.isRenderQueueThread()) { + if (!rq.tryLock()) { + // if we could not obtain the lock, repaint the area + // that was supposed to be swapped, and no-op this swap + final Component target = (Component)sd.getPeer().getTarget(); + SunToolkit.executeOnEventHandlerThread(target, new Runnable() { + public void run() { + target.repaint(x1, y1, x2, y2); + } + }); + return; } + } else { + rq.lock(); + } + try { + RenderBuffer buf = rq.getBuffer(); + rq.ensureCapacityAndAlignment(28, 4); + buf.putInt(SWAP_BUFFERS); + buf.putLong(pData); + buf.putInt(x1); + buf.putInt(y1); + buf.putInt(x2); + buf.putInt(y2); + rq.flushNow(); + } finally { + rq.unlock(); + } + } + + /** + * Returns destination Image associated with this SurfaceData. + */ + public Object getDestination() { + return offscreenImage; + } - if (sg2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON && - sg2d.paintState <= sg2d.PAINT_ALPHACOLOR) - { - sg2d.drawpipe = - sg2d.strokeState == sg2d.STROKE_THIN ? d3dPipe : d3dTxPipe; - sg2d.fillpipe = d3dPipe; - sg2d.shapepipe = d3dPipe; - } else if (!validated) { - super.validatePipe(sg2d); - } - // install the text pipe based on our earlier decision - sg2d.textpipe = textpipe; + public Rectangle getBounds() { + if (type == FLIP_BACKBUFFER || type == WINDOW) { + Rectangle r = peer.getBounds(); + r.x = r.y = 0; + return r; } else { - super.validatePipe(sg2d); + return new Rectangle(width, height); } + } + + public Rectangle getNativeBounds() { + D3DRenderQueue rq = D3DRenderQueue.getInstance(); + // need to lock to make sure nativeWidth and Height are consistent + // since they are set from the render thread from the native + // level + rq.lock(); + try { + // REMIND: use xyoffsets? + return new Rectangle(nativeWidth, nativeHeight); + } finally { + rq.unlock(); + } + } + - // always override the image pipe with the specialized D3D pipe - sg2d.imagepipe = d3dDrawImagePipe; + public GraphicsConfiguration getDeviceConfiguration() { + return graphicsDevice.getDefaultConfiguration(); + } + + public SurfaceData getReplacement() { + return restoreContents(offscreenImage); + } + + private static D3DGraphicsConfig getGC(WComponentPeer peer) { + GraphicsConfiguration gc; + if (peer != null) { + gc = peer.getGraphicsConfiguration(); + } else { + GraphicsEnvironment env = + GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice gd = env.getDefaultScreenDevice(); + gc = gd.getDefaultConfiguration(); + } + return (gc instanceof D3DGraphicsConfig) ? (D3DGraphicsConfig)gc : null; } /** - * Disables D3D acceleration on the surface manager of this surfaceData - * object. This can happen when we encounter a hard error in rendering a D3D - * primitive (for example, if we were unable to set a surface as D3D target - * surface). - * Upon next validation the SurfaceManager will create a non-D3D surface. + * Attempts to restore the surface by initializing the native data */ - public void disableD3D() { - markSurfaceLost(); - SurfaceManager sMgr = SurfaceManager.getManager(image); - if (sMgr instanceof WinVolatileSurfaceManager) { - ((WinVolatileSurfaceManager)sMgr).setD3DAccelerationEnabled(false); + void restoreSurface() { + initSurface(); + } + + WComponentPeer getPeer() { + return peer; + } + + /** + * We need to let the surface manager know that the surface is lost so + * that for example BufferStrategy.contentsLost() returns correct result. + * Normally the status of contentsLost is set in validate(), but in some + * cases (like Swing's buffer per window) we intentionally don't call + * validate from the toolkit thread but only check for the BS status. + */ + @Override + public void setSurfaceLost(boolean lost) { + super.setSurfaceLost(lost); + if (lost && offscreenImage != null) { + SurfaceManager sm = SurfaceManager.getManager(offscreenImage); + sm.acceleratedSurfaceLost(); } } - @Override - public boolean surfacePunted() { - // Punting is disabled for D3D surfaces - return false; + private static native long getNativeResourceNative(long sdops, int resType); + /** + * Returns a pointer to the native resource of specified {@code resType} + * associated with this surface. + * + * Specifically, for {@code D3DSurfaceData} this method returns pointers of + * the following: + *
+     * TEXTURE              - (IDirect3DTexture9*)
+     * RT_TEXTURE, RT_PLAIN - (IDirect3DSurface9*)
+     * FLIP_BACKBUFFER      - (IDirect3DSwapChain9*)
+     * D3D_DEVICE_RESOURCE  - (IDirect3DDevice9*)
+     * 
+ * + * Multiple resources may be available for some types (i.e. for render to + * texture one could retrieve both a destination surface by specifying + * RT_TEXTURE, and a texture by using TEXTURE). + * + * Note: the pointer returned by this method is only valid on the rendering + * thread. + * + * @return pointer to the native resource of specified type or 0L if + * such resource doesn't exist or can not be retrieved. + * @see sun.java2d.pipe.hw.AccelSurface#getNativeResource + */ + public long getNativeResource(int resType) { + return getNativeResourceNative(getNativeOps(), resType); } - D3DContext getContext() { - return ((Win32GraphicsDevice)graphicsConfig.getDevice()).getD3DContext(); + /** + * Class representing an on-screen d3d surface. Since d3d can't + * render to the screen directly, it is implemented as a swap chain, + * controlled by D3DScreenUpdateManager. + * + * @see D3DScreenUpdateManager + */ + public static class D3DWindowSurfaceData extends D3DSurfaceData { + StateTracker dirtyTracker; + + public D3DWindowSurfaceData(WComponentPeer peer, + D3DGraphicsConfig gc) + { + super(peer, gc, + peer.getBounds().width, peer.getBounds().height, + null, peer.getColorModel(), 1, SWAP_COPY, VSYNC_DEFAULT, + WINDOW); + dirtyTracker = getStateTracker(); + } + + /** + * {@inheritDoc} + * + * Overridden to use ScreenUpdateManager to obtain the replacement + * surface. + * + * @see sun.java2d.ScreenUpdateManager#getReplacementScreenSurface + */ + @Override + public SurfaceData getReplacement() { + ScreenUpdateManager mgr = ScreenUpdateManager.getInstance(); + return mgr.getReplacementScreenSurface(peer, this); + } + + /** + * Returns destination Component associated with this SurfaceData. + */ + @Override + public Object getDestination() { + return peer.getTarget(); + } + + @Override + void restoreSurface() { + Window fsw = graphicsDevice.getFullScreenWindow(); + if (fsw != null && fsw != peer.getTarget()) { + throw new InvalidPipeException("Can't restore onscreen surface"+ + " when in full-screen mode"); + } + super.restoreSurface(); + // if initialization was unsuccessful, an IPE will be thrown + // and the surface will remain lost + setSurfaceLost(false); + + // This is to make sure the render target is reset after this + // surface is restored. The reason for this is that sometimes this + // surface can be restored from multiple threads (the screen update + // manager's thread and app's rendering thread) at the same time, + // and when that happens the second restoration will create the + // native resource which will not be set as render target because + // the BufferedContext's validate method will think that since the + // surface data object didn't change then the current render target + // is correct and no rendering will appear on the screen. + D3DRenderQueue rq = D3DRenderQueue.getInstance(); + rq.lock(); + try { + getContext().invalidateContext(); + } finally { + rq.unlock(); + } + } + + public boolean isDirty() { + return !dirtyTracker.isCurrent(); + } + + public void markClean() { + dirtyTracker = getStateTracker(); + } } + + /** + * Updates the layered window with the contents of the surface. + * + * @param pd3dsd pointer to the D3DSDOps structure + * @param pData pointer to the AwtWindow peer data + * @param w width of the window + * @param h height of the window + * @see sun.awt.windows.TranslucentWindowPainter + */ + public static native boolean updateWindowAccelImpl(long pd3dsd, long pData, + int w, int h); }