aboutsummaryrefslogtreecommitdiff
path: root/src/windows/classes/sun/java2d/d3d/D3DSurfaceData.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/windows/classes/sun/java2d/d3d/D3DSurfaceData.java')
-rw-r--r--src/windows/classes/sun/java2d/d3d/D3DSurfaceData.java1159
1 files changed, 823 insertions, 336 deletions
diff --git a/src/windows/classes/sun/java2d/d3d/D3DSurfaceData.java b/src/windows/classes/sun/java2d/d3d/D3DSurfaceData.java
index 2dd7a183b..3d1457c72 100644
--- a/src/windows/classes/sun/java2d/d3d/D3DSurfaceData.java
+++ b/src/windows/classes/sun/java2d/d3d/D3DSurfaceData.java
@@ -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.*;
+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 class D3DSurfaceData extends Win32OffScreenSurfaceData {
+/**
+ * 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 {
- // properties of a surface
/**
- * This property is used for a back-buffer surface
+ * To be used with getNativeResource() only.
+ * @see #getNativeResource()
*/
- 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_DEVICE_RESOURCE= 100;
+ /*
+ * Surface types.
+ * We use these surface types when copying from a sw surface
+ * to a surface or texture.
*/
- public static final int D3D_RENDER_TARGET = (1 << 16);
-
- 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 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;
+
+ /** 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
*/
- public static final int
- D3D_PLAIN_SURFACE = (1 << 0) | D3D_RENDER_TARGET;
+ 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";
+
+ // 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);
+
+ 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;
+
+ private int swapEffect;
+ private VSyncType syncType;
+ private int backBuffersNum;
+
+ private WritableRasterNative wrn;
+
+ protected static D3DRenderer d3dRenderPipe;
+ protected static PixelToParallelogramConverter d3dTxRenderPipe;
+ protected static ParallelogramPipe d3dAAPgramPipe;
+ protected static D3DTextRenderer d3dTextPipe;
+ protected static D3DDrawImage d3dImagePipe;
+
+ 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 {
+ 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();
+ }
+
+ 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;
+
+ 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) {
+ return D3DSurfaceDataProxy.
+ createProxy(srcData,
+ (D3DGraphicsConfig)graphicsDevice.getDefaultConfiguration());
+ }
+
/**
- * Direct3D texture. Mostly used for cached accelerated surfaces.
- * Surfaces of this type can be copied from using hardware acceleration
- * by using texture mapping.
+ * Creates a SurfaceData object representing the back buffer of a
+ * double-buffered on-screen Window.
*/
- public static final int
- D3D_TEXTURE_SURFACE = (1 << 1);
+ 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);
+ }
+
/**
- * Direct3D Backbuffer surface - an attached surface. Used for
- * multibuffered BufferStrategies.
+ * 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.
+ *
+ * @param peer peer for which the onscreen surface is to be created
+ * @return a D3DWindowSurfaceData (flip chain) surface
*/
- public static final int
- D3D_BACKBUFFER_SURFACE = D3D_PLAIN_SURFACE | D3D_ATTACHED_SURFACE;
+ public static D3DSurfaceData createData(WComponentPeer peer) {
+ D3DGraphicsConfig gc = getGC(peer);
+ if (gc == null || !peer.isAccelCapable()) {
+ return null;
+ }
+ return new D3DWindowSurfaceData(peer, gc);
+ }
+
/**
- * 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)
+ * Creates a SurfaceData object representing an off-screen buffer (either
+ * a plain surface or Texture).
*/
- 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";
+ public static D3DSurfaceData createData(D3DGraphicsConfig gc,
+ int width, int height,
+ ColorModel cm,
+ Image image, int type)
+ {
+ 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;
+ }
/**
- * 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.
+ * Returns the appropriate SurfaceType corresponding to the given D3D
+ * surface type constant (e.g. TEXTURE -> D3DTexture).
*/
- public static final String
- DESC_DEST_D3D = "D3D render target";
+ private static SurfaceType getCustomSurfaceType(int d3dType) {
+ switch (d3dType) {
+ case TEXTURE:
+ return D3DTexture;
+ case RT_TEXTURE:
+ return D3DSurfaceRTT;
+ default:
+ return D3DSurface;
+ }
+ }
- public static final SurfaceType D3DSurface =
- SurfaceType.Any.deriveSubType("Direct3D Surface");
- public static final SurfaceType D3DTexture =
- D3DSurface.deriveSubType("Direct3D Texture");
+ 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;
+ }
+ }
/**
- * 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.
+ * 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.
*/
- public static final SurfaceType IntRgbD3D =
- IntRgbDD.deriveSubType(DESC_DEST_D3D);
-
- public static final SurfaceType IntRgbxD3D =
- IntRgbxDD.deriveSubType(DESC_DEST_D3D);
+ 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();
+ }
+ });
+ if (!status.success) {
+ throw new InvalidPipeException("Error creating D3DSurface");
+ }
+ } finally {
+ rq.unlock();
+ }
+ }
- public static final SurfaceType Ushort565RgbD3D =
- Ushort565RgbDD.deriveSubType(DESC_DEST_D3D);
+ /**
+ * Returns the D3DContext for the GraphicsConfig associated with this
+ * surface.
+ */
+ public final D3DContext getContext() {
+ return graphicsDevice.getContext();
+ }
- public static final SurfaceType Ushort555RgbxD3D =
- Ushort555RgbxDD.deriveSubType(DESC_DEST_D3D);
+ /**
+ * Returns one of the surface type constants defined above.
+ */
+ public final int getType() {
+ return type;
+ }
- public static final SurfaceType Ushort555RgbD3D =
- Ushort555RgbDD.deriveSubType(DESC_DEST_D3D);
+ 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);
+ }
- // REMIND: Is it possible to have d3d accelerated on this type of surface?
- public static final SurfaceType ThreeByteBgrD3D =
- ThreeByteBgrDD.deriveSubType(DESC_DEST_D3D);
+ 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);
+ }
+ });
+ } finally {
+ retPixel = pixel;
+ rq.unlock();
+ }
+ return retPixel;
+ }
- public static final SurfaceType IntArgbD3D =
- SurfaceType.IntArgb.deriveSubType(DESC_INT_ARGB_D3D);
+ 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);
+ }
+ });
+ sData.markDirty();
+ } finally {
+ rq.unlock();
+ }
+ }
+ }
- public static final SurfaceType Ushort4444ArgbD3D =
- SurfaceType.Ushort4444Argb.deriveSubType(DESC_USHORT_4444_ARGB_D3D);
+ 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;
- // Textures we can render to using d3d
- public static final SurfaceType IntRgbD3D_RTT =
- IntRgbD3D.deriveSubType(DESC_DEST_D3D);
+ if (dcm.getPixelSize() == 24 || dcm.getPixelSize() == 32) {
+ dataType = DataBuffer.TYPE_INT;
+ } else {
+ // 15, 16
+ dataType = DataBuffer.TYPE_USHORT;
+ }
- public static final SurfaceType IntRgbxD3D_RTT =
- IntRgbxD3D.deriveSubType(DESC_DEST_D3D);
+ // 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);
+ }
- public static final SurfaceType Ushort565RgbD3D_RTT =
- Ushort565RgbD3D.deriveSubType(DESC_DEST_D3D);
+ return wrn;
+ }
- public static final SurfaceType Ushort555RgbxD3D_RTT =
- Ushort555RgbxD3D.deriveSubType(DESC_DEST_D3D);
+ /**
+ * 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 static final SurfaceType Ushort555RgbD3D_RTT =
- Ushort555RgbD3D.deriveSubType(DESC_DEST_D3D);
+ public void validatePipe(SunGraphics2D sg2d) {
+ TextPipe textpipe;
+ boolean validated = false;
- public static final SurfaceType Ushort4444ArgbD3D_RTT =
- Ushort4444ArgbD3D.deriveSubType(DESC_DEST_D3D);
+ // 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;
+ }
- public static final SurfaceType IntArgbD3D_RTT =
- IntArgbD3D.deriveSubType(DESC_DEST_D3D);
+ // 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;
+ }
- public static final SurfaceType ThreeByteBgrD3D_RTT =
- ThreeByteBgrD3D.deriveSubType(DESC_DEST_D3D);
+ PixelToParallelogramConverter txPipe = null;
+ D3DRenderer nonTxPipe = null;
- // the type of this surface - texture, plain, back-buffer
- protected int type;
- protected int pixelFormat;
+ 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
+ }
+ } 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
+ }
- private D3DContext d3dContext;
+ 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 {
+ 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);
+ }
+ }
- protected static D3DRenderer d3dPipe;
- protected static PixelToShapeConverter d3dTxPipe;
- protected static D3DTextRenderer d3dTextPipe;
- protected static D3DDrawImage d3dDrawImagePipe;
+ // install the text pipe based on our earlier decision
+ sg2d.textpipe = textpipe;
- private native void initOps(int depth, int transparency);
+ // always override the image pipe with the specialized D3D pipe
+ sg2d.imagepipe = d3dImagePipe;
+ }
- static {
- if (WindowsFlags.isD3DEnabled()) {
- D3DBlitLoops.register();
- D3DMaskFill.register();
+ @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);
+ }
- d3dPipe = new D3DRenderer();
- d3dTxPipe = new PixelToShapeConverter(d3dPipe);
- d3dTextPipe = new D3DTextRenderer();
- d3dDrawImagePipe = new D3DDrawImage();
+ @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;
- if (GraphicsPrimitive.tracingEnabled()) {
- d3dPipe = d3dPipe.traceWrapD3D();
- d3dTextPipe = d3dTextPipe.traceWrap();
+ d3dRenderPipe.copyArea(sg2d, x, y, w, h, dx, dy);
+
+ return true;
}
+ return false;
}
@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;
+ 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();
+ }
}
/**
- * Non-public constructor. Use createData() to create an object.
- *
- * 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.
+ * 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.
*/
- protected D3DSurfaceData(int width, int height,
- int d3dSurfaceType,
- SurfaceType sType, ColorModel cm,
- GraphicsConfiguration gc,
- Image image, int transparency)
+ 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();
+ }
+ }
+
+ static void swapBuffers(D3DSurfaceData sd,
+ final int x1, final int y1,
+ final int x2, final int y2)
{
- super(width, height, sType, cm, gc, image, transparency);
- this.type = d3dSurfaceType;
+ 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();
+ }
}
/**
- * 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 destination Image associated with this SurfaceData.
*/
- 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*/);
+ public Object getDestination() {
+ return offscreenImage;
}
- 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;
+ public Rectangle getBounds() {
+ if (type == FLIP_BACKBUFFER || type == WINDOW) {
+ Rectangle r = peer.getBounds();
+ r.x = r.y = 0;
+ return r;
+ } else {
+ return new Rectangle(width, height);
}
+ }
- return new D3DSurfaceData(width, height,
- d3dSurfaceType,
- getSurfaceType(gc, cm, d3dSurfaceType),
- cm, gc, image,
- cm.getTransparency(), gd.getScreen());
+ 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();
+ }
}
- int getPixelFormat() {
- return pixelFormat;
+
+ public GraphicsConfiguration getDeviceConfiguration() {
+ return graphicsDevice.getDefaultConfiguration();
}
- 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;
+ public SurfaceData getReplacement() {
+ return restoreContents(offscreenImage);
+ }
+
+ private static D3DGraphicsConfig getGC(WComponentPeer peer) {
+ GraphicsConfiguration gc;
+ if (peer != null) {
+ gc = peer.getGraphicsConfiguration();
} 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*/;
- }
- } 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;
- }
- 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;
- }
- case 8: // not supported
- default:
- throw new sun.java2d.InvalidPipeException("Unsupported bit " +
- "depth: " +
- cm.getPixelSize());
- }
- }
+ GraphicsEnvironment env =
+ GraphicsEnvironment.getLocalGraphicsEnvironment();
+ GraphicsDevice gd = env.getDefaultScreenDevice();
+ gc = gd.getDefaultConfiguration();
}
+ return (gc instanceof D3DGraphicsConfig) ? (D3DGraphicsConfig)gc : null;
}
- private native int initOffScreenSurface(long pCtx,
- long pData, long parentPdata,
- int width, int height,
- int type, int screen);
-
- protected int initSurface(int width, int height, int screen,
- Win32SurfaceData parentData)
- {
- int pFormat = PF_INVALID;
+ /**
+ * Attempts to restore the surface by initializing the native data
+ */
+ void restoreSurface() {
+ initSurface();
+ }
- synchronized (D3DContext.LOCK) {
- long pData = getNativeOps();
- long pDataParent = 0L;
- if (parentData != null) {
- pDataParent = parentData.getNativeOps();
- }
- 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();
- }
- if (pData != 0 && pCtx != 0) {
- pFormat = initOffScreenSurface(pCtx,
- pData, pDataParent,
- width, height, type, screen);
- } else {
- // if the context can't be restored, give up for now.
- throw new InvalidPipeException("D3DSD.initSurface: pData " +
- "or pCtx is null");
- }
- }
- return pFormat;
+ 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 validatePipe(SunGraphics2D sg2d) {
- // we don't support COMP_XOR yet..
- if (sg2d.compositeState < sg2d.COMP_XOR) {
- TextPipe textpipe;
- boolean validated = false;
-
- 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;
- }
-
- 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;
- } else {
- super.validatePipe(sg2d);
+ public void setSurfaceLost(boolean lost) {
+ super.setSurfaceLost(lost);
+ if (lost && offscreenImage != null) {
+ SurfaceManager sm = SurfaceManager.getManager(offscreenImage);
+ sm.acceleratedSurfaceLost();
}
+ }
- // always override the image pipe with the specialized D3D pipe
- sg2d.imagepipe = d3dDrawImagePipe;
+ 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:
+ * <pre>
+ * TEXTURE - (IDirect3DTexture9*)
+ * RT_TEXTURE, RT_PLAIN - (IDirect3DSurface9*)
+ * FLIP_BACKBUFFER - (IDirect3DSwapChain9*)
+ * D3D_DEVICE_RESOURCE - (IDirect3DDevice9*)
+ * </pre>
+ *
+ * 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);
}
/**
- * 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.
+ * 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 void disableD3D() {
- markSurfaceLost();
- SurfaceManager sMgr = SurfaceManager.getManager(image);
- if (sMgr instanceof WinVolatileSurfaceManager) {
- ((WinVolatileSurfaceManager)sMgr).setD3DAccelerationEnabled(false);
+ 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();
}
- }
- @Override
- public boolean surfacePunted() {
- // Punting is disabled for D3D surfaces
- return false;
- }
+ /**
+ * {@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);
+ }
- D3DContext getContext() {
- return ((Win32GraphicsDevice)graphicsConfig.getDevice()).getD3DContext();
+ /**
+ * 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);
}