nine: Add state tracker nine for Direct3D9 (v3)
authorJoakim Sindholt <opensource@zhasha.com>
Thu, 4 Aug 2011 13:14:06 +0000 (15:14 +0200)
committerEmil Velikov <emil.l.velikov@gmail.com>
Tue, 18 Nov 2014 02:02:54 +0000 (02:02 +0000)
Work of Joakim Sindholt (zhasha) and Christoph Bumiller (chrisbmr).
DRI3 port done by Axel Davy (mannerov).

v2: - nine_debug.c: klass extended from 32 chars to 96 (for sure) by glennk
    - Nine improvements by Axel Davy (which also fixed some wine tests)
    - by Emil Velikov:
     - convert to static/shared drivers
     - Sort and cleanup the includes
     - Use AM_CPPFLAGS for the defines
     - Add the linker garbage collector
     - Restrict the exported symbols (think llvm)

v3: - small nine fixes
    - build system improvements by Emil Velikov

v4: [Emil Velikov]
   - Do no link against libudev. No longer needed.

Acked-by: Jose Fonseca <jfonseca@vmware.com>
Reviewed-by: Marek Olšák <marek.olsak@amd.com>
Reviewed-by: Axel Davy <axel.davy@ens.fr>
Signed-off-by: David Heidelberg <david@ixit.cz>
87 files changed:
configure.ac
include/D3D9/d3d9.h [new file with mode: 0644]
include/D3D9/d3d9caps.h [new file with mode: 0644]
include/D3D9/d3d9types.h [new file with mode: 0644]
include/d3dadapter/d3dadapter9.h [new file with mode: 0644]
include/d3dadapter/drm.h [new file with mode: 0644]
include/d3dadapter/present.h [new file with mode: 0644]
src/gallium/Makefile.am
src/gallium/auxiliary/target-helpers/inline_sw_helper.h
src/gallium/state_trackers/nine/Makefile.am [new file with mode: 0644]
src/gallium/state_trackers/nine/Makefile.sources [new file with mode: 0644]
src/gallium/state_trackers/nine/README [new file with mode: 0644]
src/gallium/state_trackers/nine/adapter9.c [new file with mode: 0644]
src/gallium/state_trackers/nine/adapter9.h [new file with mode: 0644]
src/gallium/state_trackers/nine/authenticatedchannel9.c [new file with mode: 0644]
src/gallium/state_trackers/nine/authenticatedchannel9.h [new file with mode: 0644]
src/gallium/state_trackers/nine/basetexture9.c [new file with mode: 0644]
src/gallium/state_trackers/nine/basetexture9.h [new file with mode: 0644]
src/gallium/state_trackers/nine/cryptosession9.c [new file with mode: 0644]
src/gallium/state_trackers/nine/cryptosession9.h [new file with mode: 0644]
src/gallium/state_trackers/nine/cubetexture9.c [new file with mode: 0644]
src/gallium/state_trackers/nine/cubetexture9.h [new file with mode: 0644]
src/gallium/state_trackers/nine/device9.c [new file with mode: 0644]
src/gallium/state_trackers/nine/device9.h [new file with mode: 0644]
src/gallium/state_trackers/nine/device9ex.c [new file with mode: 0644]
src/gallium/state_trackers/nine/device9ex.h [new file with mode: 0644]
src/gallium/state_trackers/nine/device9video.c [new file with mode: 0644]
src/gallium/state_trackers/nine/device9video.h [new file with mode: 0644]
src/gallium/state_trackers/nine/guid.c [new file with mode: 0644]
src/gallium/state_trackers/nine/guid.h [new file with mode: 0644]
src/gallium/state_trackers/nine/indexbuffer9.c [new file with mode: 0644]
src/gallium/state_trackers/nine/indexbuffer9.h [new file with mode: 0644]
src/gallium/state_trackers/nine/iunknown.c [new file with mode: 0644]
src/gallium/state_trackers/nine/iunknown.h [new file with mode: 0644]
src/gallium/state_trackers/nine/nine_debug.c [new file with mode: 0644]
src/gallium/state_trackers/nine/nine_debug.h [new file with mode: 0644]
src/gallium/state_trackers/nine/nine_defines.h [new file with mode: 0644]
src/gallium/state_trackers/nine/nine_dump.c [new file with mode: 0644]
src/gallium/state_trackers/nine/nine_dump.h [new file with mode: 0644]
src/gallium/state_trackers/nine/nine_ff.c [new file with mode: 0644]
src/gallium/state_trackers/nine/nine_ff.h [new file with mode: 0644]
src/gallium/state_trackers/nine/nine_helpers.c [new file with mode: 0644]
src/gallium/state_trackers/nine/nine_helpers.h [new file with mode: 0644]
src/gallium/state_trackers/nine/nine_lock.c [new file with mode: 0644]
src/gallium/state_trackers/nine/nine_lock.h [new file with mode: 0644]
src/gallium/state_trackers/nine/nine_pdata.h [new file with mode: 0644]
src/gallium/state_trackers/nine/nine_pipe.c [new file with mode: 0644]
src/gallium/state_trackers/nine/nine_pipe.h [new file with mode: 0644]
src/gallium/state_trackers/nine/nine_quirk.c [new file with mode: 0644]
src/gallium/state_trackers/nine/nine_quirk.h [new file with mode: 0644]
src/gallium/state_trackers/nine/nine_shader.c [new file with mode: 0644]
src/gallium/state_trackers/nine/nine_shader.h [new file with mode: 0644]
src/gallium/state_trackers/nine/nine_state.c [new file with mode: 0644]
src/gallium/state_trackers/nine/nine_state.h [new file with mode: 0644]
src/gallium/state_trackers/nine/nineexoverlayextension.c [new file with mode: 0644]
src/gallium/state_trackers/nine/nineexoverlayextension.h [new file with mode: 0644]
src/gallium/state_trackers/nine/pixelshader9.c [new file with mode: 0644]
src/gallium/state_trackers/nine/pixelshader9.h [new file with mode: 0644]
src/gallium/state_trackers/nine/query9.c [new file with mode: 0644]
src/gallium/state_trackers/nine/query9.h [new file with mode: 0644]
src/gallium/state_trackers/nine/resource9.c [new file with mode: 0644]
src/gallium/state_trackers/nine/resource9.h [new file with mode: 0644]
src/gallium/state_trackers/nine/stateblock9.c [new file with mode: 0644]
src/gallium/state_trackers/nine/stateblock9.h [new file with mode: 0644]
src/gallium/state_trackers/nine/surface9.c [new file with mode: 0644]
src/gallium/state_trackers/nine/surface9.h [new file with mode: 0644]
src/gallium/state_trackers/nine/swapchain9.c [new file with mode: 0644]
src/gallium/state_trackers/nine/swapchain9.h [new file with mode: 0644]
src/gallium/state_trackers/nine/swapchain9ex.c [new file with mode: 0644]
src/gallium/state_trackers/nine/swapchain9ex.h [new file with mode: 0644]
src/gallium/state_trackers/nine/texture9.c [new file with mode: 0644]
src/gallium/state_trackers/nine/texture9.h [new file with mode: 0644]
src/gallium/state_trackers/nine/vertexbuffer9.c [new file with mode: 0644]
src/gallium/state_trackers/nine/vertexbuffer9.h [new file with mode: 0644]
src/gallium/state_trackers/nine/vertexdeclaration9.c [new file with mode: 0644]
src/gallium/state_trackers/nine/vertexdeclaration9.h [new file with mode: 0644]
src/gallium/state_trackers/nine/vertexshader9.c [new file with mode: 0644]
src/gallium/state_trackers/nine/vertexshader9.h [new file with mode: 0644]
src/gallium/state_trackers/nine/volume9.c [new file with mode: 0644]
src/gallium/state_trackers/nine/volume9.h [new file with mode: 0644]
src/gallium/state_trackers/nine/volumetexture9.c [new file with mode: 0644]
src/gallium/state_trackers/nine/volumetexture9.h [new file with mode: 0644]
src/gallium/targets/d3dadapter9/Makefile.am [new file with mode: 0644]
src/gallium/targets/d3dadapter9/d3d.pc.in [new file with mode: 0644]
src/gallium/targets/d3dadapter9/d3dadapter9.sym [new file with mode: 0644]
src/gallium/targets/d3dadapter9/drm.c [new file with mode: 0644]
src/gallium/targets/d3dadapter9/getproc.c [new file with mode: 0644]

index 8aa070d2125d85c1b442f6690d3a8b239529928e..33cbf227ddc694b0fac9ec226617cf83f1737fc3 100644 (file)
@@ -669,6 +669,11 @@ AC_ARG_ENABLE([gbm],
          [enable gbm library @<:@default=auto@:>@])],
    [enable_gbm="$enableval"],
    [enable_gbm=auto])
+AC_ARG_ENABLE([nine],
+    [AS_HELP_STRING([--enable-nine],
+        [enable build of the nine Direct3D9 API @<:@default=no@:>@])],
+    [enable_nine="$enableval"],
+    [enable_nine=no])
 
 AC_ARG_ENABLE([xvmc],
    [AS_HELP_STRING([--enable-xvmc],
@@ -742,6 +747,7 @@ esac
 if test "x$enable_opengl" = xno -a \
         "x$enable_gles1" = xno -a \
         "x$enable_gles2" = xno -a \
+        "x$enable_nine" = xno -a \
         "x$enable_openvg" = xno -a \
         "x$enable_xa" = xno -a \
         "x$enable_xvmc" = xno -a \
@@ -1394,6 +1400,24 @@ if test "x$enable_va" = xyes; then
 fi
 AM_CONDITIONAL(HAVE_ST_VA, test "x$enable_va" = xyes)
 
+dnl
+dnl Nine Direct3D9 configuration
+dnl
+if test "x$enable_nine" = xyes; then
+    if ! echo "$with_gallium_drivers" | grep -q 'swrast'; then
+        AC_MSG_ERROR([nine requires the gallium swrast driver])
+    fi
+    if test "x$with_gallium_drivers" == xswrast; then
+        AC_MSG_ERROR([nine requires at least one non-swrast gallium driver])
+    fi
+    if test "x$enable_dri3" = xno; then
+        AC_MSG_WARN([using nine together with wine requires DRI3 enabled system])
+    fi
+
+    enable_gallium_loader=$enable_shared_pipe_drivers
+fi
+AM_CONDITIONAL(HAVE_ST_NINE, test "x$enable_nine" = xyes)
+
 dnl
 dnl OpenCL configuration
 dnl
@@ -1768,6 +1792,13 @@ AC_ARG_WITH([va-libdir],
     [VA_LIB_INSTALL_DIR="${libdir}/dri"])
 AC_SUBST([VA_LIB_INSTALL_DIR])
 
+AC_ARG_WITH([d3d-libdir],
+    [AS_HELP_STRING([--with-d3d-libdir=DIR],
+        [directory for the D3D modules @<:@${libdir}/d3d@:>@])],
+    [D3D_DRIVER_INSTALL_DIR="$withval"],
+    [D3D_DRIVER_INSTALL_DIR="${libdir}/d3d"])
+AC_SUBST([D3D_DRIVER_INSTALL_DIR])
+
 dnl
 dnl Gallium helper functions
 dnl
@@ -2052,6 +2083,9 @@ AM_CONDITIONAL(HAVE_X86_ASM, test "x$asm_arch" = xx86 -o "x$asm_arch" = xx86_64)
 AM_CONDITIONAL(HAVE_X86_64_ASM, test "x$asm_arch" = xx86_64)
 AM_CONDITIONAL(HAVE_SPARC_ASM, test "x$asm_arch" = xsparc)
 
+AC_SUBST([NINE_MAJOR], 1)
+AC_SUBST([NINE_MINOR], 0)
+
 AC_SUBST([VDPAU_MAJOR], 1)
 AC_SUBST([VDPAU_MINOR], 0)
 
@@ -2121,6 +2155,7 @@ AC_CONFIG_FILES([Makefile
                src/gallium/state_trackers/clover/Makefile
                src/gallium/state_trackers/dri/Makefile
                src/gallium/state_trackers/glx/xlib/Makefile
+               src/gallium/state_trackers/nine/Makefile
                src/gallium/state_trackers/omx/Makefile
                src/gallium/state_trackers/osmesa/Makefile
                src/gallium/state_trackers/va/Makefile
@@ -2128,6 +2163,8 @@ AC_CONFIG_FILES([Makefile
                src/gallium/state_trackers/vega/Makefile
                src/gallium/state_trackers/xa/Makefile
                src/gallium/state_trackers/xvmc/Makefile
+               src/gallium/targets/d3dadapter9/Makefile
+               src/gallium/targets/d3dadapter9/d3d.pc
                src/gallium/targets/dri/Makefile
                src/gallium/targets/egl-static/Makefile
                src/gallium/targets/gbm/Makefile
diff --git a/include/D3D9/d3d9.h b/include/D3D9/d3d9.h
new file mode 100644 (file)
index 0000000..f872be7
--- /dev/null
@@ -0,0 +1,1858 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+/*** THIS FILE IS AUTOGENERATED. DO NOT MODIFY MANUALLY. ***/
+
+#ifndef _D3D9_H_
+#define _D3D9_H_
+
+#include "d3d9types.h"
+#include "d3d9caps.h"
+
+typedef struct IDirect3D9 IDirect3D9, *PDIRECT3D9, *LPDIRECT3D9;
+typedef struct IDirect3D9Ex IDirect3D9Ex, *PDIRECT3D9EX, *LPDIRECT3D9EX;
+typedef struct IDirect3D9ExOverlayExtension IDirect3D9ExOverlayExtension, *PDIRECT3D9EXOVERLAYEXTENSION, *LPDIRECT3D9EXOVERLAYEXTENSION;
+typedef struct IDirect3DAuthenticatedChannel9 IDirect3DAuthenticatedChannel9, *PDIRECT3DAUTHENTICATEDCHANNEL9, *LPDIRECT3DAUTHENTICATEDCHANNEL9;
+typedef struct IDirect3DBaseTexture9 IDirect3DBaseTexture9, *PDIRECT3DBASETEXTURE9, *LPDIRECT3DBASETEXTURE9;
+typedef struct IDirect3DCryptoSession9 IDirect3DCryptoSession9, *PDIRECT3DCRYPTOSESSION9, *LPDIRECT3DCRYPTOSESSION9;
+typedef struct IDirect3DCubeTexture9 IDirect3DCubeTexture9, *PDIRECT3DCUBETEXTURE9, *LPDIRECT3DCUBETEXTURE9;
+typedef struct IDirect3DDevice9 IDirect3DDevice9, *PDIRECT3DDEVICE9, *LPDIRECT3DDEVICE9;
+typedef struct IDirect3DDevice9Ex IDirect3DDevice9Ex, *PDIRECT3DDEVICE9EX, *LPDIRECT3DDEVICE9EX;
+typedef struct IDirect3DDevice9Video IDirect3DDevice9Video, *PDIRECT3DDEVICE9VIDEO, *LPDIRECT3DDEVICE9VIDEO;
+typedef struct IDirect3DIndexBuffer9 IDirect3DIndexBuffer9, *PDIRECT3DINDEXBUFFER9, *LPDIRECT3DINDEXBUFFER9;
+typedef struct IDirect3DPixelShader9 IDirect3DPixelShader9, *PDIRECT3DPIXELSHADER9, *LPDIRECT3DPIXELSHADER9;
+typedef struct IDirect3DQuery9 IDirect3DQuery9, *PDIRECT3DQUERY9, *LPDIRECT3DQUERY9;
+typedef struct IDirect3DResource9 IDirect3DResource9, *PDIRECT3DRESOURCE9, *LPDIRECT3DRESOURCE9;
+typedef struct IDirect3DStateBlock9 IDirect3DStateBlock9, *PDIRECT3DSTATEBLOCK9, *LPDIRECT3DSTATEBLOCK9;
+typedef struct IDirect3DSurface9 IDirect3DSurface9, *PDIRECT3DSURFACE9, *LPDIRECT3DSURFACE9;
+typedef struct IDirect3DSwapChain9 IDirect3DSwapChain9, *PDIRECT3DSWAPCHAIN9, *LPDIRECT3DSWAPCHAIN9;
+typedef struct IDirect3DSwapChain9Ex IDirect3DSwapChain9Ex, *PDIRECT3DSWAPCHAIN9EX, *LPDIRECT3DSWAPCHAIN9EX;
+typedef struct IDirect3DTexture9 IDirect3DTexture9, *PDIRECT3DTEXTURE9, *LPDIRECT3DTEXTURE9;
+typedef struct IDirect3DVertexBuffer9 IDirect3DVertexBuffer9, *PDIRECT3DVERTEXBUFFER9, *LPDIRECT3DVERTEXBUFFER9;
+typedef struct IDirect3DVertexDeclaration9 IDirect3DVertexDeclaration9, *PDIRECT3DVERTEXDECLARATION9, *LPDIRECT3DVERTEXDECLARATION9;
+typedef struct IDirect3DVertexShader9 IDirect3DVertexShader9, *PDIRECT3DVERTEXSHADER9, *LPDIRECT3DVERTEXSHADER9;
+typedef struct IDirect3DVolume9 IDirect3DVolume9, *PDIRECT3DVOLUME9, *LPDIRECT3DVOLUME9;
+typedef struct IDirect3DVolumeTexture9 IDirect3DVolumeTexture9, *PDIRECT3DVOLUMETEXTURE9, *LPDIRECT3DVOLUMETEXTURE9;
+
+#ifdef __cplusplus
+
+extern "C" const GUID IID_IDirect3D9;
+extern "C" const GUID IID_IDirect3D9Ex;
+extern "C" const GUID IID_IDirect3D9ExOverlayExtension;
+extern "C" const GUID IID_IDirect3DAuthenticatedChannel9;
+extern "C" const GUID IID_IDirect3DBaseTexture9;
+extern "C" const GUID IID_IDirect3DCryptoSession9;
+extern "C" const GUID IID_IDirect3DCubeTexture9;
+extern "C" const GUID IID_IDirect3DDevice9;
+extern "C" const GUID IID_IDirect3DDevice9Ex;
+extern "C" const GUID IID_IDirect3DDevice9Video;
+extern "C" const GUID IID_IDirect3DIndexBuffer9;
+extern "C" const GUID IID_IDirect3DPixelShader9;
+extern "C" const GUID IID_IDirect3DQuery9;
+extern "C" const GUID IID_IDirect3DResource9;
+extern "C" const GUID IID_IDirect3DStateBlock9;
+extern "C" const GUID IID_IDirect3DSurface9;
+extern "C" const GUID IID_IDirect3DSwapChain9;
+extern "C" const GUID IID_IDirect3DSwapChain9Ex;
+extern "C" const GUID IID_IDirect3DTexture9;
+extern "C" const GUID IID_IDirect3DVertexBuffer9;
+extern "C" const GUID IID_IDirect3DVertexDeclaration9;
+extern "C" const GUID IID_IDirect3DVertexShader9;
+extern "C" const GUID IID_IDirect3DVolume9;
+extern "C" const GUID IID_IDirect3DVolumeTexture9;
+
+struct IDirect3D9 : public IUnknown
+{
+       virtual HRESULT WINAPI RegisterSoftwareDevice(void *pInitializeFunction) = 0;
+       virtual UINT WINAPI GetAdapterCount() = 0;
+       virtual HRESULT WINAPI GetAdapterIdentifier(UINT Adapter, DWORD Flags, D3DADAPTER_IDENTIFIER9 *pIdentifier) = 0;
+       virtual UINT WINAPI GetAdapterModeCount(UINT Adapter, D3DFORMAT Format) = 0;
+       virtual HRESULT WINAPI EnumAdapterModes(UINT Adapter, D3DFORMAT Format, UINT Mode, D3DDISPLAYMODE *pMode) = 0;
+       virtual HRESULT WINAPI GetAdapterDisplayMode(UINT Adapter, D3DDISPLAYMODE *pMode) = 0;
+       virtual HRESULT WINAPI CheckDeviceType(UINT Adapter, D3DDEVTYPE DevType, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, BOOL bWindowed) = 0;
+       virtual HRESULT WINAPI CheckDeviceFormat(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, DWORD Usage, D3DRESOURCETYPE RType, D3DFORMAT CheckFormat) = 0;
+       virtual HRESULT WINAPI CheckDeviceMultiSampleType(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SurfaceFormat, BOOL Windowed, D3DMULTISAMPLE_TYPE MultiSampleType, DWORD *pQualityLevels) = 0;
+       virtual HRESULT WINAPI CheckDepthStencilMatch(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, D3DFORMAT RenderTargetFormat, D3DFORMAT DepthStencilFormat) = 0;
+       virtual HRESULT WINAPI CheckDeviceFormatConversion(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SourceFormat, D3DFORMAT TargetFormat) = 0;
+       virtual HRESULT WINAPI GetDeviceCaps(UINT Adapter, D3DDEVTYPE DeviceType, D3DCAPS9 *pCaps) = 0;
+       virtual HMONITOR WINAPI GetAdapterMonitor(UINT Adapter) = 0;
+       virtual HRESULT WINAPI CreateDevice(UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS *pPresentationParameters, IDirect3DDevice9 **ppReturnedDeviceInterface) = 0;
+};
+
+struct IDirect3D9Ex : public IDirect3D9
+{
+       virtual UINT WINAPI GetAdapterModeCountEx(UINT Adapter, const D3DDISPLAYMODEFILTER *pFilter) = 0;
+       virtual HRESULT WINAPI EnumAdapterModesEx(UINT Adapter, const D3DDISPLAYMODEFILTER *pFilter, UINT Mode, D3DDISPLAYMODEEX *pMode) = 0;
+       virtual HRESULT WINAPI GetAdapterDisplayModeEx(UINT Adapter, D3DDISPLAYMODEEX *pMode, D3DDISPLAYROTATION *pRotation) = 0;
+       virtual HRESULT WINAPI CreateDeviceEx(UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS *pPresentationParameters, D3DDISPLAYMODEEX *pFullscreenDisplayMode, IDirect3DDevice9Ex **ppReturnedDeviceInterface) = 0;
+       virtual HRESULT WINAPI GetAdapterLUID(UINT Adapter, LUID *pLUID) = 0;
+};
+
+struct IDirect3D9ExOverlayExtension : public IUnknown
+{
+       virtual HRESULT WINAPI CheckDeviceOverlayType(UINT Adapter, D3DDEVTYPE DevType, UINT OverlayWidth, UINT OverlayHeight, D3DFORMAT OverlayFormat, D3DDISPLAYMODEEX *pDisplayMode, D3DDISPLAYROTATION DisplayRotation, D3DOVERLAYCAPS *pOverlayCaps) = 0;
+};
+
+struct IDirect3DResource9 : public IUnknown
+{
+       virtual HRESULT WINAPI GetDevice(IDirect3DDevice9 **ppDevice) = 0;
+       virtual HRESULT WINAPI SetPrivateData(REFGUID refguid, const void *pData, DWORD SizeOfData, DWORD Flags) = 0;
+       virtual HRESULT WINAPI GetPrivateData(REFGUID refguid, void *pData, DWORD *pSizeOfData) = 0;
+       virtual HRESULT WINAPI FreePrivateData(REFGUID refguid) = 0;
+       virtual DWORD WINAPI SetPriority(DWORD PriorityNew) = 0;
+       virtual DWORD WINAPI GetPriority() = 0;
+       virtual void WINAPI PreLoad() = 0;
+       virtual D3DRESOURCETYPE WINAPI GetType() = 0;
+};
+
+struct IDirect3DBaseTexture9 : public IDirect3DResource9
+{
+       virtual DWORD WINAPI SetLOD(DWORD LODNew) = 0;
+       virtual DWORD WINAPI GetLOD() = 0;
+       virtual DWORD WINAPI GetLevelCount() = 0;
+       virtual HRESULT WINAPI SetAutoGenFilterType(D3DTEXTUREFILTERTYPE FilterType) = 0;
+       virtual D3DTEXTUREFILTERTYPE WINAPI GetAutoGenFilterType() = 0;
+       virtual void WINAPI GenerateMipSubLevels() = 0;
+};
+
+struct IDirect3DCryptoSession9 : public IUnknown
+{
+       virtual HRESULT WINAPI GetCertificateSize(UINT *pCertificateSize) = 0;
+       virtual HRESULT WINAPI GetCertificate(UINT CertifacteSize, BYTE *ppCertificate) = 0;
+       virtual HRESULT WINAPI NegotiateKeyExchange(UINT DataSize, void *pData) = 0;
+       virtual HRESULT WINAPI EncryptionBlt(IDirect3DSurface9 *pSrcSurface, IDirect3DSurface9 *pDstSurface, UINT DstSurfaceSize, void *pIV) = 0;
+       virtual HRESULT WINAPI DecryptionBlt(IDirect3DSurface9 *pSrcSurface, IDirect3DSurface9 *pDstSurface, UINT SrcSurfaceSize, D3DENCRYPTED_BLOCK_INFO *pEncryptedBlockInfo, void *pContentKey, void *pIV) = 0;
+       virtual HRESULT WINAPI GetSurfacePitch(IDirect3DSurface9 *pSrcSurface, UINT *pSurfacePitch) = 0;
+       virtual HRESULT WINAPI StartSessionKeyRefresh(void *pRandomNumber, UINT RandomNumberSize) = 0;
+       virtual HRESULT WINAPI FinishSessionKeyRefresh() = 0;
+       virtual HRESULT WINAPI GetEncryptionBltKey(void *pReadbackKey, UINT KeySize) = 0;
+};
+
+struct IDirect3DCubeTexture9 : public IDirect3DBaseTexture9
+{
+       virtual HRESULT WINAPI GetLevelDesc(UINT Level, D3DSURFACE_DESC *pDesc) = 0;
+       virtual HRESULT WINAPI GetCubeMapSurface(D3DCUBEMAP_FACES FaceType, UINT Level, IDirect3DSurface9 **ppCubeMapSurface) = 0;
+       virtual HRESULT WINAPI LockRect(D3DCUBEMAP_FACES FaceType, UINT Level, D3DLOCKED_RECT *pLockedRect, const RECT *pRect, DWORD Flags) = 0;
+       virtual HRESULT WINAPI UnlockRect(D3DCUBEMAP_FACES FaceType, UINT Level) = 0;
+       virtual HRESULT WINAPI AddDirtyRect(D3DCUBEMAP_FACES FaceType, const RECT *pDirtyRect) = 0;
+};
+
+struct IDirect3DDevice9 : public IUnknown
+{
+       virtual HRESULT WINAPI TestCooperativeLevel() = 0;
+       virtual UINT WINAPI GetAvailableTextureMem() = 0;
+       virtual HRESULT WINAPI EvictManagedResources() = 0;
+       virtual HRESULT WINAPI GetDirect3D(IDirect3D9 **ppD3D9) = 0;
+       virtual HRESULT WINAPI GetDeviceCaps(D3DCAPS9 *pCaps) = 0;
+       virtual HRESULT WINAPI GetDisplayMode(UINT iSwapChain, D3DDISPLAYMODE *pMode) = 0;
+       virtual HRESULT WINAPI GetCreationParameters(D3DDEVICE_CREATION_PARAMETERS *pParameters) = 0;
+       virtual HRESULT WINAPI SetCursorProperties(UINT XHotSpot, UINT YHotSpot, IDirect3DSurface9 *pCursorBitmap) = 0;
+       virtual void WINAPI SetCursorPosition(int X, int Y, DWORD Flags) = 0;
+       virtual BOOL WINAPI ShowCursor(BOOL bShow) = 0;
+       virtual HRESULT WINAPI CreateAdditionalSwapChain(D3DPRESENT_PARAMETERS *pPresentationParameters, IDirect3DSwapChain9 **pSwapChain) = 0;
+       virtual HRESULT WINAPI GetSwapChain(UINT iSwapChain, IDirect3DSwapChain9 **pSwapChain) = 0;
+       virtual UINT WINAPI GetNumberOfSwapChains() = 0;
+       virtual HRESULT WINAPI Reset(D3DPRESENT_PARAMETERS *pPresentationParameters) = 0;
+       virtual HRESULT WINAPI Present(const RECT *pSourceRect, const RECT *pDestRect, HWND hDestWindowOverride, const RGNDATA *pDirtyRegion) = 0;
+       virtual HRESULT WINAPI GetBackBuffer(UINT iSwapChain, UINT iBackBuffer, D3DBACKBUFFER_TYPE Type, IDirect3DSurface9 **ppBackBuffer) = 0;
+       virtual HRESULT WINAPI GetRasterStatus(UINT iSwapChain, D3DRASTER_STATUS *pRasterStatus) = 0;
+       virtual HRESULT WINAPI SetDialogBoxMode(BOOL bEnableDialogs) = 0;
+       virtual void WINAPI SetGammaRamp(UINT iSwapChain, DWORD Flags, const D3DGAMMARAMP *pRamp) = 0;
+       virtual void WINAPI GetGammaRamp(UINT iSwapChain, D3DGAMMARAMP *pRamp) = 0;
+       virtual HRESULT WINAPI CreateTexture(UINT Width, UINT Height, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DTexture9 **ppTexture, HANDLE *pSharedHandle) = 0;
+       virtual HRESULT WINAPI CreateVolumeTexture(UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DVolumeTexture9 **ppVolumeTexture, HANDLE *pSharedHandle) = 0;
+       virtual HRESULT WINAPI CreateCubeTexture(UINT EdgeLength, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DCubeTexture9 **ppCubeTexture, HANDLE *pSharedHandle) = 0;
+       virtual HRESULT WINAPI CreateVertexBuffer(UINT Length, DWORD Usage, DWORD FVF, D3DPOOL Pool, IDirect3DVertexBuffer9 **ppVertexBuffer, HANDLE *pSharedHandle) = 0;
+       virtual HRESULT WINAPI CreateIndexBuffer(UINT Length, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DIndexBuffer9 **ppIndexBuffer, HANDLE *pSharedHandle) = 0;
+       virtual HRESULT WINAPI CreateRenderTarget(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Lockable, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle) = 0;
+       virtual HRESULT WINAPI CreateDepthStencilSurface(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Discard, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle) = 0;
+       virtual HRESULT WINAPI UpdateSurface(IDirect3DSurface9 *pSourceSurface, const RECT *pSourceRect, IDirect3DSurface9 *pDestinationSurface, const POINT *pDestPoint) = 0;
+       virtual HRESULT WINAPI UpdateTexture(IDirect3DBaseTexture9 *pSourceTexture, IDirect3DBaseTexture9 *pDestinationTexture) = 0;
+       virtual HRESULT WINAPI GetRenderTargetData(IDirect3DSurface9 *pRenderTarget, IDirect3DSurface9 *pDestSurface) = 0;
+       virtual HRESULT WINAPI GetFrontBufferData(UINT iSwapChain, IDirect3DSurface9 *pDestSurface) = 0;
+       virtual HRESULT WINAPI StretchRect(IDirect3DSurface9 *pSourceSurface, const RECT *pSourceRect, IDirect3DSurface9 *pDestSurface, const RECT *pDestRect, D3DTEXTUREFILTERTYPE Filter) = 0;
+       virtual HRESULT WINAPI ColorFill(IDirect3DSurface9 *pSurface, const RECT *pRect, D3DCOLOR color) = 0;
+       virtual HRESULT WINAPI CreateOffscreenPlainSurface(UINT Width, UINT Height, D3DFORMAT Format, D3DPOOL Pool, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle) = 0;
+       virtual HRESULT WINAPI SetRenderTarget(DWORD RenderTargetIndex, IDirect3DSurface9 *pRenderTarget) = 0;
+       virtual HRESULT WINAPI GetRenderTarget(DWORD RenderTargetIndex, IDirect3DSurface9 **ppRenderTarget) = 0;
+       virtual HRESULT WINAPI SetDepthStencilSurface(IDirect3DSurface9 *pNewZStencil) = 0;
+       virtual HRESULT WINAPI GetDepthStencilSurface(IDirect3DSurface9 **ppZStencilSurface) = 0;
+       virtual HRESULT WINAPI BeginScene() = 0;
+       virtual HRESULT WINAPI EndScene() = 0;
+       virtual HRESULT WINAPI Clear(DWORD Count, const D3DRECT *pRects, DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil) = 0;
+       virtual HRESULT WINAPI SetTransform(D3DTRANSFORMSTATETYPE State, const D3DMATRIX *pMatrix) = 0;
+       virtual HRESULT WINAPI GetTransform(D3DTRANSFORMSTATETYPE State, D3DMATRIX *pMatrix) = 0;
+       virtual HRESULT WINAPI MultiplyTransform(D3DTRANSFORMSTATETYPE State, const D3DMATRIX *pMatrix) = 0;
+       virtual HRESULT WINAPI SetViewport(const D3DVIEWPORT9 *pViewport) = 0;
+       virtual HRESULT WINAPI GetViewport(D3DVIEWPORT9 *pViewport) = 0;
+       virtual HRESULT WINAPI SetMaterial(const D3DMATERIAL9 *pMaterial) = 0;
+       virtual HRESULT WINAPI GetMaterial(D3DMATERIAL9 *pMaterial) = 0;
+       virtual HRESULT WINAPI SetLight(DWORD Index, const D3DLIGHT9 *pLight) = 0;
+       virtual HRESULT WINAPI GetLight(DWORD Index, D3DLIGHT9 *pLight) = 0;
+       virtual HRESULT WINAPI LightEnable(DWORD Index, BOOL Enable) = 0;
+       virtual HRESULT WINAPI GetLightEnable(DWORD Index, BOOL *pEnable) = 0;
+       virtual HRESULT WINAPI SetClipPlane(DWORD Index, const float *pPlane) = 0;
+       virtual HRESULT WINAPI GetClipPlane(DWORD Index, float *pPlane) = 0;
+       virtual HRESULT WINAPI SetRenderState(D3DRENDERSTATETYPE State, DWORD Value) = 0;
+       virtual HRESULT WINAPI GetRenderState(D3DRENDERSTATETYPE State, DWORD *pValue) = 0;
+       virtual HRESULT WINAPI CreateStateBlock(D3DSTATEBLOCKTYPE Type, IDirect3DStateBlock9 **ppSB) = 0;
+       virtual HRESULT WINAPI BeginStateBlock() = 0;
+       virtual HRESULT WINAPI EndStateBlock(IDirect3DStateBlock9 **ppSB) = 0;
+       virtual HRESULT WINAPI SetClipStatus(const D3DCLIPSTATUS9 *pClipStatus) = 0;
+       virtual HRESULT WINAPI GetClipStatus(D3DCLIPSTATUS9 *pClipStatus) = 0;
+       virtual HRESULT WINAPI GetTexture(DWORD Stage, IDirect3DBaseTexture9 **ppTexture) = 0;
+       virtual HRESULT WINAPI SetTexture(DWORD Stage, IDirect3DBaseTexture9 *pTexture) = 0;
+       virtual HRESULT WINAPI GetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD *pValue) = 0;
+       virtual HRESULT WINAPI SetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value) = 0;
+       virtual HRESULT WINAPI GetSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD *pValue) = 0;
+       virtual HRESULT WINAPI SetSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value) = 0;
+       virtual HRESULT WINAPI ValidateDevice(DWORD *pNumPasses) = 0;
+       virtual HRESULT WINAPI SetPaletteEntries(UINT PaletteNumber, const PALETTEENTRY *pEntries) = 0;
+       virtual HRESULT WINAPI GetPaletteEntries(UINT PaletteNumber, PALETTEENTRY *pEntries) = 0;
+       virtual HRESULT WINAPI SetCurrentTexturePalette(UINT PaletteNumber) = 0;
+       virtual HRESULT WINAPI GetCurrentTexturePalette(UINT *PaletteNumber) = 0;
+       virtual HRESULT WINAPI SetScissorRect(const RECT *pRect) = 0;
+       virtual HRESULT WINAPI GetScissorRect(RECT *pRect) = 0;
+       virtual HRESULT WINAPI SetSoftwareVertexProcessing(BOOL bSoftware) = 0;
+       virtual BOOL WINAPI GetSoftwareVertexProcessing() = 0;
+       virtual HRESULT WINAPI SetNPatchMode(float nSegments) = 0;
+       virtual float WINAPI GetNPatchMode() = 0;
+       virtual HRESULT WINAPI DrawPrimitive(D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount) = 0;
+       virtual HRESULT WINAPI DrawIndexedPrimitive(D3DPRIMITIVETYPE PrimitiveType, INT BaseVertexIndex, UINT MinVertexIndex, UINT NumVertices, UINT startIndex, UINT primCount) = 0;
+       virtual HRESULT WINAPI DrawPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, const void *pVertexStreamZeroData, UINT VertexStreamZeroStride) = 0;
+       virtual HRESULT WINAPI DrawIndexedPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UINT MinVertexIndex, UINT NumVertices, UINT PrimitiveCount, const void *pIndexData, D3DFORMAT IndexDataFormat, const void *pVertexStreamZeroData, UINT VertexStreamZeroStride) = 0;
+       virtual HRESULT WINAPI ProcessVertices(UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IDirect3DVertexBuffer9 *pDestBuffer, IDirect3DVertexDeclaration9 *pVertexDecl, DWORD Flags) = 0;
+       virtual HRESULT WINAPI CreateVertexDeclaration(const D3DVERTEXELEMENT9 *pVertexElements, IDirect3DVertexDeclaration9 **ppDecl) = 0;
+       virtual HRESULT WINAPI SetVertexDeclaration(IDirect3DVertexDeclaration9 *pDecl) = 0;
+       virtual HRESULT WINAPI GetVertexDeclaration(IDirect3DVertexDeclaration9 **ppDecl) = 0;
+       virtual HRESULT WINAPI SetFVF(DWORD FVF) = 0;
+       virtual HRESULT WINAPI GetFVF(DWORD *pFVF) = 0;
+       virtual HRESULT WINAPI CreateVertexShader(const DWORD *pFunction, IDirect3DVertexShader9 **ppShader) = 0;
+       virtual HRESULT WINAPI SetVertexShader(IDirect3DVertexShader9 *pShader) = 0;
+       virtual HRESULT WINAPI GetVertexShader(IDirect3DVertexShader9 **ppShader) = 0;
+       virtual HRESULT WINAPI SetVertexShaderConstantF(UINT StartRegister, const float *pConstantData, UINT Vector4fCount) = 0;
+       virtual HRESULT WINAPI GetVertexShaderConstantF(UINT StartRegister, float *pConstantData, UINT Vector4fCount) = 0;
+       virtual HRESULT WINAPI SetVertexShaderConstantI(UINT StartRegister, const int *pConstantData, UINT Vector4iCount) = 0;
+       virtual HRESULT WINAPI GetVertexShaderConstantI(UINT StartRegister, int *pConstantData, UINT Vector4iCount) = 0;
+       virtual HRESULT WINAPI SetVertexShaderConstantB(UINT StartRegister, const BOOL *pConstantData, UINT BoolCount) = 0;
+       virtual HRESULT WINAPI GetVertexShaderConstantB(UINT StartRegister, BOOL *pConstantData, UINT BoolCount) = 0;
+       virtual HRESULT WINAPI SetStreamSource(UINT StreamNumber, IDirect3DVertexBuffer9 *pStreamData, UINT OffsetInBytes, UINT Stride) = 0;
+       virtual HRESULT WINAPI GetStreamSource(UINT StreamNumber, IDirect3DVertexBuffer9 **ppStreamData, UINT *pOffsetInBytes, UINT *pStride) = 0;
+       virtual HRESULT WINAPI SetStreamSourceFreq(UINT StreamNumber, UINT Setting) = 0;
+       virtual HRESULT WINAPI GetStreamSourceFreq(UINT StreamNumber, UINT *pSetting) = 0;
+       virtual HRESULT WINAPI SetIndices(IDirect3DIndexBuffer9 *pIndexData) = 0;
+       virtual HRESULT WINAPI GetIndices(IDirect3DIndexBuffer9 **ppIndexData, UINT *pBaseVertexIndex) = 0;
+       virtual HRESULT WINAPI CreatePixelShader(const DWORD *pFunction, IDirect3DPixelShader9 **ppShader) = 0;
+       virtual HRESULT WINAPI SetPixelShader(IDirect3DPixelShader9 *pShader) = 0;
+       virtual HRESULT WINAPI GetPixelShader(IDirect3DPixelShader9 **ppShader) = 0;
+       virtual HRESULT WINAPI SetPixelShaderConstantF(UINT StartRegister, const float *pConstantData, UINT Vector4fCount) = 0;
+       virtual HRESULT WINAPI GetPixelShaderConstantF(UINT StartRegister, float *pConstantData, UINT Vector4fCount) = 0;
+       virtual HRESULT WINAPI SetPixelShaderConstantI(UINT StartRegister, const int *pConstantData, UINT Vector4iCount) = 0;
+       virtual HRESULT WINAPI GetPixelShaderConstantI(UINT StartRegister, int *pConstantData, UINT Vector4iCount) = 0;
+       virtual HRESULT WINAPI SetPixelShaderConstantB(UINT StartRegister, const BOOL *pConstantData, UINT BoolCount) = 0;
+       virtual HRESULT WINAPI GetPixelShaderConstantB(UINT StartRegister, BOOL *pConstantData, UINT BoolCount) = 0;
+       virtual HRESULT WINAPI DrawRectPatch(UINT Handle, const float *pNumSegs, const D3DRECTPATCH_INFO *pRectPatchInfo) = 0;
+       virtual HRESULT WINAPI DrawTriPatch(UINT Handle, const float *pNumSegs, const D3DTRIPATCH_INFO *pTriPatchInfo) = 0;
+       virtual HRESULT WINAPI DeletePatch(UINT Handle) = 0;
+       virtual HRESULT WINAPI CreateQuery(D3DQUERYTYPE Type, IDirect3DQuery9 **ppQuery) = 0;
+};
+
+struct IDirect3DDevice9Ex : public IDirect3DDevice9
+{
+       virtual HRESULT WINAPI SetConvolutionMonoKernel(UINT width, UINT height, float *rows, float *columns) = 0;
+       virtual HRESULT WINAPI ComposeRects(IDirect3DSurface9 *pSrc, IDirect3DSurface9 *pDst, IDirect3DVertexBuffer9 *pSrcRectDescs, UINT NumRects, IDirect3DVertexBuffer9 *pDstRectDescs, D3DCOMPOSERECTSOP Operation, int Xoffset, int Yoffset) = 0;
+       virtual HRESULT WINAPI PresentEx(const RECT *pSourceRect, const RECT *pDestRect, HWND hDestWindowOverride, const RGNDATA *pDirtyRegion, DWORD dwFlags) = 0;
+       virtual HRESULT WINAPI GetGPUThreadPriority(INT *pPriority) = 0;
+       virtual HRESULT WINAPI SetGPUThreadPriority(INT Priority) = 0;
+       virtual HRESULT WINAPI WaitForVBlank(UINT iSwapChain) = 0;
+       virtual HRESULT WINAPI CheckResourceResidency(IDirect3DResource9 **pResourceArray, UINT32 NumResources) = 0;
+       virtual HRESULT WINAPI SetMaximumFrameLatency(UINT MaxLatency) = 0;
+       virtual HRESULT WINAPI GetMaximumFrameLatency(UINT *pMaxLatency) = 0;
+       virtual HRESULT WINAPI CheckDeviceState(HWND hDestinationWindow) = 0;
+       virtual HRESULT WINAPI CreateRenderTargetEx(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Lockable, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle, DWORD Usage) = 0;
+       virtual HRESULT WINAPI CreateOffscreenPlainSurfaceEx(UINT Width, UINT Height, D3DFORMAT Format, D3DPOOL Pool, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle, DWORD Usage) = 0;
+       virtual HRESULT WINAPI CreateDepthStencilSurfaceEx(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Discard, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle, DWORD Usage) = 0;
+       virtual HRESULT WINAPI ResetEx(D3DPRESENT_PARAMETERS *pPresentationParameters, D3DDISPLAYMODEEX *pFullscreenDisplayMode) = 0;
+       virtual HRESULT WINAPI GetDisplayModeEx(UINT iSwapChain, D3DDISPLAYMODEEX *pMode, D3DDISPLAYROTATION *pRotation) = 0;
+};
+
+struct IDirect3DDevice9Video : public IUnknown
+{
+       virtual HRESULT WINAPI GetContentProtectionCaps(const GUID *pCryptoType, const GUID *pDecodeProfile, D3DCONTENTPROTECTIONCAPS *pCaps) = 0;
+       virtual HRESULT WINAPI CreateAuthenticatedChannel(D3DAUTHENTICATEDCHANNELTYPE ChannelType, IDirect3DAuthenticatedChannel9 **ppAuthenticatedChannel, HANDLE *pChannelHandle) = 0;
+       virtual HRESULT WINAPI CreateCryptoSession(const GUID *pCryptoType, const GUID *pDecodeProfile, IDirect3DCryptoSession9 **ppCryptoSession, HANDLE *pCryptoHandle) = 0;
+};
+
+struct IDirect3DIndexBuffer9 : public IDirect3DResource9
+{
+       virtual HRESULT WINAPI Lock(UINT OffsetToLock, UINT SizeToLock, void **ppbData, DWORD Flags) = 0;
+       virtual HRESULT WINAPI Unlock() = 0;
+       virtual HRESULT WINAPI GetDesc(D3DINDEXBUFFER_DESC *pDesc) = 0;
+};
+
+struct IDirect3DPixelShader9 : public IUnknown
+{
+       virtual HRESULT WINAPI GetDevice(IDirect3DDevice9 **ppDevice) = 0;
+       virtual HRESULT WINAPI GetFunction(void *pData, UINT *pSizeOfData) = 0;
+};
+
+struct IDirect3DQuery9 : public IUnknown
+{
+       virtual HRESULT WINAPI GetDevice(IDirect3DDevice9 **ppDevice) = 0;
+       virtual D3DQUERYTYPE WINAPI GetType() = 0;
+       virtual DWORD WINAPI GetDataSize() = 0;
+       virtual HRESULT WINAPI Issue(DWORD dwIssueFlags) = 0;
+       virtual HRESULT WINAPI GetData(void *pData, DWORD dwSize, DWORD dwGetDataFlags) = 0;
+};
+
+struct IDirect3DStateBlock9 : public IUnknown
+{
+       virtual HRESULT WINAPI GetDevice(IDirect3DDevice9 **ppDevice) = 0;
+       virtual HRESULT WINAPI Capture() = 0;
+       virtual HRESULT WINAPI Apply() = 0;
+};
+
+struct IDirect3DSurface9 : public IDirect3DResource9
+{
+       virtual HRESULT WINAPI GetContainer(REFIID riid, void **ppContainer) = 0;
+       virtual HRESULT WINAPI GetDesc(D3DSURFACE_DESC *pDesc) = 0;
+       virtual HRESULT WINAPI LockRect(D3DLOCKED_RECT *pLockedRect, const RECT *pRect, DWORD Flags) = 0;
+       virtual HRESULT WINAPI UnlockRect() = 0;
+       virtual HRESULT WINAPI GetDC(HDC *phdc) = 0;
+       virtual HRESULT WINAPI ReleaseDC(HDC hdc) = 0;
+};
+
+struct IDirect3DSwapChain9 : public IUnknown
+{
+       virtual HRESULT WINAPI Present(const RECT *pSourceRect, const RECT *pDestRect, HWND hDestWindowOverride, const RGNDATA *pDirtyRegion, DWORD dwFlags) = 0;
+       virtual HRESULT WINAPI GetFrontBufferData(IDirect3DSurface9 *pDestSurface) = 0;
+       virtual HRESULT WINAPI GetBackBuffer(UINT iBackBuffer, D3DBACKBUFFER_TYPE Type, IDirect3DSurface9 **ppBackBuffer) = 0;
+       virtual HRESULT WINAPI GetRasterStatus(D3DRASTER_STATUS *pRasterStatus) = 0;
+       virtual HRESULT WINAPI GetDisplayMode(D3DDISPLAYMODE *pMode) = 0;
+       virtual HRESULT WINAPI GetDevice(IDirect3DDevice9 **ppDevice) = 0;
+       virtual HRESULT WINAPI GetPresentParameters(D3DPRESENT_PARAMETERS *pPresentationParameters) = 0;
+};
+
+struct IDirect3DSwapChain9Ex : public IDirect3DSwapChain9
+{
+       virtual HRESULT WINAPI GetLastPresentCount(UINT *pLastPresentCount) = 0;
+       virtual HRESULT WINAPI GetPresentStats(D3DPRESENTSTATS *pPresentationStatistics) = 0;
+       virtual HRESULT WINAPI GetDisplayModeEx(D3DDISPLAYMODEEX *pMode, D3DDISPLAYROTATION *pRotation) = 0;
+};
+
+struct IDirect3DTexture9 : public IDirect3DBaseTexture9
+{
+       virtual HRESULT WINAPI GetLevelDesc(UINT Level, D3DSURFACE_DESC *pDesc) = 0;
+       virtual HRESULT WINAPI GetSurfaceLevel(UINT Level, IDirect3DSurface9 **ppSurfaceLevel) = 0;
+       virtual HRESULT WINAPI LockRect(UINT Level, D3DLOCKED_RECT *pLockedRect, const RECT *pRect, DWORD Flags) = 0;
+       virtual HRESULT WINAPI UnlockRect(UINT Level) = 0;
+       virtual HRESULT WINAPI AddDirtyRect(const RECT *pDirtyRect) = 0;
+};
+
+struct IDirect3DVertexBuffer9 : public IDirect3DResource9
+{
+       virtual HRESULT WINAPI Lock(UINT OffsetToLock, UINT SizeToLock, void **ppbData, DWORD Flags) = 0;
+       virtual HRESULT WINAPI Unlock() = 0;
+       virtual HRESULT WINAPI GetDesc(D3DVERTEXBUFFER_DESC *pDesc) = 0;
+};
+
+struct IDirect3DVertexDeclaration9 : public IUnknown
+{
+       virtual HRESULT WINAPI GetDevice(IDirect3DDevice9 **ppDevice) = 0;
+       virtual HRESULT WINAPI GetDeclaration(D3DVERTEXELEMENT9 *pElement, UINT *pNumElements) = 0;
+};
+
+struct IDirect3DVertexShader9 : public IUnknown
+{
+       virtual HRESULT WINAPI GetDevice(IDirect3DDevice9 **ppDevice) = 0;
+       virtual HRESULT WINAPI GetFunction(void *pData, UINT *pSizeOfData) = 0;
+};
+
+struct IDirect3DVolume9 : public IUnknown
+{
+       virtual HRESULT WINAPI GetDevice(IDirect3DDevice9 **ppDevice) = 0;
+       virtual HRESULT WINAPI SetPrivateData(REFGUID refguid, const void *pData, DWORD SizeOfData, DWORD Flags) = 0;
+       virtual HRESULT WINAPI GetPrivateData(REFGUID refguid, void *pData, DWORD *pSizeOfData) = 0;
+       virtual HRESULT WINAPI FreePrivateData(REFGUID refguid) = 0;
+       virtual HRESULT WINAPI GetContainer(REFIID riid, void **ppContainer) = 0;
+       virtual HRESULT WINAPI GetDesc(D3DVOLUME_DESC *pDesc) = 0;
+       virtual HRESULT WINAPI LockBox(D3DLOCKED_BOX *pLockedVolume, const D3DBOX *pBox, DWORD Flags) = 0;
+       virtual HRESULT WINAPI UnlockBox() = 0;
+};
+
+#else /* __cplusplus */
+
+extern const GUID IID_IDirect3D9;
+extern const GUID IID_IDirect3D9Ex;
+extern const GUID IID_IDirect3D9ExOverlayExtension;
+extern const GUID IID_IDirect3DAuthenticatedChannel9;
+extern const GUID IID_IDirect3DBaseTexture9;
+extern const GUID IID_IDirect3DCryptoSession9;
+extern const GUID IID_IDirect3DCubeTexture9;
+extern const GUID IID_IDirect3DDevice9;
+extern const GUID IID_IDirect3DDevice9Ex;
+extern const GUID IID_IDirect3DDevice9Video;
+extern const GUID IID_IDirect3DIndexBuffer9;
+extern const GUID IID_IDirect3DPixelShader9;
+extern const GUID IID_IDirect3DQuery9;
+extern const GUID IID_IDirect3DResource9;
+extern const GUID IID_IDirect3DStateBlock9;
+extern const GUID IID_IDirect3DSurface9;
+extern const GUID IID_IDirect3DSwapChain9;
+extern const GUID IID_IDirect3DSwapChain9Ex;
+extern const GUID IID_IDirect3DTexture9;
+extern const GUID IID_IDirect3DVertexBuffer9;
+extern const GUID IID_IDirect3DVertexDeclaration9;
+extern const GUID IID_IDirect3DVertexShader9;
+extern const GUID IID_IDirect3DVolume9;
+extern const GUID IID_IDirect3DVolumeTexture9;
+
+typedef struct IDirect3D9Vtbl
+{
+       /* IUnknown */
+       HRESULT (WINAPI *QueryInterface)(IDirect3D9 *This, REFIID riid, void **ppvObject);
+       ULONG (WINAPI *AddRef)(IDirect3D9 *This);
+       ULONG (WINAPI *Release)(IDirect3D9 *This);
+       /* IDirect3D9 */
+       HRESULT (WINAPI *RegisterSoftwareDevice)(IDirect3D9 *This, void *pInitializeFunction);
+       UINT (WINAPI *GetAdapterCount)(IDirect3D9 *This);
+       HRESULT (WINAPI *GetAdapterIdentifier)(IDirect3D9 *This, UINT Adapter, DWORD Flags, D3DADAPTER_IDENTIFIER9 *pIdentifier);
+       UINT (WINAPI *GetAdapterModeCount)(IDirect3D9 *This, UINT Adapter, D3DFORMAT Format);
+       HRESULT (WINAPI *EnumAdapterModes)(IDirect3D9 *This, UINT Adapter, D3DFORMAT Format, UINT Mode, D3DDISPLAYMODE *pMode);
+       HRESULT (WINAPI *GetAdapterDisplayMode)(IDirect3D9 *This, UINT Adapter, D3DDISPLAYMODE *pMode);
+       HRESULT (WINAPI *CheckDeviceType)(IDirect3D9 *This, UINT Adapter, D3DDEVTYPE DevType, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, BOOL bWindowed);
+       HRESULT (WINAPI *CheckDeviceFormat)(IDirect3D9 *This, UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, DWORD Usage, D3DRESOURCETYPE RType, D3DFORMAT CheckFormat);
+       HRESULT (WINAPI *CheckDeviceMultiSampleType)(IDirect3D9 *This, UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SurfaceFormat, BOOL Windowed, D3DMULTISAMPLE_TYPE MultiSampleType, DWORD *pQualityLevels);
+       HRESULT (WINAPI *CheckDepthStencilMatch)(IDirect3D9 *This, UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, D3DFORMAT RenderTargetFormat, D3DFORMAT DepthStencilFormat);
+       HRESULT (WINAPI *CheckDeviceFormatConversion)(IDirect3D9 *This, UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SourceFormat, D3DFORMAT TargetFormat);
+       HRESULT (WINAPI *GetDeviceCaps)(IDirect3D9 *This, UINT Adapter, D3DDEVTYPE DeviceType, D3DCAPS9 *pCaps);
+       HMONITOR (WINAPI *GetAdapterMonitor)(IDirect3D9 *This, UINT Adapter);
+       HRESULT (WINAPI *CreateDevice)(IDirect3D9 *This, UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS *pPresentationParameters, IDirect3DDevice9 **ppReturnedDeviceInterface);
+} IDirect3D9Vtbl;
+struct IDirect3D9
+{
+       IDirect3D9Vtbl *lpVtbl;
+};
+
+/* IUnknown macros */
+#define IDirect3D9_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
+#define IDirect3D9_AddRef(p) (p)->lpVtbl->AddRef(p)
+#define IDirect3D9_Release(p) (p)->lpVtbl->Release(p)
+/* IDirect3D9 macros */
+#define IDirect3D9_RegisterSoftwareDevice(p,a) (p)->lpVtbl->RegisterSoftwareDevice(p,a)
+#define IDirect3D9_GetAdapterCount(p) (p)->lpVtbl->GetAdapterCount(p)
+#define IDirect3D9_GetAdapterIdentifier(p,a,b,c) (p)->lpVtbl->GetAdapterIdentifier(p,a,b,c)
+#define IDirect3D9_GetAdapterModeCount(p,a,b) (p)->lpVtbl->GetAdapterModeCount(p,a,b)
+#define IDirect3D9_EnumAdapterModes(p,a,b,c,d) (p)->lpVtbl->EnumAdapterModes(p,a,b,c,d)
+#define IDirect3D9_GetAdapterDisplayMode(p,a,b) (p)->lpVtbl->GetAdapterDisplayMode(p,a,b)
+#define IDirect3D9_CheckDeviceType(p,a,b,c,d,e) (p)->lpVtbl->CheckDeviceType(p,a,b,c,d,e)
+#define IDirect3D9_CheckDeviceFormat(p,a,b,c,d,e,f) (p)->lpVtbl->CheckDeviceFormat(p,a,b,c,d,e,f)
+#define IDirect3D9_CheckDeviceMultiSampleType(p,a,b,c,d,e,f) (p)->lpVtbl->CheckDeviceMultiSampleType(p,a,b,c,d,e,f)
+#define IDirect3D9_CheckDepthStencilMatch(p,a,b,c,d,e) (p)->lpVtbl->CheckDepthStencilMatch(p,a,b,c,d,e)
+#define IDirect3D9_CheckDeviceFormatConversion(p,a,b,c,d) (p)->lpVtbl->CheckDeviceFormatConversion(p,a,b,c,d)
+#define IDirect3D9_GetDeviceCaps(p,a,b,c) (p)->lpVtbl->GetDeviceCaps(p,a,b,c)
+#define IDirect3D9_GetAdapterMonitor(p,a) (p)->lpVtbl->GetAdapterMonitor(p,a)
+#define IDirect3D9_CreateDevice(p,a,b,c,d,e,f) (p)->lpVtbl->CreateDevice(p,a,b,c,d,e,f)
+
+typedef struct IDirect3D9ExVtbl
+{
+       /* IUnknown */
+       HRESULT (WINAPI *QueryInterface)(IDirect3D9Ex *This, REFIID riid, void **ppvObject);
+       ULONG (WINAPI *AddRef)(IDirect3D9Ex *This);
+       ULONG (WINAPI *Release)(IDirect3D9Ex *This);
+       /* IDirect3D9 */
+       HRESULT (WINAPI *RegisterSoftwareDevice)(IDirect3D9Ex *This, void *pInitializeFunction);
+       UINT (WINAPI *GetAdapterCount)(IDirect3D9Ex *This);
+       HRESULT (WINAPI *GetAdapterIdentifier)(IDirect3D9Ex *This, UINT Adapter, DWORD Flags, D3DADAPTER_IDENTIFIER9 *pIdentifier);
+       UINT (WINAPI *GetAdapterModeCount)(IDirect3D9Ex *This, UINT Adapter, D3DFORMAT Format);
+       HRESULT (WINAPI *EnumAdapterModes)(IDirect3D9Ex *This, UINT Adapter, D3DFORMAT Format, UINT Mode, D3DDISPLAYMODE *pMode);
+       HRESULT (WINAPI *GetAdapterDisplayMode)(IDirect3D9Ex *This, UINT Adapter, D3DDISPLAYMODE *pMode);
+       HRESULT (WINAPI *CheckDeviceType)(IDirect3D9Ex *This, UINT Adapter, D3DDEVTYPE DevType, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, BOOL bWindowed);
+       HRESULT (WINAPI *CheckDeviceFormat)(IDirect3D9Ex *This, UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, DWORD Usage, D3DRESOURCETYPE RType, D3DFORMAT CheckFormat);
+       HRESULT (WINAPI *CheckDeviceMultiSampleType)(IDirect3D9Ex *This, UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SurfaceFormat, BOOL Windowed, D3DMULTISAMPLE_TYPE MultiSampleType, DWORD *pQualityLevels);
+       HRESULT (WINAPI *CheckDepthStencilMatch)(IDirect3D9Ex *This, UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, D3DFORMAT RenderTargetFormat, D3DFORMAT DepthStencilFormat);
+       HRESULT (WINAPI *CheckDeviceFormatConversion)(IDirect3D9Ex *This, UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SourceFormat, D3DFORMAT TargetFormat);
+       HRESULT (WINAPI *GetDeviceCaps)(IDirect3D9Ex *This, UINT Adapter, D3DDEVTYPE DeviceType, D3DCAPS9 *pCaps);
+       HMONITOR (WINAPI *GetAdapterMonitor)(IDirect3D9Ex *This, UINT Adapter);
+       HRESULT (WINAPI *CreateDevice)(IDirect3D9Ex *This, UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS *pPresentationParameters, IDirect3DDevice9 **ppReturnedDeviceInterface);
+       /* IDirect3D9Ex */
+       UINT (WINAPI *GetAdapterModeCountEx)(IDirect3D9Ex *This, UINT Adapter, const D3DDISPLAYMODEFILTER *pFilter);
+       HRESULT (WINAPI *EnumAdapterModesEx)(IDirect3D9Ex *This, UINT Adapter, const D3DDISPLAYMODEFILTER *pFilter, UINT Mode, D3DDISPLAYMODEEX *pMode);
+       HRESULT (WINAPI *GetAdapterDisplayModeEx)(IDirect3D9Ex *This, UINT Adapter, D3DDISPLAYMODEEX *pMode, D3DDISPLAYROTATION *pRotation);
+       HRESULT (WINAPI *CreateDeviceEx)(IDirect3D9Ex *This, UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS *pPresentationParameters, D3DDISPLAYMODEEX *pFullscreenDisplayMode, IDirect3DDevice9Ex **ppReturnedDeviceInterface);
+       HRESULT (WINAPI *GetAdapterLUID)(IDirect3D9Ex *This, UINT Adapter, LUID *pLUID);
+} IDirect3D9ExVtbl;
+struct IDirect3D9Ex
+{
+       IDirect3D9ExVtbl *lpVtbl;
+};
+
+/* IUnknown macros */
+#define IDirect3D9Ex_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
+#define IDirect3D9Ex_AddRef(p) (p)->lpVtbl->AddRef(p)
+#define IDirect3D9Ex_Release(p) (p)->lpVtbl->Release(p)
+/* IDirect3D9 macros */
+#define IDirect3D9Ex_RegisterSoftwareDevice(p,a) (p)->lpVtbl->RegisterSoftwareDevice(p,a)
+#define IDirect3D9Ex_GetAdapterCount(p) (p)->lpVtbl->GetAdapterCount(p)
+#define IDirect3D9Ex_GetAdapterIdentifier(p,a,b,c) (p)->lpVtbl->GetAdapterIdentifier(p,a,b,c)
+#define IDirect3D9Ex_GetAdapterModeCount(p,a,b) (p)->lpVtbl->GetAdapterModeCount(p,a,b)
+#define IDirect3D9Ex_EnumAdapterModes(p,a,b,c,d) (p)->lpVtbl->EnumAdapterModes(p,a,b,c,d)
+#define IDirect3D9Ex_GetAdapterDisplayMode(p,a,b) (p)->lpVtbl->GetAdapterDisplayMode(p,a,b)
+#define IDirect3D9Ex_CheckDeviceType(p,a,b,c,d,e) (p)->lpVtbl->CheckDeviceType(p,a,b,c,d,e)
+#define IDirect3D9Ex_CheckDeviceFormat(p,a,b,c,d,e,f) (p)->lpVtbl->CheckDeviceFormat(p,a,b,c,d,e,f)
+#define IDirect3D9Ex_CheckDeviceMultiSampleType(p,a,b,c,d,e,f) (p)->lpVtbl->CheckDeviceMultiSampleType(p,a,b,c,d,e,f)
+#define IDirect3D9Ex_CheckDepthStencilMatch(p,a,b,c,d,e) (p)->lpVtbl->CheckDepthStencilMatch(p,a,b,c,d,e)
+#define IDirect3D9Ex_CheckDeviceFormatConversion(p,a,b,c,d) (p)->lpVtbl->CheckDeviceFormatConversion(p,a,b,c,d)
+#define IDirect3D9Ex_GetDeviceCaps(p,a,b,c) (p)->lpVtbl->GetDeviceCaps(p,a,b,c)
+#define IDirect3D9Ex_GetAdapterMonitor(p,a) (p)->lpVtbl->GetAdapterMonitor(p,a)
+#define IDirect3D9Ex_CreateDevice(p,a,b,c,d,e,f) (p)->lpVtbl->CreateDevice(p,a,b,c,d,e,f)
+/* IDirect3D9Ex macros */
+#define IDirect3D9Ex_GetAdapterModeCountEx(p,a,b) (p)->lpVtbl->GetAdapterModeCountEx(p,a,b)
+#define IDirect3D9Ex_EnumAdapterModesEx(p,a,b,c,d) (p)->lpVtbl->EnumAdapterModesEx(p,a,b,c,d)
+#define IDirect3D9Ex_GetAdapterDisplayModeEx(p,a,b,c) (p)->lpVtbl->GetAdapterDisplayModeEx(p,a,b,c)
+#define IDirect3D9Ex_CreateDeviceEx(p,a,b,c,d,e,f,g) (p)->lpVtbl->CreateDeviceEx(p,a,b,c,d,e,f,g)
+#define IDirect3D9Ex_GetAdapterLUID(p,a,b) (p)->lpVtbl->GetAdapterLUID(p,a,b)
+
+typedef struct IDirect3D9ExOverlayExtensionVtbl
+{
+       /* IUnknown */
+       HRESULT (WINAPI *QueryInterface)(IDirect3D9ExOverlayExtension *This, REFIID riid, void **ppvObject);
+       ULONG (WINAPI *AddRef)(IDirect3D9ExOverlayExtension *This);
+       ULONG (WINAPI *Release)(IDirect3D9ExOverlayExtension *This);
+       /* IDirect3D9ExOverlayExtension */
+       HRESULT (WINAPI *CheckDeviceOverlayType)(IDirect3D9ExOverlayExtension *This, UINT Adapter, D3DDEVTYPE DevType, UINT OverlayWidth, UINT OverlayHeight, D3DFORMAT OverlayFormat, D3DDISPLAYMODEEX *pDisplayMode, D3DDISPLAYROTATION DisplayRotation, D3DOVERLAYCAPS *pOverlayCaps);
+} IDirect3D9ExOverlayExtensionVtbl;
+struct IDirect3D9ExOverlayExtension
+{
+       IDirect3D9ExOverlayExtensionVtbl *lpVtbl;
+};
+
+/* IUnknown macros */
+#define IDirect3D9ExOverlayExtension_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
+#define IDirect3D9ExOverlayExtension_AddRef(p) (p)->lpVtbl->AddRef(p)
+#define IDirect3D9ExOverlayExtension_Release(p) (p)->lpVtbl->Release(p)
+/* IDirect3D9ExOverlayExtension macros */
+#define IDirect3D9ExOverlayExtension_CheckDeviceOverlayType(p,a,b,c,d,e,f,g,h) (p)->lpVtbl->CheckDeviceOverlayType(p,a,b,c,d,e,f,g,h)
+
+typedef struct IDirect3DAuthenticatedChannel9Vtbl
+{
+       /* IUnknown */
+       HRESULT (WINAPI *QueryInterface)(IDirect3DAuthenticatedChannel9 *This, REFIID riid, void **ppvObject);
+       ULONG (WINAPI *AddRef)(IDirect3DAuthenticatedChannel9 *This);
+       ULONG (WINAPI *Release)(IDirect3DAuthenticatedChannel9 *This);
+       /* IDirect3DAuthenticatedChannel9 */
+       HRESULT (WINAPI *GetCertificateSize)(IDirect3DAuthenticatedChannel9 *This, UINT *pCertificateSize);
+       HRESULT (WINAPI *GetCertificate)(IDirect3DAuthenticatedChannel9 *This, UINT CertifacteSize, BYTE *ppCertificate);
+       HRESULT (WINAPI *NegotiateKeyExchange)(IDirect3DAuthenticatedChannel9 *This, UINT DataSize, void *pData);
+       HRESULT (WINAPI *Query)(IDirect3DAuthenticatedChannel9 *This, UINT InputSize, const void *pInput, UINT OutputSize, void *pOutput);
+       HRESULT (WINAPI *Configure)(IDirect3DAuthenticatedChannel9 *This, UINT InputSize, const void *pInput, D3DAUTHENTICATEDCHANNEL_CONFIGURE_OUTPUT *pOutput);
+} IDirect3DAuthenticatedChannel9Vtbl;
+struct IDirect3DAuthenticatedChannel9
+{
+       IDirect3DAuthenticatedChannel9Vtbl *lpVtbl;
+};
+
+/* IUnknown macros */
+#define IDirect3DAuthenticatedChannel9_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
+#define IDirect3DAuthenticatedChannel9_AddRef(p) (p)->lpVtbl->AddRef(p)
+#define IDirect3DAuthenticatedChannel9_Release(p) (p)->lpVtbl->Release(p)
+/* IDirect3DAuthenticatedChannel9 macros */
+#define IDirect3DAuthenticatedChannel9_GetCertificateSize(p,a) (p)->lpVtbl->GetCertificateSize(p,a)
+#define IDirect3DAuthenticatedChannel9_GetCertificate(p,a,b) (p)->lpVtbl->GetCertificate(p,a,b)
+#define IDirect3DAuthenticatedChannel9_NegotiateKeyExchange(p,a,b) (p)->lpVtbl->NegotiateKeyExchange(p,a,b)
+#define IDirect3DAuthenticatedChannel9_Query(p,a,b,c,d) (p)->lpVtbl->Query(p,a,b,c,d)
+#define IDirect3DAuthenticatedChannel9_Configure(p,a,b,c) (p)->lpVtbl->Configure(p,a,b,c)
+
+typedef struct IDirect3DBaseTexture9Vtbl
+{
+       /* IUnknown */
+       HRESULT (WINAPI *QueryInterface)(IDirect3DBaseTexture9 *This, REFIID riid, void **ppvObject);
+       ULONG (WINAPI *AddRef)(IDirect3DBaseTexture9 *This);
+       ULONG (WINAPI *Release)(IDirect3DBaseTexture9 *This);
+       /* IDirect3DResource9 */
+       HRESULT (WINAPI *GetDevice)(IDirect3DBaseTexture9 *This, IDirect3DDevice9 **ppDevice);
+       HRESULT (WINAPI *SetPrivateData)(IDirect3DBaseTexture9 *This, REFGUID refguid, const void *pData, DWORD SizeOfData, DWORD Flags);
+       HRESULT (WINAPI *GetPrivateData)(IDirect3DBaseTexture9 *This, REFGUID refguid, void *pData, DWORD *pSizeOfData);
+       HRESULT (WINAPI *FreePrivateData)(IDirect3DBaseTexture9 *This, REFGUID refguid);
+       DWORD (WINAPI *SetPriority)(IDirect3DBaseTexture9 *This, DWORD PriorityNew);
+       DWORD (WINAPI *GetPriority)(IDirect3DBaseTexture9 *This);
+       void (WINAPI *PreLoad)(IDirect3DBaseTexture9 *This);
+       D3DRESOURCETYPE (WINAPI *GetType)(IDirect3DBaseTexture9 *This);
+       /* IDirect3DBaseTexture9 */
+       DWORD (WINAPI *SetLOD)(IDirect3DBaseTexture9 *This, DWORD LODNew);
+       DWORD (WINAPI *GetLOD)(IDirect3DBaseTexture9 *This);
+       DWORD (WINAPI *GetLevelCount)(IDirect3DBaseTexture9 *This);
+       HRESULT (WINAPI *SetAutoGenFilterType)(IDirect3DBaseTexture9 *This, D3DTEXTUREFILTERTYPE FilterType);
+       D3DTEXTUREFILTERTYPE (WINAPI *GetAutoGenFilterType)(IDirect3DBaseTexture9 *This);
+       void (WINAPI *GenerateMipSubLevels)(IDirect3DBaseTexture9 *This);
+} IDirect3DBaseTexture9Vtbl;
+struct IDirect3DBaseTexture9
+{
+       IDirect3DBaseTexture9Vtbl *lpVtbl;
+};
+
+/* IUnknown macros */
+#define IDirect3DBaseTexture9_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
+#define IDirect3DBaseTexture9_AddRef(p) (p)->lpVtbl->AddRef(p)
+#define IDirect3DBaseTexture9_Release(p) (p)->lpVtbl->Release(p)
+/* IDirect3DResource9 macros */
+#define IDirect3DBaseTexture9_GetDevice(p,a) (p)->lpVtbl->GetDevice(p,a)
+#define IDirect3DBaseTexture9_SetPrivateData(p,a,b,c,d) (p)->lpVtbl->SetPrivateData(p,a,b,c,d)
+#define IDirect3DBaseTexture9_GetPrivateData(p,a,b,c) (p)->lpVtbl->GetPrivateData(p,a,b,c)
+#define IDirect3DBaseTexture9_FreePrivateData(p,a) (p)->lpVtbl->FreePrivateData(p,a)
+#define IDirect3DBaseTexture9_SetPriority(p,a) (p)->lpVtbl->SetPriority(p,a)
+#define IDirect3DBaseTexture9_GetPriority(p) (p)->lpVtbl->GetPriority(p)
+#define IDirect3DBaseTexture9_PreLoad(p) (p)->lpVtbl->PreLoad(p)
+#define IDirect3DBaseTexture9_GetType(p) (p)->lpVtbl->GetType(p)
+/* IDirect3DBaseTexture9 macros */
+#define IDirect3DBaseTexture9_SetLOD(p,a) (p)->lpVtbl->SetLOD(p,a)
+#define IDirect3DBaseTexture9_GetLOD(p) (p)->lpVtbl->GetLOD(p)
+#define IDirect3DBaseTexture9_GetLevelCount(p) (p)->lpVtbl->GetLevelCount(p)
+#define IDirect3DBaseTexture9_SetAutoGenFilterType(p,a) (p)->lpVtbl->SetAutoGenFilterType(p,a)
+#define IDirect3DBaseTexture9_GetAutoGenFilterType(p) (p)->lpVtbl->GetAutoGenFilterType(p)
+#define IDirect3DBaseTexture9_GenerateMipSubLevels(p) (p)->lpVtbl->GenerateMipSubLevels(p)
+
+typedef struct IDirect3DCryptoSession9Vtbl
+{
+       /* IUnknown */
+       HRESULT (WINAPI *QueryInterface)(IDirect3DCryptoSession9 *This, REFIID riid, void **ppvObject);
+       ULONG (WINAPI *AddRef)(IDirect3DCryptoSession9 *This);
+       ULONG (WINAPI *Release)(IDirect3DCryptoSession9 *This);
+       /* IDirect3DCryptoSession9 */
+       HRESULT (WINAPI *GetCertificateSize)(IDirect3DCryptoSession9 *This, UINT *pCertificateSize);
+       HRESULT (WINAPI *GetCertificate)(IDirect3DCryptoSession9 *This, UINT CertifacteSize, BYTE *ppCertificate);
+       HRESULT (WINAPI *NegotiateKeyExchange)(IDirect3DCryptoSession9 *This, UINT DataSize, void *pData);
+       HRESULT (WINAPI *EncryptionBlt)(IDirect3DCryptoSession9 *This, IDirect3DSurface9 *pSrcSurface, IDirect3DSurface9 *pDstSurface, UINT DstSurfaceSize, void *pIV);
+       HRESULT (WINAPI *DecryptionBlt)(IDirect3DCryptoSession9 *This, IDirect3DSurface9 *pSrcSurface, IDirect3DSurface9 *pDstSurface, UINT SrcSurfaceSize, D3DENCRYPTED_BLOCK_INFO *pEncryptedBlockInfo, void *pContentKey, void *pIV);
+       HRESULT (WINAPI *GetSurfacePitch)(IDirect3DCryptoSession9 *This, IDirect3DSurface9 *pSrcSurface, UINT *pSurfacePitch);
+       HRESULT (WINAPI *StartSessionKeyRefresh)(IDirect3DCryptoSession9 *This, void *pRandomNumber, UINT RandomNumberSize);
+       HRESULT (WINAPI *FinishSessionKeyRefresh)(IDirect3DCryptoSession9 *This);
+       HRESULT (WINAPI *GetEncryptionBltKey)(IDirect3DCryptoSession9 *This, void *pReadbackKey, UINT KeySize);
+} IDirect3DCryptoSession9Vtbl;
+struct IDirect3DCryptoSession9
+{
+       IDirect3DCryptoSession9Vtbl *lpVtbl;
+};
+
+/* IUnknown macros */
+#define IDirect3DCryptoSession9_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
+#define IDirect3DCryptoSession9_AddRef(p) (p)->lpVtbl->AddRef(p)
+#define IDirect3DCryptoSession9_Release(p) (p)->lpVtbl->Release(p)
+/* IDirect3DCryptoSession9 macros */
+#define IDirect3DCryptoSession9_GetCertificateSize(p,a) (p)->lpVtbl->GetCertificateSize(p,a)
+#define IDirect3DCryptoSession9_GetCertificate(p,a,b) (p)->lpVtbl->GetCertificate(p,a,b)
+#define IDirect3DCryptoSession9_NegotiateKeyExchange(p,a,b) (p)->lpVtbl->NegotiateKeyExchange(p,a,b)
+#define IDirect3DCryptoSession9_EncryptionBlt(p,a,b,c,d) (p)->lpVtbl->EncryptionBlt(p,a,b,c,d)
+#define IDirect3DCryptoSession9_DecryptionBlt(p,a,b,c,d,e,f) (p)->lpVtbl->DecryptionBlt(p,a,b,c,d,e,f)
+#define IDirect3DCryptoSession9_GetSurfacePitch(p,a,b) (p)->lpVtbl->GetSurfacePitch(p,a,b)
+#define IDirect3DCryptoSession9_StartSessionKeyRefresh(p,a,b) (p)->lpVtbl->StartSessionKeyRefresh(p,a,b)
+#define IDirect3DCryptoSession9_FinishSessionKeyRefresh(p) (p)->lpVtbl->FinishSessionKeyRefresh(p)
+#define IDirect3DCryptoSession9_GetEncryptionBltKey(p,a,b) (p)->lpVtbl->GetEncryptionBltKey(p,a,b)
+
+typedef struct IDirect3DCubeTexture9Vtbl
+{
+       /* IUnknown */
+       HRESULT (WINAPI *QueryInterface)(IDirect3DCubeTexture9 *This, REFIID riid, void **ppvObject);
+       ULONG (WINAPI *AddRef)(IDirect3DCubeTexture9 *This);
+       ULONG (WINAPI *Release)(IDirect3DCubeTexture9 *This);
+       /* IDirect3DResource9 */
+       HRESULT (WINAPI *GetDevice)(IDirect3DCubeTexture9 *This, IDirect3DDevice9 **ppDevice);
+       HRESULT (WINAPI *SetPrivateData)(IDirect3DCubeTexture9 *This, REFGUID refguid, const void *pData, DWORD SizeOfData, DWORD Flags);
+       HRESULT (WINAPI *GetPrivateData)(IDirect3DCubeTexture9 *This, REFGUID refguid, void *pData, DWORD *pSizeOfData);
+       HRESULT (WINAPI *FreePrivateData)(IDirect3DCubeTexture9 *This, REFGUID refguid);
+       DWORD (WINAPI *SetPriority)(IDirect3DCubeTexture9 *This, DWORD PriorityNew);
+       DWORD (WINAPI *GetPriority)(IDirect3DCubeTexture9 *This);
+       void (WINAPI *PreLoad)(IDirect3DCubeTexture9 *This);
+       D3DRESOURCETYPE (WINAPI *GetType)(IDirect3DCubeTexture9 *This);
+       /* IDirect3DBaseTexture9 */
+       DWORD (WINAPI *SetLOD)(IDirect3DCubeTexture9 *This, DWORD LODNew);
+       DWORD (WINAPI *GetLOD)(IDirect3DCubeTexture9 *This);
+       DWORD (WINAPI *GetLevelCount)(IDirect3DCubeTexture9 *This);
+       HRESULT (WINAPI *SetAutoGenFilterType)(IDirect3DCubeTexture9 *This, D3DTEXTUREFILTERTYPE FilterType);
+       D3DTEXTUREFILTERTYPE (WINAPI *GetAutoGenFilterType)(IDirect3DCubeTexture9 *This);
+       void (WINAPI *GenerateMipSubLevels)(IDirect3DCubeTexture9 *This);
+       /* IDirect3DCubeTexture9 */
+       HRESULT (WINAPI *GetLevelDesc)(IDirect3DCubeTexture9 *This, UINT Level, D3DSURFACE_DESC *pDesc);
+       HRESULT (WINAPI *GetCubeMapSurface)(IDirect3DCubeTexture9 *This, D3DCUBEMAP_FACES FaceType, UINT Level, IDirect3DSurface9 **ppCubeMapSurface);
+       HRESULT (WINAPI *LockRect)(IDirect3DCubeTexture9 *This, D3DCUBEMAP_FACES FaceType, UINT Level, D3DLOCKED_RECT *pLockedRect, const RECT *pRect, DWORD Flags);
+       HRESULT (WINAPI *UnlockRect)(IDirect3DCubeTexture9 *This, D3DCUBEMAP_FACES FaceType, UINT Level);
+       HRESULT (WINAPI *AddDirtyRect)(IDirect3DCubeTexture9 *This, D3DCUBEMAP_FACES FaceType, const RECT *pDirtyRect);
+} IDirect3DCubeTexture9Vtbl;
+struct IDirect3DCubeTexture9
+{
+       IDirect3DCubeTexture9Vtbl *lpVtbl;
+};
+
+/* IUnknown macros */
+#define IDirect3DCubeTexture9_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
+#define IDirect3DCubeTexture9_AddRef(p) (p)->lpVtbl->AddRef(p)
+#define IDirect3DCubeTexture9_Release(p) (p)->lpVtbl->Release(p)
+/* IDirect3DResource9 macros */
+#define IDirect3DCubeTexture9_GetDevice(p,a) (p)->lpVtbl->GetDevice(p,a)
+#define IDirect3DCubeTexture9_SetPrivateData(p,a,b,c,d) (p)->lpVtbl->SetPrivateData(p,a,b,c,d)
+#define IDirect3DCubeTexture9_GetPrivateData(p,a,b,c) (p)->lpVtbl->GetPrivateData(p,a,b,c)
+#define IDirect3DCubeTexture9_FreePrivateData(p,a) (p)->lpVtbl->FreePrivateData(p,a)
+#define IDirect3DCubeTexture9_SetPriority(p,a) (p)->lpVtbl->SetPriority(p,a)
+#define IDirect3DCubeTexture9_GetPriority(p) (p)->lpVtbl->GetPriority(p)
+#define IDirect3DCubeTexture9_PreLoad(p) (p)->lpVtbl->PreLoad(p)
+#define IDirect3DCubeTexture9_GetType(p) (p)->lpVtbl->GetType(p)
+/* IDirect3DBaseTexture9 macros */
+#define IDirect3DCubeTexture9_SetLOD(p,a) (p)->lpVtbl->SetLOD(p,a)
+#define IDirect3DCubeTexture9_GetLOD(p) (p)->lpVtbl->GetLOD(p)
+#define IDirect3DCubeTexture9_GetLevelCount(p) (p)->lpVtbl->GetLevelCount(p)
+#define IDirect3DCubeTexture9_SetAutoGenFilterType(p,a) (p)->lpVtbl->SetAutoGenFilterType(p,a)
+#define IDirect3DCubeTexture9_GetAutoGenFilterType(p) (p)->lpVtbl->GetAutoGenFilterType(p)
+#define IDirect3DCubeTexture9_GenerateMipSubLevels(p) (p)->lpVtbl->GenerateMipSubLevels(p)
+/* IDirect3DCubeTexture9 macros */
+#define IDirect3DCubeTexture9_GetLevelDesc(p,a,b) (p)->lpVtbl->GetLevelDesc(p,a,b)
+#define IDirect3DCubeTexture9_GetCubeMapSurface(p,a,b,c) (p)->lpVtbl->GetCubeMapSurface(p,a,b,c)
+#define IDirect3DCubeTexture9_LockRect(p,a,b,c,d,e) (p)->lpVtbl->LockRect(p,a,b,c,d,e)
+#define IDirect3DCubeTexture9_UnlockRect(p,a,b) (p)->lpVtbl->UnlockRect(p,a,b)
+#define IDirect3DCubeTexture9_AddDirtyRect(p,a,b) (p)->lpVtbl->AddDirtyRect(p,a,b)
+
+typedef struct IDirect3DDevice9Vtbl
+{
+       /* IUnknown */
+       HRESULT (WINAPI *QueryInterface)(IDirect3DDevice9 *This, REFIID riid, void **ppvObject);
+       ULONG (WINAPI *AddRef)(IDirect3DDevice9 *This);
+       ULONG (WINAPI *Release)(IDirect3DDevice9 *This);
+       /* IDirect3DDevice9 */
+       HRESULT (WINAPI *TestCooperativeLevel)(IDirect3DDevice9 *This);
+       UINT (WINAPI *GetAvailableTextureMem)(IDirect3DDevice9 *This);
+       HRESULT (WINAPI *EvictManagedResources)(IDirect3DDevice9 *This);
+       HRESULT (WINAPI *GetDirect3D)(IDirect3DDevice9 *This, IDirect3D9 **ppD3D9);
+       HRESULT (WINAPI *GetDeviceCaps)(IDirect3DDevice9 *This, D3DCAPS9 *pCaps);
+       HRESULT (WINAPI *GetDisplayMode)(IDirect3DDevice9 *This, UINT iSwapChain, D3DDISPLAYMODE *pMode);
+       HRESULT (WINAPI *GetCreationParameters)(IDirect3DDevice9 *This, D3DDEVICE_CREATION_PARAMETERS *pParameters);
+       HRESULT (WINAPI *SetCursorProperties)(IDirect3DDevice9 *This, UINT XHotSpot, UINT YHotSpot, IDirect3DSurface9 *pCursorBitmap);
+       void (WINAPI *SetCursorPosition)(IDirect3DDevice9 *This, int X, int Y, DWORD Flags);
+       BOOL (WINAPI *ShowCursor)(IDirect3DDevice9 *This, BOOL bShow);
+       HRESULT (WINAPI *CreateAdditionalSwapChain)(IDirect3DDevice9 *This, D3DPRESENT_PARAMETERS *pPresentationParameters, IDirect3DSwapChain9 **pSwapChain);
+       HRESULT (WINAPI *GetSwapChain)(IDirect3DDevice9 *This, UINT iSwapChain, IDirect3DSwapChain9 **pSwapChain);
+       UINT (WINAPI *GetNumberOfSwapChains)(IDirect3DDevice9 *This);
+       HRESULT (WINAPI *Reset)(IDirect3DDevice9 *This, D3DPRESENT_PARAMETERS *pPresentationParameters);
+       HRESULT (WINAPI *Present)(IDirect3DDevice9 *This, const RECT *pSourceRect, const RECT *pDestRect, HWND hDestWindowOverride, const RGNDATA *pDirtyRegion);
+       HRESULT (WINAPI *GetBackBuffer)(IDirect3DDevice9 *This, UINT iSwapChain, UINT iBackBuffer, D3DBACKBUFFER_TYPE Type, IDirect3DSurface9 **ppBackBuffer);
+       HRESULT (WINAPI *GetRasterStatus)(IDirect3DDevice9 *This, UINT iSwapChain, D3DRASTER_STATUS *pRasterStatus);
+       HRESULT (WINAPI *SetDialogBoxMode)(IDirect3DDevice9 *This, BOOL bEnableDialogs);
+       void (WINAPI *SetGammaRamp)(IDirect3DDevice9 *This, UINT iSwapChain, DWORD Flags, const D3DGAMMARAMP *pRamp);
+       void (WINAPI *GetGammaRamp)(IDirect3DDevice9 *This, UINT iSwapChain, D3DGAMMARAMP *pRamp);
+       HRESULT (WINAPI *CreateTexture)(IDirect3DDevice9 *This, UINT Width, UINT Height, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DTexture9 **ppTexture, HANDLE *pSharedHandle);
+       HRESULT (WINAPI *CreateVolumeTexture)(IDirect3DDevice9 *This, UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DVolumeTexture9 **ppVolumeTexture, HANDLE *pSharedHandle);
+       HRESULT (WINAPI *CreateCubeTexture)(IDirect3DDevice9 *This, UINT EdgeLength, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DCubeTexture9 **ppCubeTexture, HANDLE *pSharedHandle);
+       HRESULT (WINAPI *CreateVertexBuffer)(IDirect3DDevice9 *This, UINT Length, DWORD Usage, DWORD FVF, D3DPOOL Pool, IDirect3DVertexBuffer9 **ppVertexBuffer, HANDLE *pSharedHandle);
+       HRESULT (WINAPI *CreateIndexBuffer)(IDirect3DDevice9 *This, UINT Length, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DIndexBuffer9 **ppIndexBuffer, HANDLE *pSharedHandle);
+       HRESULT (WINAPI *CreateRenderTarget)(IDirect3DDevice9 *This, UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Lockable, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle);
+       HRESULT (WINAPI *CreateDepthStencilSurface)(IDirect3DDevice9 *This, UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Discard, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle);
+       HRESULT (WINAPI *UpdateSurface)(IDirect3DDevice9 *This, IDirect3DSurface9 *pSourceSurface, const RECT *pSourceRect, IDirect3DSurface9 *pDestinationSurface, const POINT *pDestPoint);
+       HRESULT (WINAPI *UpdateTexture)(IDirect3DDevice9 *This, IDirect3DBaseTexture9 *pSourceTexture, IDirect3DBaseTexture9 *pDestinationTexture);
+       HRESULT (WINAPI *GetRenderTargetData)(IDirect3DDevice9 *This, IDirect3DSurface9 *pRenderTarget, IDirect3DSurface9 *pDestSurface);
+       HRESULT (WINAPI *GetFrontBufferData)(IDirect3DDevice9 *This, UINT iSwapChain, IDirect3DSurface9 *pDestSurface);
+       HRESULT (WINAPI *StretchRect)(IDirect3DDevice9 *This, IDirect3DSurface9 *pSourceSurface, const RECT *pSourceRect, IDirect3DSurface9 *pDestSurface, const RECT *pDestRect, D3DTEXTUREFILTERTYPE Filter);
+       HRESULT (WINAPI *ColorFill)(IDirect3DDevice9 *This, IDirect3DSurface9 *pSurface, const RECT *pRect, D3DCOLOR color);
+       HRESULT (WINAPI *CreateOffscreenPlainSurface)(IDirect3DDevice9 *This, UINT Width, UINT Height, D3DFORMAT Format, D3DPOOL Pool, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle);
+       HRESULT (WINAPI *SetRenderTarget)(IDirect3DDevice9 *This, DWORD RenderTargetIndex, IDirect3DSurface9 *pRenderTarget);
+       HRESULT (WINAPI *GetRenderTarget)(IDirect3DDevice9 *This, DWORD RenderTargetIndex, IDirect3DSurface9 **ppRenderTarget);
+       HRESULT (WINAPI *SetDepthStencilSurface)(IDirect3DDevice9 *This, IDirect3DSurface9 *pNewZStencil);
+       HRESULT (WINAPI *GetDepthStencilSurface)(IDirect3DDevice9 *This, IDirect3DSurface9 **ppZStencilSurface);
+       HRESULT (WINAPI *BeginScene)(IDirect3DDevice9 *This);
+       HRESULT (WINAPI *EndScene)(IDirect3DDevice9 *This);
+       HRESULT (WINAPI *Clear)(IDirect3DDevice9 *This, DWORD Count, const D3DRECT *pRects, DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil);
+       HRESULT (WINAPI *SetTransform)(IDirect3DDevice9 *This, D3DTRANSFORMSTATETYPE State, const D3DMATRIX *pMatrix);
+       HRESULT (WINAPI *GetTransform)(IDirect3DDevice9 *This, D3DTRANSFORMSTATETYPE State, D3DMATRIX *pMatrix);
+       HRESULT (WINAPI *MultiplyTransform)(IDirect3DDevice9 *This, D3DTRANSFORMSTATETYPE State, const D3DMATRIX *pMatrix);
+       HRESULT (WINAPI *SetViewport)(IDirect3DDevice9 *This, const D3DVIEWPORT9 *pViewport);
+       HRESULT (WINAPI *GetViewport)(IDirect3DDevice9 *This, D3DVIEWPORT9 *pViewport);
+       HRESULT (WINAPI *SetMaterial)(IDirect3DDevice9 *This, const D3DMATERIAL9 *pMaterial);
+       HRESULT (WINAPI *GetMaterial)(IDirect3DDevice9 *This, D3DMATERIAL9 *pMaterial);
+       HRESULT (WINAPI *SetLight)(IDirect3DDevice9 *This, DWORD Index, const D3DLIGHT9 *pLight);
+       HRESULT (WINAPI *GetLight)(IDirect3DDevice9 *This, DWORD Index, D3DLIGHT9 *pLight);
+       HRESULT (WINAPI *LightEnable)(IDirect3DDevice9 *This, DWORD Index, BOOL Enable);
+       HRESULT (WINAPI *GetLightEnable)(IDirect3DDevice9 *This, DWORD Index, BOOL *pEnable);
+       HRESULT (WINAPI *SetClipPlane)(IDirect3DDevice9 *This, DWORD Index, const float *pPlane);
+       HRESULT (WINAPI *GetClipPlane)(IDirect3DDevice9 *This, DWORD Index, float *pPlane);
+       HRESULT (WINAPI *SetRenderState)(IDirect3DDevice9 *This, D3DRENDERSTATETYPE State, DWORD Value);
+       HRESULT (WINAPI *GetRenderState)(IDirect3DDevice9 *This, D3DRENDERSTATETYPE State, DWORD *pValue);
+       HRESULT (WINAPI *CreateStateBlock)(IDirect3DDevice9 *This, D3DSTATEBLOCKTYPE Type, IDirect3DStateBlock9 **ppSB);
+       HRESULT (WINAPI *BeginStateBlock)(IDirect3DDevice9 *This);
+       HRESULT (WINAPI *EndStateBlock)(IDirect3DDevice9 *This, IDirect3DStateBlock9 **ppSB);
+       HRESULT (WINAPI *SetClipStatus)(IDirect3DDevice9 *This, const D3DCLIPSTATUS9 *pClipStatus);
+       HRESULT (WINAPI *GetClipStatus)(IDirect3DDevice9 *This, D3DCLIPSTATUS9 *pClipStatus);
+       HRESULT (WINAPI *GetTexture)(IDirect3DDevice9 *This, DWORD Stage, IDirect3DBaseTexture9 **ppTexture);
+       HRESULT (WINAPI *SetTexture)(IDirect3DDevice9 *This, DWORD Stage, IDirect3DBaseTexture9 *pTexture);
+       HRESULT (WINAPI *GetTextureStageState)(IDirect3DDevice9 *This, DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD *pValue);
+       HRESULT (WINAPI *SetTextureStageState)(IDirect3DDevice9 *This, DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value);
+       HRESULT (WINAPI *GetSamplerState)(IDirect3DDevice9 *This, DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD *pValue);
+       HRESULT (WINAPI *SetSamplerState)(IDirect3DDevice9 *This, DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value);
+       HRESULT (WINAPI *ValidateDevice)(IDirect3DDevice9 *This, DWORD *pNumPasses);
+       HRESULT (WINAPI *SetPaletteEntries)(IDirect3DDevice9 *This, UINT PaletteNumber, const PALETTEENTRY *pEntries);
+       HRESULT (WINAPI *GetPaletteEntries)(IDirect3DDevice9 *This, UINT PaletteNumber, PALETTEENTRY *pEntries);
+       HRESULT (WINAPI *SetCurrentTexturePalette)(IDirect3DDevice9 *This, UINT PaletteNumber);
+       HRESULT (WINAPI *GetCurrentTexturePalette)(IDirect3DDevice9 *This, UINT *PaletteNumber);
+       HRESULT (WINAPI *SetScissorRect)(IDirect3DDevice9 *This, const RECT *pRect);
+       HRESULT (WINAPI *GetScissorRect)(IDirect3DDevice9 *This, RECT *pRect);
+       HRESULT (WINAPI *SetSoftwareVertexProcessing)(IDirect3DDevice9 *This, BOOL bSoftware);
+       BOOL (WINAPI *GetSoftwareVertexProcessing)(IDirect3DDevice9 *This);
+       HRESULT (WINAPI *SetNPatchMode)(IDirect3DDevice9 *This, float nSegments);
+       float (WINAPI *GetNPatchMode)(IDirect3DDevice9 *This);
+       HRESULT (WINAPI *DrawPrimitive)(IDirect3DDevice9 *This, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount);
+       HRESULT (WINAPI *DrawIndexedPrimitive)(IDirect3DDevice9 *This, D3DPRIMITIVETYPE PrimitiveType, INT BaseVertexIndex, UINT MinVertexIndex, UINT NumVertices, UINT startIndex, UINT primCount);
+       HRESULT (WINAPI *DrawPrimitiveUP)(IDirect3DDevice9 *This, D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, const void *pVertexStreamZeroData, UINT VertexStreamZeroStride);
+       HRESULT (WINAPI *DrawIndexedPrimitiveUP)(IDirect3DDevice9 *This, D3DPRIMITIVETYPE PrimitiveType, UINT MinVertexIndex, UINT NumVertices, UINT PrimitiveCount, const void *pIndexData, D3DFORMAT IndexDataFormat, const void *pVertexStreamZeroData, UINT VertexStreamZeroStride);
+       HRESULT (WINAPI *ProcessVertices)(IDirect3DDevice9 *This, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IDirect3DVertexBuffer9 *pDestBuffer, IDirect3DVertexDeclaration9 *pVertexDecl, DWORD Flags);
+       HRESULT (WINAPI *CreateVertexDeclaration)(IDirect3DDevice9 *This, const D3DVERTEXELEMENT9 *pVertexElements, IDirect3DVertexDeclaration9 **ppDecl);
+       HRESULT (WINAPI *SetVertexDeclaration)(IDirect3DDevice9 *This, IDirect3DVertexDeclaration9 *pDecl);
+       HRESULT (WINAPI *GetVertexDeclaration)(IDirect3DDevice9 *This, IDirect3DVertexDeclaration9 **ppDecl);
+       HRESULT (WINAPI *SetFVF)(IDirect3DDevice9 *This, DWORD FVF);
+       HRESULT (WINAPI *GetFVF)(IDirect3DDevice9 *This, DWORD *pFVF);
+       HRESULT (WINAPI *CreateVertexShader)(IDirect3DDevice9 *This, const DWORD *pFunction, IDirect3DVertexShader9 **ppShader);
+       HRESULT (WINAPI *SetVertexShader)(IDirect3DDevice9 *This, IDirect3DVertexShader9 *pShader);
+       HRESULT (WINAPI *GetVertexShader)(IDirect3DDevice9 *This, IDirect3DVertexShader9 **ppShader);
+       HRESULT (WINAPI *SetVertexShaderConstantF)(IDirect3DDevice9 *This, UINT StartRegister, const float *pConstantData, UINT Vector4fCount);
+       HRESULT (WINAPI *GetVertexShaderConstantF)(IDirect3DDevice9 *This, UINT StartRegister, float *pConstantData, UINT Vector4fCount);
+       HRESULT (WINAPI *SetVertexShaderConstantI)(IDirect3DDevice9 *This, UINT StartRegister, const int *pConstantData, UINT Vector4iCount);
+       HRESULT (WINAPI *GetVertexShaderConstantI)(IDirect3DDevice9 *This, UINT StartRegister, int *pConstantData, UINT Vector4iCount);
+       HRESULT (WINAPI *SetVertexShaderConstantB)(IDirect3DDevice9 *This, UINT StartRegister, const BOOL *pConstantData, UINT BoolCount);
+       HRESULT (WINAPI *GetVertexShaderConstantB)(IDirect3DDevice9 *This, UINT StartRegister, BOOL *pConstantData, UINT BoolCount);
+       HRESULT (WINAPI *SetStreamSource)(IDirect3DDevice9 *This, UINT StreamNumber, IDirect3DVertexBuffer9 *pStreamData, UINT OffsetInBytes, UINT Stride);
+       HRESULT (WINAPI *GetStreamSource)(IDirect3DDevice9 *This, UINT StreamNumber, IDirect3DVertexBuffer9 **ppStreamData, UINT *pOffsetInBytes, UINT *pStride);
+       HRESULT (WINAPI *SetStreamSourceFreq)(IDirect3DDevice9 *This, UINT StreamNumber, UINT Setting);
+       HRESULT (WINAPI *GetStreamSourceFreq)(IDirect3DDevice9 *This, UINT StreamNumber, UINT *pSetting);
+       HRESULT (WINAPI *SetIndices)(IDirect3DDevice9 *This, IDirect3DIndexBuffer9 *pIndexData);
+       HRESULT (WINAPI *GetIndices)(IDirect3DDevice9 *This, IDirect3DIndexBuffer9 **ppIndexData, UINT *pBaseVertexIndex);
+       HRESULT (WINAPI *CreatePixelShader)(IDirect3DDevice9 *This, const DWORD *pFunction, IDirect3DPixelShader9 **ppShader);
+       HRESULT (WINAPI *SetPixelShader)(IDirect3DDevice9 *This, IDirect3DPixelShader9 *pShader);
+       HRESULT (WINAPI *GetPixelShader)(IDirect3DDevice9 *This, IDirect3DPixelShader9 **ppShader);
+       HRESULT (WINAPI *SetPixelShaderConstantF)(IDirect3DDevice9 *This, UINT StartRegister, const float *pConstantData, UINT Vector4fCount);
+       HRESULT (WINAPI *GetPixelShaderConstantF)(IDirect3DDevice9 *This, UINT StartRegister, float *pConstantData, UINT Vector4fCount);
+       HRESULT (WINAPI *SetPixelShaderConstantI)(IDirect3DDevice9 *This, UINT StartRegister, const int *pConstantData, UINT Vector4iCount);
+       HRESULT (WINAPI *GetPixelShaderConstantI)(IDirect3DDevice9 *This, UINT StartRegister, int *pConstantData, UINT Vector4iCount);
+       HRESULT (WINAPI *SetPixelShaderConstantB)(IDirect3DDevice9 *This, UINT StartRegister, const BOOL *pConstantData, UINT BoolCount);
+       HRESULT (WINAPI *GetPixelShaderConstantB)(IDirect3DDevice9 *This, UINT StartRegister, BOOL *pConstantData, UINT BoolCount);
+       HRESULT (WINAPI *DrawRectPatch)(IDirect3DDevice9 *This, UINT Handle, const float *pNumSegs, const D3DRECTPATCH_INFO *pRectPatchInfo);
+       HRESULT (WINAPI *DrawTriPatch)(IDirect3DDevice9 *This, UINT Handle, const float *pNumSegs, const D3DTRIPATCH_INFO *pTriPatchInfo);
+       HRESULT (WINAPI *DeletePatch)(IDirect3DDevice9 *This, UINT Handle);
+       HRESULT (WINAPI *CreateQuery)(IDirect3DDevice9 *This, D3DQUERYTYPE Type, IDirect3DQuery9 **ppQuery);
+} IDirect3DDevice9Vtbl;
+struct IDirect3DDevice9
+{
+       IDirect3DDevice9Vtbl *lpVtbl;
+};
+
+/* IUnknown macros */
+#define IDirect3DDevice9_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
+#define IDirect3DDevice9_AddRef(p) (p)->lpVtbl->AddRef(p)
+#define IDirect3DDevice9_Release(p) (p)->lpVtbl->Release(p)
+/* IDirect3DDevice9 macros */
+#define IDirect3DDevice9_TestCooperativeLevel(p) (p)->lpVtbl->TestCooperativeLevel(p)
+#define IDirect3DDevice9_GetAvailableTextureMem(p) (p)->lpVtbl->GetAvailableTextureMem(p)
+#define IDirect3DDevice9_EvictManagedResources(p) (p)->lpVtbl->EvictManagedResources(p)
+#define IDirect3DDevice9_GetDirect3D(p,a) (p)->lpVtbl->GetDirect3D(p,a)
+#define IDirect3DDevice9_GetDeviceCaps(p,a) (p)->lpVtbl->GetDeviceCaps(p,a)
+#define IDirect3DDevice9_GetDisplayMode(p,a,b) (p)->lpVtbl->GetDisplayMode(p,a,b)
+#define IDirect3DDevice9_GetCreationParameters(p,a) (p)->lpVtbl->GetCreationParameters(p,a)
+#define IDirect3DDevice9_SetCursorProperties(p,a,b,c) (p)->lpVtbl->SetCursorProperties(p,a,b,c)
+#define IDirect3DDevice9_SetCursorPosition(p,a,b,c) (p)->lpVtbl->SetCursorPosition(p,a,b,c)
+#define IDirect3DDevice9_ShowCursor(p,a) (p)->lpVtbl->ShowCursor(p,a)
+#define IDirect3DDevice9_CreateAdditionalSwapChain(p,a,b) (p)->lpVtbl->CreateAdditionalSwapChain(p,a,b)
+#define IDirect3DDevice9_GetSwapChain(p,a,b) (p)->lpVtbl->GetSwapChain(p,a,b)
+#define IDirect3DDevice9_GetNumberOfSwapChains(p) (p)->lpVtbl->GetNumberOfSwapChains(p)
+#define IDirect3DDevice9_Reset(p,a) (p)->lpVtbl->Reset(p,a)
+#define IDirect3DDevice9_Present(p,a,b,c,d) (p)->lpVtbl->Present(p,a,b,c,d)
+#define IDirect3DDevice9_GetBackBuffer(p,a,b,c,d) (p)->lpVtbl->GetBackBuffer(p,a,b,c,d)
+#define IDirect3DDevice9_GetRasterStatus(p,a,b) (p)->lpVtbl->GetRasterStatus(p,a,b)
+#define IDirect3DDevice9_SetDialogBoxMode(p,a) (p)->lpVtbl->SetDialogBoxMode(p,a)
+#define IDirect3DDevice9_SetGammaRamp(p,a,b,c) (p)->lpVtbl->SetGammaRamp(p,a,b,c)
+#define IDirect3DDevice9_GetGammaRamp(p,a,b) (p)->lpVtbl->GetGammaRamp(p,a,b)
+#define IDirect3DDevice9_CreateTexture(p,a,b,c,d,e,f,g,h) (p)->lpVtbl->CreateTexture(p,a,b,c,d,e,f,g,h)
+#define IDirect3DDevice9_CreateVolumeTexture(p,a,b,c,d,e,f,g,h,i) (p)->lpVtbl->CreateVolumeTexture(p,a,b,c,d,e,f,g,h,i)
+#define IDirect3DDevice9_CreateCubeTexture(p,a,b,c,d,e,f,g) (p)->lpVtbl->CreateCubeTexture(p,a,b,c,d,e,f,g)
+#define IDirect3DDevice9_CreateVertexBuffer(p,a,b,c,d,e,f) (p)->lpVtbl->CreateVertexBuffer(p,a,b,c,d,e,f)
+#define IDirect3DDevice9_CreateIndexBuffer(p,a,b,c,d,e,f) (p)->lpVtbl->CreateIndexBuffer(p,a,b,c,d,e,f)
+#define IDirect3DDevice9_CreateRenderTarget(p,a,b,c,d,e,f,g,h) (p)->lpVtbl->CreateRenderTarget(p,a,b,c,d,e,f,g,h)
+#define IDirect3DDevice9_CreateDepthStencilSurface(p,a,b,c,d,e,f,g,h) (p)->lpVtbl->CreateDepthStencilSurface(p,a,b,c,d,e,f,g,h)
+#define IDirect3DDevice9_UpdateSurface(p,a,b,c,d) (p)->lpVtbl->UpdateSurface(p,a,b,c,d)
+#define IDirect3DDevice9_UpdateTexture(p,a,b) (p)->lpVtbl->UpdateTexture(p,a,b)
+#define IDirect3DDevice9_GetRenderTargetData(p,a,b) (p)->lpVtbl->GetRenderTargetData(p,a,b)
+#define IDirect3DDevice9_GetFrontBufferData(p,a,b) (p)->lpVtbl->GetFrontBufferData(p,a,b)
+#define IDirect3DDevice9_StretchRect(p,a,b,c,d,e) (p)->lpVtbl->StretchRect(p,a,b,c,d,e)
+#define IDirect3DDevice9_ColorFill(p,a,b,c) (p)->lpVtbl->ColorFill(p,a,b,c)
+#define IDirect3DDevice9_CreateOffscreenPlainSurface(p,a,b,c,d,e,f) (p)->lpVtbl->CreateOffscreenPlainSurface(p,a,b,c,d,e,f)
+#define IDirect3DDevice9_SetRenderTarget(p,a,b) (p)->lpVtbl->SetRenderTarget(p,a,b)
+#define IDirect3DDevice9_GetRenderTarget(p,a,b) (p)->lpVtbl->GetRenderTarget(p,a,b)
+#define IDirect3DDevice9_SetDepthStencilSurface(p,a) (p)->lpVtbl->SetDepthStencilSurface(p,a)
+#define IDirect3DDevice9_GetDepthStencilSurface(p,a) (p)->lpVtbl->GetDepthStencilSurface(p,a)
+#define IDirect3DDevice9_BeginScene(p) (p)->lpVtbl->BeginScene(p)
+#define IDirect3DDevice9_EndScene(p) (p)->lpVtbl->EndScene(p)
+#define IDirect3DDevice9_Clear(p,a,b,c,d,e,f) (p)->lpVtbl->Clear(p,a,b,c,d,e,f)
+#define IDirect3DDevice9_SetTransform(p,a,b) (p)->lpVtbl->SetTransform(p,a,b)
+#define IDirect3DDevice9_GetTransform(p,a,b) (p)->lpVtbl->GetTransform(p,a,b)
+#define IDirect3DDevice9_MultiplyTransform(p,a,b) (p)->lpVtbl->MultiplyTransform(p,a,b)
+#define IDirect3DDevice9_SetViewport(p,a) (p)->lpVtbl->SetViewport(p,a)
+#define IDirect3DDevice9_GetViewport(p,a) (p)->lpVtbl->GetViewport(p,a)
+#define IDirect3DDevice9_SetMaterial(p,a) (p)->lpVtbl->SetMaterial(p,a)
+#define IDirect3DDevice9_GetMaterial(p,a) (p)->lpVtbl->GetMaterial(p,a)
+#define IDirect3DDevice9_SetLight(p,a,b) (p)->lpVtbl->SetLight(p,a,b)
+#define IDirect3DDevice9_GetLight(p,a,b) (p)->lpVtbl->GetLight(p,a,b)
+#define IDirect3DDevice9_LightEnable(p,a,b) (p)->lpVtbl->LightEnable(p,a,b)
+#define IDirect3DDevice9_GetLightEnable(p,a,b) (p)->lpVtbl->GetLightEnable(p,a,b)
+#define IDirect3DDevice9_SetClipPlane(p,a,b) (p)->lpVtbl->SetClipPlane(p,a,b)
+#define IDirect3DDevice9_GetClipPlane(p,a,b) (p)->lpVtbl->GetClipPlane(p,a,b)
+#define IDirect3DDevice9_SetRenderState(p,a,b) (p)->lpVtbl->SetRenderState(p,a,b)
+#define IDirect3DDevice9_GetRenderState(p,a,b) (p)->lpVtbl->GetRenderState(p,a,b)
+#define IDirect3DDevice9_CreateStateBlock(p,a,b) (p)->lpVtbl->CreateStateBlock(p,a,b)
+#define IDirect3DDevice9_BeginStateBlock(p) (p)->lpVtbl->BeginStateBlock(p)
+#define IDirect3DDevice9_EndStateBlock(p,a) (p)->lpVtbl->EndStateBlock(p,a)
+#define IDirect3DDevice9_SetClipStatus(p,a) (p)->lpVtbl->SetClipStatus(p,a)
+#define IDirect3DDevice9_GetClipStatus(p,a) (p)->lpVtbl->GetClipStatus(p,a)
+#define IDirect3DDevice9_GetTexture(p,a,b) (p)->lpVtbl->GetTexture(p,a,b)
+#define IDirect3DDevice9_SetTexture(p,a,b) (p)->lpVtbl->SetTexture(p,a,b)
+#define IDirect3DDevice9_GetTextureStageState(p,a,b,c) (p)->lpVtbl->GetTextureStageState(p,a,b,c)
+#define IDirect3DDevice9_SetTextureStageState(p,a,b,c) (p)->lpVtbl->SetTextureStageState(p,a,b,c)
+#define IDirect3DDevice9_GetSamplerState(p,a,b,c) (p)->lpVtbl->GetSamplerState(p,a,b,c)
+#define IDirect3DDevice9_SetSamplerState(p,a,b,c) (p)->lpVtbl->SetSamplerState(p,a,b,c)
+#define IDirect3DDevice9_ValidateDevice(p,a) (p)->lpVtbl->ValidateDevice(p,a)
+#define IDirect3DDevice9_SetPaletteEntries(p,a,b) (p)->lpVtbl->SetPaletteEntries(p,a,b)
+#define IDirect3DDevice9_GetPaletteEntries(p,a,b) (p)->lpVtbl->GetPaletteEntries(p,a,b)
+#define IDirect3DDevice9_SetCurrentTexturePalette(p,a) (p)->lpVtbl->SetCurrentTexturePalette(p,a)
+#define IDirect3DDevice9_GetCurrentTexturePalette(p,a) (p)->lpVtbl->GetCurrentTexturePalette(p,a)
+#define IDirect3DDevice9_SetScissorRect(p,a) (p)->lpVtbl->SetScissorRect(p,a)
+#define IDirect3DDevice9_GetScissorRect(p,a) (p)->lpVtbl->GetScissorRect(p,a)
+#define IDirect3DDevice9_SetSoftwareVertexProcessing(p,a) (p)->lpVtbl->SetSoftwareVertexProcessing(p,a)
+#define IDirect3DDevice9_GetSoftwareVertexProcessing(p) (p)->lpVtbl->GetSoftwareVertexProcessing(p)
+#define IDirect3DDevice9_SetNPatchMode(p,a) (p)->lpVtbl->SetNPatchMode(p,a)
+#define IDirect3DDevice9_GetNPatchMode(p) (p)->lpVtbl->GetNPatchMode(p)
+#define IDirect3DDevice9_DrawPrimitive(p,a,b,c) (p)->lpVtbl->DrawPrimitive(p,a,b,c)
+#define IDirect3DDevice9_DrawIndexedPrimitive(p,a,b,c,d,e,f) (p)->lpVtbl->DrawIndexedPrimitive(p,a,b,c,d,e,f)
+#define IDirect3DDevice9_DrawPrimitiveUP(p,a,b,c,d) (p)->lpVtbl->DrawPrimitiveUP(p,a,b,c,d)
+#define IDirect3DDevice9_DrawIndexedPrimitiveUP(p,a,b,c,d,e,f,g,h) (p)->lpVtbl->DrawIndexedPrimitiveUP(p,a,b,c,d,e,f,g,h)
+#define IDirect3DDevice9_ProcessVertices(p,a,b,c,d,e,f) (p)->lpVtbl->ProcessVertices(p,a,b,c,d,e,f)
+#define IDirect3DDevice9_CreateVertexDeclaration(p,a,b) (p)->lpVtbl->CreateVertexDeclaration(p,a,b)
+#define IDirect3DDevice9_SetVertexDeclaration(p,a) (p)->lpVtbl->SetVertexDeclaration(p,a)
+#define IDirect3DDevice9_GetVertexDeclaration(p,a) (p)->lpVtbl->GetVertexDeclaration(p,a)
+#define IDirect3DDevice9_SetFVF(p,a) (p)->lpVtbl->SetFVF(p,a)
+#define IDirect3DDevice9_GetFVF(p,a) (p)->lpVtbl->GetFVF(p,a)
+#define IDirect3DDevice9_CreateVertexShader(p,a,b) (p)->lpVtbl->CreateVertexShader(p,a,b)
+#define IDirect3DDevice9_SetVertexShader(p,a) (p)->lpVtbl->SetVertexShader(p,a)
+#define IDirect3DDevice9_GetVertexShader(p,a) (p)->lpVtbl->GetVertexShader(p,a)
+#define IDirect3DDevice9_SetVertexShaderConstantF(p,a,b,c) (p)->lpVtbl->SetVertexShaderConstantF(p,a,b,c)
+#define IDirect3DDevice9_GetVertexShaderConstantF(p,a,b,c) (p)->lpVtbl->GetVertexShaderConstantF(p,a,b,c)
+#define IDirect3DDevice9_SetVertexShaderConstantI(p,a,b,c) (p)->lpVtbl->SetVertexShaderConstantI(p,a,b,c)
+#define IDirect3DDevice9_GetVertexShaderConstantI(p,a,b,c) (p)->lpVtbl->GetVertexShaderConstantI(p,a,b,c)
+#define IDirect3DDevice9_SetVertexShaderConstantB(p,a,b,c) (p)->lpVtbl->SetVertexShaderConstantB(p,a,b,c)
+#define IDirect3DDevice9_GetVertexShaderConstantB(p,a,b,c) (p)->lpVtbl->GetVertexShaderConstantB(p,a,b,c)
+#define IDirect3DDevice9_SetStreamSource(p,a,b,c,d) (p)->lpVtbl->SetStreamSource(p,a,b,c,d)
+#define IDirect3DDevice9_GetStreamSource(p,a,b,c,d) (p)->lpVtbl->GetStreamSource(p,a,b,c,d)
+#define IDirect3DDevice9_SetStreamSourceFreq(p,a,b) (p)->lpVtbl->SetStreamSourceFreq(p,a,b)
+#define IDirect3DDevice9_GetStreamSourceFreq(p,a,b) (p)->lpVtbl->GetStreamSourceFreq(p,a,b)
+#define IDirect3DDevice9_SetIndices(p,a) (p)->lpVtbl->SetIndices(p,a)
+#define IDirect3DDevice9_GetIndices(p,a,b) (p)->lpVtbl->GetIndices(p,a,b)
+#define IDirect3DDevice9_CreatePixelShader(p,a,b) (p)->lpVtbl->CreatePixelShader(p,a,b)
+#define IDirect3DDevice9_SetPixelShader(p,a) (p)->lpVtbl->SetPixelShader(p,a)
+#define IDirect3DDevice9_GetPixelShader(p,a) (p)->lpVtbl->GetPixelShader(p,a)
+#define IDirect3DDevice9_SetPixelShaderConstantF(p,a,b,c) (p)->lpVtbl->SetPixelShaderConstantF(p,a,b,c)
+#define IDirect3DDevice9_GetPixelShaderConstantF(p,a,b,c) (p)->lpVtbl->GetPixelShaderConstantF(p,a,b,c)
+#define IDirect3DDevice9_SetPixelShaderConstantI(p,a,b,c) (p)->lpVtbl->SetPixelShaderConstantI(p,a,b,c)
+#define IDirect3DDevice9_GetPixelShaderConstantI(p,a,b,c) (p)->lpVtbl->GetPixelShaderConstantI(p,a,b,c)
+#define IDirect3DDevice9_SetPixelShaderConstantB(p,a,b,c) (p)->lpVtbl->SetPixelShaderConstantB(p,a,b,c)
+#define IDirect3DDevice9_GetPixelShaderConstantB(p,a,b,c) (p)->lpVtbl->GetPixelShaderConstantB(p,a,b,c)
+#define IDirect3DDevice9_DrawRectPatch(p,a,b,c) (p)->lpVtbl->DrawRectPatch(p,a,b,c)
+#define IDirect3DDevice9_DrawTriPatch(p,a,b,c) (p)->lpVtbl->DrawTriPatch(p,a,b,c)
+#define IDirect3DDevice9_DeletePatch(p,a) (p)->lpVtbl->DeletePatch(p,a)
+#define IDirect3DDevice9_CreateQuery(p,a,b) (p)->lpVtbl->CreateQuery(p,a,b)
+
+typedef struct IDirect3DDevice9ExVtbl
+{
+       /* IUnknown */
+       HRESULT (WINAPI *QueryInterface)(IDirect3DDevice9Ex *This, REFIID riid, void **ppvObject);
+       ULONG (WINAPI *AddRef)(IDirect3DDevice9Ex *This);
+       ULONG (WINAPI *Release)(IDirect3DDevice9Ex *This);
+       /* IDirect3DDevice9 */
+       HRESULT (WINAPI *TestCooperativeLevel)(IDirect3DDevice9Ex *This);
+       UINT (WINAPI *GetAvailableTextureMem)(IDirect3DDevice9Ex *This);
+       HRESULT (WINAPI *EvictManagedResources)(IDirect3DDevice9Ex *This);
+       HRESULT (WINAPI *GetDirect3D)(IDirect3DDevice9Ex *This, IDirect3D9 **ppD3D9);
+       HRESULT (WINAPI *GetDeviceCaps)(IDirect3DDevice9Ex *This, D3DCAPS9 *pCaps);
+       HRESULT (WINAPI *GetDisplayMode)(IDirect3DDevice9Ex *This, UINT iSwapChain, D3DDISPLAYMODE *pMode);
+       HRESULT (WINAPI *GetCreationParameters)(IDirect3DDevice9Ex *This, D3DDEVICE_CREATION_PARAMETERS *pParameters);
+       HRESULT (WINAPI *SetCursorProperties)(IDirect3DDevice9Ex *This, UINT XHotSpot, UINT YHotSpot, IDirect3DSurface9 *pCursorBitmap);
+       void (WINAPI *SetCursorPosition)(IDirect3DDevice9Ex *This, int X, int Y, DWORD Flags);
+       BOOL (WINAPI *ShowCursor)(IDirect3DDevice9Ex *This, BOOL bShow);
+       HRESULT (WINAPI *CreateAdditionalSwapChain)(IDirect3DDevice9Ex *This, D3DPRESENT_PARAMETERS *pPresentationParameters, IDirect3DSwapChain9 **pSwapChain);
+       HRESULT (WINAPI *GetSwapChain)(IDirect3DDevice9Ex *This, UINT iSwapChain, IDirect3DSwapChain9 **pSwapChain);
+       UINT (WINAPI *GetNumberOfSwapChains)(IDirect3DDevice9Ex *This);
+       HRESULT (WINAPI *Reset)(IDirect3DDevice9Ex *This, D3DPRESENT_PARAMETERS *pPresentationParameters);
+       HRESULT (WINAPI *Present)(IDirect3DDevice9Ex *This, const RECT *pSourceRect, const RECT *pDestRect, HWND hDestWindowOverride, const RGNDATA *pDirtyRegion);
+       HRESULT (WINAPI *GetBackBuffer)(IDirect3DDevice9Ex *This, UINT iSwapChain, UINT iBackBuffer, D3DBACKBUFFER_TYPE Type, IDirect3DSurface9 **ppBackBuffer);
+       HRESULT (WINAPI *GetRasterStatus)(IDirect3DDevice9Ex *This, UINT iSwapChain, D3DRASTER_STATUS *pRasterStatus);
+       HRESULT (WINAPI *SetDialogBoxMode)(IDirect3DDevice9Ex *This, BOOL bEnableDialogs);
+       void (WINAPI *SetGammaRamp)(IDirect3DDevice9Ex *This, UINT iSwapChain, DWORD Flags, const D3DGAMMARAMP *pRamp);
+       void (WINAPI *GetGammaRamp)(IDirect3DDevice9Ex *This, UINT iSwapChain, D3DGAMMARAMP *pRamp);
+       HRESULT (WINAPI *CreateTexture)(IDirect3DDevice9Ex *This, UINT Width, UINT Height, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DTexture9 **ppTexture, HANDLE *pSharedHandle);
+       HRESULT (WINAPI *CreateVolumeTexture)(IDirect3DDevice9Ex *This, UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DVolumeTexture9 **ppVolumeTexture, HANDLE *pSharedHandle);
+       HRESULT (WINAPI *CreateCubeTexture)(IDirect3DDevice9Ex *This, UINT EdgeLength, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DCubeTexture9 **ppCubeTexture, HANDLE *pSharedHandle);
+       HRESULT (WINAPI *CreateVertexBuffer)(IDirect3DDevice9Ex *This, UINT Length, DWORD Usage, DWORD FVF, D3DPOOL Pool, IDirect3DVertexBuffer9 **ppVertexBuffer, HANDLE *pSharedHandle);
+       HRESULT (WINAPI *CreateIndexBuffer)(IDirect3DDevice9Ex *This, UINT Length, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DIndexBuffer9 **ppIndexBuffer, HANDLE *pSharedHandle);
+       HRESULT (WINAPI *CreateRenderTarget)(IDirect3DDevice9Ex *This, UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Lockable, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle);
+       HRESULT (WINAPI *CreateDepthStencilSurface)(IDirect3DDevice9Ex *This, UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Discard, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle);
+       HRESULT (WINAPI *UpdateSurface)(IDirect3DDevice9Ex *This, IDirect3DSurface9 *pSourceSurface, const RECT *pSourceRect, IDirect3DSurface9 *pDestinationSurface, const POINT *pDestPoint);
+       HRESULT (WINAPI *UpdateTexture)(IDirect3DDevice9Ex *This, IDirect3DBaseTexture9 *pSourceTexture, IDirect3DBaseTexture9 *pDestinationTexture);
+       HRESULT (WINAPI *GetRenderTargetData)(IDirect3DDevice9Ex *This, IDirect3DSurface9 *pRenderTarget, IDirect3DSurface9 *pDestSurface);
+       HRESULT (WINAPI *GetFrontBufferData)(IDirect3DDevice9Ex *This, UINT iSwapChain, IDirect3DSurface9 *pDestSurface);
+       HRESULT (WINAPI *StretchRect)(IDirect3DDevice9Ex *This, IDirect3DSurface9 *pSourceSurface, const RECT *pSourceRect, IDirect3DSurface9 *pDestSurface, const RECT *pDestRect, D3DTEXTUREFILTERTYPE Filter);
+       HRESULT (WINAPI *ColorFill)(IDirect3DDevice9Ex *This, IDirect3DSurface9 *pSurface, const RECT *pRect, D3DCOLOR color);
+       HRESULT (WINAPI *CreateOffscreenPlainSurface)(IDirect3DDevice9Ex *This, UINT Width, UINT Height, D3DFORMAT Format, D3DPOOL Pool, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle);
+       HRESULT (WINAPI *SetRenderTarget)(IDirect3DDevice9Ex *This, DWORD RenderTargetIndex, IDirect3DSurface9 *pRenderTarget);
+       HRESULT (WINAPI *GetRenderTarget)(IDirect3DDevice9Ex *This, DWORD RenderTargetIndex, IDirect3DSurface9 **ppRenderTarget);
+       HRESULT (WINAPI *SetDepthStencilSurface)(IDirect3DDevice9Ex *This, IDirect3DSurface9 *pNewZStencil);
+       HRESULT (WINAPI *GetDepthStencilSurface)(IDirect3DDevice9Ex *This, IDirect3DSurface9 **ppZStencilSurface);
+       HRESULT (WINAPI *BeginScene)(IDirect3DDevice9Ex *This);
+       HRESULT (WINAPI *EndScene)(IDirect3DDevice9Ex *This);
+       HRESULT (WINAPI *Clear)(IDirect3DDevice9Ex *This, DWORD Count, const D3DRECT *pRects, DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil);
+       HRESULT (WINAPI *SetTransform)(IDirect3DDevice9Ex *This, D3DTRANSFORMSTATETYPE State, const D3DMATRIX *pMatrix);
+       HRESULT (WINAPI *GetTransform)(IDirect3DDevice9Ex *This, D3DTRANSFORMSTATETYPE State, D3DMATRIX *pMatrix);
+       HRESULT (WINAPI *MultiplyTransform)(IDirect3DDevice9Ex *This, D3DTRANSFORMSTATETYPE State, const D3DMATRIX *pMatrix);
+       HRESULT (WINAPI *SetViewport)(IDirect3DDevice9Ex *This, const D3DVIEWPORT9 *pViewport);
+       HRESULT (WINAPI *GetViewport)(IDirect3DDevice9Ex *This, D3DVIEWPORT9 *pViewport);
+       HRESULT (WINAPI *SetMaterial)(IDirect3DDevice9Ex *This, const D3DMATERIAL9 *pMaterial);
+       HRESULT (WINAPI *GetMaterial)(IDirect3DDevice9Ex *This, D3DMATERIAL9 *pMaterial);
+       HRESULT (WINAPI *SetLight)(IDirect3DDevice9Ex *This, DWORD Index, const D3DLIGHT9 *pLight);
+       HRESULT (WINAPI *GetLight)(IDirect3DDevice9Ex *This, DWORD Index, D3DLIGHT9 *pLight);
+       HRESULT (WINAPI *LightEnable)(IDirect3DDevice9Ex *This, DWORD Index, BOOL Enable);
+       HRESULT (WINAPI *GetLightEnable)(IDirect3DDevice9Ex *This, DWORD Index, BOOL *pEnable);
+       HRESULT (WINAPI *SetClipPlane)(IDirect3DDevice9Ex *This, DWORD Index, const float *pPlane);
+       HRESULT (WINAPI *GetClipPlane)(IDirect3DDevice9Ex *This, DWORD Index, float *pPlane);
+       HRESULT (WINAPI *SetRenderState)(IDirect3DDevice9Ex *This, D3DRENDERSTATETYPE State, DWORD Value);
+       HRESULT (WINAPI *GetRenderState)(IDirect3DDevice9Ex *This, D3DRENDERSTATETYPE State, DWORD *pValue);
+       HRESULT (WINAPI *CreateStateBlock)(IDirect3DDevice9Ex *This, D3DSTATEBLOCKTYPE Type, IDirect3DStateBlock9 **ppSB);
+       HRESULT (WINAPI *BeginStateBlock)(IDirect3DDevice9Ex *This);
+       HRESULT (WINAPI *EndStateBlock)(IDirect3DDevice9Ex *This, IDirect3DStateBlock9 **ppSB);
+       HRESULT (WINAPI *SetClipStatus)(IDirect3DDevice9Ex *This, const D3DCLIPSTATUS9 *pClipStatus);
+       HRESULT (WINAPI *GetClipStatus)(IDirect3DDevice9Ex *This, D3DCLIPSTATUS9 *pClipStatus);
+       HRESULT (WINAPI *GetTexture)(IDirect3DDevice9Ex *This, DWORD Stage, IDirect3DBaseTexture9 **ppTexture);
+       HRESULT (WINAPI *SetTexture)(IDirect3DDevice9Ex *This, DWORD Stage, IDirect3DBaseTexture9 *pTexture);
+       HRESULT (WINAPI *GetTextureStageState)(IDirect3DDevice9Ex *This, DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD *pValue);
+       HRESULT (WINAPI *SetTextureStageState)(IDirect3DDevice9Ex *This, DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value);
+       HRESULT (WINAPI *GetSamplerState)(IDirect3DDevice9Ex *This, DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD *pValue);
+       HRESULT (WINAPI *SetSamplerState)(IDirect3DDevice9Ex *This, DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value);
+       HRESULT (WINAPI *ValidateDevice)(IDirect3DDevice9Ex *This, DWORD *pNumPasses);
+       HRESULT (WINAPI *SetPaletteEntries)(IDirect3DDevice9Ex *This, UINT PaletteNumber, const PALETTEENTRY *pEntries);
+       HRESULT (WINAPI *GetPaletteEntries)(IDirect3DDevice9Ex *This, UINT PaletteNumber, PALETTEENTRY *pEntries);
+       HRESULT (WINAPI *SetCurrentTexturePalette)(IDirect3DDevice9Ex *This, UINT PaletteNumber);
+       HRESULT (WINAPI *GetCurrentTexturePalette)(IDirect3DDevice9Ex *This, UINT *PaletteNumber);
+       HRESULT (WINAPI *SetScissorRect)(IDirect3DDevice9Ex *This, const RECT *pRect);
+       HRESULT (WINAPI *GetScissorRect)(IDirect3DDevice9Ex *This, RECT *pRect);
+       HRESULT (WINAPI *SetSoftwareVertexProcessing)(IDirect3DDevice9Ex *This, BOOL bSoftware);
+       BOOL (WINAPI *GetSoftwareVertexProcessing)(IDirect3DDevice9Ex *This);
+       HRESULT (WINAPI *SetNPatchMode)(IDirect3DDevice9Ex *This, float nSegments);
+       float (WINAPI *GetNPatchMode)(IDirect3DDevice9Ex *This);
+       HRESULT (WINAPI *DrawPrimitive)(IDirect3DDevice9Ex *This, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount);
+       HRESULT (WINAPI *DrawIndexedPrimitive)(IDirect3DDevice9Ex *This, D3DPRIMITIVETYPE PrimitiveType, INT BaseVertexIndex, UINT MinVertexIndex, UINT NumVertices, UINT startIndex, UINT primCount);
+       HRESULT (WINAPI *DrawPrimitiveUP)(IDirect3DDevice9Ex *This, D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, const void *pVertexStreamZeroData, UINT VertexStreamZeroStride);
+       HRESULT (WINAPI *DrawIndexedPrimitiveUP)(IDirect3DDevice9Ex *This, D3DPRIMITIVETYPE PrimitiveType, UINT MinVertexIndex, UINT NumVertices, UINT PrimitiveCount, const void *pIndexData, D3DFORMAT IndexDataFormat, const void *pVertexStreamZeroData, UINT VertexStreamZeroStride);
+       HRESULT (WINAPI *ProcessVertices)(IDirect3DDevice9Ex *This, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IDirect3DVertexBuffer9 *pDestBuffer, IDirect3DVertexDeclaration9 *pVertexDecl, DWORD Flags);
+       HRESULT (WINAPI *CreateVertexDeclaration)(IDirect3DDevice9Ex *This, const D3DVERTEXELEMENT9 *pVertexElements, IDirect3DVertexDeclaration9 **ppDecl);
+       HRESULT (WINAPI *SetVertexDeclaration)(IDirect3DDevice9Ex *This, IDirect3DVertexDeclaration9 *pDecl);
+       HRESULT (WINAPI *GetVertexDeclaration)(IDirect3DDevice9Ex *This, IDirect3DVertexDeclaration9 **ppDecl);
+       HRESULT (WINAPI *SetFVF)(IDirect3DDevice9Ex *This, DWORD FVF);
+       HRESULT (WINAPI *GetFVF)(IDirect3DDevice9Ex *This, DWORD *pFVF);
+       HRESULT (WINAPI *CreateVertexShader)(IDirect3DDevice9Ex *This, const DWORD *pFunction, IDirect3DVertexShader9 **ppShader);
+       HRESULT (WINAPI *SetVertexShader)(IDirect3DDevice9Ex *This, IDirect3DVertexShader9 *pShader);
+       HRESULT (WINAPI *GetVertexShader)(IDirect3DDevice9Ex *This, IDirect3DVertexShader9 **ppShader);
+       HRESULT (WINAPI *SetVertexShaderConstantF)(IDirect3DDevice9Ex *This, UINT StartRegister, const float *pConstantData, UINT Vector4fCount);
+       HRESULT (WINAPI *GetVertexShaderConstantF)(IDirect3DDevice9Ex *This, UINT StartRegister, float *pConstantData, UINT Vector4fCount);
+       HRESULT (WINAPI *SetVertexShaderConstantI)(IDirect3DDevice9Ex *This, UINT StartRegister, const int *pConstantData, UINT Vector4iCount);
+       HRESULT (WINAPI *GetVertexShaderConstantI)(IDirect3DDevice9Ex *This, UINT StartRegister, int *pConstantData, UINT Vector4iCount);
+       HRESULT (WINAPI *SetVertexShaderConstantB)(IDirect3DDevice9Ex *This, UINT StartRegister, const BOOL *pConstantData, UINT BoolCount);
+       HRESULT (WINAPI *GetVertexShaderConstantB)(IDirect3DDevice9Ex *This, UINT StartRegister, BOOL *pConstantData, UINT BoolCount);
+       HRESULT (WINAPI *SetStreamSource)(IDirect3DDevice9Ex *This, UINT StreamNumber, IDirect3DVertexBuffer9 *pStreamData, UINT OffsetInBytes, UINT Stride);
+       HRESULT (WINAPI *GetStreamSource)(IDirect3DDevice9Ex *This, UINT StreamNumber, IDirect3DVertexBuffer9 **ppStreamData, UINT *pOffsetInBytes, UINT *pStride);
+       HRESULT (WINAPI *SetStreamSourceFreq)(IDirect3DDevice9Ex *This, UINT StreamNumber, UINT Setting);
+       HRESULT (WINAPI *GetStreamSourceFreq)(IDirect3DDevice9Ex *This, UINT StreamNumber, UINT *pSetting);
+       HRESULT (WINAPI *SetIndices)(IDirect3DDevice9Ex *This, IDirect3DIndexBuffer9 *pIndexData);
+       HRESULT (WINAPI *GetIndices)(IDirect3DDevice9Ex *This, IDirect3DIndexBuffer9 **ppIndexData, UINT *pBaseVertexIndex);
+       HRESULT (WINAPI *CreatePixelShader)(IDirect3DDevice9Ex *This, const DWORD *pFunction, IDirect3DPixelShader9 **ppShader);
+       HRESULT (WINAPI *SetPixelShader)(IDirect3DDevice9Ex *This, IDirect3DPixelShader9 *pShader);
+       HRESULT (WINAPI *GetPixelShader)(IDirect3DDevice9Ex *This, IDirect3DPixelShader9 **ppShader);
+       HRESULT (WINAPI *SetPixelShaderConstantF)(IDirect3DDevice9Ex *This, UINT StartRegister, const float *pConstantData, UINT Vector4fCount);
+       HRESULT (WINAPI *GetPixelShaderConstantF)(IDirect3DDevice9Ex *This, UINT StartRegister, float *pConstantData, UINT Vector4fCount);
+       HRESULT (WINAPI *SetPixelShaderConstantI)(IDirect3DDevice9Ex *This, UINT StartRegister, const int *pConstantData, UINT Vector4iCount);
+       HRESULT (WINAPI *GetPixelShaderConstantI)(IDirect3DDevice9Ex *This, UINT StartRegister, int *pConstantData, UINT Vector4iCount);
+       HRESULT (WINAPI *SetPixelShaderConstantB)(IDirect3DDevice9Ex *This, UINT StartRegister, const BOOL *pConstantData, UINT BoolCount);
+       HRESULT (WINAPI *GetPixelShaderConstantB)(IDirect3DDevice9Ex *This, UINT StartRegister, BOOL *pConstantData, UINT BoolCount);
+       HRESULT (WINAPI *DrawRectPatch)(IDirect3DDevice9Ex *This, UINT Handle, const float *pNumSegs, const D3DRECTPATCH_INFO *pRectPatchInfo);
+       HRESULT (WINAPI *DrawTriPatch)(IDirect3DDevice9Ex *This, UINT Handle, const float *pNumSegs, const D3DTRIPATCH_INFO *pTriPatchInfo);
+       HRESULT (WINAPI *DeletePatch)(IDirect3DDevice9Ex *This, UINT Handle);
+       HRESULT (WINAPI *CreateQuery)(IDirect3DDevice9Ex *This, D3DQUERYTYPE Type, IDirect3DQuery9 **ppQuery);
+       /* IDirect3DDevice9Ex */
+       HRESULT (WINAPI *SetConvolutionMonoKernel)(IDirect3DDevice9Ex *This, UINT width, UINT height, float *rows, float *columns);
+       HRESULT (WINAPI *ComposeRects)(IDirect3DDevice9Ex *This, IDirect3DSurface9 *pSrc, IDirect3DSurface9 *pDst, IDirect3DVertexBuffer9 *pSrcRectDescs, UINT NumRects, IDirect3DVertexBuffer9 *pDstRectDescs, D3DCOMPOSERECTSOP Operation, int Xoffset, int Yoffset);
+       HRESULT (WINAPI *PresentEx)(IDirect3DDevice9Ex *This, const RECT *pSourceRect, const RECT *pDestRect, HWND hDestWindowOverride, const RGNDATA *pDirtyRegion, DWORD dwFlags);
+       HRESULT (WINAPI *GetGPUThreadPriority)(IDirect3DDevice9Ex *This, INT *pPriority);
+       HRESULT (WINAPI *SetGPUThreadPriority)(IDirect3DDevice9Ex *This, INT Priority);
+       HRESULT (WINAPI *WaitForVBlank)(IDirect3DDevice9Ex *This, UINT iSwapChain);
+       HRESULT (WINAPI *CheckResourceResidency)(IDirect3DDevice9Ex *This, IDirect3DResource9 **pResourceArray, UINT32 NumResources);
+       HRESULT (WINAPI *SetMaximumFrameLatency)(IDirect3DDevice9Ex *This, UINT MaxLatency);
+       HRESULT (WINAPI *GetMaximumFrameLatency)(IDirect3DDevice9Ex *This, UINT *pMaxLatency);
+       HRESULT (WINAPI *CheckDeviceState)(IDirect3DDevice9Ex *This, HWND hDestinationWindow);
+       HRESULT (WINAPI *CreateRenderTargetEx)(IDirect3DDevice9Ex *This, UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Lockable, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle, DWORD Usage);
+       HRESULT (WINAPI *CreateOffscreenPlainSurfaceEx)(IDirect3DDevice9Ex *This, UINT Width, UINT Height, D3DFORMAT Format, D3DPOOL Pool, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle, DWORD Usage);
+       HRESULT (WINAPI *CreateDepthStencilSurfaceEx)(IDirect3DDevice9Ex *This, UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Discard, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle, DWORD Usage);
+       HRESULT (WINAPI *ResetEx)(IDirect3DDevice9Ex *This, D3DPRESENT_PARAMETERS *pPresentationParameters, D3DDISPLAYMODEEX *pFullscreenDisplayMode);
+       HRESULT (WINAPI *GetDisplayModeEx)(IDirect3DDevice9Ex *This, UINT iSwapChain, D3DDISPLAYMODEEX *pMode, D3DDISPLAYROTATION *pRotation);
+} IDirect3DDevice9ExVtbl;
+struct IDirect3DDevice9Ex
+{
+       IDirect3DDevice9ExVtbl *lpVtbl;
+};
+
+/* IUnknown macros */
+#define IDirect3DDevice9Ex_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
+#define IDirect3DDevice9Ex_AddRef(p) (p)->lpVtbl->AddRef(p)
+#define IDirect3DDevice9Ex_Release(p) (p)->lpVtbl->Release(p)
+/* IDirect3DDevice9 macros */
+#define IDirect3DDevice9Ex_TestCooperativeLevel(p) (p)->lpVtbl->TestCooperativeLevel(p)
+#define IDirect3DDevice9Ex_GetAvailableTextureMem(p) (p)->lpVtbl->GetAvailableTextureMem(p)
+#define IDirect3DDevice9Ex_EvictManagedResources(p) (p)->lpVtbl->EvictManagedResources(p)
+#define IDirect3DDevice9Ex_GetDirect3D(p,a) (p)->lpVtbl->GetDirect3D(p,a)
+#define IDirect3DDevice9Ex_GetDeviceCaps(p,a) (p)->lpVtbl->GetDeviceCaps(p,a)
+#define IDirect3DDevice9Ex_GetDisplayMode(p,a,b) (p)->lpVtbl->GetDisplayMode(p,a,b)
+#define IDirect3DDevice9Ex_GetCreationParameters(p,a) (p)->lpVtbl->GetCreationParameters(p,a)
+#define IDirect3DDevice9Ex_SetCursorProperties(p,a,b,c) (p)->lpVtbl->SetCursorProperties(p,a,b,c)
+#define IDirect3DDevice9Ex_SetCursorPosition(p,a,b,c) (p)->lpVtbl->SetCursorPosition(p,a,b,c)
+#define IDirect3DDevice9Ex_ShowCursor(p,a) (p)->lpVtbl->ShowCursor(p,a)
+#define IDirect3DDevice9Ex_CreateAdditionalSwapChain(p,a,b) (p)->lpVtbl->CreateAdditionalSwapChain(p,a,b)
+#define IDirect3DDevice9Ex_GetSwapChain(p,a,b) (p)->lpVtbl->GetSwapChain(p,a,b)
+#define IDirect3DDevice9Ex_GetNumberOfSwapChains(p) (p)->lpVtbl->GetNumberOfSwapChains(p)
+#define IDirect3DDevice9Ex_Reset(p,a) (p)->lpVtbl->Reset(p,a)
+#define IDirect3DDevice9Ex_Present(p,a,b,c,d) (p)->lpVtbl->Present(p,a,b,c,d)
+#define IDirect3DDevice9Ex_GetBackBuffer(p,a,b,c,d) (p)->lpVtbl->GetBackBuffer(p,a,b,c,d)
+#define IDirect3DDevice9Ex_GetRasterStatus(p,a,b) (p)->lpVtbl->GetRasterStatus(p,a,b)
+#define IDirect3DDevice9Ex_SetDialogBoxMode(p,a) (p)->lpVtbl->SetDialogBoxMode(p,a)
+#define IDirect3DDevice9Ex_SetGammaRamp(p,a,b,c) (p)->lpVtbl->SetGammaRamp(p,a,b,c)
+#define IDirect3DDevice9Ex_GetGammaRamp(p,a,b) (p)->lpVtbl->GetGammaRamp(p,a,b)
+#define IDirect3DDevice9Ex_CreateTexture(p,a,b,c,d,e,f,g,h) (p)->lpVtbl->CreateTexture(p,a,b,c,d,e,f,g,h)
+#define IDirect3DDevice9Ex_CreateVolumeTexture(p,a,b,c,d,e,f,g,h,i) (p)->lpVtbl->CreateVolumeTexture(p,a,b,c,d,e,f,g,h,i)
+#define IDirect3DDevice9Ex_CreateCubeTexture(p,a,b,c,d,e,f,g) (p)->lpVtbl->CreateCubeTexture(p,a,b,c,d,e,f,g)
+#define IDirect3DDevice9Ex_CreateVertexBuffer(p,a,b,c,d,e,f) (p)->lpVtbl->CreateVertexBuffer(p,a,b,c,d,e,f)
+#define IDirect3DDevice9Ex_CreateIndexBuffer(p,a,b,c,d,e,f) (p)->lpVtbl->CreateIndexBuffer(p,a,b,c,d,e,f)
+#define IDirect3DDevice9Ex_CreateRenderTarget(p,a,b,c,d,e,f,g,h) (p)->lpVtbl->CreateRenderTarget(p,a,b,c,d,e,f,g,h)
+#define IDirect3DDevice9Ex_CreateDepthStencilSurface(p,a,b,c,d,e,f,g,h) (p)->lpVtbl->CreateDepthStencilSurface(p,a,b,c,d,e,f,g,h)
+#define IDirect3DDevice9Ex_UpdateSurface(p,a,b,c,d) (p)->lpVtbl->UpdateSurface(p,a,b,c,d)
+#define IDirect3DDevice9Ex_UpdateTexture(p,a,b) (p)->lpVtbl->UpdateTexture(p,a,b)
+#define IDirect3DDevice9Ex_GetRenderTargetData(p,a,b) (p)->lpVtbl->GetRenderTargetData(p,a,b)
+#define IDirect3DDevice9Ex_GetFrontBufferData(p,a,b) (p)->lpVtbl->GetFrontBufferData(p,a,b)
+#define IDirect3DDevice9Ex_StretchRect(p,a,b,c,d,e) (p)->lpVtbl->StretchRect(p,a,b,c,d,e)
+#define IDirect3DDevice9Ex_ColorFill(p,a,b,c) (p)->lpVtbl->ColorFill(p,a,b,c)
+#define IDirect3DDevice9Ex_CreateOffscreenPlainSurface(p,a,b,c,d,e,f) (p)->lpVtbl->CreateOffscreenPlainSurface(p,a,b,c,d,e,f)
+#define IDirect3DDevice9Ex_SetRenderTarget(p,a,b) (p)->lpVtbl->SetRenderTarget(p,a,b)
+#define IDirect3DDevice9Ex_GetRenderTarget(p,a,b) (p)->lpVtbl->GetRenderTarget(p,a,b)
+#define IDirect3DDevice9Ex_SetDepthStencilSurface(p,a) (p)->lpVtbl->SetDepthStencilSurface(p,a)
+#define IDirect3DDevice9Ex_GetDepthStencilSurface(p,a) (p)->lpVtbl->GetDepthStencilSurface(p,a)
+#define IDirect3DDevice9Ex_BeginScene(p) (p)->lpVtbl->BeginScene(p)
+#define IDirect3DDevice9Ex_EndScene(p) (p)->lpVtbl->EndScene(p)
+#define IDirect3DDevice9Ex_Clear(p,a,b,c,d,e,f) (p)->lpVtbl->Clear(p,a,b,c,d,e,f)
+#define IDirect3DDevice9Ex_SetTransform(p,a,b) (p)->lpVtbl->SetTransform(p,a,b)
+#define IDirect3DDevice9Ex_GetTransform(p,a,b) (p)->lpVtbl->GetTransform(p,a,b)
+#define IDirect3DDevice9Ex_MultiplyTransform(p,a,b) (p)->lpVtbl->MultiplyTransform(p,a,b)
+#define IDirect3DDevice9Ex_SetViewport(p,a) (p)->lpVtbl->SetViewport(p,a)
+#define IDirect3DDevice9Ex_GetViewport(p,a) (p)->lpVtbl->GetViewport(p,a)
+#define IDirect3DDevice9Ex_SetMaterial(p,a) (p)->lpVtbl->SetMaterial(p,a)
+#define IDirect3DDevice9Ex_GetMaterial(p,a) (p)->lpVtbl->GetMaterial(p,a)
+#define IDirect3DDevice9Ex_SetLight(p,a,b) (p)->lpVtbl->SetLight(p,a,b)
+#define IDirect3DDevice9Ex_GetLight(p,a,b) (p)->lpVtbl->GetLight(p,a,b)
+#define IDirect3DDevice9Ex_LightEnable(p,a,b) (p)->lpVtbl->LightEnable(p,a,b)
+#define IDirect3DDevice9Ex_GetLightEnable(p,a,b) (p)->lpVtbl->GetLightEnable(p,a,b)
+#define IDirect3DDevice9Ex_SetClipPlane(p,a,b) (p)->lpVtbl->SetClipPlane(p,a,b)
+#define IDirect3DDevice9Ex_GetClipPlane(p,a,b) (p)->lpVtbl->GetClipPlane(p,a,b)
+#define IDirect3DDevice9Ex_SetRenderState(p,a,b) (p)->lpVtbl->SetRenderState(p,a,b)
+#define IDirect3DDevice9Ex_GetRenderState(p,a,b) (p)->lpVtbl->GetRenderState(p,a,b)
+#define IDirect3DDevice9Ex_CreateStateBlock(p,a,b) (p)->lpVtbl->CreateStateBlock(p,a,b)
+#define IDirect3DDevice9Ex_BeginStateBlock(p) (p)->lpVtbl->BeginStateBlock(p)
+#define IDirect3DDevice9Ex_EndStateBlock(p,a) (p)->lpVtbl->EndStateBlock(p,a)
+#define IDirect3DDevice9Ex_SetClipStatus(p,a) (p)->lpVtbl->SetClipStatus(p,a)
+#define IDirect3DDevice9Ex_GetClipStatus(p,a) (p)->lpVtbl->GetClipStatus(p,a)
+#define IDirect3DDevice9Ex_GetTexture(p,a,b) (p)->lpVtbl->GetTexture(p,a,b)
+#define IDirect3DDevice9Ex_SetTexture(p,a,b) (p)->lpVtbl->SetTexture(p,a,b)
+#define IDirect3DDevice9Ex_GetTextureStageState(p,a,b,c) (p)->lpVtbl->GetTextureStageState(p,a,b,c)
+#define IDirect3DDevice9Ex_SetTextureStageState(p,a,b,c) (p)->lpVtbl->SetTextureStageState(p,a,b,c)
+#define IDirect3DDevice9Ex_GetSamplerState(p,a,b,c) (p)->lpVtbl->GetSamplerState(p,a,b,c)
+#define IDirect3DDevice9Ex_SetSamplerState(p,a,b,c) (p)->lpVtbl->SetSamplerState(p,a,b,c)
+#define IDirect3DDevice9Ex_ValidateDevice(p,a) (p)->lpVtbl->ValidateDevice(p,a)
+#define IDirect3DDevice9Ex_SetPaletteEntries(p,a,b) (p)->lpVtbl->SetPaletteEntries(p,a,b)
+#define IDirect3DDevice9Ex_GetPaletteEntries(p,a,b) (p)->lpVtbl->GetPaletteEntries(p,a,b)
+#define IDirect3DDevice9Ex_SetCurrentTexturePalette(p,a) (p)->lpVtbl->SetCurrentTexturePalette(p,a)
+#define IDirect3DDevice9Ex_GetCurrentTexturePalette(p,a) (p)->lpVtbl->GetCurrentTexturePalette(p,a)
+#define IDirect3DDevice9Ex_SetScissorRect(p,a) (p)->lpVtbl->SetScissorRect(p,a)
+#define IDirect3DDevice9Ex_GetScissorRect(p,a) (p)->lpVtbl->GetScissorRect(p,a)
+#define IDirect3DDevice9Ex_SetSoftwareVertexProcessing(p,a) (p)->lpVtbl->SetSoftwareVertexProcessing(p,a)
+#define IDirect3DDevice9Ex_GetSoftwareVertexProcessing(p) (p)->lpVtbl->GetSoftwareVertexProcessing(p)
+#define IDirect3DDevice9Ex_SetNPatchMode(p,a) (p)->lpVtbl->SetNPatchMode(p,a)
+#define IDirect3DDevice9Ex_GetNPatchMode(p) (p)->lpVtbl->GetNPatchMode(p)
+#define IDirect3DDevice9Ex_DrawPrimitive(p,a,b,c) (p)->lpVtbl->DrawPrimitive(p,a,b,c)
+#define IDirect3DDevice9Ex_DrawIndexedPrimitive(p,a,b,c,d,e,f) (p)->lpVtbl->DrawIndexedPrimitive(p,a,b,c,d,e,f)
+#define IDirect3DDevice9Ex_DrawPrimitiveUP(p,a,b,c,d) (p)->lpVtbl->DrawPrimitiveUP(p,a,b,c,d)
+#define IDirect3DDevice9Ex_DrawIndexedPrimitiveUP(p,a,b,c,d,e,f,g,h) (p)->lpVtbl->DrawIndexedPrimitiveUP(p,a,b,c,d,e,f,g,h)
+#define IDirect3DDevice9Ex_ProcessVertices(p,a,b,c,d,e,f) (p)->lpVtbl->ProcessVertices(p,a,b,c,d,e,f)
+#define IDirect3DDevice9Ex_CreateVertexDeclaration(p,a,b) (p)->lpVtbl->CreateVertexDeclaration(p,a,b)
+#define IDirect3DDevice9Ex_SetVertexDeclaration(p,a) (p)->lpVtbl->SetVertexDeclaration(p,a)
+#define IDirect3DDevice9Ex_GetVertexDeclaration(p,a) (p)->lpVtbl->GetVertexDeclaration(p,a)
+#define IDirect3DDevice9Ex_SetFVF(p,a) (p)->lpVtbl->SetFVF(p,a)
+#define IDirect3DDevice9Ex_GetFVF(p,a) (p)->lpVtbl->GetFVF(p,a)
+#define IDirect3DDevice9Ex_CreateVertexShader(p,a,b) (p)->lpVtbl->CreateVertexShader(p,a,b)
+#define IDirect3DDevice9Ex_SetVertexShader(p,a) (p)->lpVtbl->SetVertexShader(p,a)
+#define IDirect3DDevice9Ex_GetVertexShader(p,a) (p)->lpVtbl->GetVertexShader(p,a)
+#define IDirect3DDevice9Ex_SetVertexShaderConstantF(p,a,b,c) (p)->lpVtbl->SetVertexShaderConstantF(p,a,b,c)
+#define IDirect3DDevice9Ex_GetVertexShaderConstantF(p,a,b,c) (p)->lpVtbl->GetVertexShaderConstantF(p,a,b,c)
+#define IDirect3DDevice9Ex_SetVertexShaderConstantI(p,a,b,c) (p)->lpVtbl->SetVertexShaderConstantI(p,a,b,c)
+#define IDirect3DDevice9Ex_GetVertexShaderConstantI(p,a,b,c) (p)->lpVtbl->GetVertexShaderConstantI(p,a,b,c)
+#define IDirect3DDevice9Ex_SetVertexShaderConstantB(p,a,b,c) (p)->lpVtbl->SetVertexShaderConstantB(p,a,b,c)
+#define IDirect3DDevice9Ex_GetVertexShaderConstantB(p,a,b,c) (p)->lpVtbl->GetVertexShaderConstantB(p,a,b,c)
+#define IDirect3DDevice9Ex_SetStreamSource(p,a,b,c,d) (p)->lpVtbl->SetStreamSource(p,a,b,c,d)
+#define IDirect3DDevice9Ex_GetStreamSource(p,a,b,c,d) (p)->lpVtbl->GetStreamSource(p,a,b,c,d)
+#define IDirect3DDevice9Ex_SetStreamSourceFreq(p,a,b) (p)->lpVtbl->SetStreamSourceFreq(p,a,b)
+#define IDirect3DDevice9Ex_GetStreamSourceFreq(p,a,b) (p)->lpVtbl->GetStreamSourceFreq(p,a,b)
+#define IDirect3DDevice9Ex_SetIndices(p,a) (p)->lpVtbl->SetIndices(p,a)
+#define IDirect3DDevice9Ex_GetIndices(p,a,b) (p)->lpVtbl->GetIndices(p,a,b)
+#define IDirect3DDevice9Ex_CreatePixelShader(p,a,b) (p)->lpVtbl->CreatePixelShader(p,a,b)
+#define IDirect3DDevice9Ex_SetPixelShader(p,a) (p)->lpVtbl->SetPixelShader(p,a)
+#define IDirect3DDevice9Ex_GetPixelShader(p,a) (p)->lpVtbl->GetPixelShader(p,a)
+#define IDirect3DDevice9Ex_SetPixelShaderConstantF(p,a,b,c) (p)->lpVtbl->SetPixelShaderConstantF(p,a,b,c)
+#define IDirect3DDevice9Ex_GetPixelShaderConstantF(p,a,b,c) (p)->lpVtbl->GetPixelShaderConstantF(p,a,b,c)
+#define IDirect3DDevice9Ex_SetPixelShaderConstantI(p,a,b,c) (p)->lpVtbl->SetPixelShaderConstantI(p,a,b,c)
+#define IDirect3DDevice9Ex_GetPixelShaderConstantI(p,a,b,c) (p)->lpVtbl->GetPixelShaderConstantI(p,a,b,c)
+#define IDirect3DDevice9Ex_SetPixelShaderConstantB(p,a,b,c) (p)->lpVtbl->SetPixelShaderConstantB(p,a,b,c)
+#define IDirect3DDevice9Ex_GetPixelShaderConstantB(p,a,b,c) (p)->lpVtbl->GetPixelShaderConstantB(p,a,b,c)
+#define IDirect3DDevice9Ex_DrawRectPatch(p,a,b,c) (p)->lpVtbl->DrawRectPatch(p,a,b,c)
+#define IDirect3DDevice9Ex_DrawTriPatch(p,a,b,c) (p)->lpVtbl->DrawTriPatch(p,a,b,c)
+#define IDirect3DDevice9Ex_DeletePatch(p,a) (p)->lpVtbl->DeletePatch(p,a)
+#define IDirect3DDevice9Ex_CreateQuery(p,a,b) (p)->lpVtbl->CreateQuery(p,a,b)
+/* IDirect3DDevice9Ex macros */
+#define IDirect3DDevice9Ex_SetConvolutionMonoKernel(p,a,b,c,d) (p)->lpVtbl->SetConvolutionMonoKernel(p,a,b,c,d)
+#define IDirect3DDevice9Ex_ComposeRects(p,a,b,c,d,e,f,g,h) (p)->lpVtbl->ComposeRects(p,a,b,c,d,e,f,g,h)
+#define IDirect3DDevice9Ex_PresentEx(p,a,b,c,d,e) (p)->lpVtbl->PresentEx(p,a,b,c,d,e)
+#define IDirect3DDevice9Ex_GetGPUThreadPriority(p,a) (p)->lpVtbl->GetGPUThreadPriority(p,a)
+#define IDirect3DDevice9Ex_SetGPUThreadPriority(p,a) (p)->lpVtbl->SetGPUThreadPriority(p,a)
+#define IDirect3DDevice9Ex_WaitForVBlank(p,a) (p)->lpVtbl->WaitForVBlank(p,a)
+#define IDirect3DDevice9Ex_CheckResourceResidency(p,a,b) (p)->lpVtbl->CheckResourceResidency(p,a,b)
+#define IDirect3DDevice9Ex_SetMaximumFrameLatency(p,a) (p)->lpVtbl->SetMaximumFrameLatency(p,a)
+#define IDirect3DDevice9Ex_GetMaximumFrameLatency(p,a) (p)->lpVtbl->GetMaximumFrameLatency(p,a)
+#define IDirect3DDevice9Ex_CheckDeviceState(p,a) (p)->lpVtbl->CheckDeviceState(p,a)
+#define IDirect3DDevice9Ex_CreateRenderTargetEx(p,a,b,c,d,e,f,g,h,i) (p)->lpVtbl->CreateRenderTargetEx(p,a,b,c,d,e,f,g,h,i)
+#define IDirect3DDevice9Ex_CreateOffscreenPlainSurfaceEx(p,a,b,c,d,e,f,g) (p)->lpVtbl->CreateOffscreenPlainSurfaceEx(p,a,b,c,d,e,f,g)
+#define IDirect3DDevice9Ex_CreateDepthStencilSurfaceEx(p,a,b,c,d,e,f,g,h,i) (p)->lpVtbl->CreateDepthStencilSurfaceEx(p,a,b,c,d,e,f,g,h,i)
+#define IDirect3DDevice9Ex_ResetEx(p,a,b) (p)->lpVtbl->ResetEx(p,a,b)
+#define IDirect3DDevice9Ex_GetDisplayModeEx(p,a,b,c) (p)->lpVtbl->GetDisplayModeEx(p,a,b,c)
+
+typedef struct IDirect3DDevice9VideoVtbl
+{
+       /* IUnknown */
+       HRESULT (WINAPI *QueryInterface)(IDirect3DDevice9Video *This, REFIID riid, void **ppvObject);
+       ULONG (WINAPI *AddRef)(IDirect3DDevice9Video *This);
+       ULONG (WINAPI *Release)(IDirect3DDevice9Video *This);
+       /* IDirect3DDevice9Video */
+       HRESULT (WINAPI *GetContentProtectionCaps)(IDirect3DDevice9Video *This, const GUID *pCryptoType, const GUID *pDecodeProfile, D3DCONTENTPROTECTIONCAPS *pCaps);
+       HRESULT (WINAPI *CreateAuthenticatedChannel)(IDirect3DDevice9Video *This, D3DAUTHENTICATEDCHANNELTYPE ChannelType, IDirect3DAuthenticatedChannel9 **ppAuthenticatedChannel, HANDLE *pChannelHandle);
+       HRESULT (WINAPI *CreateCryptoSession)(IDirect3DDevice9Video *This, const GUID *pCryptoType, const GUID *pDecodeProfile, IDirect3DCryptoSession9 **ppCryptoSession, HANDLE *pCryptoHandle);
+} IDirect3DDevice9VideoVtbl;
+struct IDirect3DDevice9Video
+{
+       IDirect3DDevice9VideoVtbl *lpVtbl;
+};
+
+/* IUnknown macros */
+#define IDirect3DDevice9Video_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
+#define IDirect3DDevice9Video_AddRef(p) (p)->lpVtbl->AddRef(p)
+#define IDirect3DDevice9Video_Release(p) (p)->lpVtbl->Release(p)
+/* IDirect3DDevice9Video macros */
+#define IDirect3DDevice9Video_GetContentProtectionCaps(p,a,b,c) (p)->lpVtbl->GetContentProtectionCaps(p,a,b,c)
+#define IDirect3DDevice9Video_CreateAuthenticatedChannel(p,a,b,c) (p)->lpVtbl->CreateAuthenticatedChannel(p,a,b,c)
+#define IDirect3DDevice9Video_CreateCryptoSession(p,a,b,c,d) (p)->lpVtbl->CreateCryptoSession(p,a,b,c,d)
+
+typedef struct IDirect3DIndexBuffer9Vtbl
+{
+       /* IUnknown */
+       HRESULT (WINAPI *QueryInterface)(IDirect3DIndexBuffer9 *This, REFIID riid, void **ppvObject);
+       ULONG (WINAPI *AddRef)(IDirect3DIndexBuffer9 *This);
+       ULONG (WINAPI *Release)(IDirect3DIndexBuffer9 *This);
+       /* IDirect3DResource9 */
+       HRESULT (WINAPI *GetDevice)(IDirect3DIndexBuffer9 *This, IDirect3DDevice9 **ppDevice);
+       HRESULT (WINAPI *SetPrivateData)(IDirect3DIndexBuffer9 *This, REFGUID refguid, const void *pData, DWORD SizeOfData, DWORD Flags);
+       HRESULT (WINAPI *GetPrivateData)(IDirect3DIndexBuffer9 *This, REFGUID refguid, void *pData, DWORD *pSizeOfData);
+       HRESULT (WINAPI *FreePrivateData)(IDirect3DIndexBuffer9 *This, REFGUID refguid);
+       DWORD (WINAPI *SetPriority)(IDirect3DIndexBuffer9 *This, DWORD PriorityNew);
+       DWORD (WINAPI *GetPriority)(IDirect3DIndexBuffer9 *This);
+       void (WINAPI *PreLoad)(IDirect3DIndexBuffer9 *This);
+       D3DRESOURCETYPE (WINAPI *GetType)(IDirect3DIndexBuffer9 *This);
+       /* IDirect3DIndexBuffer9 */
+       HRESULT (WINAPI *Lock)(IDirect3DIndexBuffer9 *This, UINT OffsetToLock, UINT SizeToLock, void **ppbData, DWORD Flags);
+       HRESULT (WINAPI *Unlock)(IDirect3DIndexBuffer9 *This);
+       HRESULT (WINAPI *GetDesc)(IDirect3DIndexBuffer9 *This, D3DINDEXBUFFER_DESC *pDesc);
+} IDirect3DIndexBuffer9Vtbl;
+struct IDirect3DIndexBuffer9
+{
+       IDirect3DIndexBuffer9Vtbl *lpVtbl;
+};
+
+/* IUnknown macros */
+#define IDirect3DIndexBuffer9_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
+#define IDirect3DIndexBuffer9_AddRef(p) (p)->lpVtbl->AddRef(p)
+#define IDirect3DIndexBuffer9_Release(p) (p)->lpVtbl->Release(p)
+/* IDirect3DResource9 macros */
+#define IDirect3DIndexBuffer9_GetDevice(p,a) (p)->lpVtbl->GetDevice(p,a)
+#define IDirect3DIndexBuffer9_SetPrivateData(p,a,b,c,d) (p)->lpVtbl->SetPrivateData(p,a,b,c,d)
+#define IDirect3DIndexBuffer9_GetPrivateData(p,a,b,c) (p)->lpVtbl->GetPrivateData(p,a,b,c)
+#define IDirect3DIndexBuffer9_FreePrivateData(p,a) (p)->lpVtbl->FreePrivateData(p,a)
+#define IDirect3DIndexBuffer9_SetPriority(p,a) (p)->lpVtbl->SetPriority(p,a)
+#define IDirect3DIndexBuffer9_GetPriority(p) (p)->lpVtbl->GetPriority(p)
+#define IDirect3DIndexBuffer9_PreLoad(p) (p)->lpVtbl->PreLoad(p)
+#define IDirect3DIndexBuffer9_GetType(p) (p)->lpVtbl->GetType(p)
+/* IDirect3DIndexBuffer9 macros */
+#define IDirect3DIndexBuffer9_Lock(p,a,b,c,d) (p)->lpVtbl->Lock(p,a,b,c,d)
+#define IDirect3DIndexBuffer9_Unlock(p) (p)->lpVtbl->Unlock(p)
+#define IDirect3DIndexBuffer9_GetDesc(p,a) (p)->lpVtbl->GetDesc(p,a)
+
+typedef struct IDirect3DPixelShader9Vtbl
+{
+       /* IUnknown */
+       HRESULT (WINAPI *QueryInterface)(IDirect3DPixelShader9 *This, REFIID riid, void **ppvObject);
+       ULONG (WINAPI *AddRef)(IDirect3DPixelShader9 *This);
+       ULONG (WINAPI *Release)(IDirect3DPixelShader9 *This);
+       /* IDirect3DPixelShader9 */
+       HRESULT (WINAPI *GetDevice)(IDirect3DPixelShader9 *This, IDirect3DDevice9 **ppDevice);
+       HRESULT (WINAPI *GetFunction)(IDirect3DPixelShader9 *This, void *pData, UINT *pSizeOfData);
+} IDirect3DPixelShader9Vtbl;
+struct IDirect3DPixelShader9
+{
+       IDirect3DPixelShader9Vtbl *lpVtbl;
+};
+
+/* IUnknown macros */
+#define IDirect3DPixelShader9_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
+#define IDirect3DPixelShader9_AddRef(p) (p)->lpVtbl->AddRef(p)
+#define IDirect3DPixelShader9_Release(p) (p)->lpVtbl->Release(p)
+/* IDirect3DPixelShader9 macros */
+#define IDirect3DPixelShader9_GetDevice(p,a) (p)->lpVtbl->GetDevice(p,a)
+#define IDirect3DPixelShader9_GetFunction(p,a,b) (p)->lpVtbl->GetFunction(p,a,b)
+
+typedef struct IDirect3DQuery9Vtbl
+{
+       /* IUnknown */
+       HRESULT (WINAPI *QueryInterface)(IDirect3DQuery9 *This, REFIID riid, void **ppvObject);
+       ULONG (WINAPI *AddRef)(IDirect3DQuery9 *This);
+       ULONG (WINAPI *Release)(IDirect3DQuery9 *This);
+       /* IDirect3DQuery9 */
+       HRESULT (WINAPI *GetDevice)(IDirect3DQuery9 *This, IDirect3DDevice9 **ppDevice);
+       D3DQUERYTYPE (WINAPI *GetType)(IDirect3DQuery9 *This);
+       DWORD (WINAPI *GetDataSize)(IDirect3DQuery9 *This);
+       HRESULT (WINAPI *Issue)(IDirect3DQuery9 *This, DWORD dwIssueFlags);
+       HRESULT (WINAPI *GetData)(IDirect3DQuery9 *This, void *pData, DWORD dwSize, DWORD dwGetDataFlags);
+} IDirect3DQuery9Vtbl;
+struct IDirect3DQuery9
+{
+       IDirect3DQuery9Vtbl *lpVtbl;
+};
+
+/* IUnknown macros */
+#define IDirect3DQuery9_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
+#define IDirect3DQuery9_AddRef(p) (p)->lpVtbl->AddRef(p)
+#define IDirect3DQuery9_Release(p) (p)->lpVtbl->Release(p)
+/* IDirect3DQuery9 macros */
+#define IDirect3DQuery9_GetDevice(p,a) (p)->lpVtbl->GetDevice(p,a)
+#define IDirect3DQuery9_GetType(p) (p)->lpVtbl->GetType(p)
+#define IDirect3DQuery9_GetDataSize(p) (p)->lpVtbl->GetDataSize(p)
+#define IDirect3DQuery9_Issue(p,a) (p)->lpVtbl->Issue(p,a)
+#define IDirect3DQuery9_GetData(p,a,b,c) (p)->lpVtbl->GetData(p,a,b,c)
+
+typedef struct IDirect3DResource9Vtbl
+{
+       /* IUnknown */
+       HRESULT (WINAPI *QueryInterface)(IDirect3DResource9 *This, REFIID riid, void **ppvObject);
+       ULONG (WINAPI *AddRef)(IDirect3DResource9 *This);
+       ULONG (WINAPI *Release)(IDirect3DResource9 *This);
+       /* IDirect3DResource9 */
+       HRESULT (WINAPI *GetDevice)(IDirect3DResource9 *This, IDirect3DDevice9 **ppDevice);
+       HRESULT (WINAPI *SetPrivateData)(IDirect3DResource9 *This, REFGUID refguid, const void *pData, DWORD SizeOfData, DWORD Flags);
+       HRESULT (WINAPI *GetPrivateData)(IDirect3DResource9 *This, REFGUID refguid, void *pData, DWORD *pSizeOfData);
+       HRESULT (WINAPI *FreePrivateData)(IDirect3DResource9 *This, REFGUID refguid);
+       DWORD (WINAPI *SetPriority)(IDirect3DResource9 *This, DWORD PriorityNew);
+       DWORD (WINAPI *GetPriority)(IDirect3DResource9 *This);
+       void (WINAPI *PreLoad)(IDirect3DResource9 *This);
+       D3DRESOURCETYPE (WINAPI *GetType)(IDirect3DResource9 *This);
+} IDirect3DResource9Vtbl;
+struct IDirect3DResource9
+{
+       IDirect3DResource9Vtbl *lpVtbl;
+};
+
+/* IUnknown macros */
+#define IDirect3DResource9_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
+#define IDirect3DResource9_AddRef(p) (p)->lpVtbl->AddRef(p)
+#define IDirect3DResource9_Release(p) (p)->lpVtbl->Release(p)
+/* IDirect3DResource9 macros */
+#define IDirect3DResource9_GetDevice(p,a) (p)->lpVtbl->GetDevice(p,a)
+#define IDirect3DResource9_SetPrivateData(p,a,b,c,d) (p)->lpVtbl->SetPrivateData(p,a,b,c,d)
+#define IDirect3DResource9_GetPrivateData(p,a,b,c) (p)->lpVtbl->GetPrivateData(p,a,b,c)
+#define IDirect3DResource9_FreePrivateData(p,a) (p)->lpVtbl->FreePrivateData(p,a)
+#define IDirect3DResource9_SetPriority(p,a) (p)->lpVtbl->SetPriority(p,a)
+#define IDirect3DResource9_GetPriority(p) (p)->lpVtbl->GetPriority(p)
+#define IDirect3DResource9_PreLoad(p) (p)->lpVtbl->PreLoad(p)
+#define IDirect3DResource9_GetType(p) (p)->lpVtbl->GetType(p)
+
+typedef struct IDirect3DStateBlock9Vtbl
+{
+       /* IUnknown */
+       HRESULT (WINAPI *QueryInterface)(IDirect3DStateBlock9 *This, REFIID riid, void **ppvObject);
+       ULONG (WINAPI *AddRef)(IDirect3DStateBlock9 *This);
+       ULONG (WINAPI *Release)(IDirect3DStateBlock9 *This);
+       /* IDirect3DStateBlock9 */
+       HRESULT (WINAPI *GetDevice)(IDirect3DStateBlock9 *This, IDirect3DDevice9 **ppDevice);
+       HRESULT (WINAPI *Capture)(IDirect3DStateBlock9 *This);
+       HRESULT (WINAPI *Apply)(IDirect3DStateBlock9 *This);
+} IDirect3DStateBlock9Vtbl;
+struct IDirect3DStateBlock9
+{
+       IDirect3DStateBlock9Vtbl *lpVtbl;
+};
+
+/* IUnknown macros */
+#define IDirect3DStateBlock9_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
+#define IDirect3DStateBlock9_AddRef(p) (p)->lpVtbl->AddRef(p)
+#define IDirect3DStateBlock9_Release(p) (p)->lpVtbl->Release(p)
+/* IDirect3DStateBlock9 macros */
+#define IDirect3DStateBlock9_GetDevice(p,a) (p)->lpVtbl->GetDevice(p,a)
+#define IDirect3DStateBlock9_Capture(p) (p)->lpVtbl->Capture(p)
+#define IDirect3DStateBlock9_Apply(p) (p)->lpVtbl->Apply(p)
+
+typedef struct IDirect3DSurface9Vtbl
+{
+       /* IUnknown */
+       HRESULT (WINAPI *QueryInterface)(IDirect3DSurface9 *This, REFIID riid, void **ppvObject);
+       ULONG (WINAPI *AddRef)(IDirect3DSurface9 *This);
+       ULONG (WINAPI *Release)(IDirect3DSurface9 *This);
+       /* IDirect3DResource9 */
+       HRESULT (WINAPI *GetDevice)(IDirect3DSurface9 *This, IDirect3DDevice9 **ppDevice);
+       HRESULT (WINAPI *SetPrivateData)(IDirect3DSurface9 *This, REFGUID refguid, const void *pData, DWORD SizeOfData, DWORD Flags);
+       HRESULT (WINAPI *GetPrivateData)(IDirect3DSurface9 *This, REFGUID refguid, void *pData, DWORD *pSizeOfData);
+       HRESULT (WINAPI *FreePrivateData)(IDirect3DSurface9 *This, REFGUID refguid);
+       DWORD (WINAPI *SetPriority)(IDirect3DSurface9 *This, DWORD PriorityNew);
+       DWORD (WINAPI *GetPriority)(IDirect3DSurface9 *This);
+       void (WINAPI *PreLoad)(IDirect3DSurface9 *This);
+       D3DRESOURCETYPE (WINAPI *GetType)(IDirect3DSurface9 *This);
+       /* IDirect3DSurface9 */
+       HRESULT (WINAPI *GetContainer)(IDirect3DSurface9 *This, REFIID riid, void **ppContainer);
+       HRESULT (WINAPI *GetDesc)(IDirect3DSurface9 *This, D3DSURFACE_DESC *pDesc);
+       HRESULT (WINAPI *LockRect)(IDirect3DSurface9 *This, D3DLOCKED_RECT *pLockedRect, const RECT *pRect, DWORD Flags);
+       HRESULT (WINAPI *UnlockRect)(IDirect3DSurface9 *This);
+       HRESULT (WINAPI *GetDC)(IDirect3DSurface9 *This, HDC *phdc);
+       HRESULT (WINAPI *ReleaseDC)(IDirect3DSurface9 *This, HDC hdc);
+} IDirect3DSurface9Vtbl;
+struct IDirect3DSurface9
+{
+       IDirect3DSurface9Vtbl *lpVtbl;
+};
+
+/* IUnknown macros */
+#define IDirect3DSurface9_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
+#define IDirect3DSurface9_AddRef(p) (p)->lpVtbl->AddRef(p)
+#define IDirect3DSurface9_Release(p) (p)->lpVtbl->Release(p)
+/* IDirect3DResource9 macros */
+#define IDirect3DSurface9_GetDevice(p,a) (p)->lpVtbl->GetDevice(p,a)
+#define IDirect3DSurface9_SetPrivateData(p,a,b,c,d) (p)->lpVtbl->SetPrivateData(p,a,b,c,d)
+#define IDirect3DSurface9_GetPrivateData(p,a,b,c) (p)->lpVtbl->GetPrivateData(p,a,b,c)
+#define IDirect3DSurface9_FreePrivateData(p,a) (p)->lpVtbl->FreePrivateData(p,a)
+#define IDirect3DSurface9_SetPriority(p,a) (p)->lpVtbl->SetPriority(p,a)
+#define IDirect3DSurface9_GetPriority(p) (p)->lpVtbl->GetPriority(p)
+#define IDirect3DSurface9_PreLoad(p) (p)->lpVtbl->PreLoad(p)
+#define IDirect3DSurface9_GetType(p) (p)->lpVtbl->GetType(p)
+/* IDirect3DSurface9 macros */
+#define IDirect3DSurface9_GetContainer(p,a,b) (p)->lpVtbl->GetContainer(p,a,b)
+#define IDirect3DSurface9_GetDesc(p,a) (p)->lpVtbl->GetDesc(p,a)
+#define IDirect3DSurface9_LockRect(p,a,b,c) (p)->lpVtbl->LockRect(p,a,b,c)
+#define IDirect3DSurface9_UnlockRect(p) (p)->lpVtbl->UnlockRect(p)
+#define IDirect3DSurface9_GetDC(p,a) (p)->lpVtbl->GetDC(p,a)
+#define IDirect3DSurface9_ReleaseDC(p,a) (p)->lpVtbl->ReleaseDC(p,a)
+
+typedef struct IDirect3DSwapChain9Vtbl
+{
+       /* IUnknown */
+       HRESULT (WINAPI *QueryInterface)(IDirect3DSwapChain9 *This, REFIID riid, void **ppvObject);
+       ULONG (WINAPI *AddRef)(IDirect3DSwapChain9 *This);
+       ULONG (WINAPI *Release)(IDirect3DSwapChain9 *This);
+       /* IDirect3DSwapChain9 */
+       HRESULT (WINAPI *Present)(IDirect3DSwapChain9 *This, const RECT *pSourceRect, const RECT *pDestRect, HWND hDestWindowOverride, const RGNDATA *pDirtyRegion, DWORD dwFlags);
+       HRESULT (WINAPI *GetFrontBufferData)(IDirect3DSwapChain9 *This, IDirect3DSurface9 *pDestSurface);
+       HRESULT (WINAPI *GetBackBuffer)(IDirect3DSwapChain9 *This, UINT iBackBuffer, D3DBACKBUFFER_TYPE Type, IDirect3DSurface9 **ppBackBuffer);
+       HRESULT (WINAPI *GetRasterStatus)(IDirect3DSwapChain9 *This, D3DRASTER_STATUS *pRasterStatus);
+       HRESULT (WINAPI *GetDisplayMode)(IDirect3DSwapChain9 *This, D3DDISPLAYMODE *pMode);
+       HRESULT (WINAPI *GetDevice)(IDirect3DSwapChain9 *This, IDirect3DDevice9 **ppDevice);
+       HRESULT (WINAPI *GetPresentParameters)(IDirect3DSwapChain9 *This, D3DPRESENT_PARAMETERS *pPresentationParameters);
+} IDirect3DSwapChain9Vtbl;
+struct IDirect3DSwapChain9
+{
+       IDirect3DSwapChain9Vtbl *lpVtbl;
+};
+
+/* IUnknown macros */
+#define IDirect3DSwapChain9_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
+#define IDirect3DSwapChain9_AddRef(p) (p)->lpVtbl->AddRef(p)
+#define IDirect3DSwapChain9_Release(p) (p)->lpVtbl->Release(p)
+/* IDirect3DSwapChain9 macros */
+#define IDirect3DSwapChain9_Present(p,a,b,c,d,e) (p)->lpVtbl->Present(p,a,b,c,d,e)
+#define IDirect3DSwapChain9_GetFrontBufferData(p,a) (p)->lpVtbl->GetFrontBufferData(p,a)
+#define IDirect3DSwapChain9_GetBackBuffer(p,a,b,c) (p)->lpVtbl->GetBackBuffer(p,a,b,c)
+#define IDirect3DSwapChain9_GetRasterStatus(p,a) (p)->lpVtbl->GetRasterStatus(p,a)
+#define IDirect3DSwapChain9_GetDisplayMode(p,a) (p)->lpVtbl->GetDisplayMode(p,a)
+#define IDirect3DSwapChain9_GetDevice(p,a) (p)->lpVtbl->GetDevice(p,a)
+#define IDirect3DSwapChain9_GetPresentParameters(p,a) (p)->lpVtbl->GetPresentParameters(p,a)
+
+typedef struct IDirect3DSwapChain9ExVtbl
+{
+       /* IUnknown */
+       HRESULT (WINAPI *QueryInterface)(IDirect3DSwapChain9Ex *This, REFIID riid, void **ppvObject);
+       ULONG (WINAPI *AddRef)(IDirect3DSwapChain9Ex *This);
+       ULONG (WINAPI *Release)(IDirect3DSwapChain9Ex *This);
+       /* IDirect3DSwapChain9 */
+       HRESULT (WINAPI *Present)(IDirect3DSwapChain9Ex *This, const RECT *pSourceRect, const RECT *pDestRect, HWND hDestWindowOverride, const RGNDATA *pDirtyRegion, DWORD dwFlags);
+       HRESULT (WINAPI *GetFrontBufferData)(IDirect3DSwapChain9Ex *This, IDirect3DSurface9 *pDestSurface);
+       HRESULT (WINAPI *GetBackBuffer)(IDirect3DSwapChain9Ex *This, UINT iBackBuffer, D3DBACKBUFFER_TYPE Type, IDirect3DSurface9 **ppBackBuffer);
+       HRESULT (WINAPI *GetRasterStatus)(IDirect3DSwapChain9Ex *This, D3DRASTER_STATUS *pRasterStatus);
+       HRESULT (WINAPI *GetDisplayMode)(IDirect3DSwapChain9Ex *This, D3DDISPLAYMODE *pMode);
+       HRESULT (WINAPI *GetDevice)(IDirect3DSwapChain9Ex *This, IDirect3DDevice9 **ppDevice);
+       HRESULT (WINAPI *GetPresentParameters)(IDirect3DSwapChain9Ex *This, D3DPRESENT_PARAMETERS *pPresentationParameters);
+       /* IDirect3DSwapChain9Ex */
+       HRESULT (WINAPI *GetLastPresentCount)(IDirect3DSwapChain9Ex *This, UINT *pLastPresentCount);
+       HRESULT (WINAPI *GetPresentStats)(IDirect3DSwapChain9Ex *This, D3DPRESENTSTATS *pPresentationStatistics);
+       HRESULT (WINAPI *GetDisplayModeEx)(IDirect3DSwapChain9Ex *This, D3DDISPLAYMODEEX *pMode, D3DDISPLAYROTATION *pRotation);
+} IDirect3DSwapChain9ExVtbl;
+struct IDirect3DSwapChain9Ex
+{
+       IDirect3DSwapChain9ExVtbl *lpVtbl;
+};
+
+/* IUnknown macros */
+#define IDirect3DSwapChain9Ex_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
+#define IDirect3DSwapChain9Ex_AddRef(p) (p)->lpVtbl->AddRef(p)
+#define IDirect3DSwapChain9Ex_Release(p) (p)->lpVtbl->Release(p)
+/* IDirect3DSwapChain9 macros */
+#define IDirect3DSwapChain9Ex_Present(p,a,b,c,d,e) (p)->lpVtbl->Present(p,a,b,c,d,e)
+#define IDirect3DSwapChain9Ex_GetFrontBufferData(p,a) (p)->lpVtbl->GetFrontBufferData(p,a)
+#define IDirect3DSwapChain9Ex_GetBackBuffer(p,a,b,c) (p)->lpVtbl->GetBackBuffer(p,a,b,c)
+#define IDirect3DSwapChain9Ex_GetRasterStatus(p,a) (p)->lpVtbl->GetRasterStatus(p,a)
+#define IDirect3DSwapChain9Ex_GetDisplayMode(p,a) (p)->lpVtbl->GetDisplayMode(p,a)
+#define IDirect3DSwapChain9Ex_GetDevice(p,a) (p)->lpVtbl->GetDevice(p,a)
+#define IDirect3DSwapChain9Ex_GetPresentParameters(p,a) (p)->lpVtbl->GetPresentParameters(p,a)
+/* IDirect3DSwapChain9Ex macros */
+#define IDirect3DSwapChain9Ex_GetLastPresentCount(p,a) (p)->lpVtbl->GetLastPresentCount(p,a)
+#define IDirect3DSwapChain9Ex_GetPresentStats(p,a) (p)->lpVtbl->GetPresentStats(p,a)
+#define IDirect3DSwapChain9Ex_GetDisplayModeEx(p,a,b) (p)->lpVtbl->GetDisplayModeEx(p,a,b)
+
+typedef struct IDirect3DTexture9Vtbl
+{
+       /* IUnknown */
+       HRESULT (WINAPI *QueryInterface)(IDirect3DTexture9 *This, REFIID riid, void **ppvObject);
+       ULONG (WINAPI *AddRef)(IDirect3DTexture9 *This);
+       ULONG (WINAPI *Release)(IDirect3DTexture9 *This);
+       /* IDirect3DResource9 */
+       HRESULT (WINAPI *GetDevice)(IDirect3DTexture9 *This, IDirect3DDevice9 **ppDevice);
+       HRESULT (WINAPI *SetPrivateData)(IDirect3DTexture9 *This, REFGUID refguid, const void *pData, DWORD SizeOfData, DWORD Flags);
+       HRESULT (WINAPI *GetPrivateData)(IDirect3DTexture9 *This, REFGUID refguid, void *pData, DWORD *pSizeOfData);
+       HRESULT (WINAPI *FreePrivateData)(IDirect3DTexture9 *This, REFGUID refguid);
+       DWORD (WINAPI *SetPriority)(IDirect3DTexture9 *This, DWORD PriorityNew);
+       DWORD (WINAPI *GetPriority)(IDirect3DTexture9 *This);
+       void (WINAPI *PreLoad)(IDirect3DTexture9 *This);
+       D3DRESOURCETYPE (WINAPI *GetType)(IDirect3DTexture9 *This);
+       /* IDirect3DBaseTexture9 */
+       DWORD (WINAPI *SetLOD)(IDirect3DTexture9 *This, DWORD LODNew);
+       DWORD (WINAPI *GetLOD)(IDirect3DTexture9 *This);
+       DWORD (WINAPI *GetLevelCount)(IDirect3DTexture9 *This);
+       HRESULT (WINAPI *SetAutoGenFilterType)(IDirect3DTexture9 *This, D3DTEXTUREFILTERTYPE FilterType);
+       D3DTEXTUREFILTERTYPE (WINAPI *GetAutoGenFilterType)(IDirect3DTexture9 *This);
+       void (WINAPI *GenerateMipSubLevels)(IDirect3DTexture9 *This);
+       /* IDirect3DTexture9 */
+       HRESULT (WINAPI *GetLevelDesc)(IDirect3DTexture9 *This, UINT Level, D3DSURFACE_DESC *pDesc);
+       HRESULT (WINAPI *GetSurfaceLevel)(IDirect3DTexture9 *This, UINT Level, IDirect3DSurface9 **ppSurfaceLevel);
+       HRESULT (WINAPI *LockRect)(IDirect3DTexture9 *This, UINT Level, D3DLOCKED_RECT *pLockedRect, const RECT *pRect, DWORD Flags);
+       HRESULT (WINAPI *UnlockRect)(IDirect3DTexture9 *This, UINT Level);
+       HRESULT (WINAPI *AddDirtyRect)(IDirect3DTexture9 *This, const RECT *pDirtyRect);
+} IDirect3DTexture9Vtbl;
+struct IDirect3DTexture9
+{
+       IDirect3DTexture9Vtbl *lpVtbl;
+};
+
+/* IUnknown macros */
+#define IDirect3DTexture9_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
+#define IDirect3DTexture9_AddRef(p) (p)->lpVtbl->AddRef(p)
+#define IDirect3DTexture9_Release(p) (p)->lpVtbl->Release(p)
+/* IDirect3DResource9 macros */
+#define IDirect3DTexture9_GetDevice(p,a) (p)->lpVtbl->GetDevice(p,a)
+#define IDirect3DTexture9_SetPrivateData(p,a,b,c,d) (p)->lpVtbl->SetPrivateData(p,a,b,c,d)
+#define IDirect3DTexture9_GetPrivateData(p,a,b,c) (p)->lpVtbl->GetPrivateData(p,a,b,c)
+#define IDirect3DTexture9_FreePrivateData(p,a) (p)->lpVtbl->FreePrivateData(p,a)
+#define IDirect3DTexture9_SetPriority(p,a) (p)->lpVtbl->SetPriority(p,a)
+#define IDirect3DTexture9_GetPriority(p) (p)->lpVtbl->GetPriority(p)
+#define IDirect3DTexture9_PreLoad(p) (p)->lpVtbl->PreLoad(p)
+#define IDirect3DTexture9_GetType(p) (p)->lpVtbl->GetType(p)
+/* IDirect3DBaseTexture9 macros */
+#define IDirect3DTexture9_SetLOD(p,a) (p)->lpVtbl->SetLOD(p,a)
+#define IDirect3DTexture9_GetLOD(p) (p)->lpVtbl->GetLOD(p)
+#define IDirect3DTexture9_GetLevelCount(p) (p)->lpVtbl->GetLevelCount(p)
+#define IDirect3DTexture9_SetAutoGenFilterType(p,a) (p)->lpVtbl->SetAutoGenFilterType(p,a)
+#define IDirect3DTexture9_GetAutoGenFilterType(p) (p)->lpVtbl->GetAutoGenFilterType(p)
+#define IDirect3DTexture9_GenerateMipSubLevels(p) (p)->lpVtbl->GenerateMipSubLevels(p)
+/* IDirect3DTexture9 macros */
+#define IDirect3DTexture9_GetLevelDesc(p,a,b) (p)->lpVtbl->GetLevelDesc(p,a,b)
+#define IDirect3DTexture9_GetSurfaceLevel(p,a,b) (p)->lpVtbl->GetSurfaceLevel(p,a,b)
+#define IDirect3DTexture9_LockRect(p,a,b,c,d) (p)->lpVtbl->LockRect(p,a,b,c,d)
+#define IDirect3DTexture9_UnlockRect(p,a) (p)->lpVtbl->UnlockRect(p,a)
+#define IDirect3DTexture9_AddDirtyRect(p,a) (p)->lpVtbl->AddDirtyRect(p,a)
+
+typedef struct IDirect3DVertexBuffer9Vtbl
+{
+       /* IUnknown */
+       HRESULT (WINAPI *QueryInterface)(IDirect3DVertexBuffer9 *This, REFIID riid, void **ppvObject);
+       ULONG (WINAPI *AddRef)(IDirect3DVertexBuffer9 *This);
+       ULONG (WINAPI *Release)(IDirect3DVertexBuffer9 *This);
+       /* IDirect3DResource9 */
+       HRESULT (WINAPI *GetDevice)(IDirect3DVertexBuffer9 *This, IDirect3DDevice9 **ppDevice);
+       HRESULT (WINAPI *SetPrivateData)(IDirect3DVertexBuffer9 *This, REFGUID refguid, const void *pData, DWORD SizeOfData, DWORD Flags);
+       HRESULT (WINAPI *GetPrivateData)(IDirect3DVertexBuffer9 *This, REFGUID refguid, void *pData, DWORD *pSizeOfData);
+       HRESULT (WINAPI *FreePrivateData)(IDirect3DVertexBuffer9 *This, REFGUID refguid);
+       DWORD (WINAPI *SetPriority)(IDirect3DVertexBuffer9 *This, DWORD PriorityNew);
+       DWORD (WINAPI *GetPriority)(IDirect3DVertexBuffer9 *This);
+       void (WINAPI *PreLoad)(IDirect3DVertexBuffer9 *This);
+       D3DRESOURCETYPE (WINAPI *GetType)(IDirect3DVertexBuffer9 *This);
+       /* IDirect3DVertexBuffer9 */
+       HRESULT (WINAPI *Lock)(IDirect3DVertexBuffer9 *This, UINT OffsetToLock, UINT SizeToLock, void **ppbData, DWORD Flags);
+       HRESULT (WINAPI *Unlock)(IDirect3DVertexBuffer9 *This);
+       HRESULT (WINAPI *GetDesc)(IDirect3DVertexBuffer9 *This, D3DVERTEXBUFFER_DESC *pDesc);
+} IDirect3DVertexBuffer9Vtbl;
+struct IDirect3DVertexBuffer9
+{
+       IDirect3DVertexBuffer9Vtbl *lpVtbl;
+};
+
+/* IUnknown macros */
+#define IDirect3DVertexBuffer9_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
+#define IDirect3DVertexBuffer9_AddRef(p) (p)->lpVtbl->AddRef(p)
+#define IDirect3DVertexBuffer9_Release(p) (p)->lpVtbl->Release(p)
+/* IDirect3DResource9 macros */
+#define IDirect3DVertexBuffer9_GetDevice(p,a) (p)->lpVtbl->GetDevice(p,a)
+#define IDirect3DVertexBuffer9_SetPrivateData(p,a,b,c,d) (p)->lpVtbl->SetPrivateData(p,a,b,c,d)
+#define IDirect3DVertexBuffer9_GetPrivateData(p,a,b,c) (p)->lpVtbl->GetPrivateData(p,a,b,c)
+#define IDirect3DVertexBuffer9_FreePrivateData(p,a) (p)->lpVtbl->FreePrivateData(p,a)
+#define IDirect3DVertexBuffer9_SetPriority(p,a) (p)->lpVtbl->SetPriority(p,a)
+#define IDirect3DVertexBuffer9_GetPriority(p) (p)->lpVtbl->GetPriority(p)
+#define IDirect3DVertexBuffer9_PreLoad(p) (p)->lpVtbl->PreLoad(p)
+#define IDirect3DVertexBuffer9_GetType(p) (p)->lpVtbl->GetType(p)
+/* IDirect3DVertexBuffer9 macros */
+#define IDirect3DVertexBuffer9_Lock(p,a,b,c,d) (p)->lpVtbl->Lock(p,a,b,c,d)
+#define IDirect3DVertexBuffer9_Unlock(p) (p)->lpVtbl->Unlock(p)
+#define IDirect3DVertexBuffer9_GetDesc(p,a) (p)->lpVtbl->GetDesc(p,a)
+
+typedef struct IDirect3DVertexDeclaration9Vtbl
+{
+       /* IUnknown */
+       HRESULT (WINAPI *QueryInterface)(IDirect3DVertexDeclaration9 *This, REFIID riid, void **ppvObject);
+       ULONG (WINAPI *AddRef)(IDirect3DVertexDeclaration9 *This);
+       ULONG (WINAPI *Release)(IDirect3DVertexDeclaration9 *This);
+       /* IDirect3DVertexDeclaration9 */
+       HRESULT (WINAPI *GetDevice)(IDirect3DVertexDeclaration9 *This, IDirect3DDevice9 **ppDevice);
+       HRESULT (WINAPI *GetDeclaration)(IDirect3DVertexDeclaration9 *This, D3DVERTEXELEMENT9 *pElement, UINT *pNumElements);
+} IDirect3DVertexDeclaration9Vtbl;
+struct IDirect3DVertexDeclaration9
+{
+       IDirect3DVertexDeclaration9Vtbl *lpVtbl;
+};
+
+/* IUnknown macros */
+#define IDirect3DVertexDeclaration9_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
+#define IDirect3DVertexDeclaration9_AddRef(p) (p)->lpVtbl->AddRef(p)
+#define IDirect3DVertexDeclaration9_Release(p) (p)->lpVtbl->Release(p)
+/* IDirect3DVertexDeclaration9 macros */
+#define IDirect3DVertexDeclaration9_GetDevice(p,a) (p)->lpVtbl->GetDevice(p,a)
+#define IDirect3DVertexDeclaration9_GetDeclaration(p,a,b) (p)->lpVtbl->GetDeclaration(p,a,b)
+
+typedef struct IDirect3DVertexShader9Vtbl
+{
+       /* IUnknown */
+       HRESULT (WINAPI *QueryInterface)(IDirect3DVertexShader9 *This, REFIID riid, void **ppvObject);
+       ULONG (WINAPI *AddRef)(IDirect3DVertexShader9 *This);
+       ULONG (WINAPI *Release)(IDirect3DVertexShader9 *This);
+       /* IDirect3DVertexShader9 */
+       HRESULT (WINAPI *GetDevice)(IDirect3DVertexShader9 *This, IDirect3DDevice9 **ppDevice);
+       HRESULT (WINAPI *GetFunction)(IDirect3DVertexShader9 *This, void *pData, UINT *pSizeOfData);
+} IDirect3DVertexShader9Vtbl;
+struct IDirect3DVertexShader9
+{
+       IDirect3DVertexShader9Vtbl *lpVtbl;
+};
+
+/* IUnknown macros */
+#define IDirect3DVertexShader9_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
+#define IDirect3DVertexShader9_AddRef(p) (p)->lpVtbl->AddRef(p)
+#define IDirect3DVertexShader9_Release(p) (p)->lpVtbl->Release(p)
+/* IDirect3DVertexShader9 macros */
+#define IDirect3DVertexShader9_GetDevice(p,a) (p)->lpVtbl->GetDevice(p,a)
+#define IDirect3DVertexShader9_GetFunction(p,a,b) (p)->lpVtbl->GetFunction(p,a,b)
+
+typedef struct IDirect3DVolume9Vtbl
+{
+       /* IUnknown */
+       HRESULT (WINAPI *QueryInterface)(IDirect3DVolume9 *This, REFIID riid, void **ppvObject);
+       ULONG (WINAPI *AddRef)(IDirect3DVolume9 *This);
+       ULONG (WINAPI *Release)(IDirect3DVolume9 *This);
+       /* IDirect3DVolume9 */
+       HRESULT (WINAPI *GetDevice)(IDirect3DVolume9 *This, IDirect3DDevice9 **ppDevice);
+       HRESULT (WINAPI *SetPrivateData)(IDirect3DVolume9 *This, REFGUID refguid, const void *pData, DWORD SizeOfData, DWORD Flags);
+       HRESULT (WINAPI *GetPrivateData)(IDirect3DVolume9 *This, REFGUID refguid, void *pData, DWORD *pSizeOfData);
+       HRESULT (WINAPI *FreePrivateData)(IDirect3DVolume9 *This, REFGUID refguid);
+       HRESULT (WINAPI *GetContainer)(IDirect3DVolume9 *This, REFIID riid, void **ppContainer);
+       HRESULT (WINAPI *GetDesc)(IDirect3DVolume9 *This, D3DVOLUME_DESC *pDesc);
+       HRESULT (WINAPI *LockBox)(IDirect3DVolume9 *This, D3DLOCKED_BOX *pLockedVolume, const D3DBOX *pBox, DWORD Flags);
+       HRESULT (WINAPI *UnlockBox)(IDirect3DVolume9 *This);
+} IDirect3DVolume9Vtbl;
+struct IDirect3DVolume9
+{
+       IDirect3DVolume9Vtbl *lpVtbl;
+};
+
+/* IUnknown macros */
+#define IDirect3DVolume9_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
+#define IDirect3DVolume9_AddRef(p) (p)->lpVtbl->AddRef(p)
+#define IDirect3DVolume9_Release(p) (p)->lpVtbl->Release(p)
+/* IDirect3DVolume9 macros */
+#define IDirect3DVolume9_GetDevice(p,a) (p)->lpVtbl->GetDevice(p,a)
+#define IDirect3DVolume9_SetPrivateData(p,a,b,c,d) (p)->lpVtbl->SetPrivateData(p,a,b,c,d)
+#define IDirect3DVolume9_GetPrivateData(p,a,b,c) (p)->lpVtbl->GetPrivateData(p,a,b,c)
+#define IDirect3DVolume9_FreePrivateData(p,a) (p)->lpVtbl->FreePrivateData(p,a)
+#define IDirect3DVolume9_GetContainer(p,a,b) (p)->lpVtbl->GetContainer(p,a,b)
+#define IDirect3DVolume9_GetDesc(p,a) (p)->lpVtbl->GetDesc(p,a)
+#define IDirect3DVolume9_LockBox(p,a,b,c) (p)->lpVtbl->LockBox(p,a,b,c)
+#define IDirect3DVolume9_UnlockBox(p) (p)->lpVtbl->UnlockBox(p)
+
+typedef struct IDirect3DVolumeTexture9Vtbl
+{
+       /* IUnknown */
+       HRESULT (WINAPI *QueryInterface)(IDirect3DVolumeTexture9 *This, REFIID riid, void **ppvObject);
+       ULONG (WINAPI *AddRef)(IDirect3DVolumeTexture9 *This);
+       ULONG (WINAPI *Release)(IDirect3DVolumeTexture9 *This);
+       /* IDirect3DResource9 */
+       HRESULT (WINAPI *GetDevice)(IDirect3DVolumeTexture9 *This, IDirect3DDevice9 **ppDevice);
+       HRESULT (WINAPI *SetPrivateData)(IDirect3DVolumeTexture9 *This, REFGUID refguid, const void *pData, DWORD SizeOfData, DWORD Flags);
+       HRESULT (WINAPI *GetPrivateData)(IDirect3DVolumeTexture9 *This, REFGUID refguid, void *pData, DWORD *pSizeOfData);
+       HRESULT (WINAPI *FreePrivateData)(IDirect3DVolumeTexture9 *This, REFGUID refguid);
+       DWORD (WINAPI *SetPriority)(IDirect3DVolumeTexture9 *This, DWORD PriorityNew);
+       DWORD (WINAPI *GetPriority)(IDirect3DVolumeTexture9 *This);
+       void (WINAPI *PreLoad)(IDirect3DVolumeTexture9 *This);
+       D3DRESOURCETYPE (WINAPI *GetType)(IDirect3DVolumeTexture9 *This);
+       /* IDirect3DBaseTexture9 */
+       DWORD (WINAPI *SetLOD)(IDirect3DVolumeTexture9 *This, DWORD LODNew);
+       DWORD (WINAPI *GetLOD)(IDirect3DVolumeTexture9 *This);
+       DWORD (WINAPI *GetLevelCount)(IDirect3DVolumeTexture9 *This);
+       HRESULT (WINAPI *SetAutoGenFilterType)(IDirect3DVolumeTexture9 *This, D3DTEXTUREFILTERTYPE FilterType);
+       D3DTEXTUREFILTERTYPE (WINAPI *GetAutoGenFilterType)(IDirect3DVolumeTexture9 *This);
+       void (WINAPI *GenerateMipSubLevels)(IDirect3DVolumeTexture9 *This);
+       /* IDirect3DVolumeTexture9 */
+       HRESULT (WINAPI *GetLevelDesc)(IDirect3DVolumeTexture9 *This, UINT Level, D3DVOLUME_DESC *pDesc);
+       HRESULT (WINAPI *GetVolumeLevel)(IDirect3DVolumeTexture9 *This, UINT Level, IDirect3DVolume9 **ppVolumeLevel);
+       HRESULT (WINAPI *LockBox)(IDirect3DVolumeTexture9 *This, UINT Level, D3DLOCKED_BOX *pLockedVolume, const D3DBOX *pBox, DWORD Flags);
+       HRESULT (WINAPI *UnlockBox)(IDirect3DVolumeTexture9 *This, UINT Level);
+       HRESULT (WINAPI *AddDirtyBox)(IDirect3DVolumeTexture9 *This, const D3DBOX *pDirtyBox);
+} IDirect3DVolumeTexture9Vtbl;
+struct IDirect3DVolumeTexture9
+{
+       IDirect3DVolumeTexture9Vtbl *lpVtbl;
+};
+
+/* IUnknown macros */
+#define IDirect3DVolumeTexture9_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
+#define IDirect3DVolumeTexture9_AddRef(p) (p)->lpVtbl->AddRef(p)
+#define IDirect3DVolumeTexture9_Release(p) (p)->lpVtbl->Release(p)
+/* IDirect3DResource9 macros */
+#define IDirect3DVolumeTexture9_GetDevice(p,a) (p)->lpVtbl->GetDevice(p,a)
+#define IDirect3DVolumeTexture9_SetPrivateData(p,a,b,c,d) (p)->lpVtbl->SetPrivateData(p,a,b,c,d)
+#define IDirect3DVolumeTexture9_GetPrivateData(p,a,b,c) (p)->lpVtbl->GetPrivateData(p,a,b,c)
+#define IDirect3DVolumeTexture9_FreePrivateData(p,a) (p)->lpVtbl->FreePrivateData(p,a)
+#define IDirect3DVolumeTexture9_SetPriority(p,a) (p)->lpVtbl->SetPriority(p,a)
+#define IDirect3DVolumeTexture9_GetPriority(p) (p)->lpVtbl->GetPriority(p)
+#define IDirect3DVolumeTexture9_PreLoad(p) (p)->lpVtbl->PreLoad(p)
+#define IDirect3DVolumeTexture9_GetType(p) (p)->lpVtbl->GetType(p)
+/* IDirect3DBaseTexture9 macros */
+#define IDirect3DVolumeTexture9_SetLOD(p,a) (p)->lpVtbl->SetLOD(p,a)
+#define IDirect3DVolumeTexture9_GetLOD(p) (p)->lpVtbl->GetLOD(p)
+#define IDirect3DVolumeTexture9_GetLevelCount(p) (p)->lpVtbl->GetLevelCount(p)
+#define IDirect3DVolumeTexture9_SetAutoGenFilterType(p,a) (p)->lpVtbl->SetAutoGenFilterType(p,a)
+#define IDirect3DVolumeTexture9_GetAutoGenFilterType(p) (p)->lpVtbl->GetAutoGenFilterType(p)
+#define IDirect3DVolumeTexture9_GenerateMipSubLevels(p) (p)->lpVtbl->GenerateMipSubLevels(p)
+/* IDirect3DVolumeTexture9 macros */
+#define IDirect3DVolumeTexture9_GetLevelDesc(p,a,b) (p)->lpVtbl->GetLevelDesc(p,a,b)
+#define IDirect3DVolumeTexture9_GetVolumeLevel(p,a,b) (p)->lpVtbl->GetVolumeLevel(p,a,b)
+#define IDirect3DVolumeTexture9_LockBox(p,a,b,c,d) (p)->lpVtbl->LockBox(p,a,b,c,d)
+#define IDirect3DVolumeTexture9_UnlockBox(p,a) (p)->lpVtbl->UnlockBox(p,a)
+#define IDirect3DVolumeTexture9_AddDirtyBox(p,a) (p)->lpVtbl->AddDirtyBox(p,a)
+
+#endif /* __cplusplus */
+
+#ifdef _WIN32
+
+IDirect3D9 *WINAPI
+Direct3DCreate9( UINT SDKVersion );
+
+HRESULT WINAPI
+Direct3DCreate9Ex( UINT SDKVersion,
+                   IDirect3D9Ex **ppD3D9 );
+
+void *WINAPI
+Direct3DShaderValidatorCreate9( void );
+
+int WINAPI
+D3DPERF_BeginEvent( D3DCOLOR color,
+                    LPCWSTR name );
+
+int WINAPI
+D3DPERF_EndEvent( void );
+
+DWORD WINAPI
+D3DPERF_GetStatus( void );
+
+void WINAPI
+D3DPERF_SetOptions( DWORD options );
+
+BOOL WINAPI
+D3DPERF_QueryRepeatFrame( void );
+
+void WINAPI
+D3DPERF_SetMarker( D3DCOLOR color,
+                   LPCWSTR name );
+
+void WINAPI
+D3DPERF_SetRegion( D3DCOLOR color,
+                   LPCWSTR name );
+
+void WINAPI
+DebugSetMute( void );
+
+#endif
+
+#endif /* _D3D9_H_ */
diff --git a/include/D3D9/d3d9caps.h b/include/D3D9/d3d9caps.h
new file mode 100644 (file)
index 0000000..0cce5d3
--- /dev/null
@@ -0,0 +1,387 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _D3D9CAPS_H_
+#define _D3D9CAPS_H_
+
+#include "d3d9types.h"
+
+/* Caps flags */
+#define D3DCAPS2_FULLSCREENGAMMA   0x00020000
+#define D3DCAPS2_CANCALIBRATEGAMMA 0x00100000
+#define D3DCAPS2_RESERVED          0x02000000
+#define D3DCAPS2_CANMANAGERESOURCE 0x10000000
+#define D3DCAPS2_DYNAMICTEXTURES   0x20000000
+#define D3DCAPS2_CANAUTOGENMIPMAP  0x40000000
+#define D3DCAPS2_CANSHARERESOURCE  0x80000000
+
+#define D3DCAPS3_ALPHA_FULLSCREEN_FLIP_OR_DISCARD 0x00000020
+#define D3DCAPS3_LINEAR_TO_SRGB_PRESENTATION      0x00000080
+#define D3DCAPS3_COPY_TO_VIDMEM                   0x00000100
+#define D3DCAPS3_COPY_TO_SYSTEMMEM                0x00000200
+#define D3DCAPS3_DXVAHD                           0x00000400
+#define D3DCAPS3_RESERVED                         0x8000001F
+
+#define D3DPRESENT_INTERVAL_DEFAULT   0x00000000
+#define D3DPRESENT_INTERVAL_ONE       0x00000001
+#define D3DPRESENT_INTERVAL_TWO       0x00000002
+#define D3DPRESENT_INTERVAL_THREE     0x00000004
+#define D3DPRESENT_INTERVAL_FOUR      0x00000008
+#define D3DPRESENT_INTERVAL_IMMEDIATE 0x80000000
+
+#define D3DCURSORCAPS_COLOR  0x00000001
+#define D3DCURSORCAPS_LOWRES 0x00000002
+
+#define D3DDEVCAPS_EXECUTESYSTEMMEMORY     0x00000010
+#define D3DDEVCAPS_EXECUTEVIDEOMEMORY      0x00000020
+#define D3DDEVCAPS_TLVERTEXSYSTEMMEMORY    0x00000040
+#define D3DDEVCAPS_TLVERTEXVIDEOMEMORY     0x00000080
+#define D3DDEVCAPS_TEXTURESYSTEMMEMORY     0x00000100
+#define D3DDEVCAPS_TEXTUREVIDEOMEMORY      0x00000200
+#define D3DDEVCAPS_DRAWPRIMTLVERTEX        0x00000400
+#define D3DDEVCAPS_CANRENDERAFTERFLIP      0x00000800
+#define D3DDEVCAPS_TEXTURENONLOCALVIDMEM   0x00001000
+#define D3DDEVCAPS_DRAWPRIMITIVES2         0x00002000
+#define D3DDEVCAPS_SEPARATETEXTUREMEMORIES 0x00004000
+#define D3DDEVCAPS_DRAWPRIMITIVES2EX       0x00008000
+#define D3DDEVCAPS_HWTRANSFORMANDLIGHT     0x00010000
+#define D3DDEVCAPS_CANBLTSYSTONONLOCAL     0x00020000
+#define D3DDEVCAPS_HWRASTERIZATION         0x00080000
+#define D3DDEVCAPS_PUREDEVICE              0x00100000
+#define D3DDEVCAPS_QUINTICRTPATCHES        0x00200000
+#define D3DDEVCAPS_RTPATCHES               0x00400000
+#define D3DDEVCAPS_RTPATCHHANDLEZERO       0x00800000
+#define D3DDEVCAPS_NPATCHES                0x01000000
+
+#define D3DPMISCCAPS_MASKZ                      0x00000002
+#define D3DPMISCCAPS_CULLNONE                   0x00000010
+#define D3DPMISCCAPS_CULLCW                     0x00000020
+#define D3DPMISCCAPS_CULLCCW                    0x00000040
+#define D3DPMISCCAPS_COLORWRITEENABLE           0x00000080
+#define D3DPMISCCAPS_CLIPPLANESCALEDPOINTS      0x00000100
+#define D3DPMISCCAPS_CLIPTLVERTS                0x00000200
+#define D3DPMISCCAPS_TSSARGTEMP                 0x00000400
+#define D3DPMISCCAPS_BLENDOP                    0x00000800
+#define D3DPMISCCAPS_NULLREFERENCE              0x00001000
+#define D3DPMISCCAPS_INDEPENDENTWRITEMASKS      0x00004000
+#define D3DPMISCCAPS_PERSTAGECONSTANT           0x00008000
+#define D3DPMISCCAPS_FOGANDSPECULARALPHA        0x00010000
+#define D3DPMISCCAPS_SEPARATEALPHABLEND         0x00020000
+#define D3DPMISCCAPS_MRTINDEPENDENTBITDEPTHS    0x00040000
+#define D3DPMISCCAPS_MRTPOSTPIXELSHADERBLENDING 0x00080000
+#define D3DPMISCCAPS_FOGVERTEXCLAMPED           0x00100000
+#define D3DPMISCCAPS_POSTBLENDSRGBCONVERT       0x00200000
+
+#define D3DPRASTERCAPS_DITHER              0x00000001
+#define D3DPRASTERCAPS_ZTEST               0x00000010
+#define D3DPRASTERCAPS_FOGVERTEX           0x00000080
+#define D3DPRASTERCAPS_FOGTABLE            0x00000100
+#define D3DPRASTERCAPS_MIPMAPLODBIAS       0x00002000
+#define D3DPRASTERCAPS_ZBUFFERLESSHSR      0x00008000
+#define D3DPRASTERCAPS_FOGRANGE            0x00010000
+#define D3DPRASTERCAPS_ANISOTROPY          0x00020000
+#define D3DPRASTERCAPS_WBUFFER             0x00040000
+#define D3DPRASTERCAPS_WFOG                0x00100000
+#define D3DPRASTERCAPS_ZFOG                0x00200000
+#define D3DPRASTERCAPS_COLORPERSPECTIVE    0x00400000
+#define D3DPRASTERCAPS_SCISSORTEST         0x01000000
+#define D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS 0x02000000
+#define D3DPRASTERCAPS_DEPTHBIAS           0x04000000
+#define D3DPRASTERCAPS_MULTISAMPLE_TOGGLE  0x08000000
+
+#define D3DPCMPCAPS_NEVER        0x00000001
+#define D3DPCMPCAPS_LESS         0x00000002
+#define D3DPCMPCAPS_EQUAL        0x00000004
+#define D3DPCMPCAPS_LESSEQUAL    0x00000008
+#define D3DPCMPCAPS_GREATER      0x00000010
+#define D3DPCMPCAPS_NOTEQUAL     0x00000020
+#define D3DPCMPCAPS_GREATEREQUAL 0x00000040
+#define D3DPCMPCAPS_ALWAYS       0x00000080
+
+#define D3DPBLENDCAPS_ZERO            0x00000001
+#define D3DPBLENDCAPS_ONE             0x00000002
+#define D3DPBLENDCAPS_SRCCOLOR        0x00000004
+#define D3DPBLENDCAPS_INVSRCCOLOR     0x00000008
+#define D3DPBLENDCAPS_SRCALPHA        0x00000010
+#define D3DPBLENDCAPS_INVSRCALPHA     0x00000020
+#define D3DPBLENDCAPS_DESTALPHA       0x00000040
+#define D3DPBLENDCAPS_INVDESTALPHA    0x00000080
+#define D3DPBLENDCAPS_DESTCOLOR       0x00000100
+#define D3DPBLENDCAPS_INVDESTCOLOR    0x00000200
+#define D3DPBLENDCAPS_SRCALPHASAT     0x00000400
+#define D3DPBLENDCAPS_BOTHSRCALPHA    0x00000800
+#define D3DPBLENDCAPS_BOTHINVSRCALPHA 0x00001000
+#define D3DPBLENDCAPS_BLENDFACTOR     0x00002000
+#ifndef D3D_DISABLE_9EX
+# define D3DPBLENDCAPS_SRCCOLOR2      0x00004000
+# define D3DPBLENDCAPS_INVSRCCOLOR2   0x00008000
+#endif
+
+#define D3DPSHADECAPS_COLORGOURAUDRGB    0x00000008
+#define D3DPSHADECAPS_SPECULARGOURAUDRGB 0x00000200
+#define D3DPSHADECAPS_ALPHAGOURAUDBLEND  0x00004000
+#define D3DPSHADECAPS_FOGGOURAUD         0x00080000
+
+#define D3DPTEXTURECAPS_PERSPECTIVE              0x00000001
+#define D3DPTEXTURECAPS_POW2                     0x00000002
+#define D3DPTEXTURECAPS_ALPHA                    0x00000004
+#define D3DPTEXTURECAPS_SQUAREONLY               0x00000020
+#define D3DPTEXTURECAPS_TEXREPEATNOTSCALEDBYSIZE 0x00000040
+#define D3DPTEXTURECAPS_ALPHAPALETTE             0x00000080
+#define D3DPTEXTURECAPS_NONPOW2CONDITIONAL       0x00000100
+#define D3DPTEXTURECAPS_PROJECTED                0x00000400
+#define D3DPTEXTURECAPS_CUBEMAP                  0x00000800
+#define D3DPTEXTURECAPS_VOLUMEMAP                0x00002000
+#define D3DPTEXTURECAPS_MIPMAP                   0x00004000
+#define D3DPTEXTURECAPS_MIPVOLUMEMAP             0x00008000
+#define D3DPTEXTURECAPS_MIPCUBEMAP               0x00010000
+#define D3DPTEXTURECAPS_CUBEMAP_POW2             0x00020000
+#define D3DPTEXTURECAPS_VOLUMEMAP_POW2           0x00040000
+#define D3DPTEXTURECAPS_NOPROJECTEDBUMPENV       0x00200000
+
+#define D3DPTFILTERCAPS_MINFPOINT         0x00000100
+#define D3DPTFILTERCAPS_MINFLINEAR        0x00000200
+#define D3DPTFILTERCAPS_MINFANISOTROPIC   0x00000400
+#define D3DPTFILTERCAPS_MINFPYRAMIDALQUAD 0x00000800
+#define D3DPTFILTERCAPS_MINFGAUSSIANQUAD  0x00001000
+#define D3DPTFILTERCAPS_MIPFPOINT         0x00010000
+#define D3DPTFILTERCAPS_MIPFLINEAR        0x00020000
+#define D3DPTFILTERCAPS_MAGFPOINT         0x01000000
+#define D3DPTFILTERCAPS_MAGFLINEAR        0x02000000
+#define D3DPTFILTERCAPS_MAGFANISOTROPIC   0x04000000
+#define D3DPTFILTERCAPS_MAGFPYRAMIDALQUAD 0x08000000
+#define D3DPTFILTERCAPS_MAGFGAUSSIANQUAD  0x10000000
+
+#define D3DPTADDRESSCAPS_WRAP          0x00000001
+#define D3DPTADDRESSCAPS_MIRROR        0x00000002
+#define D3DPTADDRESSCAPS_CLAMP         0x00000004
+#define D3DPTADDRESSCAPS_BORDER        0x00000008
+#define D3DPTADDRESSCAPS_INDEPENDENTUV 0x00000010
+#define D3DPTADDRESSCAPS_MIRRORONCE    0x00000020
+
+#define D3DLINECAPS_TEXTURE   0x00000001
+#define D3DLINECAPS_ZTEST     0x00000002
+#define D3DLINECAPS_BLEND     0x00000004
+#define D3DLINECAPS_ALPHACMP  0x00000008
+#define D3DLINECAPS_FOG       0x00000010
+#define D3DLINECAPS_ANTIALIAS 0x00000020
+
+#define D3DSTENCILCAPS_KEEP     0x00000001
+#define D3DSTENCILCAPS_ZERO     0x00000002
+#define D3DSTENCILCAPS_REPLACE  0x00000004
+#define D3DSTENCILCAPS_INCRSAT  0x00000008
+#define D3DSTENCILCAPS_DECRSAT  0x00000010
+#define D3DSTENCILCAPS_INVERT   0x00000020
+#define D3DSTENCILCAPS_INCR     0x00000040
+#define D3DSTENCILCAPS_DECR     0x00000080
+#define D3DSTENCILCAPS_TWOSIDED 0x00000100
+
+#define D3DFVFCAPS_TEXCOORDCOUNTMASK  0x0000FFFF
+#define D3DFVFCAPS_DONOTSTRIPELEMENTS 0x00080000
+#define D3DFVFCAPS_PSIZE              0x00100000
+
+#define D3DTEXOPCAPS_DISABLE                   0x00000001
+#define D3DTEXOPCAPS_SELECTARG1                0x00000002
+#define D3DTEXOPCAPS_SELECTARG2                0x00000004
+#define D3DTEXOPCAPS_MODULATE                  0x00000008
+#define D3DTEXOPCAPS_MODULATE2X                0x00000010
+#define D3DTEXOPCAPS_MODULATE4X                0x00000020
+#define D3DTEXOPCAPS_ADD                       0x00000040
+#define D3DTEXOPCAPS_ADDSIGNED                 0x00000080
+#define D3DTEXOPCAPS_ADDSIGNED2X               0x00000100
+#define D3DTEXOPCAPS_SUBTRACT                  0x00000200
+#define D3DTEXOPCAPS_ADDSMOOTH                 0x00000400
+#define D3DTEXOPCAPS_BLENDDIFFUSEALPHA         0x00000800
+#define D3DTEXOPCAPS_BLENDTEXTUREALPHA         0x00001000
+#define D3DTEXOPCAPS_BLENDFACTORALPHA          0x00002000
+#define D3DTEXOPCAPS_BLENDTEXTUREALPHAPM       0x00004000
+#define D3DTEXOPCAPS_BLENDCURRENTALPHA         0x00008000
+#define D3DTEXOPCAPS_PREMODULATE               0x00010000
+#define D3DTEXOPCAPS_MODULATEALPHA_ADDCOLOR    0x00020000
+#define D3DTEXOPCAPS_MODULATECOLOR_ADDALPHA    0x00040000
+#define D3DTEXOPCAPS_MODULATEINVALPHA_ADDCOLOR 0x00080000
+#define D3DTEXOPCAPS_MODULATEINVCOLOR_ADDALPHA 0x00100000
+#define D3DTEXOPCAPS_BUMPENVMAP                0x00200000
+#define D3DTEXOPCAPS_BUMPENVMAPLUMINANCE       0x00400000
+#define D3DTEXOPCAPS_DOTPRODUCT3               0x00800000
+#define D3DTEXOPCAPS_MULTIPLYADD               0x01000000
+#define D3DTEXOPCAPS_LERP                      0x02000000
+
+#define D3DVTXPCAPS_TEXGEN                   0x00000001
+#define D3DVTXPCAPS_MATERIALSOURCE7          0x00000002
+#define D3DVTXPCAPS_DIRECTIONALLIGHTS        0x00000008
+#define D3DVTXPCAPS_POSITIONALLIGHTS         0x00000010
+#define D3DVTXPCAPS_LOCALVIEWER              0x00000020
+#define D3DVTXPCAPS_TWEENING                 0x00000040
+#define D3DVTXPCAPS_TEXGEN_SPHEREMAP         0x00000100
+#define D3DVTXPCAPS_NO_TEXGEN_NONLOCALVIEWER 0x00000200
+
+#define D3DDEVCAPS2_STREAMOFFSET                       0x00000001
+#define D3DDEVCAPS2_DMAPNPATCH                         0x00000002
+#define D3DDEVCAPS2_ADAPTIVETESSRTPATCH                0x00000004
+#define D3DDEVCAPS2_ADAPTIVETESSNPATCH                 0x00000008
+#define D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES      0x00000010
+#define D3DDEVCAPS2_PRESAMPLEDDMAPNPATCH               0x00000020
+#define D3DDEVCAPS2_VERTEXELEMENTSCANSHARESTREAMOFFSET 0x00000040
+
+#define D3DDTCAPS_UBYTE4    0x00000001
+#define D3DDTCAPS_UBYTE4N   0x00000002
+#define D3DDTCAPS_SHORT2N   0x00000004
+#define D3DDTCAPS_SHORT4N   0x00000008
+#define D3DDTCAPS_USHORT2N  0x00000010
+#define D3DDTCAPS_USHORT4N  0x00000020
+#define D3DDTCAPS_UDEC3     0x00000040
+#define D3DDTCAPS_DEC3N     0x00000080
+#define D3DDTCAPS_FLOAT16_2 0x00000100
+#define D3DDTCAPS_FLOAT16_4 0x00000200
+
+
+#define D3DVS20_MAX_DYNAMICFLOWCONTROLDEPTH  24
+#define D3DVS20_MIN_DYNAMICFLOWCONTROLDEPTH  0
+#define D3DVS20_MAX_NUMTEMPS                 32
+#define D3DVS20_MIN_NUMTEMPS                 12
+#define D3DVS20_MAX_STATICFLOWCONTROLDEPTH   4
+#define D3DVS20_MIN_STATICFLOWCONTROLDEPTH   1
+
+#define D3DVS20CAPS_PREDICATION              (1 << 0)
+
+#define D3DPS20CAPS_ARBITRARYSWIZZLE         (1 << 0)
+#define D3DPS20CAPS_GRADIENTINSTRUCTIONS     (1 << 1)
+#define D3DPS20CAPS_PREDICATION              (1 << 2)
+#define D3DPS20CAPS_NODEPENDENTREADLIMIT     (1 << 3)
+#define D3DPS20CAPS_NOTEXINSTRUCTIONLIMIT    (1 << 4)
+
+#define D3DPS20_MAX_DYNAMICFLOWCONTROLDEPTH  24
+#define D3DPS20_MIN_DYNAMICFLOWCONTROLDEPTH  0
+#define D3DPS20_MAX_NUMTEMPS                 32
+#define D3DPS20_MIN_NUMTEMPS                 12
+#define D3DPS20_MAX_STATICFLOWCONTROLDEPTH   4
+#define D3DPS20_MIN_STATICFLOWCONTROLDEPTH   0
+#define D3DPS20_MAX_NUMINSTRUCTIONSLOTS      512
+#define D3DPS20_MIN_NUMINSTRUCTIONSLOTS      96
+
+#define D3DMIN30SHADERINSTRUCTIONS          512
+#define D3DMAX30SHADERINSTRUCTIONS          32768
+
+/* Structs */
+typedef struct _D3DVSHADERCAPS2_0 {
+       DWORD Caps;
+       INT DynamicFlowControlDepth;
+       INT NumTemps;
+       INT StaticFlowControlDepth;
+} D3DVSHADERCAPS2_0, *PD3DVSHADERCAPS2_0, *LPD3DVSHADERCAPS2_0;
+
+typedef struct _D3DPSHADERCAPS2_0 {
+       DWORD Caps;
+       INT DynamicFlowControlDepth;
+       INT NumTemps;
+       INT StaticFlowControlDepth;
+       INT NumInstructionSlots;
+} D3DPSHADERCAPS2_0, *PD3DPSHADERCAPS2_0, *LPD3DPSHADERCAPS2_0;
+
+typedef struct _D3DCAPS9 {
+       D3DDEVTYPE DeviceType;
+       UINT AdapterOrdinal;
+       DWORD Caps;
+       DWORD Caps2;
+       DWORD Caps3;
+       DWORD PresentationIntervals;
+       DWORD CursorCaps;
+       DWORD DevCaps;
+       DWORD PrimitiveMiscCaps;
+       DWORD RasterCaps;
+       DWORD ZCmpCaps;
+       DWORD SrcBlendCaps;
+       DWORD DestBlendCaps;
+       DWORD AlphaCmpCaps;
+       DWORD ShadeCaps;
+       DWORD TextureCaps;
+       DWORD TextureFilterCaps;
+       DWORD CubeTextureFilterCaps;
+       DWORD VolumeTextureFilterCaps;
+       DWORD TextureAddressCaps;
+       DWORD VolumeTextureAddressCaps;
+       DWORD LineCaps;
+       DWORD MaxTextureWidth;
+       DWORD MaxTextureHeight;
+       DWORD MaxVolumeExtent;
+       DWORD MaxTextureRepeat;
+       DWORD MaxTextureAspectRatio;
+       DWORD MaxAnisotropy;
+       float MaxVertexW;
+       float GuardBandLeft;
+       float GuardBandTop;
+       float GuardBandRight;
+       float GuardBandBottom;
+       float ExtentsAdjust;
+       DWORD StencilCaps;
+       DWORD FVFCaps;
+       DWORD TextureOpCaps;
+       DWORD MaxTextureBlendStages;
+       DWORD MaxSimultaneousTextures;
+       DWORD VertexProcessingCaps;
+       DWORD MaxActiveLights;
+       DWORD MaxUserClipPlanes;
+       DWORD MaxVertexBlendMatrices;
+       DWORD MaxVertexBlendMatrixIndex;
+       float MaxPointSize;
+       DWORD MaxPrimitiveCount;
+       DWORD MaxVertexIndex;
+       DWORD MaxStreams;
+       DWORD MaxStreamStride;
+       DWORD VertexShaderVersion;
+       DWORD MaxVertexShaderConst;
+       DWORD PixelShaderVersion;
+       float PixelShader1xMaxValue;
+       DWORD DevCaps2;
+       float MaxNpatchTessellationLevel;
+       DWORD Reserved5;
+       UINT MasterAdapterOrdinal;
+       UINT AdapterOrdinalInGroup;
+       UINT NumberOfAdaptersInGroup;
+       DWORD DeclTypes;
+       DWORD NumSimultaneousRTs;
+       DWORD StretchRectFilterCaps;
+       D3DVSHADERCAPS2_0 VS20Caps;
+       D3DPSHADERCAPS2_0 PS20Caps;
+       DWORD VertexTextureFilterCaps;
+       DWORD MaxVShaderInstructionsExecuted;
+       DWORD MaxPShaderInstructionsExecuted;
+       DWORD MaxVertexShader30InstructionSlots;
+       DWORD MaxPixelShader30InstructionSlots;
+} D3DCAPS9, *PD3DCAPS9, *LPD3DCAPS9;
+
+typedef struct _D3DCONTENTPROTECTIONCAPS {
+    DWORD Caps;
+    GUID KeyExchangeType;
+    UINT BufferAlignmentStart;
+    UINT BlockAlignmentSize;
+    ULONGLONG ProtectedMemorySize;
+} D3DCONTENTPROTECTIONCAPS, *PD3DCONTENTPROTECTIONCAPS, *LPD3DCONTENTPROTECTIONCAPS;
+
+typedef struct _D3DOVERLAYCAPS {
+    UINT Caps;
+    UINT MaxOverlayDisplayWidth;
+    UINT MaxOverlayDisplayHeight;
+} D3DOVERLAYCAPS, *PD3DOVERLAYCAPS, *LPD3DOVERLAYCAPS;
+
+#endif /* _D3D9CAPS_H_ */
diff --git a/include/D3D9/d3d9types.h b/include/D3D9/d3d9types.h
new file mode 100644 (file)
index 0000000..0a8f9e5
--- /dev/null
@@ -0,0 +1,1797 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _D3D9TYPES_H_
+#define _D3D9TYPES_H_
+
+#ifdef _WIN32
+#include <windows.h>
+#else /* _WIN32 */
+#include <stdint.h>
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/********************************************************
+ * Windows types                                        *
+ ********************************************************/
+/* Function macros */
+#define FAILED(x)    ((HRESULT)(x) < 0)
+#define SUCCEEDED(x) ((HRESULT)(x) >= 0)
+
+#define MAKE_HRESULT(sev,fac,code) \
+    ( \
+        ((HRESULT)(sev) << 31) | \
+        ((HRESULT)(fac) << 16) | \
+         (HRESULT)(code) \
+    )
+
+/* Windows errors */
+#define E_OUTOFMEMORY MAKE_HRESULT(1, 0x007, 14)
+#define E_NOINTERFACE MAKE_HRESULT(1, 0x000, 0x4002)
+#define E_POINTER     MAKE_HRESULT(1, 0x000, 0x4003)
+
+#define S_OK          ((HRESULT)0)
+#define S_FALSE       ((HRESULT)1)
+
+/* WORD types */
+typedef uint8_t BYTE;
+typedef uint16_t WORD;
+typedef uint32_t DWORD;
+
+/* Renamed types */
+typedef int BOOL;
+#ifndef FALSE
+#define FALSE 0
+#define TRUE (!FALSE)
+#endif
+
+typedef uint32_t UINT32;
+typedef uint64_t UINT64;
+
+typedef unsigned short USHORT;
+typedef unsigned int UINT;
+typedef unsigned int ULONG;
+typedef unsigned long long ULONGLONG;
+
+typedef short SHORT;
+typedef int INT;
+typedef int LONG;
+typedef long long LONGLONG;
+typedef float FLOAT;
+
+/* Windows types */
+typedef void *HANDLE;
+typedef int32_t HRESULT;
+typedef HANDLE HWND;
+typedef HANDLE HMONITOR;
+typedef HANDLE HDC;
+
+/* Unions */
+typedef union {
+    struct {
+        DWORD LowPart;
+        LONG HighPart;
+    };
+
+    struct {
+        DWORD LowPart;
+        LONG HighPart;
+    } u;
+
+    LONGLONG QuadPart;
+} LARGE_INTEGER, *LPLARGE_INTEGER;
+
+/* Structs */
+
+typedef struct _GUID {
+    DWORD Data1;
+    WORD Data2;
+    WORD Data3;
+    BYTE Data4[8];
+} GUID, IID, *LPGUID, *REFGUID, *REFIID;
+
+typedef struct _LUID {
+    DWORD LowPart;
+    LONG HighPart;
+} LUID, *LPLUID, *PLUID;
+
+typedef struct _PALETTEENTRY {
+    BYTE peRed;
+    BYTE peGreen;
+    BYTE peBlue;
+    BYTE peFlags;
+} PALETTEENTRY, *LPPALETTEENTRY;
+
+typedef struct _POINT {
+    LONG x;
+    LONG y;
+} POINT, *LPPOINT;
+
+typedef struct _RECT {
+    LONG left;
+    LONG top;
+    LONG right;
+    LONG bottom;
+} RECT, *LPRECT;
+
+typedef struct _RGNDATAHEADER {
+    DWORD dwSize;
+    DWORD iType;
+    DWORD nCount;
+    DWORD nRgnSize;
+    RECT rcBound;
+} RGNDATAHEADER, *LPRGNDATAHEADER;
+
+typedef struct _RGNDATA {
+    RGNDATAHEADER rdh;
+    char Buffer[1];
+} RGNDATA, *LPRGNDATA;
+#endif /* _WIN32 */
+
+#ifndef MAKEFOURCC
+#define MAKEFOURCC(a, b, c, d) \
+    ( \
+         (DWORD)(BYTE)(a) | \
+        ((DWORD)(BYTE)(b) << 8) | \
+        ((DWORD)(BYTE)(c) << 16) | \
+        ((DWORD)(BYTE)(d) << 24) \
+    )
+#endif /* MAKEFOURCC */
+
+
+#define D3DPRESENTFLAG_LOCKABLE_BACKBUFFER             0x00000001
+#define D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL            0x00000002
+#define D3DPRESENTFLAG_DEVICECLIP                      0x00000004
+#define D3DPRESENTFLAG_VIDEO                           0x00000010
+#define D3DPRESENTFLAG_NOAUTOROTATE                    0x00000020
+#define D3DPRESENTFLAG_UNPRUNEDMODE                    0x00000040
+#define D3DPRESENTFLAG_OVERLAY_LIMITEDRGB              0x00000080
+#define D3DPRESENTFLAG_OVERLAY_YCbCr_BT709             0x00000100
+#define D3DPRESENTFLAG_OVERLAY_YCbCr_xvYCC             0x00000200
+#define D3DPRESENTFLAG_RESTRICTED_CONTENT              0x00000400
+#define D3DPRESENTFLAG_RESTRICT_SHARED_RESOURCE_DRIVER 0x00000800
+
+
+#ifdef WINAPI
+#undef WINAPI
+#endif /* WINAPI*/
+
+#if defined(__x86_64__) || defined(_M_X64)
+#define WINAPI __attribute__((ms_abi))
+#else /* x86_64 */
+#define WINAPI __attribute__((__stdcall__))
+#endif /* x86_64 */
+
+/* Implementation caps */
+#define D3DPRESENT_BACK_BUFFERS_MAX    3
+#define D3DPRESENT_BACK_BUFFERS_MAX_EX 30
+
+/* Functions */
+#define MAKE_D3DHRESULT(code) MAKE_HRESULT(1, 0x876, code)
+#define MAKE_D3DSTATUS(code)  MAKE_HRESULT(0, 0x876, code)
+
+/* SDK version */
+#define D3D_SDK_VERSION 32
+
+/* Adapter */
+#define D3DADAPTER_DEFAULT 0
+
+/********************************************************
+ * Return codes                                         *
+ ********************************************************/
+#define D3D_OK                           S_OK
+#define D3DOK_NOAUTOGEN                  MAKE_D3DSTATUS(2159)
+#define D3DERR_OUTOFVIDEOMEMORY          MAKE_D3DHRESULT(380)
+#define D3DERR_WASSTILLDRAWING           MAKE_D3DHRESULT(540)
+#define D3DERR_WRONGTEXTUREFORMAT        MAKE_D3DHRESULT(2072)
+#define D3DERR_UNSUPPORTEDCOLOROPERATION MAKE_D3DHRESULT(2073)
+#define D3DERR_UNSUPPORTEDCOLORARG       MAKE_D3DHRESULT(2074)
+#define D3DERR_UNSUPPORTEDALPHAOPERATION MAKE_D3DHRESULT(2075)
+#define D3DERR_UNSUPPORTEDALPHAARG       MAKE_D3DHRESULT(2076)
+#define D3DERR_TOOMANYOPERATIONS         MAKE_D3DHRESULT(2077)
+#define D3DERR_CONFLICTINGTEXTUREFILTER  MAKE_D3DHRESULT(2078)
+#define D3DERR_UNSUPPORTEDFACTORVALUE    MAKE_D3DHRESULT(2079)
+#define D3DERR_CONFLICTINGRENDERSTATE    MAKE_D3DHRESULT(2081)
+#define D3DERR_UNSUPPORTEDTEXTUREFILTER  MAKE_D3DHRESULT(2082)
+#define D3DERR_CONFLICTINGTEXTUREPALETTE MAKE_D3DHRESULT(2086)
+#define D3DERR_DRIVERINTERNALERROR       MAKE_D3DHRESULT(2087)
+#define D3DERR_NOTFOUND                  MAKE_D3DHRESULT(2150)
+#define D3DERR_MOREDATA                  MAKE_D3DHRESULT(2151)
+#define D3DERR_DEVICELOST                MAKE_D3DHRESULT(2152)
+#define D3DERR_DEVICENOTRESET            MAKE_D3DHRESULT(2153)
+#define D3DERR_NOTAVAILABLE              MAKE_D3DHRESULT(2154)
+#define D3DERR_INVALIDDEVICE             MAKE_D3DHRESULT(2155)
+#define D3DERR_INVALIDCALL               MAKE_D3DHRESULT(2156)
+#define D3DERR_DRIVERINVALIDCALL         MAKE_D3DHRESULT(2157)
+
+/********************************************************
+ * Bitmasks                                             *
+ *******************************************************/
+/* IDirect3DDevice9::Clear */
+#define D3DCLEAR_TARGET  0x00000001
+#define D3DCLEAR_ZBUFFER 0x00000002
+#define D3DCLEAR_STENCIL 0x00000004
+
+/* Usage */
+/* http://msdn.microsoft.com/en-us/library/ee416659(VS.85).aspx */
+#define D3DUSAGE_RENDERTARGET                    0x00000001
+#define D3DUSAGE_DEPTHSTENCIL                    0x00000002
+#define D3DUSAGE_WRITEONLY                       0x00000008
+#define D3DUSAGE_SOFTWAREPROCESSING              0x00000010
+#define D3DUSAGE_DONOTCLIP                       0x00000020
+#define D3DUSAGE_POINTS                          0x00000040
+#define D3DUSAGE_RTPATCHES                       0x00000080
+#define D3DUSAGE_NPATCHES                        0x00000100
+#define D3DUSAGE_DYNAMIC                         0x00000200
+#define D3DUSAGE_AUTOGENMIPMAP                   0x00000400
+#ifndef D3D_DISABLE_9EX
+#define D3DUSAGE_RESTRICTED_CONTENT              0x00000800
+#define D3DUSAGE_RESTRICT_SHARED_RESOURCE_DRIVER 0x00001000
+#define D3DUSAGE_RESTRICT_SHARED_RESOURCE        0x00002000
+#endif
+#define D3DUSAGE_DMAP                            0x00004000
+#define D3DUSAGE_QUERY_LEGACYBUMPMAP             0x00008000
+#define D3DUSAGE_QUERY_SRGBREAD                  0x00010000
+#define D3DUSAGE_QUERY_FILTER                    0x00020000
+#define D3DUSAGE_QUERY_SRGBWRITE                 0x00040000
+#define D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING  0x00080000
+#define D3DUSAGE_QUERY_VERTEXTEXTURE             0x00100000
+#define D3DUSAGE_QUERY_WRAPANDMIP                   0x00200000
+#ifndef D3D_DISABLE_9EX
+#define D3DUSAGE_NONSECURE                       0x00800000
+#define D3DUSAGE_TEXTAPI                         0x10000000
+#endif
+
+/* Buffer locking */
+/* http://msdn.microsoft.com/en-us/library/ee416503(VS.85).aspx */
+#define D3DLOCK_READONLY        0x00000010
+#define D3DLOCK_NOSYSLOCK       0x00000800
+#define D3DLOCK_NOOVERWRITE     0x00001000
+#define D3DLOCK_DISCARD         0x00002000
+#define D3DLOCK_DONOTWAIT       0x00004000
+#define D3DLOCK_NO_DIRTY_UPDATE 0x00008000
+
+/* FVF */
+/* http://msdn.microsoft.com/en-us/library/ee416490(VS.85).aspx */
+/* http://msdn.microsoft.com/en-us/library/ms791638.aspx */
+#define D3DFVF_XYZ              0x00000002
+#define D3DFVF_XYZRHW           0x00000004
+#define D3DFVF_XYZB1            0x00000006
+#define D3DFVF_XYZB2            0x00000008
+#define D3DFVF_XYZB3            0x0000000A
+#define D3DFVF_XYZB4            0x0000000C
+#define D3DFVF_XYZB5            0x0000000E
+#define D3DFVF_XYZW             0x00004002
+#define D3DFVF_POSITION_MASK    0x0000400E
+
+#define D3DFVF_NORMAL           0x00000010
+#define D3DFVF_PSIZE            0x00000020
+#define D3DFVF_DIFFUSE          0x00000040
+#define D3DFVF_SPECULAR         0x00000080
+
+#define D3DFVF_TEX0             0x00000000
+#define D3DFVF_TEX1             0x00000100
+#define D3DFVF_TEX2             0x00000200
+#define D3DFVF_TEX3             0x00000300
+#define D3DFVF_TEX4             0x00000400
+#define D3DFVF_TEX5             0x00000500
+#define D3DFVF_TEX6             0x00000600
+#define D3DFVF_TEX7             0x00000700
+#define D3DFVF_TEX8             0x00000800
+#define D3DFVF_TEXCOUNT_MASK    0x00000F00
+#define D3DFVF_TEXCOUNT_SHIFT            8
+#define D3DFVF_TEXTUREFORMAT1   0x00000003
+#define D3DFVF_TEXTUREFORMAT2   0x00000000
+#define D3DFVF_TEXTUREFORMAT3   0x00000001
+#define D3DFVF_TEXTUREFORMAT4   0x00000002
+
+#define D3DFVF_POSITION_MASK  0x0000400E
+#define D3DFVF_TEXCOUNT_MASK  0x00000F00
+#define D3DFVF_TEXCOUNT_SHIFT 8
+
+#define D3DFVF_LASTBETA_UBYTE4   0x00001000
+#define D3DFVF_LASTBETA_D3DCOLOR 0x00008000
+
+#define D3DFVF_RESERVED0 0x00000001
+#define D3DFVF_RESERVED2 0x00006000
+
+#define D3DTA_SELECTMASK        0x0000000f
+#define D3DTA_DIFFUSE           0x00000000
+#define D3DTA_CURRENT           0x00000001
+#define D3DTA_TEXTURE           0x00000002
+#define D3DTA_TFACTOR           0x00000003
+#define D3DTA_SPECULAR          0x00000004
+#define D3DTA_TEMP              0x00000005
+#define D3DTA_CONSTANT          0x00000006
+#define D3DTA_COMPLEMENT        0x00000010
+#define D3DTA_ALPHAREPLICATE    0x00000020
+
+#define D3DSPD_IUNKNOWN 0x00000001
+
+#define D3DPRESENT_DONOTWAIT      0x00000001
+#define D3DPRESENT_LINEAR_CONTENT 0x00000002
+
+#define D3DCREATE_FPU_PRESERVE              0x00000002
+#define D3DCREATE_MULTITHREADED             0x00000004
+#define D3DCREATE_PUREDEVICE                0x00000010
+#define D3DCREATE_SOFTWARE_VERTEXPROCESSING 0x00000020
+#define D3DCREATE_HARDWARE_VERTEXPROCESSING 0x00000040
+#define D3DCREATE_MIXED_VERTEXPROCESSING    0x00000080
+#define D3DCREATE_DISABLE_DRIVER_MANAGEMENT 0x00000100
+#define D3DCREATE_ADAPTERGROUP_DEVICE       0x00000200
+
+#define D3DSTREAMSOURCE_INDEXEDDATA  (1 << 30)
+#define D3DSTREAMSOURCE_INSTANCEDATA (2 << 30)
+
+/********************************************************
+ * Function macros                                      *
+ *******************************************************/
+
+/* Colors */
+#define D3DCOLOR_ARGB(a,r,g,b) \
+    ((D3DCOLOR)( \
+        (((a) & 0xFF) << 24) | \
+        (((r) & 0xFF) << 16) | \
+        (((g) & 0xFF) << 8) | \
+         ((b) & 0xFF) \
+    ))
+
+#define D3DCOLOR_RGBA(r,g,b,a) D3DCOLOR_ARGB(a,r,g,b)
+#define D3DCOLOR_XRGB(r,g,b)   D3DCOLOR_ARGB(0xFF,r,g,b)
+#define D3DCOLOR_AYUV(a,y,u,v) D3DCOLOR_ARGB(a,y,u,v)
+#define D3DCOLOR_XYUV(y,u,v)   D3DCOLOR_ARGB(0xFF,y,u,v)
+
+#define D3DCOLOR_COLORVALUE(r,g,b,a) \
+    D3DCOLOR_RGBA( \
+        (DWORD)((r) * 255.0f), \
+        (DWORD)((g) * 255.0f), \
+        (DWORD)((b) * 255.0f), \
+        (DWORD)((a) * 255.0f) \
+    )
+
+/* Shaders */
+#define D3DDECL_END() { 0xFF, 0, D3DDECLTYPE_UNUSED, 0, 0, 0 }
+
+/*****************************************************************************
+ * Typedefs                                                                  *
+ *****************************************************************************/
+typedef DWORD D3DCOLOR;
+
+/*****************************************************************************
+ * Enums                                                                     *
+ *****************************************************************************/
+typedef enum D3DDISPLAYROTATION {
+    D3DDISPLAYROTATION_IDENTITY = 1,
+    D3DDISPLAYROTATION_90 = 2,
+    D3DDISPLAYROTATION_180 = 3,
+    D3DDISPLAYROTATION_270 = 4
+} D3DDISPLAYROTATION;
+
+typedef enum D3DSCANLINEORDERING {
+    D3DSCANLINEORDERING_UNKNOWN = 0,
+    D3DSCANLINEORDERING_PROGRESSIVE = 1,
+    D3DSCANLINEORDERING_INTERLACED = 2
+} D3DSCANLINEORDERING;
+
+typedef enum _D3DAUTHENTICATEDCHANNELTYPE {
+    D3DAUTHENTICATEDCHANNEL_D3D9 = 1,
+    D3DAUTHENTICATEDCHANNEL_DRIVER_SOFTWARE = 2,
+    D3DAUTHENTICATEDCHANNEL_DRIVER_HARDWARE = 3
+} D3DAUTHENTICATEDCHANNELTYPE;
+
+typedef enum _D3DAUTHENTICATEDCHANNEL_PROCESSIDENTIFIERTYPE {
+    PROCESSIDTYPE_UNKNOWN = 0,
+    PROCESSIDTYPE_DWM = 1,
+    PROCESSIDTYPE_HANDLE = 2
+} D3DAUTHENTICATEDCHANNEL_PROCESSIDENTIFIERTYPE;
+
+typedef enum _D3DBACKBUFFER_TYPE {
+    D3DBACKBUFFER_TYPE_MONO = 0,
+    D3DBACKBUFFER_TYPE_LEFT = 1,
+    D3DBACKBUFFER_TYPE_RIGHT = 2
+} D3DBACKBUFFER_TYPE;
+
+typedef enum _D3DBASISTYPE {
+   D3DBASIS_BEZIER = 0,
+   D3DBASIS_BSPLINE = 1,
+   D3DBASIS_CATMULL_ROM = 2
+} D3DBASISTYPE;
+
+typedef enum _D3DBLEND {
+    D3DBLEND_ZERO = 1,
+    D3DBLEND_ONE = 2,
+    D3DBLEND_SRCCOLOR = 3,
+    D3DBLEND_INVSRCCOLOR = 4,
+    D3DBLEND_SRCALPHA = 5,
+    D3DBLEND_INVSRCALPHA = 6,
+    D3DBLEND_DESTALPHA = 7,
+    D3DBLEND_INVDESTALPHA = 8,
+    D3DBLEND_DESTCOLOR = 9,
+    D3DBLEND_INVDESTCOLOR = 10,
+    D3DBLEND_SRCALPHASAT = 11,
+    D3DBLEND_BOTHSRCALPHA = 12,
+    D3DBLEND_BOTHINVSRCALPHA = 13,
+    D3DBLEND_BLENDFACTOR = 14,
+    D3DBLEND_INVBLENDFACTOR = 15,
+    D3DBLEND_SRCCOLOR2 = 16,
+    D3DBLEND_INVSRCCOLOR2 = 17
+} D3DBLEND;
+
+typedef enum _D3DBLENDOP {
+    D3DBLENDOP_ADD = 1,
+    D3DBLENDOP_SUBTRACT = 2,
+    D3DBLENDOP_REVSUBTRACT = 3,
+    D3DBLENDOP_MIN = 4,
+    D3DBLENDOP_MAX = 5
+} D3DBLENDOP;
+
+typedef enum _D3DBUSTYPE {
+    D3DBUSTYPE_OTHER = 0x00000000,
+    D3DBUSTYPE_PCI = 0x00000001,
+    D3DBUSTYPE_PCIX = 0x00000002,
+    D3DBUSTYPE_PCIEXPRESS = 0x00000003,
+    D3DBUSTYPE_AGP = 0x00000004,
+    D3DBUSIMPL_MODIFIER_INSIDE_OF_CHIPSET = 0x00010000,
+    D3DBUSIMPL_MODIFIER_TRACKS_ON_MOTHER_BOARD_TO_CHIP = 0x00020000,
+    D3DBUSIMPL_MODIFIER_TRACKS_ON_MOTHER_BOARD_TO_SOCKET = 0x00030000,
+    D3DBUSIMPL_MODIFIER_DAUGHTER_BOARD_CONNECTOR = 0x00040000,
+    D3DBUSIMPL_MODIFIER_DAUGHTER_BOARD_CONNECTOR_INSIDE_OF_NUAE = 0x00050000,
+    D3DBUSIMPL_MODIFIER_NON_STANDARD = 0x80000000
+} D3DBUSTYPE;
+
+typedef enum _D3DCMPFUNC {
+    D3DCMP_NEVER = 1,
+    D3DCMP_LESS = 2,
+    D3DCMP_EQUAL = 3,
+    D3DCMP_LESSEQUAL = 4,
+    D3DCMP_GREATER = 5,
+    D3DCMP_NOTEQUAL = 6,
+    D3DCMP_GREATEREQUAL = 7,
+    D3DCMP_ALWAYS = 8
+} D3DCMPFUNC;
+
+typedef enum _D3DCOMPOSERECTSOP{
+    D3DCOMPOSERECTS_COPY = 1,
+    D3DCOMPOSERECTS_OR = 2,
+    D3DCOMPOSERECTS_AND = 3,
+    D3DCOMPOSERECTS_NEG = 4
+} D3DCOMPOSERECTSOP;
+
+typedef enum _D3DCUBEMAP_FACES {
+    D3DCUBEMAP_FACE_POSITIVE_X = 0,
+    D3DCUBEMAP_FACE_NEGATIVE_X = 1,
+    D3DCUBEMAP_FACE_POSITIVE_Y = 2,
+    D3DCUBEMAP_FACE_NEGATIVE_Y = 3,
+    D3DCUBEMAP_FACE_POSITIVE_Z = 4,
+    D3DCUBEMAP_FACE_NEGATIVE_Z = 5
+} D3DCUBEMAP_FACES;
+
+typedef enum _D3DCULL {
+    D3DCULL_NONE = 1,
+    D3DCULL_CW = 2,
+    D3DCULL_CCW = 3
+} D3DCULL;
+
+typedef enum _D3DDEBUGMONITORTOKENS {
+    D3DDMT_ENABLE = 0,
+    D3DDMT_DISABLE = 1
+} D3DDEBUGMONITORTOKENS;
+
+typedef enum _D3DDECLMETHOD {
+    D3DDECLMETHOD_DEFAULT = 0,
+    D3DDECLMETHOD_PARTIALU = 1,
+    D3DDECLMETHOD_PARTIALV = 2,
+    D3DDECLMETHOD_CROSSUV = 3,
+    D3DDECLMETHOD_UV = 4,
+    D3DDECLMETHOD_LOOKUP = 5,
+    D3DDECLMETHOD_LOOKUPPRESAMPLED = 6
+} D3DDECLMETHOD;
+
+typedef enum _D3DDECLTYPE {
+    D3DDECLTYPE_FLOAT1 = 0,
+    D3DDECLTYPE_FLOAT2 = 1,
+    D3DDECLTYPE_FLOAT3 = 2,
+    D3DDECLTYPE_FLOAT4 = 3,
+    D3DDECLTYPE_D3DCOLOR = 4,
+    D3DDECLTYPE_UBYTE4 = 5,
+    D3DDECLTYPE_SHORT2 = 6,
+    D3DDECLTYPE_SHORT4 = 7,
+    D3DDECLTYPE_UBYTE4N = 8,
+    D3DDECLTYPE_SHORT2N = 9,
+    D3DDECLTYPE_SHORT4N = 10,
+    D3DDECLTYPE_USHORT2N = 11,
+    D3DDECLTYPE_USHORT4N = 12,
+    D3DDECLTYPE_UDEC3 = 13,
+    D3DDECLTYPE_DEC3N = 14,
+    D3DDECLTYPE_FLOAT16_2 = 15,
+    D3DDECLTYPE_FLOAT16_4 = 16,
+    D3DDECLTYPE_UNUSED = 17
+} D3DDECLTYPE;
+
+typedef enum _D3DDECLUSAGE {
+    D3DDECLUSAGE_POSITION = 0,
+    D3DDECLUSAGE_BLENDWEIGHT = 1,
+    D3DDECLUSAGE_BLENDINDICES = 2,
+    D3DDECLUSAGE_NORMAL = 3,
+    D3DDECLUSAGE_PSIZE = 4,
+    D3DDECLUSAGE_TEXCOORD = 5,
+    D3DDECLUSAGE_TANGENT = 6,
+    D3DDECLUSAGE_BINORMAL = 7,
+    D3DDECLUSAGE_TESSFACTOR = 8,
+    D3DDECLUSAGE_POSITIONT = 9,
+    D3DDECLUSAGE_COLOR = 10,
+    D3DDECLUSAGE_FOG = 11,
+    D3DDECLUSAGE_DEPTH = 12,
+    D3DDECLUSAGE_SAMPLE = 13
+} D3DDECLUSAGE;
+
+typedef enum _D3DDEGREETYPE {
+   D3DDEGREE_LINEAR = 1,
+   D3DDEGREE_QUADRATIC = 2,
+   D3DDEGREE_CUBIC = 3,
+   D3DDEGREE_QUINTIC = 5
+} D3DDEGREETYPE;
+
+typedef enum _D3DDEVTYPE {
+    D3DDEVTYPE_HAL = 1,
+    D3DDEVTYPE_REF = 2,
+    D3DDEVTYPE_SW = 3,
+    D3DDEVTYPE_NULLREF = 4
+} D3DDEVTYPE;
+
+typedef enum _D3DFILLMODE {
+    D3DFILL_POINT = 1,
+    D3DFILL_WIREFRAME = 2,
+    D3DFILL_SOLID = 3
+} D3DFILLMODE;
+
+typedef enum _D3DFOGMODE {
+    D3DFOG_NONE = 0,
+    D3DFOG_EXP = 1,
+    D3DFOG_EXP2 = 2,
+    D3DFOG_LINEAR = 3
+} D3DFOGMODE;
+
+typedef enum _D3DFORMAT {
+    D3DFMT_UNKNOWN = 0,
+    D3DFMT_R8G8B8 = 20,
+    D3DFMT_A8R8G8B8 = 21,
+    D3DFMT_X8R8G8B8 = 22,
+    D3DFMT_R5G6B5 = 23,
+    D3DFMT_X1R5G5B5 = 24,
+    D3DFMT_A1R5G5B5 = 25,
+    D3DFMT_A4R4G4B4 = 26,
+    D3DFMT_R3G3B2 = 27,
+    D3DFMT_A8 = 28,
+    D3DFMT_A8R3G3B2 = 29,
+    D3DFMT_X4R4G4B4 = 30,
+    D3DFMT_A2B10G10R10 = 31,
+    D3DFMT_A8B8G8R8 = 32,
+    D3DFMT_X8B8G8R8 = 33,
+    D3DFMT_G16R16 = 34,
+    D3DFMT_A2R10G10B10 = 35,
+    D3DFMT_A16B16G16R16 = 36,
+    D3DFMT_A8P8 = 40,
+    D3DFMT_P8 = 41,
+    D3DFMT_L8 = 50,
+    D3DFMT_A8L8 = 51,
+    D3DFMT_A4L4 = 52,
+    D3DFMT_V8U8 = 60,
+    D3DFMT_L6V5U5 = 61,
+    D3DFMT_X8L8V8U8 = 62,
+    D3DFMT_Q8W8V8U8 = 63,
+    D3DFMT_V16U16 = 64,
+    D3DFMT_A2W10V10U10 = 67,
+    D3DFMT_UYVY = MAKEFOURCC('U', 'Y', 'V', 'Y'),
+    D3DFMT_R8G8_B8G8 = MAKEFOURCC('R', 'G', 'B', 'G'),
+    D3DFMT_YUY2 = MAKEFOURCC('Y', 'U', 'Y', '2'),
+    D3DFMT_G8R8_G8B8 = MAKEFOURCC('G', 'R', 'G', 'B'),
+    D3DFMT_DXT1 = MAKEFOURCC('D', 'X', 'T', '1'),
+    D3DFMT_DXT2 = MAKEFOURCC('D', 'X', 'T', '2'),
+    D3DFMT_DXT3 = MAKEFOURCC('D', 'X', 'T', '3'),
+    D3DFMT_DXT4 = MAKEFOURCC('D', 'X', 'T', '4'),
+    D3DFMT_DXT5 = MAKEFOURCC('D', 'X', 'T', '5'),
+    D3DFMT_D16_LOCKABLE = 70,
+    D3DFMT_D32 = 71,
+    D3DFMT_D15S1 = 73,
+    D3DFMT_D24S8 = 75,
+    D3DFMT_D24X8 = 77,
+    D3DFMT_D24X4S4 = 79,
+    D3DFMT_D16 = 80,
+    D3DFMT_D32F_LOCKABLE = 82,
+    D3DFMT_D24FS8 = 83,
+    D3DFMT_D32_LOCKABLE = 84,
+    D3DFMT_S8_LOCKABLE = 85,
+    D3DFMT_L16 = 81,
+    D3DFMT_VERTEXDATA = 100,
+    D3DFMT_INDEX16 = 101,
+    D3DFMT_INDEX32 = 102,
+    D3DFMT_Q16W16V16U16 = 110,
+    D3DFMT_MULTI2_ARGB8 = MAKEFOURCC('M','E','T','1'),
+    D3DFMT_R16F = 111,
+    D3DFMT_G16R16F = 112,
+    D3DFMT_A16B16G16R16F = 113,
+    D3DFMT_R32F = 114,
+    D3DFMT_G32R32F = 115,
+    D3DFMT_A32B32G32R32F = 116,
+    D3DFMT_CxV8U8 = 117,
+    D3DFMT_A1 = 118,
+    D3DFMT_A2B10G10R10_XR_BIAS = 119,
+    D3DFMT_BINARYBUFFER = 199,
+    D3DFMT_DF16 = MAKEFOURCC('D', 'F', '1', '6'),
+    D3DFMT_DF24 = MAKEFOURCC('D', 'F', '2', '4'),
+    D3DFMT_INTZ = MAKEFOURCC('I', 'N', 'T', 'Z'),
+    D3DFMT_NULL = MAKEFOURCC('N', 'U', 'L', 'L'),
+    D3DFMT_NV11 = MAKEFOURCC('N', 'V', '1', '1'),
+    D3DFMT_NV12 = MAKEFOURCC('N', 'V', '1', '2'),
+    D3DFMT_Y210 = MAKEFOURCC('Y', '2', '1', '0'),
+    D3DFMT_Y216 = MAKEFOURCC('Y', '2', '1', '6'),
+    D3DFMT_Y410 = MAKEFOURCC('Y', '4', '1', '0')
+} D3DFORMAT;
+
+typedef enum _D3DLIGHTTYPE {
+    D3DLIGHT_POINT = 1,
+    D3DLIGHT_SPOT = 2,
+    D3DLIGHT_DIRECTIONAL = 3
+} D3DLIGHTTYPE;
+
+typedef enum _D3DMATERIALCOLORSOURCE {
+    D3DMCS_MATERIAL = 0,
+    D3DMCS_COLOR1 = 1,
+    D3DMCS_COLOR2 = 2
+} D3DMATERIALCOLORSOURCE;
+
+typedef enum _D3DMULTISAMPLE_TYPE {
+    D3DMULTISAMPLE_NONE = 0,
+    D3DMULTISAMPLE_NONMASKABLE = 1,
+    D3DMULTISAMPLE_2_SAMPLES = 2,
+    D3DMULTISAMPLE_3_SAMPLES = 3,
+    D3DMULTISAMPLE_4_SAMPLES = 4,
+    D3DMULTISAMPLE_5_SAMPLES = 5,
+    D3DMULTISAMPLE_6_SAMPLES = 6,
+    D3DMULTISAMPLE_7_SAMPLES = 7,
+    D3DMULTISAMPLE_8_SAMPLES = 8,
+    D3DMULTISAMPLE_9_SAMPLES = 9,
+    D3DMULTISAMPLE_10_SAMPLES = 10,
+    D3DMULTISAMPLE_11_SAMPLES = 11,
+    D3DMULTISAMPLE_12_SAMPLES = 12,
+    D3DMULTISAMPLE_13_SAMPLES = 13,
+    D3DMULTISAMPLE_14_SAMPLES = 14,
+    D3DMULTISAMPLE_15_SAMPLES = 15,
+    D3DMULTISAMPLE_16_SAMPLES = 16
+} D3DMULTISAMPLE_TYPE;
+
+typedef enum _D3DPATCHEDGESTYLE {
+   D3DPATCHEDGE_DISCRETE = 0,
+   D3DPATCHEDGE_CONTINUOUS = 1
+} D3DPATCHEDGESTYLE;
+
+typedef enum _D3DPOOL {
+    D3DPOOL_DEFAULT = 0,
+    D3DPOOL_MANAGED = 1,
+    D3DPOOL_SYSTEMMEM = 2,
+    D3DPOOL_SCRATCH = 3
+} D3DPOOL;
+
+typedef enum _D3DPRIMITIVETYPE {
+    D3DPT_POINTLIST = 1,
+    D3DPT_LINELIST = 2,
+    D3DPT_LINESTRIP = 3,
+    D3DPT_TRIANGLELIST = 4,
+    D3DPT_TRIANGLESTRIP = 5,
+    D3DPT_TRIANGLEFAN = 6
+} D3DPRIMITIVETYPE;
+
+typedef enum _D3DQUERYTYPE {
+    D3DQUERYTYPE_VCACHE = 4,
+    D3DQUERYTYPE_RESOURCEMANAGER = 5,
+    D3DQUERYTYPE_VERTEXSTATS = 6,
+    D3DQUERYTYPE_EVENT = 8,
+    D3DQUERYTYPE_OCCLUSION = 9,
+    D3DQUERYTYPE_TIMESTAMP = 10,
+    D3DQUERYTYPE_TIMESTAMPDISJOINT = 11,
+    D3DQUERYTYPE_TIMESTAMPFREQ = 12,
+    D3DQUERYTYPE_PIPELINETIMINGS = 13,
+    D3DQUERYTYPE_INTERFACETIMINGS = 14,
+    D3DQUERYTYPE_VERTEXTIMINGS = 15,
+    D3DQUERYTYPE_PIXELTIMINGS = 16,
+    D3DQUERYTYPE_BANDWIDTHTIMINGS = 17,
+    D3DQUERYTYPE_CACHEUTILIZATION = 18,
+    D3DQUERYTYPE_MEMORYPRESSURE = 19
+} D3DQUERYTYPE;
+
+#define D3DISSUE_BEGIN   (1 << 1)
+#define D3DISSUE_END     (1 << 0)
+#define D3DGETDATA_FLUSH (1 << 0)
+
+
+typedef enum _D3DRENDERSTATETYPE {
+    D3DRS_ZENABLE = 7,
+    D3DRS_FILLMODE = 8,
+    D3DRS_SHADEMODE = 9,
+    D3DRS_ZWRITEENABLE = 14,
+    D3DRS_ALPHATESTENABLE = 15,
+    D3DRS_LASTPIXEL = 16,
+    D3DRS_SRCBLEND = 19,
+    D3DRS_DESTBLEND = 20,
+    D3DRS_CULLMODE = 22,
+    D3DRS_ZFUNC = 23,
+    D3DRS_ALPHAREF = 24,
+    D3DRS_ALPHAFUNC = 25,
+    D3DRS_DITHERENABLE = 26,
+    D3DRS_ALPHABLENDENABLE = 27,
+    D3DRS_FOGENABLE = 28,
+    D3DRS_SPECULARENABLE = 29,
+    D3DRS_FOGCOLOR = 34,
+    D3DRS_FOGTABLEMODE = 35,
+    D3DRS_FOGSTART = 36,
+    D3DRS_FOGEND = 37,
+    D3DRS_FOGDENSITY = 38,
+    D3DRS_RANGEFOGENABLE = 48,
+    D3DRS_STENCILENABLE = 52,
+    D3DRS_STENCILFAIL = 53,
+    D3DRS_STENCILZFAIL = 54,
+    D3DRS_STENCILPASS = 55,
+    D3DRS_STENCILFUNC = 56,
+    D3DRS_STENCILREF = 57,
+    D3DRS_STENCILMASK = 58,
+    D3DRS_STENCILWRITEMASK = 59,
+    D3DRS_TEXTUREFACTOR = 60,
+    D3DRS_WRAP0 = 128,
+    D3DRS_WRAP1 = 129,
+    D3DRS_WRAP2 = 130,
+    D3DRS_WRAP3 = 131,
+    D3DRS_WRAP4 = 132,
+    D3DRS_WRAP5 = 133,
+    D3DRS_WRAP6 = 134,
+    D3DRS_WRAP7 = 135,
+    D3DRS_CLIPPING = 136,
+    D3DRS_LIGHTING = 137,
+    D3DRS_AMBIENT = 139,
+    D3DRS_FOGVERTEXMODE = 140,
+    D3DRS_COLORVERTEX = 141,
+    D3DRS_LOCALVIEWER = 142,
+    D3DRS_NORMALIZENORMALS = 143,
+    D3DRS_DIFFUSEMATERIALSOURCE = 145,
+    D3DRS_SPECULARMATERIALSOURCE = 146,
+    D3DRS_AMBIENTMATERIALSOURCE = 147,
+    D3DRS_EMISSIVEMATERIALSOURCE = 148,
+    D3DRS_VERTEXBLEND = 151,
+    D3DRS_CLIPPLANEENABLE = 152,
+    D3DRS_POINTSIZE = 154,
+    D3DRS_POINTSIZE_MIN = 155,
+    D3DRS_POINTSPRITEENABLE = 156,
+    D3DRS_POINTSCALEENABLE = 157,
+    D3DRS_POINTSCALE_A = 158,
+    D3DRS_POINTSCALE_B = 159,
+    D3DRS_POINTSCALE_C = 160,
+    D3DRS_MULTISAMPLEANTIALIAS = 161,
+    D3DRS_MULTISAMPLEMASK = 162,
+    D3DRS_PATCHEDGESTYLE = 163,
+    D3DRS_DEBUGMONITORTOKEN = 165,
+    D3DRS_POINTSIZE_MAX = 166,
+    D3DRS_INDEXEDVERTEXBLENDENABLE = 167,
+    D3DRS_COLORWRITEENABLE = 168,
+    D3DRS_TWEENFACTOR = 170,
+    D3DRS_BLENDOP = 171,
+    D3DRS_POSITIONDEGREE = 172,
+    D3DRS_NORMALDEGREE = 173,
+    D3DRS_SCISSORTESTENABLE = 174,
+    D3DRS_SLOPESCALEDEPTHBIAS = 175,
+    D3DRS_ANTIALIASEDLINEENABLE = 176,
+    D3DRS_MINTESSELLATIONLEVEL = 178,
+    D3DRS_MAXTESSELLATIONLEVEL = 179,
+    D3DRS_ADAPTIVETESS_X = 180,
+    D3DRS_ADAPTIVETESS_Y = 181,
+    D3DRS_ADAPTIVETESS_Z = 182,
+    D3DRS_ADAPTIVETESS_W = 183,
+    D3DRS_ENABLEADAPTIVETESSELLATION = 184,
+    D3DRS_TWOSIDEDSTENCILMODE = 185,
+    D3DRS_CCW_STENCILFAIL = 186,
+    D3DRS_CCW_STENCILZFAIL = 187,
+    D3DRS_CCW_STENCILPASS = 188,
+    D3DRS_CCW_STENCILFUNC = 189,
+    D3DRS_COLORWRITEENABLE1 = 190,
+    D3DRS_COLORWRITEENABLE2 = 191,
+    D3DRS_COLORWRITEENABLE3 = 192,
+    D3DRS_BLENDFACTOR = 193,
+    D3DRS_SRGBWRITEENABLE = 194,
+    D3DRS_DEPTHBIAS = 195,
+    D3DRS_WRAP8 = 198,
+    D3DRS_WRAP9 = 199,
+    D3DRS_WRAP10 = 200,
+    D3DRS_WRAP11 = 201,
+    D3DRS_WRAP12 = 202,
+    D3DRS_WRAP13 = 203,
+    D3DRS_WRAP14 = 204,
+    D3DRS_WRAP15 = 205,
+    D3DRS_SEPARATEALPHABLENDENABLE = 206,
+    D3DRS_SRCBLENDALPHA = 207,
+    D3DRS_DESTBLENDALPHA = 208,
+    D3DRS_BLENDOPALPHA = 209
+} D3DRENDERSTATETYPE;
+
+typedef enum _D3DRESOURCETYPE {
+    D3DRTYPE_SURFACE = 1,
+    D3DRTYPE_VOLUME = 2,
+    D3DRTYPE_TEXTURE = 3,
+    D3DRTYPE_VOLUMETEXTURE = 4,
+    D3DRTYPE_CUBETEXTURE = 5,
+    D3DRTYPE_VERTEXBUFFER = 6,
+    D3DRTYPE_INDEXBUFFER = 7
+} D3DRESOURCETYPE;
+#define D3DRTYPECOUNT (D3DRTYPE_INDEXBUFFER+1)
+
+typedef enum _D3DSAMPLERSTATETYPE {
+    D3DSAMP_ADDRESSU = 1,
+    D3DSAMP_ADDRESSV = 2,
+    D3DSAMP_ADDRESSW = 3,
+    D3DSAMP_BORDERCOLOR = 4,
+    D3DSAMP_MAGFILTER = 5,
+    D3DSAMP_MINFILTER = 6,
+    D3DSAMP_MIPFILTER = 7,
+    D3DSAMP_MIPMAPLODBIAS = 8,
+    D3DSAMP_MAXMIPLEVEL = 9,
+    D3DSAMP_MAXANISOTROPY = 10,
+    D3DSAMP_SRGBTEXTURE = 11,
+    D3DSAMP_ELEMENTINDEX = 12,
+    D3DSAMP_DMAPOFFSET = 13
+} D3DSAMPLERSTATETYPE;
+
+typedef enum _D3DSAMPLER_TEXTURE_TYPE {
+    D3DSTT_UNKNOWN = 0<<27,
+    D3DSTT_1D = 1<<27,
+    D3DSTT_2D = 2<<27,
+    D3DSTT_CUBE = 3<<27,
+    D3DSTT_VOLUME = 4<<27
+} D3DSAMPLER_TEXTURE_TYPE;
+
+typedef enum _D3DSHADEMODE {
+    D3DSHADE_FLAT = 1,
+    D3DSHADE_GOURAUD = 2,
+    D3DSHADE_PHONG = 3
+} D3DSHADEMODE;
+
+typedef enum _D3DSHADER_ADDRESSMODE_TYPE {
+    D3DSHADER_ADDRMODE_ABSOLUTE = 0<<13,
+    D3DSHADER_ADDRMODE_RELATIVE = 1<<13
+} D3DSHADER_ADDRESSMODE_TYPE;
+
+typedef enum _D3DSHADER_COMPARISON {
+    D3DSPC_RESERVED0 = 0,
+    D3DSPC_GT = 1,
+    D3DSPC_EQ = 2,
+    D3DSPC_GE = 3,
+    D3DSPC_LT = 4,
+    D3DSPC_NE = 5,
+    D3DSPC_LE = 6,
+    D3DSPC_RESERVED1 = 7
+} D3DSHADER_COMPARISON;
+
+#define D3DDP_MAXTEXCOORD   8
+
+#define D3DSI_OPCODE_MASK       0x0000FFFF
+#define D3DSI_INSTLENGTH_MASK   0x0F000000
+#define D3DSI_INSTLENGTH_SHIFT  24
+
+typedef enum _D3DSHADER_INSTRUCTION_OPCODE_TYPE {
+    D3DSIO_NOP = 0,
+    D3DSIO_MOV = 1,
+    D3DSIO_ADD = 2,
+    D3DSIO_SUB = 3,
+    D3DSIO_MAD = 4,
+    D3DSIO_MUL = 5,
+    D3DSIO_RCP = 6,
+    D3DSIO_RSQ = 7,
+    D3DSIO_DP3 = 8,
+    D3DSIO_DP4 = 9,
+    D3DSIO_MIN = 10,
+    D3DSIO_MAX = 11,
+    D3DSIO_SLT = 12,
+    D3DSIO_SGE = 13,
+    D3DSIO_EXP = 14,
+    D3DSIO_LOG = 15,
+    D3DSIO_LIT = 16,
+    D3DSIO_DST = 17,
+    D3DSIO_LRP = 18,
+    D3DSIO_FRC = 19,
+    D3DSIO_M4x4 = 20,
+    D3DSIO_M4x3 = 21,
+    D3DSIO_M3x4 = 22,
+    D3DSIO_M3x3 = 23,
+    D3DSIO_M3x2 = 24,
+    D3DSIO_CALL = 25,
+    D3DSIO_CALLNZ = 26,
+    D3DSIO_LOOP = 27,
+    D3DSIO_RET = 28,
+    D3DSIO_ENDLOOP = 29,
+    D3DSIO_LABEL = 30,
+    D3DSIO_DCL = 31,
+    D3DSIO_POW = 32,
+    D3DSIO_CRS = 33,
+    D3DSIO_SGN = 34,
+    D3DSIO_ABS = 35,
+    D3DSIO_NRM = 36,
+    D3DSIO_SINCOS = 37,
+    D3DSIO_REP = 38,
+    D3DSIO_ENDREP = 39,
+    D3DSIO_IF = 40,
+    D3DSIO_IFC = 41,
+    D3DSIO_ELSE = 42,
+    D3DSIO_ENDIF = 43,
+    D3DSIO_BREAK = 44,
+    D3DSIO_BREAKC = 45,
+    D3DSIO_MOVA = 46,
+    D3DSIO_DEFB = 47,
+    D3DSIO_DEFI = 48,
+    D3DSIO_TEXCOORD = 64,
+    D3DSIO_TEXKILL = 65,
+    D3DSIO_TEX = 66,
+    D3DSIO_TEXBEM = 67,
+    D3DSIO_TEXBEML = 68,
+    D3DSIO_TEXREG2AR = 69,
+    D3DSIO_TEXREG2GB = 70,
+    D3DSIO_TEXM3x2PAD = 71,
+    D3DSIO_TEXM3x2TEX = 72,
+    D3DSIO_TEXM3x3PAD = 73,
+    D3DSIO_TEXM3x3TEX = 74,
+    D3DSIO_RESERVED0 = 75,
+    D3DSIO_TEXM3x3SPEC = 76,
+    D3DSIO_TEXM3x3VSPEC = 77,
+    D3DSIO_EXPP = 78,
+    D3DSIO_LOGP = 79,
+    D3DSIO_CND = 80,
+    D3DSIO_DEF = 81,
+    D3DSIO_TEXREG2RGB = 82,
+    D3DSIO_TEXDP3TEX = 83,
+    D3DSIO_TEXM3x2DEPTH = 84,
+    D3DSIO_TEXDP3 = 85,
+    D3DSIO_TEXM3x3 = 86,
+    D3DSIO_TEXDEPTH = 87,
+    D3DSIO_CMP = 88,
+    D3DSIO_BEM = 89,
+    D3DSIO_DP2ADD = 90,
+    D3DSIO_DSX = 91,
+    D3DSIO_DSY = 92,
+    D3DSIO_TEXLDD = 93,
+    D3DSIO_SETP = 94,
+    D3DSIO_TEXLDL = 95,
+    D3DSIO_BREAKP = 96,
+    D3DSIO_PHASE = 0xFFFD,
+    D3DSIO_COMMENT = 0xFFFE,
+    D3DSIO_END = 0xFFFF
+} D3DSHADER_INSTRUCTION_OPCODE_TYPE;
+
+#define D3DSI_COISSUE 0x40000000
+
+#define D3DSP_DCL_USAGE_SHIFT 0
+#define D3DSP_DCL_USAGE_MASK  0x0000000f
+
+#define D3DSP_DCL_USAGEINDEX_SHIFT 16
+#define D3DSP_DCL_USAGEINDEX_MASK  0x000f0000
+
+#define D3DSP_TEXTURETYPE_SHIFT 27
+#define D3DSP_TEXTURETYPE_MASK  0x78000000
+
+#define D3DSP_REGNUM_MASK       0x000007FF
+
+#define D3DSP_WRITEMASK_0       0x00010000
+#define D3DSP_WRITEMASK_1       0x00020000
+#define D3DSP_WRITEMASK_2       0x00040000
+#define D3DSP_WRITEMASK_3       0x00080000
+#define D3DSP_WRITEMASK_ALL     0x000F0000
+
+#define D3DSP_DSTMOD_SHIFT      20
+#define D3DSP_DSTMOD_MASK       (0xF << D3DSP_DSTMOD_SHIFT)
+
+typedef enum _D3DSHADER_PARAM_DSTMOD_TYPE {
+    D3DSPDM_NONE             = 0 << D3DSP_DSTMOD_SHIFT,
+    D3DSPDM_SATURATE         = 1 << D3DSP_DSTMOD_SHIFT,
+    D3DSPDM_PARTIALPRECISION = 2 << D3DSP_DSTMOD_SHIFT,
+    D3DSPDM_MSAMPCENTROID    = 4 << D3DSP_DSTMOD_SHIFT,
+    D3DSPDM_FORCE_DWORD  = 0x7FFFFFFF
+} D3DSHADER_PARAM_DSTMOD_TYPE;
+
+#define D3DSP_DSTSHIFT_SHIFT     24
+#define D3DSP_DSTSHIFT_MASK      (0xF << D3DSP_DSTSHIFT_SHIFT)
+
+#define D3DSP_REGTYPE_SHIFT      28
+#define D3DSP_REGTYPE_SHIFT2     8
+#define D3DSP_REGTYPE_MASK       (0x7 << D3DSP_REGTYPE_SHIFT)
+#define D3DSP_REGTYPE_MASK2      0x00001800
+
+typedef enum _D3DSHADER_MISCTYPE_OFFSETS {
+    D3DSMO_POSITION = 0,
+    D3DSMO_FACE = 1
+} D3DSHADER_MISCTYPE_OFFSETS;
+
+typedef enum _D3DSHADER_PARAM_REGISTER_TYPE {
+    D3DSPR_TEMP = 0,
+    D3DSPR_INPUT = 1,
+    D3DSPR_CONST = 2,
+    D3DSPR_ADDR = 3,
+    D3DSPR_TEXTURE = 3,
+    D3DSPR_RASTOUT = 4,
+    D3DSPR_ATTROUT = 5,
+    D3DSPR_TEXCRDOUT = 6,
+    D3DSPR_OUTPUT = 6,
+    D3DSPR_CONSTINT = 7,
+    D3DSPR_COLOROUT = 8,
+    D3DSPR_DEPTHOUT = 9,
+    D3DSPR_SAMPLER = 10,
+    D3DSPR_CONST2 = 11,
+    D3DSPR_CONST3 = 12,
+    D3DSPR_CONST4 = 13,
+    D3DSPR_CONSTBOOL = 14,
+    D3DSPR_LOOP = 15,
+    D3DSPR_TEMPFLOAT16 = 16,
+    D3DSPR_MISCTYPE = 17,
+    D3DSPR_LABEL = 18,
+    D3DSPR_PREDICATE = 19
+} D3DSHADER_PARAM_REGISTER_TYPE;
+
+#define D3DSP_SWIZZLE_SHIFT      16
+#define D3DSP_SWIZZLE_MASK       (0xFF << D3DSP_SWIZZLE_SHIFT)
+
+#define D3DSP_NOSWIZZLE \
+    ((0 << (D3DSP_SWIZZLE_SHIFT + 0)) | (1 << (D3DSP_SWIZZLE_SHIFT + 2)) | (2 << (D3DSP_SWIZZLE_SHIFT + 4)) | (3 << (D3DSP_SWIZZLE_SHIFT + 6)))
+
+#define D3DSP_SRCMOD_SHIFT      24
+#define D3DSP_SRCMOD_MASK       (0xF << D3DSP_SRCMOD_SHIFT)
+
+typedef enum _D3DSHADER_PARAM_SRCMOD_TYPE {
+    D3DSPSM_NONE = 0<<24,
+    D3DSPSM_NEG = 1<<24,
+    D3DSPSM_BIAS = 2<<24,
+    D3DSPSM_BIASNEG = 3<<24,
+    D3DSPSM_SIGN = 4<<24,
+    D3DSPSM_SIGNNEG = 5<<24,
+    D3DSPSM_COMP = 6<<24,
+    D3DSPSM_X2 = 7<<24,
+    D3DSPSM_X2NEG = 8<<24,
+    D3DSPSM_DZ = 9<<24,
+    D3DSPSM_DW = 10<<24,
+    D3DSPSM_ABS = 11<<24,
+    D3DSPSM_ABSNEG = 12<<24,
+    D3DSPSM_NOT = 13<<24
+} D3DSHADER_PARAM_SRCMOD_TYPE;
+
+#define D3DPS_VERSION(major, minor) (0xFFFF0000 | ((major) << 8) | (minor))
+#define D3DVS_VERSION(major, minor) (0xFFFE0000 | ((major) << 8) | (minor))
+#define D3DSHADER_VERSION_MAJOR(version) (((version) >> 8) & 0xFF)
+#define D3DSHADER_VERSION_MINOR(version) (((version) >> 0) & 0xFF)
+
+#define D3DSI_COMMENTSIZE_SHIFT 16
+#define D3DSI_COMMENTSIZE_MASK (0x7FFF << D3DSI_COMMENTSIZE_SHIFT)
+
+typedef enum _D3DSTATEBLOCKTYPE {
+    D3DSBT_ALL = 1,
+    D3DSBT_PIXELSTATE = 2,
+    D3DSBT_VERTEXSTATE = 3
+} D3DSTATEBLOCKTYPE;
+
+typedef enum _D3DSTENCILOP {
+    D3DSTENCILOP_KEEP = 1,
+    D3DSTENCILOP_ZERO = 2,
+    D3DSTENCILOP_REPLACE = 3,
+    D3DSTENCILOP_INCRSAT = 4,
+    D3DSTENCILOP_DECRSAT = 5,
+    D3DSTENCILOP_INVERT = 6,
+    D3DSTENCILOP_INCR = 7,
+    D3DSTENCILOP_DECR = 8
+} D3DSTENCILOP;
+
+typedef enum _D3DSWAPEFFECT {
+    D3DSWAPEFFECT_DISCARD = 1,
+    D3DSWAPEFFECT_FLIP = 2,
+    D3DSWAPEFFECT_COPY = 3,
+    D3DSWAPEFFECT_OVERLAY = 4,
+    D3DSWAPEFFECT_FLIPEX = 5
+} D3DSWAPEFFECT;
+
+typedef enum _D3DTEXTUREADDRESS {
+    D3DTADDRESS_WRAP = 1,
+    D3DTADDRESS_MIRROR = 2,
+    D3DTADDRESS_CLAMP = 3,
+    D3DTADDRESS_BORDER = 4,
+    D3DTADDRESS_MIRRORONCE = 5
+} D3DTEXTUREADDRESS;
+
+typedef enum _D3DTEXTUREFILTERTYPE {
+    D3DTEXF_NONE = 0,
+    D3DTEXF_POINT = 1,
+    D3DTEXF_LINEAR = 2,
+    D3DTEXF_ANISOTROPIC = 3,
+    D3DTEXF_PYRAMIDALQUAD = 6,
+    D3DTEXF_GAUSSIANQUAD = 7,
+    D3DTEXF_CONVOLUTIONMONO = 8
+} D3DTEXTUREFILTERTYPE;
+
+typedef enum _D3DTEXTUREOP {
+    D3DTOP_DISABLE = 1,
+    D3DTOP_SELECTARG1 = 2,
+    D3DTOP_SELECTARG2 = 3,
+    D3DTOP_MODULATE = 4,
+    D3DTOP_MODULATE2X = 5,
+    D3DTOP_MODULATE4X = 6,
+    D3DTOP_ADD = 7,
+    D3DTOP_ADDSIGNED = 8,
+    D3DTOP_ADDSIGNED2X = 9,
+    D3DTOP_SUBTRACT = 10,
+    D3DTOP_ADDSMOOTH = 11,
+    D3DTOP_BLENDDIFFUSEALPHA = 12,
+    D3DTOP_BLENDTEXTUREALPHA = 13,
+    D3DTOP_BLENDFACTORALPHA = 14,
+    D3DTOP_BLENDTEXTUREALPHAPM = 15,
+    D3DTOP_BLENDCURRENTALPHA = 16,
+    D3DTOP_PREMODULATE = 17,
+    D3DTOP_MODULATEALPHA_ADDCOLOR = 18,
+    D3DTOP_MODULATECOLOR_ADDALPHA = 19,
+    D3DTOP_MODULATEINVALPHA_ADDCOLOR = 20,
+    D3DTOP_MODULATEINVCOLOR_ADDALPHA = 21,
+    D3DTOP_BUMPENVMAP = 22,
+    D3DTOP_BUMPENVMAPLUMINANCE = 23,
+    D3DTOP_DOTPRODUCT3 = 24,
+    D3DTOP_MULTIPLYADD = 25,
+    D3DTOP_LERP = 26
+} D3DTEXTUREOP;
+
+typedef enum _D3DTEXTURESTAGESTATETYPE {
+    D3DTSS_COLOROP = 1,
+    D3DTSS_COLORARG1 = 2,
+    D3DTSS_COLORARG2 = 3,
+    D3DTSS_ALPHAOP = 4,
+    D3DTSS_ALPHAARG1 = 5,
+    D3DTSS_ALPHAARG2 = 6,
+    D3DTSS_BUMPENVMAT00 = 7,
+    D3DTSS_BUMPENVMAT01 = 8,
+    D3DTSS_BUMPENVMAT10 = 9,
+    D3DTSS_BUMPENVMAT11 = 10,
+    D3DTSS_TEXCOORDINDEX = 11,
+    D3DTSS_BUMPENVLSCALE = 22,
+    D3DTSS_BUMPENVLOFFSET = 23,
+    D3DTSS_TEXTURETRANSFORMFLAGS = 24,
+    D3DTSS_COLORARG0 = 26,
+    D3DTSS_ALPHAARG0 = 27,
+    D3DTSS_RESULTARG = 28,
+    D3DTSS_CONSTANT = 32
+} D3DTEXTURESTAGESTATETYPE;
+
+/* MSDN has this in d3d9caps.h, but it should be here */
+#define D3DTSS_TCI_PASSTHRU                       0x00000
+#define D3DTSS_TCI_CAMERASPACENORMAL              0x10000
+#define D3DTSS_TCI_CAMERASPACEPOSITION            0x20000
+#define D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR    0x30000
+#define D3DTSS_TCI_SPHEREMAP                      0x40000
+
+typedef enum _D3DTEXTURETRANSFORMFLAGS {
+    D3DTTFF_DISABLE = 0,
+    D3DTTFF_COUNT1 = 1,
+    D3DTTFF_COUNT2 = 2,
+    D3DTTFF_COUNT3 = 3,
+    D3DTTFF_COUNT4 = 4,
+    D3DTTFF_PROJECTED = 256
+} D3DTEXTURETRANSFORMFLAGS;
+
+typedef enum _D3DTRANSFORMSTATETYPE {
+    D3DTS_VIEW = 2,
+    D3DTS_PROJECTION = 3,
+    D3DTS_TEXTURE0 = 16,
+    D3DTS_TEXTURE1 = 17,
+    D3DTS_TEXTURE2 = 18,
+    D3DTS_TEXTURE3 = 19,
+    D3DTS_TEXTURE4 = 20,
+    D3DTS_TEXTURE5 = 21,
+    D3DTS_TEXTURE6 = 22,
+    D3DTS_TEXTURE7 = 23
+} D3DTRANSFORMSTATETYPE;
+
+#define D3DDMAPSAMPLER 256
+#define D3DVERTEXTEXTURESAMPLER0 (D3DDMAPSAMPLER+1)
+#define D3DVERTEXTEXTURESAMPLER1 (D3DDMAPSAMPLER+2)
+#define D3DVERTEXTEXTURESAMPLER2 (D3DDMAPSAMPLER+3)
+#define D3DVERTEXTEXTURESAMPLER3 (D3DDMAPSAMPLER+4)
+
+#define D3DTS_WORLD  D3DTS_WORLDMATRIX(0)
+#define D3DTS_WORLD1 D3DTS_WORLDMATRIX(1)
+#define D3DTS_WORLD2 D3DTS_WORLDMATRIX(2)
+#define D3DTS_WORLD3 D3DTS_WORLDMATRIX(3)
+#define D3DTS_WORLDMATRIX(index) (D3DTRANSFORMSTATETYPE)(index + 256)
+
+typedef enum _D3DVERTEXBLENDFLAGS {
+    D3DVBF_DISABLE = 0,
+    D3DVBF_1WEIGHTS = 1,
+    D3DVBF_2WEIGHTS = 2,
+    D3DVBF_3WEIGHTS = 3,
+    D3DVBF_TWEENING = 255,
+    D3DVBF_0WEIGHTS = 256
+} D3DVERTEXBLENDFLAGS;
+
+typedef enum _D3DVS_ADDRESSMODE_TYPE {
+    D3DVS_ADDRMODE_ABSOLUTE = 0<<13,
+    D3DVS_ADDRMODE_RELATIVE = 1<<13
+} D3DVS_ADDRESSMODE_TYPE;
+
+typedef enum _D3DVS_RASTOUT_OFFSETS {
+    D3DSRO_POSITION = 0,
+    D3DSRO_FOG = 1,
+    D3DSRO_POINT_SIZE = 2
+} D3DVS_RASTOUT_OFFSETS;
+
+typedef enum _D3DZBUFFERTYPE {
+    D3DZB_FALSE = 0,
+    D3DZB_TRUE = 1,
+    D3DZB_USEW = 2
+} D3DZBUFFERTYPE;
+
+/*****************************************************************************
+ * Structs                                                                   *
+ *****************************************************************************/
+typedef struct D3DDISPLAYMODEEX {
+    UINT Size;
+    UINT Width;
+    UINT Height;
+    UINT RefreshRate;
+    D3DFORMAT Format;
+    D3DSCANLINEORDERING ScanLineOrdering;
+} D3DDISPLAYMODEEX, *PD3DDISPLAYMODEEX, *LPD3DDISPLAYMODEEX;
+
+typedef struct D3DDISPLAYMODEFILTER {
+    UINT Size;
+    D3DFORMAT Format;
+    D3DSCANLINEORDERING ScanLineOrdering;
+} D3DDISPLAYMODEFILTER, *PD3DDISPLAYMODEFILTER, *LPD3DDISPLAYMODEFILTER;
+
+typedef struct _D3D_OMAC {
+    BYTE Omac[16];
+} D3D_OMAC, *PD3D_OMAC, *LPD3D_OMAC;
+
+typedef struct _D3DADAPTER_IDENTIFIER9 {
+    char Driver[512];
+    char Description[512];
+    char DeviceName[32];
+    DWORD DriverVersionLowPart;
+    DWORD DriverVersionHighPart;
+    DWORD VendorId;
+    DWORD DeviceId;
+    DWORD SubSysId;
+    DWORD Revision;
+    GUID DeviceIdentifier;
+    DWORD WHQLLevel;
+} D3DADAPTER_IDENTIFIER9, *PD3DADAPTER_IDENTIFIER9, *LPD3DADAPTER_IDENTIFIER9;
+
+typedef struct _D3DAES_CTR_IV {
+    UINT64 IV;
+    UINT64 Count;
+} D3DAES_CTR_IV, *PD3DAES_CTR_IV, *LPD3DAES_CTR_IV;
+
+typedef struct _D3DAUTHENTICATEDCHANNEL_CONFIGURE_INPUT {
+    D3D_OMAC omac;
+    GUID ConfigureType;
+    HANDLE hChannel;
+    UINT SequenceNumber;
+} D3DAUTHENTICATEDCHANNEL_CONFIGURE_INPUT, *PD3DAUTHENTICATEDCHANNEL_CONFIGURE_INPUT, *LPD3DAUTHENTICATEDCHANNEL_CONFIGURE_INPUT;
+
+typedef struct _D3DAUTHENTICATEDCHANNEL_CONFIGURECRYPTOSESSION {
+    D3DAUTHENTICATEDCHANNEL_CONFIGURE_INPUT Parameters;
+    HANDLE DXVA2DecodeHandle;
+    HANDLE CryptoSessionHandle;
+    HANDLE DeviceHandle;
+} D3DAUTHENTICATEDCHANNEL_CONFIGURECRYPTOSESSION, *PD3DAUTHENTICATEDCHANNEL_CONFIGURECRYPTOSESSION, *LPD3DAUTHENTICATEDCHANNEL_CONFIGURECRYPTOSESSION;
+
+typedef struct _D3DAUTHENTICATEDCHANNEL_CONFIGUREINITIALIZE {
+    D3DAUTHENTICATEDCHANNEL_CONFIGURE_INPUT Parameters;
+    UINT StartSequenceQuery;
+    UINT StartSequenceConfigure;
+} D3DAUTHENTICATEDCHANNEL_CONFIGUREINITIALIZE, *PD3DAUTHENTICATEDCHANNEL_CONFIGUREINITIALIZE, *LPD3DAUTHENTICATEDCHANNEL_CONFIGUREINITIALIZE;
+
+typedef struct _D3DAUTHENTICATEDCHANNEL_PROTECTION_FLAGS {
+    union {
+        struct {
+            UINT ProtectionEnabled : 1;
+            UINT OverlayOrFullscreenRequired : 1;
+            UINT Reserved : 30;
+        };
+        UINT Value;
+    };
+} D3DAUTHENTICATEDCHANNEL_PROTECTION_FLAGS, *PD3DAUTHENTICATEDCHANNEL_PROTECTION_FLAGS, *LPD3DAUTHENTICATEDCHANNEL_PROTECTION_FLAGS;
+
+typedef struct _D3DAUTHENTICATEDCHANNEL_CONFIGUREPROTECTION {
+    D3DAUTHENTICATEDCHANNEL_CONFIGURE_INPUT Parameters;
+    D3DAUTHENTICATEDCHANNEL_PROTECTION_FLAGS Protections;
+} D3DAUTHENTICATEDCHANNEL_CONFIGUREPROTECTION, *PD3DAUTHENTICATEDCHANNEL_CONFIGUREPROTECTION, *LPD3DAUTHENTICATEDCHANNEL_CONFIGUREPROTECTION;
+
+typedef struct _D3DAUTHENTICATEDCHANNEL_CONFIGURESHAREDRESOURCE {
+    D3DAUTHENTICATEDCHANNEL_CONFIGURE_INPUT Parameters;
+    D3DAUTHENTICATEDCHANNEL_PROCESSIDENTIFIERTYPE ProcessIdentiferType;
+    HANDLE ProcessHandle;
+    BOOL AllowAccess;
+} D3DAUTHENTICATEDCHANNEL_CONFIGURESHAREDRESOURCE, *PD3DAUTHENTICATEDCHANNEL_CONFIGURESHAREDRESOURCE, *LPD3DAUTHENTICATEDCHANNEL_CONFIGURESHAREDRESOURCE;
+
+typedef struct _D3DAUTHENTICATEDCHANNEL_CONFIGUREUNCOMPRESSEDENCRYPTION {
+    D3DAUTHENTICATEDCHANNEL_CONFIGURE_INPUT Parameters;
+    GUID EncryptionGuid;
+} D3DAUTHENTICATEDCHANNEL_CONFIGUREUNCOMPRESSEDENCRYPTION, *PD3DAUTHENTICATEDCHANNEL_CONFIGUREUNCOMPRESSEDENCRYPTION, *LPD3DAUTHENTICATEDCHANNEL_CONFIGUREUNCOMPRESSEDENCRYPTION;
+
+typedef struct _D3DAUTHENTICATEDCHANNEL_CONFIGURE_OUTPUT {
+    D3D_OMAC omac;
+    GUID ConfigureType;
+    HANDLE hChannel;
+    UINT SequenceNumber;
+    HRESULT ReturnCode;
+} D3DAUTHENTICATEDCHANNEL_CONFIGURE_OUTPUT, *PD3DAUTHENTICATEDCHANNEL_CONFIGURE_OUTPUT, *LPD3DAUTHENTICATEDCHANNEL_CONFIGURE_OUTPUT;
+
+typedef struct _D3DAUTHENTICATEDCHANNEL_QUERY_INPUT {
+    GUID QueryType;
+    HANDLE hChannel;
+    UINT SequenceNumber;
+} D3DAUTHENTICATEDCHANNEL_QUERY_INPUT, *PD3DAUTHENTICATEDCHANNEL_QUERY_INPUT, *LPD3DAUTHENTICATEDCHANNEL_QUERY_INPUT;
+
+typedef struct _D3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT {
+    D3D_OMAC omac;
+    GUID QueryType;
+    HANDLE hChannel;
+    UINT SequenceNumber;
+    HRESULT ReturnCode;
+} D3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT, *PD3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT, *LPD3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT;
+
+typedef struct _D3DAUTHENTICATEDCHANNEL_QUERYCHANNELTYPE_OUTPUT {
+    D3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT Output;
+    D3DAUTHENTICATEDCHANNELTYPE ChannelType;
+} D3DAUTHENTICATEDCHANNEL_QUERYCHANNELTYPE_OUTPUT, *PD3DAUTHENTICATEDCHANNEL_QUERYCHANNELTYPE_OUTPUT, *LPD3DAUTHENTICATEDCHANNEL_QUERYCHANNELTYPE_OUTPUT;
+
+typedef struct _D3DAUTHENTICATEDCHANNEL_QUERYCRYPTOSESSION_INPUT {
+    D3DAUTHENTICATEDCHANNEL_QUERY_INPUT Input;
+    HANDLE DXVA2DecodeHandle;
+} D3DAUTHENTICATEDCHANNEL_QUERYCRYPTOSESSION_INPUT, *PD3DAUTHENTICATEDCHANNEL_QUERYCRYPTOSESSION_INPUT, *LPD3DAUTHENTICATEDCHANNEL_QUERYCRYPTOSESSION_INPUT;
+
+typedef struct _D3DAUTHENTICATEDCHANNEL_QUERYCRYPTOSESSION_OUTPUT {
+    D3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT Output;
+    HANDLE DXVA2DecodeHandle;
+    HANDLE CryptoSessionHandle;
+    HANDLE DeviceHandle;
+} D3DAUTHENTICATEDCHANNEL_QUERYCRYPTOSESSION_OUTPUT, *PD3DAUTHENTICATEDCHANNEL_QUERYCRYPTOSESSION_OUTPUT, *LPD3DAUTHENTICATEDCHANNEL_QUERYCRYPTOSESSION_OUTPUT;
+
+typedef struct _D3DAUTHENTICATEDCHANNEL_QUERYDEVICEHANDLE_OUTPUT {
+    D3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT Output;
+    HANDLE DeviceHandle;
+} D3DAUTHENTICATEDCHANNEL_QUERYDEVICEHANDLE_OUTPUT, *PD3DAUTHENTICATEDCHANNEL_QUERYDEVICEHANDLE_OUTPUT, *LPD3DAUTHENTICATEDCHANNEL_QUERYDEVICEHANDLE_OUTPUT;
+
+typedef struct _D3DAUTHENTICATEDCHANNEL_QUERYEVICTIONENCRYPTIONGUIDCOUNT_OUTPUT {
+    D3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT Output;
+    UINT NumEncryptionGuids;
+} D3DAUTHENTICATEDCHANNEL_QUERYEVICTIONENCRYPTIONGUIDCOUNT_OUTPUT, *PD3DAUTHENTICATEDCHANNEL_QUERYEVICTIONENCRYPTIONGUIDCOUNT_OUTPUT, *LPD3DAUTHENTICATEDCHANNEL_QUERYEVICTIONENCRYPTIONGUIDCOUNT_OUTPUT;
+
+typedef struct _D3DAUTHENTICATEDCHANNEL_QUERYEVICTIONENCRYPTIONGUID_INPUT {
+    D3DAUTHENTICATEDCHANNEL_QUERY_INPUT Input;
+    UINT EncryptionGuidIndex;
+} D3DAUTHENTICATEDCHANNEL_QUERYEVICTIONENCRYPTIONGUID_INPUT, *PD3DAUTHENTICATEDCHANNEL_QUERYEVICTIONENCRYPTIONGUID_INPUT, *LPD3DAUTHENTICATEDCHANNEL_QUERYEVICTIONENCRYPTIONGUID_INPUT;
+
+typedef struct _D3DAUTHENTICATEDCHANNEL_QUERYEVICTIONENCRYPTIONGUID_OUTPUT {
+    D3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT Output;
+    UINT EncryptionGuidIndex;
+    GUID EncryptionGuid;
+} D3DAUTHENTICATEDCHANNEL_QUERYEVICTIONENCRYPTIONGUID_OUTPUT, *PD3DAUTHENTICATEDCHANNEL_QUERYEVICTIONENCRYPTIONGUID_OUTPUT, *LPD3DAUTHENTICATEDCHANNEL_QUERYEVICTIONENCRYPTIONGUID_OUTPUT;
+
+typedef struct _D3DAUTHENTICATEDCHANNEL_QUERYINFOBUSTYPE_OUTPUT {
+    D3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT Output;
+    D3DBUSTYPE BusType;
+    BOOL bAccessibleInContiguousBlocks;
+    BOOL bAccessibleInNonContiguousBlocks;
+} D3DAUTHENTICATEDCHANNEL_QUERYINFOBUSTYPE_OUTPUT, *PD3DAUTHENTICATEDCHANNEL_QUERYINFOBUSTYPE_OUTPUT, *LPD3DAUTHENTICATEDCHANNEL_QUERYINFOBUSTYPE_OUTPUT;
+
+typedef struct _D3DAUTHENTICATEDCHANNEL_QUERYOUTPUTIDCOUNT_INPUT {
+    D3DAUTHENTICATEDCHANNEL_QUERY_INPUT Input;
+    HANDLE DeviceHandle;
+    HANDLE CryptoSessionHandle;
+} D3DAUTHENTICATEDCHANNEL_QUERYOUTPUTIDCOUNT_INPUT, *PD3DAUTHENTICATEDCHANNEL_QUERYOUTPUTIDCOUNT_INPUT, *LPD3DAUTHENTICATEDCHANNEL_QUERYOUTPUTIDCOUNT_INPUT;
+
+typedef struct _D3DAUTHENTICATEDCHANNEL_QUERYOUTPUTIDCOUNT_OUTPUT {
+    D3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT Output;
+    HANDLE DeviceHandle;
+    HANDLE CryptoSessionHandle;
+    UINT NumOutputIDs;
+} D3DAUTHENTICATEDCHANNEL_QUERYOUTPUTIDCOUNT_OUTPUT, *PD3DAUTHENTICATEDCHANNEL_QUERYOUTPUTIDCOUNT_OUTPUT, *LPD3DAUTHENTICATEDCHANNEL_QUERYOUTPUTIDCOUNT_OUTPUT;
+
+typedef struct _D3DAUTHENTICATEDCHANNEL_QUERYOUTPUTID_INPUT {
+    D3DAUTHENTICATEDCHANNEL_QUERY_INPUT Input;
+    HANDLE DeviceHandle;
+    HANDLE CryptoSessionHandle;
+    UINT OutputIDIndex;
+} D3DAUTHENTICATEDCHANNEL_QUERYOUTPUTID_INPUT, *PD3DAUTHENTICATEDCHANNEL_QUERYOUTPUTID_INPUT, *LPD3DAUTHENTICATEDCHANNEL_QUERYOUTPUTID_INPUT;
+
+typedef struct _D3DAUTHENTICATEDCHANNEL_QUERYOUTPUTID_OUTPUT {
+    D3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT Output;
+    HANDLE DeviceHandle;
+    HANDLE CryptoSessionHandle;
+    UINT OutputIDIndex;
+    UINT64 OutputID;
+} D3DAUTHENTICATEDCHANNEL_QUERYOUTPUTID_OUTPUT, *PD3DAUTHENTICATEDCHANNEL_QUERYOUTPUTID_OUTPUT, *LPD3DAUTHENTICATEDCHANNEL_QUERYOUTPUTID_OUTPUT;
+
+typedef struct _D3DAUTHENTICATEDCHANNEL_QUERYPROTECTION_OUTPUT {
+    D3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT Output;
+    D3DAUTHENTICATEDCHANNEL_PROTECTION_FLAGS ProtectionFlags;
+} D3DAUTHENTICATEDCHANNEL_QUERYPROTECTION_OUTPUT, *PD3DAUTHENTICATEDCHANNEL_QUERYPROTECTION_OUTPUT, *LPD3DAUTHENTICATEDCHANNEL_QUERYPROTECTION_OUTPUT;
+
+typedef struct _D3DAUTHENTICATEDCHANNEL_QUERYRESTRICTEDSHAREDRESOURCEPROCESSCOUNT_OUTPUT {
+    D3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT Output;
+    UINT NumRestrictedSharedResourceProcesses;
+} D3DAUTHENTICATEDCHANNEL_QUERYRESTRICTEDSHAREDRESOURCEPROCESSCOUNT_OUTPUT, *PD3DAUTHENTICATEDCHANNEL_QUERYRESTRICTEDSHAREDRESOURCEPROCESSCOUNT_OUTPUT, *LPD3DAUTHENTICATEDCHANNEL_QUERYRESTRICTEDSHAREDRESOURCEPROCESSCOUNT_OUTPUT;
+
+typedef struct _D3DAUTHENTICATEDCHANNEL_QUERYRESTRICTEDSHAREDRESOURCEPROCESS_INPUT {
+    D3DAUTHENTICATEDCHANNEL_QUERY_INPUT Input;
+    UINT ProcessIndex;
+} D3DAUTHENTICATEDCHANNEL_QUERYRESTRICTEDSHAREDRESOURCEPROCESS_INPUT, *PD3DAUTHENTICATEDCHANNEL_QUERYRESTRICTEDSHAREDRESOURCEPROCESS_INPUT, *LPD3DAUTHENTICATEDCHANNEL_QUERYRESTRICTEDSHAREDRESOURCEPROCESS_INPUT;
+
+typedef struct _D3DAUTHENTICATEDCHANNEL_QUERYRESTRICTEDSHAREDRESOURCEPROCESS_OUTPUT {
+    D3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT Output;
+    UINT ProcessIndex;
+    D3DAUTHENTICATEDCHANNEL_PROCESSIDENTIFIERTYPE ProcessIdentifer;
+    HANDLE ProcessHandle;
+} D3DAUTHENTICATEDCHANNEL_QUERYRESTRICTEDSHAREDRESOURCEPROCESS_OUTPUT, *PD3DAUTHENTICATEDCHANNEL_QUERYRESTRICTEDSHAREDRESOURCEPROCESS_OUTPUT, *LPD3DAUTHENTICATEDCHANNEL_QUERYRESTRICTEDSHAREDRESOURCEPROCESS_OUTPUT;
+
+typedef struct _D3DAUTHENTICATEDCHANNEL_QUERYUNCOMPRESSEDENCRYPTIONLEVEL_OUTPUT {
+    D3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT Output;
+    GUID EncryptionGuid;
+} D3DAUTHENTICATEDCHANNEL_QUERYUNCOMPRESSEDENCRYPTIONLEVEL_OUTPUT, *PD3DAUTHENTICATEDCHANNEL_QUERYUNCOMPRESSEDENCRYPTIONLEVEL_OUTPUT, *LPD3DAUTHENTICATEDCHANNEL_QUERYUNCOMPRESSEDENCRYPTIONLEVEL_OUTPUT;
+
+typedef struct _D3DAUTHENTICATEDCHANNEL_QUERYUNRESTRICTEDPROTECTEDSHAREDRESOURCECOUNT_OUTPUT {
+    D3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT Output;
+    UINT NumUnrestrictedProtectedSharedResources;
+} D3DAUTHENTICATEDCHANNEL_QUERYUNRESTRICTEDPROTECTEDSHAREDRESOURCECOUNT_OUTPUT, *PD3DAUTHENTICATEDCHANNEL_QUERYUNRESTRICTEDPROTECTEDSHAREDRESOURCECOUNT_OUTPUT, *LPD3DAUTHENTICATEDCHANNEL_QUERYUNRESTRICTEDPROTECTEDSHAREDRESOURCECOUNT_OUTPUT;
+
+typedef struct _D3DBOX {
+    UINT Left;
+    UINT Top;
+    UINT Right;
+    UINT Bottom;
+    UINT Front;
+    UINT Back;
+} D3DBOX, *PD3DBOX, *LPD3DBOX;
+
+typedef struct _D3DCLIPSTATUS9 {
+    DWORD ClipUnion;
+    DWORD ClipIntersection;
+} D3DCLIPSTATUS9, *PD3DCLIPSTATUS9, *LPD3DCLIPSTATUS9;
+
+typedef struct _D3DCOLORVALUE {
+    float r;
+    float g;
+    float b;
+    float a;
+} D3DCOLORVALUE, *PD3DCOLORVALUE, *LPD3DCOLORVALUE;
+
+typedef struct _D3DCOMPOSERECTDESC {
+    USHORT X, Y;
+    USHORT Width, Height;
+} D3DCOMPOSERECTDESC, *PD3DCOMPOSERECTDESC, *LPD3DCOMPOSERECTDESC;
+
+typedef struct _D3DCOMPOSERECTDESTINATION {
+    USHORT SrcRectIndex;
+    USHORT Reserved;
+    SHORT X, Y;
+} D3DCOMPOSERECTDESTINATION, *PD3DCOMPOSERECTDESTINATION, *LPD3DCOMPOSERECTDESTINATION;
+
+typedef struct _D3DDEVICE_CREATION_PARAMETERS {
+    UINT AdapterOrdinal;
+    D3DDEVTYPE DeviceType;
+    HWND hFocusWindow;
+    DWORD BehaviorFlags;
+} D3DDEVICE_CREATION_PARAMETERS, *PD3DDEVICE_CREATION_PARAMETERS, *LPD3DDEVICE_CREATION_PARAMETERS;
+
+typedef struct _D3DDEVINFO_D3D9BANDWIDTHTIMINGS {
+    FLOAT MaxBandwidthUtilized;
+    FLOAT FrontEndUploadMemoryUtilizedPercent;
+    FLOAT VertexRateUtilizedPercent;
+    FLOAT TriangleSetupRateUtilizedPercent;
+    FLOAT FillRateUtilizedPercent;
+} D3DDEVINFO_D3D9BANDWIDTHTIMINGS, *PD3DDEVINFO_D3D9BANDWIDTHTIMINGS, *LPD3DDEVINFO_D3D9BANDWIDTHTIMINGS;
+
+typedef struct _D3DDEVINFO_D3D9CACHEUTILIZATION {
+    FLOAT TextureCacheHitRate;
+    FLOAT PostTransformVertexCacheHitRate;
+} D3DDEVINFO_D3D9CACHEUTILIZATION, *PD3DDEVINFO_D3D9CACHEUTILIZATION, *LPD3DDEVINFO_D3D9CACHEUTILIZATION;
+
+typedef struct _D3DDEVINFO_D3D9INTERFACETIMINGS {
+    FLOAT WaitingForGPUToUseApplicationResourceTimePercent;
+    FLOAT WaitingForGPUToAcceptMoreCommandsTimePercent;
+    FLOAT WaitingForGPUToStayWithinLatencyTimePercent;
+    FLOAT WaitingForGPUExclusiveResourceTimePercent;
+    FLOAT WaitingForGPUOtherTimePercent;
+} D3DDEVINFO_D3D9INTERFACETIMINGS, *PD3DDEVINFO_D3D9INTERFACETIMINGS, *LPD3DDEVINFO_D3D9INTERFACETIMINGS;
+
+typedef struct _D3DDEVINFO_D3D9PIPELINETIMINGS {
+    FLOAT VertexProcessingTimePercent;
+    FLOAT PixelProcessingTimePercent;
+    FLOAT OtherGPUProcessingTimePercent;
+    FLOAT GPUIdleTimePercent;
+} D3DDEVINFO_D3D9PIPELINETIMINGS, *PD3DDEVINFO_D3D9PIPELINETIMINGS, *LPD3DDEVINFO_D3D9PIPELINETIMINGS;
+
+typedef struct _D3DDEVINFO_D3D9STAGETIMINGS {
+    FLOAT MemoryProcessingPercent;
+    FLOAT ComputationProcessingPercent;
+} D3DDEVINFO_D3D9STAGETIMINGS, *PD3DDEVINFO_D3D9STAGETIMINGS, *LPD3DDEVINFO_D3D9STAGETIMINGS;
+
+typedef struct _D3DDEVINFO_D3DVERTEXSTATS {
+    DWORD NumRenderedTriangles;
+    DWORD NumExtraClippingTriangles;
+} D3DDEVINFO_D3DVERTEXSTATS, *LPD3DDEVINFO_D3DVERTEXSTATS;
+
+typedef struct _D3DRESOURCESTATS {
+    BOOL bThrashing;
+    DWORD ApproxBytesDownloaded;
+    DWORD NumEvicts;
+    DWORD NumVidCreates;
+    DWORD LastPri;
+    DWORD NumUsed;
+    DWORD NumUsedInVidMem;
+    DWORD WorkingSet;
+    DWORD WorkingSetBytes;
+    DWORD TotalManaged;
+    DWORD TotalBytes;
+} D3DRESOURCESTATS, *PD3DRESOURCESTATS, *LPD3DRESOURCESTATS;
+
+typedef struct _D3DDEVINFO_RESOURCEMANAGER {
+    D3DRESOURCESTATS stats[(D3DRTYPE_INDEXBUFFER+1)];
+} D3DDEVINFO_RESOURCEMANAGER, *LPD3DDEVINFO_RESOURCEMANAGER;
+
+typedef struct _D3DDEVINFO_VCACHE {
+    DWORD Pattern;
+    DWORD OptMethod;
+    DWORD CacheSize;
+    DWORD MagicNumber;
+} D3DDEVINFO_VCACHE, *LPD3DDEVINFO_VCACHE;
+
+typedef struct _D3DDISPLAYMODE {
+    UINT Width;
+    UINT Height;
+    UINT RefreshRate;
+    D3DFORMAT Format;
+} D3DDISPLAYMODE, *PD3DDISPLAYMODE, *LPD3DDISPLAYMODE;
+
+typedef struct _D3DENCRYPTED_BLOCK_INFO {
+    UINT NumEncryptedBytesAtBeginning;
+    UINT NumBytesInSkipPattern;
+    UINT NumBytesInEncryptPattern;
+} D3DENCRYPTED_BLOCK_INFO, *PD3DENCRYPTED_BLOCK_INFO, *LPD3DENCRYPTED_BLOCK_INFO;
+
+typedef struct _D3DGAMMARAMP {
+    WORD red [256];
+    WORD green[256];
+    WORD blue [256];
+} D3DGAMMARAMP, *PD3DGAMMARAMP, *LPD3DGAMMARAMP;
+
+typedef struct _D3DINDEXBUFFER_DESC {
+    D3DFORMAT Format;
+    D3DRESOURCETYPE Type;
+    DWORD Usage;
+    D3DPOOL Pool;
+    UINT Size;
+} D3DINDEXBUFFER_DESC, *PD3DINDEXBUFFER_DESC, *LPD3DINDEXBUFFER_DESC;
+
+typedef struct _D3DVECTOR {
+    float x;
+    float y;
+    float z;
+} D3DVECTOR, *PD3DVECTOR, *LPD3DVECTOR;
+
+typedef struct _D3DLIGHT9 {
+    D3DLIGHTTYPE Type;
+    D3DCOLORVALUE Diffuse;
+    D3DCOLORVALUE Specular;
+    D3DCOLORVALUE Ambient;
+    D3DVECTOR Position;
+    D3DVECTOR Direction;
+    float Range;
+    float Falloff;
+    float Attenuation0;
+    float Attenuation1;
+    float Attenuation2;
+    float Theta;
+    float Phi;
+} D3DLIGHT9, *PD3DLIGHT9, *LPD3DLIGHT9;
+
+typedef struct _D3DLOCKED_BOX {
+    INT RowPitch;
+    INT SlicePitch;
+    void* pBits;
+} D3DLOCKED_BOX, *PD3DLOCKED_BOX, *LPD3DLOCKED_BOX;
+
+typedef struct _D3DLOCKED_RECT {
+    INT Pitch;
+    void* pBits;
+} D3DLOCKED_RECT, *PD3DLOCKED_RECT, *LPD3DLOCKED_RECT;
+
+typedef struct _D3DMATERIAL9 {
+    D3DCOLORVALUE Diffuse;
+    D3DCOLORVALUE Ambient;
+    D3DCOLORVALUE Specular;
+    D3DCOLORVALUE Emissive;
+    float Power;
+} D3DMATERIAL9, *PD3DMATERIAL9, *LPD3DMATERIAL9;
+
+typedef struct _D3DMATRIX {
+    union {
+        struct {
+            float _11, _12, _13, _14;
+            float _21, _22, _23, _24;
+            float _31, _32, _33, _34;
+            float _41, _42, _43, _44;
+        };
+        float m[4][4];
+    };
+} D3DMATRIX, *PD3DMATRIX, *LPD3DMATRIX;
+
+typedef struct _D3DMEMORYPRESSURE {
+    UINT64 BytesEvictedFromProcess;
+    UINT64 SizeOfInefficientAllocation;
+    DWORD LevelOfEfficiency;
+} D3DMEMORYPRESSURE, *PD3DMEMORYPRESSURE, *LPD3DMEMORYPRESSURE;
+
+typedef struct _D3DPRESENTSTATS {
+    UINT PresentCount;
+    UINT PresentRefreshCount;
+    UINT SyncRefreshCount;
+    LARGE_INTEGER SyncQPCTime;
+    LARGE_INTEGER SyncGPUTime;
+} D3DPRESENTSTATS, *PD3DPRESENTSTATS, *LPD3DPRESENTSTATS;
+
+typedef struct _D3DPRESENT_PARAMETERS_ {
+    UINT BackBufferWidth;
+    UINT BackBufferHeight;
+    D3DFORMAT BackBufferFormat;
+    UINT BackBufferCount;
+    D3DMULTISAMPLE_TYPE MultiSampleType;
+    DWORD MultiSampleQuality;
+    D3DSWAPEFFECT SwapEffect;
+    HWND hDeviceWindow;
+    BOOL Windowed;
+    BOOL EnableAutoDepthStencil;
+    D3DFORMAT AutoDepthStencilFormat;
+    DWORD Flags;
+    UINT FullScreen_RefreshRateInHz;
+    UINT PresentationInterval;
+} D3DPRESENT_PARAMETERS, *PD3DPRESENT_PARAMETERS, *LPD3DPRESENT_PARAMETERS;
+
+typedef struct _D3DRANGE {
+    UINT Offset;
+    UINT Size;
+} D3DRANGE, *PD3DRANGE, *LPD3DRANGE;
+
+typedef struct _D3DRASTER_STATUS {
+    BOOL InVBlank;
+    UINT ScanLine;
+} D3DRASTER_STATUS, *PD3DRASTER_STATUS, *LPD3DRASTER_STATUS;
+
+typedef struct _D3DRECT {
+    LONG x1;
+    LONG y1;
+    LONG x2;
+    LONG y2;
+} D3DRECT, *PD3DRECT, *LPD3DRECT;
+
+typedef struct _D3DRECTPATCH_INFO {
+    UINT StartVertexOffsetWidth;
+    UINT StartVertexOffsetHeight;
+    UINT Width;
+    UINT Height;
+    UINT Stride;
+    D3DBASISTYPE Basis;
+    D3DDEGREETYPE Degree;
+} D3DRECTPATCH_INFO, *PD3DRECTPATCH_INFO, *LPD3DRECTPATCH_INFO;
+
+typedef struct _D3DSURFACE_DESC {
+    D3DFORMAT Format;
+    D3DRESOURCETYPE Type;
+    DWORD Usage;
+    D3DPOOL Pool;
+    D3DMULTISAMPLE_TYPE MultiSampleType;
+    DWORD MultiSampleQuality;
+    UINT Width;
+    UINT Height;
+} D3DSURFACE_DESC, *PD3DSURFACE_DESC, *LPD3DSURFACE_DESC;
+
+typedef struct _D3DTRIPATCH_INFO {
+    UINT StartVertexOffset;
+    UINT NumVertices;
+    D3DBASISTYPE Basis;
+    D3DDEGREETYPE Degree;
+} D3DTRIPATCH_INFO, *PD3DTRIPATCH_INFO, *LPD3DTRIPATCH_INFO;
+
+typedef struct _D3DVERTEXBUFFER_DESC {
+    D3DFORMAT Format;
+    D3DRESOURCETYPE Type;
+    DWORD Usage;
+    D3DPOOL Pool;
+    UINT Size;
+    DWORD FVF;
+} D3DVERTEXBUFFER_DESC, *PD3DVERTEXBUFFER_DESC, *LPD3DVERTEXBUFFER_DESC;
+
+typedef struct _D3DVERTEXELEMENT9 {
+    WORD Stream;
+    WORD Offset;
+    BYTE Type;
+    BYTE Method;
+    BYTE Usage;
+    BYTE UsageIndex;
+} D3DVERTEXELEMENT9, *LPD3DVERTEXELEMENT9;
+
+typedef struct _D3DVIEWPORT9 {
+    DWORD X;
+    DWORD Y;
+    DWORD Width;
+    DWORD Height;
+    float MinZ;
+    float MaxZ;
+} D3DVIEWPORT9, *PD3DVIEWPORT9, *LPD3DVIEWPORT9;
+
+typedef struct _D3DVOLUME_DESC {
+    D3DFORMAT Format;
+    D3DRESOURCETYPE Type;
+    DWORD Usage;
+    D3DPOOL Pool;
+    UINT Width;
+    UINT Height;
+    UINT Depth;
+} D3DVOLUME_DESC, *PD3DVOLUME_DESC, *LPD3DVOLUME_DESC;
+
+#ifndef _WIN32
+/* If _WIN32 isn't declared it means only internal header files are used. To
+ * avoid a conflict, IUnknown is declared here rather than in d3d9.h */
+
+typedef struct IUnknown IUnknown, *PUNKNOWN, *LPUNKNOWN;
+
+#ifdef __cplusplus
+extern "C" const GUID IID_IUnknown;
+
+struct IUnknown
+{
+       virtual HRESULT WINAPI QueryInterface(REFIID riid, void **ppvObject) = 0;
+       virtual ULONG WINAPI AddRef() = 0;
+       virtual ULONG WINAPI Release() = 0;
+};
+#else /* __cplusplus */
+extern const GUID IID_IUnknown;
+
+typedef struct IUnknownVtbl
+{
+       /* IUnknown */
+       HRESULT (WINAPI *QueryInterface)(IUnknown *This, REFIID riid, void **ppvObject);
+       ULONG (WINAPI *AddRef)(IUnknown *This);
+       ULONG (WINAPI *Release)(IUnknown *This);
+} IUnknownVtbl;
+
+struct IUnknown
+{
+       IUnknownVtbl *lpVtbl;
+};
+
+/* IUnknown macros */
+#define IUnknown_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
+#define IUnknown_AddRef(p) (p)->lpVtbl->AddRef(p)
+#define IUnknown_Release(p) (p)->lpVtbl->Release(p)
+#endif /* __cplusplus */
+#endif /* _WIN32 */
+
+#endif /* _D3D9TYPES_H_ */
diff --git a/include/d3dadapter/d3dadapter9.h b/include/d3dadapter/d3dadapter9.h
new file mode 100644 (file)
index 0000000..76ad3d4
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _D3DADAPTER9_H_
+#define _D3DADAPTER9_H_
+
+#include "present.h"
+
+#ifndef __cplusplus
+
+/* Representation of an adapter group, although since this is implemented by
+ * the driver, it knows nothing about the windowing system it's on */
+typedef struct ID3DAdapter9Vtbl
+{
+    /* IUnknown */
+    HRESULT (WINAPI *QueryInterface)(ID3DAdapter9 *This, REFIID riid, void **ppvObject);
+    ULONG (WINAPI *AddRef)(ID3DAdapter9 *This);
+    ULONG (WINAPI *Release)(ID3DAdapter9 *This);
+
+    /* ID3DAdapter9 */
+    HRESULT (WINAPI *GetAdapterIdentifier)(ID3DAdapter9 *This, DWORD Flags, D3DADAPTER_IDENTIFIER9 *pIdentifier);
+    HRESULT (WINAPI *CheckDeviceType)(ID3DAdapter9 *This, D3DDEVTYPE DevType, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, BOOL bWindowed);
+    HRESULT (WINAPI *CheckDeviceFormat)(ID3DAdapter9 *This, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, DWORD Usage, D3DRESOURCETYPE RType, D3DFORMAT CheckFormat);
+    HRESULT (WINAPI *CheckDeviceMultiSampleType)(ID3DAdapter9 *This, D3DDEVTYPE DeviceType, D3DFORMAT SurfaceFormat, BOOL Windowed, D3DMULTISAMPLE_TYPE MultiSampleType, DWORD *pQualityLevels);
+    HRESULT (WINAPI *CheckDepthStencilMatch)(ID3DAdapter9 *This, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, D3DFORMAT RenderTargetFormat, D3DFORMAT DepthStencilFormat);
+    HRESULT (WINAPI *CheckDeviceFormatConversion)(ID3DAdapter9 *This, D3DDEVTYPE DeviceType, D3DFORMAT SourceFormat, D3DFORMAT TargetFormat);
+    HRESULT (WINAPI *GetDeviceCaps)(ID3DAdapter9 *This, D3DDEVTYPE DeviceType, D3DCAPS9 *pCaps);
+    HRESULT (WINAPI *CreateDevice)(ID3DAdapter9 *This, UINT RealAdapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS *pPresentationParameters, IDirect3D9 *pD3D9, ID3DPresentGroup *pPresentationFactory, IDirect3DDevice9 **ppReturnedDeviceInterface);
+    HRESULT (WINAPI *CreateDeviceEx)(ID3DAdapter9 *This, UINT RealAdapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS *pPresentationParameters, D3DDISPLAYMODEEX *pFullscreenDisplayMode, IDirect3D9Ex *pD3D9Ex, ID3DPresentGroup *pPresentationFactory, IDirect3DDevice9Ex **ppReturnedDeviceInterface);
+} ID3DAdapter9Vtbl;
+
+struct ID3DAdapter9
+{
+    ID3DAdapter9Vtbl *lpVtbl;
+};
+
+/* IUnknown macros */
+#define ID3DAdapter9_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
+#define ID3DAdapter9_AddRef(p) (p)->lpVtbl->AddRef(p)
+#define ID3DAdapter9_Release(p) (p)->lpVtbl->Release(p)
+/* ID3DAdapter9 macros */
+#define ID3DAdapter9_GetAdapterIdentifier(p,a,b) (p)->lpVtbl->GetAdapterIdentifier(p,a,b)
+#define ID3DAdapter9_CheckDeviceType(p,a,b,c,d) (p)->lpVtbl->CheckDeviceType(p,a,b,c,d)
+#define ID3DAdapter9_CheckDeviceFormat(p,a,b,c,d,e) (p)->lpVtbl->CheckDeviceFormat(p,a,b,c,d,e)
+#define ID3DAdapter9_CheckDeviceMultiSampleType(p,a,b,c,d,e) (p)->lpVtbl->CheckDeviceMultiSampleType(p,a,b,c,d,e)
+#define ID3DAdapter9_CheckDepthStencilMatch(p,a,b,c,d) (p)->lpVtbl->CheckDepthStencilMatch(p,a,b,c,d)
+#define ID3DAdapter9_CheckDeviceFormatConversion(p,a,b,c) (p)->lpVtbl->CheckDeviceFormatConversion(p,a,b,c)
+#define ID3DAdapter9_GetDeviceCaps(p,a,b) (p)->lpVtbl->GetDeviceCaps(p,a,b)
+#define ID3DAdapter9_CreateDevice(p,a,b,c,d,e,f,g,h) (p)->lpVtbl->CreateDevice(p,a,b,c,d,e,f,g,h)
+#define ID3DAdapter9_CreateDeviceEx(p,a,b,c,d,e,f,g,h,i) (p)->lpVtbl->CreateDeviceEx(p,a,b,c,d,e,f,g,h,i)
+
+#else /* __cplusplus */
+
+struct ID3DAdapter9 : public IUnknown
+{
+    HRESULT WINAPI GetAdapterIdentifier(DWORD Flags, D3DADAPTER_IDENTIFIER9 *pIdentifier);
+    HRESULT WINAPI CheckDeviceType(D3DDEVTYPE DevType, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, BOOL bWindowed);
+    HRESULT WINAPI CheckDeviceFormat(D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, DWORD Usage, D3DRESOURCETYPE RType, D3DFORMAT CheckFormat);
+    HRESULT WINAPI CheckDeviceMultiSampleType(D3DDEVTYPE DeviceType, D3DFORMAT SurfaceFormat, BOOL Windowed, D3DMULTISAMPLE_TYPE MultiSampleType, DWORD *pQualityLevels);
+    HRESULT WINAPI CheckDepthStencilMatch(D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, D3DFORMAT RenderTargetFormat, D3DFORMAT DepthStencilFormat);
+    HRESULT WINAPI CheckDeviceFormatConversion(D3DDEVTYPE DeviceType, D3DFORMAT SourceFormat, D3DFORMAT TargetFormat);
+    HRESULT WINAPI GetDeviceCaps(D3DDEVTYPE DeviceType, D3DCAPS9 *pCaps);
+    HRESULT WINAPI CreateDevice(UINT RealAdapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS *pPresentationParameters, IDirect3D9 *pD3D9, ID3DPresentGroup *pPresentationFactory, IDirect3DDevice9 **ppReturnedDeviceInterface);
+    HRESULT WINAPI CreateDeviceEx(UINT RealAdapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS *pPresentationParameters, D3DDISPLAYMODEEX *pFullscreenDisplayMode, IDirect3D9Ex *pD3D9Ex, ID3DPresentGroup *pPresentationFactory, IDirect3DDevice9Ex **ppReturnedDeviceInterface);
+};
+
+#endif /* __cplusplus */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* acquire a const struct D3DAdapter9* structure describing the interface
+ * queried. See  */
+const void * WINAPI
+D3DAdapter9GetProc( const char *name );
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _D3DADAPTER9_H_ */
diff --git a/include/d3dadapter/drm.h b/include/d3dadapter/drm.h
new file mode 100644 (file)
index 0000000..9ec3e60
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _D3DADAPTER9_DRM_H_
+#define _D3DADAPTER9_DRM_H_
+
+#include "d3dadapter9.h"
+
+/* query driver support name */
+#define D3DADAPTER9DRM_NAME "drm"
+/* current version */
+#define D3DADAPTER9DRM_MAJOR 0
+#define D3DADAPTER9DRM_MINOR 0
+
+struct D3DAdapter9DRM
+{
+    unsigned major_version; /* ABI break */
+    unsigned minor_version; /* backwards compatible feature additions */
+
+    /* NOTE: upon passing an fd to this function, it's now owned by this
+        function. If this function fails, the fd will be closed here as well */
+    HRESULT (WINAPI *create_adapter)(int fd, ID3DAdapter9 **ppAdapter);
+};
+
+#endif /* _D3DADAPTER9_DRM_H_ */
diff --git a/include/d3dadapter/present.h b/include/d3dadapter/present.h
new file mode 100644 (file)
index 0000000..08a9729
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _D3DADAPTER_PRESENT_H_
+#define _D3DADAPTER_PRESENT_H_
+
+#include <d3d9.h>
+
+#ifndef D3DOK_WINDOW_OCCLUDED
+#define D3DOK_WINDOW_OCCLUDED MAKE_D3DSTATUS(2531)
+#endif /* D3DOK_WINDOW_OCCLUDED */
+
+#ifndef __cplusplus
+typedef struct ID3DPresent ID3DPresent;
+typedef struct ID3DPresentGroup ID3DPresentGroup;
+typedef struct ID3DAdapter9 ID3DAdapter9;
+typedef struct D3DWindowBuffer D3DWindowBuffer;
+
+/* Presentation backend for drivers to display their brilliant work */
+typedef struct ID3DPresentVtbl
+{
+    /* IUnknown */
+    HRESULT (WINAPI *QueryInterface)(ID3DPresent *This, REFIID riid, void **ppvObject);
+    ULONG (WINAPI *AddRef)(ID3DPresent *This);
+    ULONG (WINAPI *Release)(ID3DPresent *This);
+
+    /* ID3DPresent */
+    /* This function initializes the screen and window provided at creation.
+     * Hence why this should always be called as the one of first things a new
+     * swap chain does */
+    HRESULT (WINAPI *SetPresentParameters)(ID3DPresent *This, D3DPRESENT_PARAMETERS *pPresentationParameters, D3DDISPLAYMODEEX *pFullscreenDisplayMode);
+    /* Make a buffer visible to the window system via dma-buf fd.
+     * For better compatibility, it must be 32bpp and format ARGB/XRGB */
+    HRESULT (WINAPI *NewD3DWindowBufferFromDmaBuf)(ID3DPresent *This, int dmaBufFd, int width, int height, int stride, int depth, int bpp, D3DWindowBuffer **out);
+    HRESULT (WINAPI *DestroyD3DWindowBuffer)(ID3DPresent *This, D3DWindowBuffer *buffer);
+    /* After presenting a buffer to the window system, the buffer
+     * may be used as is (no copy of the content) by the window system.
+     * You must not use a non-released buffer, else the user may see undefined content. */
+    HRESULT (WINAPI *WaitBufferReleased)(ID3DPresent *This, D3DWindowBuffer *buffer);
+    HRESULT (WINAPI *FrontBufferCopy)(ID3DPresent *This, D3DWindowBuffer *buffer);
+    /* It is possible to do partial copy, but impossible to do resizing, which must
+     * be done by the client after checking the front buffer size */
+    HRESULT (WINAPI *PresentBuffer)(ID3DPresent *This, D3DWindowBuffer *buffer, HWND hWndOverride, const RECT *pSourceRect, const RECT *pDestRect, const RGNDATA *pDirtyRegion, DWORD Flags);
+    HRESULT (WINAPI *GetRasterStatus)(ID3DPresent *This, D3DRASTER_STATUS *pRasterStatus);
+    HRESULT (WINAPI *GetDisplayMode)(ID3DPresent *This, D3DDISPLAYMODEEX *pMode, D3DDISPLAYROTATION *pRotation);
+    HRESULT (WINAPI *GetPresentStats)(ID3DPresent *This, D3DPRESENTSTATS *pStats);
+    HRESULT (WINAPI *GetCursorPos)(ID3DPresent *This, POINT *pPoint);
+    HRESULT (WINAPI *SetCursorPos)(ID3DPresent *This, POINT *pPoint);
+    /* Cursor size is always 32x32. pBitmap and pHotspot can be NULL. */
+    HRESULT (WINAPI *SetCursor)(ID3DPresent *This, void *pBitmap, POINT *pHotspot, BOOL bShow);
+    HRESULT (WINAPI *SetGammaRamp)(ID3DPresent *This, const D3DGAMMARAMP *pRamp, HWND hWndOverride);
+    HRESULT (WINAPI *GetWindowInfo)(ID3DPresent *This,  HWND hWnd, int *width, int *height, int *depth);
+} ID3DPresentVtbl;
+
+struct ID3DPresent
+{
+    ID3DPresentVtbl *lpVtbl;
+};
+
+/* IUnknown macros */
+#define ID3DPresent_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
+#define ID3DPresent_AddRef(p) (p)->lpVtbl->AddRef(p)
+#define ID3DPresent_Release(p) (p)->lpVtbl->Release(p)
+/* ID3DPresent macros */
+#define ID3DPresent_GetPresentParameters(p,a) (p)->lpVtbl->GetPresentParameters(p,a)
+#define ID3DPresent_SetPresentParameters(p,a,b) (p)->lpVtbl->SetPresentParameters(p,a,b)
+#define ID3DPresent_NewD3DWindowBufferFromDmaBuf(p,a,b,c,d,e,f,g) (p)->lpVtbl->NewD3DWindowBufferFromDmaBuf(p,a,b,c,d,e,f,g)
+#define ID3DPresent_DestroyD3DWindowBuffer(p,a) (p)->lpVtbl->DestroyD3DWindowBuffer(p,a)
+#define ID3DPresent_WaitBufferReleased(p,a) (p)->lpVtbl->WaitBufferReleased(p,a)
+#define ID3DPresent_FrontBufferCopy(p,a) (p)->lpVtbl->FrontBufferCopy(p,a)
+#define ID3DPresent_PresentBuffer(p,a,b,c,d,e,f) (p)->lpVtbl->PresentBuffer(p,a,b,c,d,e,f)
+#define ID3DPresent_GetRasterStatus(p,a) (p)->lpVtbl->GetRasterStatus(p,a)
+#define ID3DPresent_GetDisplayMode(p,a,b) (p)->lpVtbl->GetDisplayMode(p,a,b)
+#define ID3DPresent_GetPresentStats(p,a) (p)->lpVtbl->GetPresentStats(p,a)
+#define ID3DPresent_GetCursorPos(p,a) (p)->lpVtbl->GetCursorPos(p,a)
+#define ID3DPresent_SetCursorPos(p,a) (p)->lpVtbl->SetCursorPos(p,a)
+#define ID3DPresent_SetCursor(p,a,b,c) (p)->lpVtbl->SetCursor(p,a,b,c)
+#define ID3DPresent_SetGammaRamp(p,a,b) (p)->lpVtbl->SetGammaRamp(p,a,b)
+#define ID3DPresent_GetWindowInfo(p,a,b,c,d) (p)->lpVtbl->GetWindowSize(p,a,b,c,d)
+
+typedef struct ID3DPresentGroupVtbl
+{
+    /* IUnknown */
+    HRESULT (WINAPI *QueryInterface)(ID3DPresentGroup *This, REFIID riid, void **ppvObject);
+    ULONG (WINAPI *AddRef)(ID3DPresentGroup *This);
+    ULONG (WINAPI *Release)(ID3DPresentGroup *This);
+
+    /* ID3DPresentGroup */
+    /* When creating a device, it's relevant for the driver to know how many
+     * implicit swap chains to create. It has to create one per monitor in a
+     * multi-monitor setup */
+    UINT (WINAPI *GetMultiheadCount)(ID3DPresentGroup *This);
+    /* returns only the implicit present interfaces */
+    HRESULT (WINAPI *GetPresent)(ID3DPresentGroup *This, UINT Index, ID3DPresent **ppPresent);
+    /* used to create additional presentation interfaces along the way */
+    HRESULT (WINAPI *CreateAdditionalPresent)(ID3DPresentGroup *This, D3DPRESENT_PARAMETERS *pPresentationParameters, ID3DPresent **ppPresent);
+    void (WINAPI *GetVersion) (ID3DPresentGroup *This, int *major, int *minor);
+} ID3DPresentGroupVtbl;
+
+struct ID3DPresentGroup
+{
+    ID3DPresentGroupVtbl *lpVtbl;
+};
+
+/* IUnknown macros */
+#define ID3DPresentGroup_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
+#define ID3DPresentGroup_AddRef(p) (p)->lpVtbl->AddRef(p)
+#define ID3DPresentGroup_Release(p) (p)->lpVtbl->Release(p)
+/* ID3DPresentGroup */
+#define ID3DPresentGroup_GetMultiheadCount(p) (p)->lpVtbl->GetMultiheadCount(p)
+#define ID3DPresentGroup_GetPresent(p,a,b) (p)->lpVtbl->GetPresent(p,a,b)
+#define ID3DPresentGroup_CreateAdditionalPresent(p,a,b) (p)->lpVtbl->CreateAdditionalPresent(p,a,b)
+#define ID3DPresentGroup_GetVersion(p,a,b) (p)->lpVtbl->GetVersion(p,a,b)
+
+#endif /* __cplusplus */
+
+#endif /* _D3DADAPTER_PRESENT_H_ */
index c9b60d62730b521c03e81c65e79fb639e7ee6bcf..81840b2081b6594cf389342dc24f4fefb217754e 100644 (file)
@@ -166,6 +166,10 @@ if HAVE_ST_XVMC
 SUBDIRS += state_trackers/xvmc targets/xvmc
 endif
 
+if HAVE_ST_NINE
+SUBDIRS += state_trackers/nine targets/d3dadapter9
+endif
+
 ##
 ## Don't forget to bundle the remaining (non autotools) state-trackers/targets
 ##
index 8a144db09c3943a5e9a5e9a663d3d49003f957ae..d8cee2b2917453fefd332e269651e950baffc161 100644 (file)
@@ -91,6 +91,34 @@ drisw_create_screen(struct drisw_loader_funcs *lf)
    return screen;
 }
 #endif // DRI_TARGET
+
+#if defined(NINE_TARGET)
+#include "sw/wrapper/wrapper_sw_winsys.h"
+#include "target-helpers/inline_debug_helper.h"
+
+extern struct pipe_screen *ninesw_create_screen(struct pipe_screen *screen);
+
+INLINE struct pipe_screen *
+ninesw_create_screen(struct pipe_screen *pscreen)
+{
+   struct sw_winsys *winsys = NULL;
+   struct pipe_screen *screen = NULL;
+
+   winsys = wrapper_sw_winsys_wrap_pipe_screen(pscreen);
+   if (winsys == NULL)
+      return NULL;
+
+   screen = sw_screen_create(winsys);
+   if (screen == NULL) {
+      winsys->destroy(winsys);
+      return NULL;
+   }
+
+   screen = debug_screen_wrap(screen);
+   return screen;
+}
+#endif // NINE_TARGET
+
 #endif // GALLIUM_SOFTPIPE
 
 
diff --git a/src/gallium/state_trackers/nine/Makefile.am b/src/gallium/state_trackers/nine/Makefile.am
new file mode 100644 (file)
index 0000000..c0c75b3
--- /dev/null
@@ -0,0 +1,13 @@
+include Makefile.sources
+include $(top_srcdir)/src/gallium/Automake.inc
+
+AM_CFLAGS = \
+       -I$(top_srcdir)/include/D3D9 \
+       $(GALLIUM_CFLAGS) \
+       $(VISIBILITY_CFLAGS)
+
+noinst_LTLIBRARIES = libninetracker.la
+
+libninetracker_la_SOURCES = $(C_SOURCES)
+
+EXTRA_DIST = README
diff --git a/src/gallium/state_trackers/nine/Makefile.sources b/src/gallium/state_trackers/nine/Makefile.sources
new file mode 100644 (file)
index 0000000..b821961
--- /dev/null
@@ -0,0 +1,71 @@
+C_SOURCES := \
+       adapter9.c \
+       adapter9.h \
+       authenticatedchannel9.c \
+       authenticatedchannel9.h \
+       basetexture9.c \
+       basetexture9.h \
+       cryptosession9.c \
+       cryptosession9.h \
+       cubetexture9.c \
+       cubetexture9.h \
+       device9.c \
+       device9.h \
+       device9ex.c \
+       device9ex.h \
+       device9video.c \
+       device9video.h \
+       guid.c \
+       guid.h \
+       indexbuffer9.c \
+       indexbuffer9.h \
+       iunknown.c \
+       iunknown.h \
+       nine_debug.c \
+       nine_debug.h \
+       nine_defines.h \
+       nine_dump.c \
+       nine_dump.h \
+       nineexoverlayextension.c \
+       nineexoverlayextension.h \
+       nine_ff.c \
+       nine_ff.h \
+       nine_helpers.c \
+       nine_helpers.h \
+       nine_lock.c \
+       nine_lock.h \
+       nine_pdata.h \
+       nine_pipe.c \
+       nine_pipe.h \
+       nine_quirk.c \
+       nine_quirk.h \
+       nine_shader.c \
+       nine_shader.h \
+       nine_state.c \
+       nine_state.h \
+       pixelshader9.c \
+       pixelshader9.h \
+       query9.c \
+       query9.h \
+       resource9.c \
+       resource9.h \
+       stateblock9.c \
+       stateblock9.h \
+       surface9.c \
+       surface9.h \
+       swapchain9.c \
+       swapchain9ex.c \
+       swapchain9ex.h \
+       swapchain9.h \
+       texture9.c \
+       texture9.h \
+       vertexbuffer9.c \
+       vertexbuffer9.h \
+       vertexdeclaration9.c \
+       vertexdeclaration9.h \
+       vertexshader9.c \
+       vertexshader9.h \
+       volume9.c \
+       volume9.h \
+       volumetexture9.c \
+       volumetexture9.h
diff --git a/src/gallium/state_trackers/nine/README b/src/gallium/state_trackers/nine/README
new file mode 100644 (file)
index 0000000..f10045c
--- /dev/null
@@ -0,0 +1,78 @@
+Quickstart Guide
+
+*** Configure and build mesa
+CFLAGS="-m32" CXXFLAGS="-m32" ./autogen.sh --prefix=/usr \
+ --with-gallium-drivers=nouveau,r600,swrast --enable-nine \
+ --with-gallium-driver-dir="`pwd`/src/gallium/targets/pipe-loader/.libs" \
+ --enable-debug --enable-texture-float --with-dri-drivers= --disable-dri \
+ --disable-opengl --disable-egl --disable-vdpau --disable-xvmc --disable-gbm \
+ --disable-gallium-llvm
+make
+
+*** Then we create some symlinks to mesa:
+ln -s "`pwd`/lib/gallium/libd3dadapter9.so.0.0.0" /usr/lib/
+ln -s "`pwd`/lib/gallium/libd3dadapter9.so.0" /usr/lib/
+ln -s "`pwd`/lib/gallium/libd3dadapter9.so" /usr/lib/
+ln -s "`pwd`/include/d3dadapter" /usr/include/
+
+*** Clone and build a patched wine
+git clone git@github.com:iXit/wine.git
+./configure
+make
+
+*** And finally we create some symlinks to our patched wine files:
+for f in d3d9.dll gdi32.dll user32.dll wineps.drv winex11.drv;
+do
+    mv /usr/lib/wine/$f.so /usr/lib/wine/$f.so.old
+    ln -s "`pwd`/dlls/`basename -s .dll $f`/$f.so" /usr/lib/wine/
+done
+
+*** Activating it within wine
+regedit
+Navigate to HKCU\Software\Wine\Direct3D
+If it's not there, create it
+Create a new DWORD value called UseNative
+Set its value to 1
+
+Every Direct3D9 program will now try using nine before wined3d
+
+If you want to selectively enable it per-exe instead, use the key:
+HKCU\Software\Wine\AppDefaults\app.exe\Direct3D\UseNative
+where app.exe is the name of your .exe file
+
+
+*** HOW IT WORKS ***
+
+Nine implements the full IDirect3DDevice9 COM interface and a custom COM
+interface called ID3DAdapter9 which is used to implement a final IDirect3D9Ex
+COM interface.
+ID3DAdapter9 is completely devoid of window system code, meaning this can be
+provided by wine, Xlib, Wayland, etc. It's inadvisible to write a non-Windows
+backend though, as we don't want to encourage linux developers to use this API.
+
+The state tracker is compiled, along with pipe-loader, into a library called
+libd3dadapter9.so. This library loads pipe_[driver].so drivers on demand and
+exports a single symbol for getting a subsystem driver. Currently only DRM is
+supported.
+This library is then linked to the library implementing the IDirect3D9[Ex]
+interface and the actual Direct3D9 entry points (Direct3DCreate9[Ex])
+
+The implementation of IDirect3D9[Ex] lies within wine and coexists with
+wined3d. It's loaded on demand and so if it's not there, it doesn't have any
+drivers or something else is wrong, d3d9.dll will automatically revert to using
+wined3d.
+Whether or not it's even tried is determined by 2 DWORD registry keys.
+> HKCU\Software\Wine\Direct3D\UseNative
+> HKCU\Software\Wine\AppDefaults\app.exe\Direct3D\UseNative
+The former is the global on-switch. The latter is per-exe.
+
+The driver search path can be set at configure time with
+--with-gallium-driver-dir and overridden at runtime with D3D9_DRIVERS_PATH.
+Debugging information can be gotten with the WINEDEBUG channels d3d9 and
+d3dadapter, and state_tracker debug information can be gotten with NINE_DEBUG.
+Help on NINE_DEBUG is shown through NINE_DEBUG=help
+
+Finally, the ID3DPresent[Group] and ID3DAdapter9 interfaces are not set in
+stone, so feel free to hack on those as well as st/nine.
+
+Happy Hacking!
diff --git a/src/gallium/state_trackers/nine/adapter9.c b/src/gallium/state_trackers/nine/adapter9.c
new file mode 100644 (file)
index 0000000..8d574de
--- /dev/null
@@ -0,0 +1,1091 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "adapter9.h"
+#include "device9ex.h"
+#include "nine_helpers.h"
+#include "nine_defines.h"
+#include "nine_pipe.h"
+#include "nine_dump.h"
+#include "util/u_math.h"
+#include "util/u_format.h"
+#include "util/u_dump.h"
+
+#include "pipe/p_screen.h"
+
+#define DBG_CHANNEL DBG_ADAPTER
+
+HRESULT
+NineAdapter9_ctor( struct NineAdapter9 *This,
+                   struct NineUnknownParams *pParams,
+                   struct d3dadapter9_context *pCTX )
+{
+    HRESULT hr = NineUnknown_ctor(&This->base, pParams);
+    if (FAILED(hr)) { return hr; }
+
+    DBG("This=%p pParams=%p pCTX=%p\n", This, pParams, pCTX);
+    nine_dump_D3DADAPTER_IDENTIFIER9(DBG_CHANNEL, &pCTX->identifier);
+
+    This->ctx = pCTX;
+    if (!This->ctx->hal->get_param(This->ctx->hal, PIPE_CAP_CLIP_HALFZ)) {
+        ERR("Driver doesn't support d3d9 coordinates\n");
+        return D3DERR_DRIVERINTERNALERROR;
+    }
+    if (This->ctx->ref &&
+        !This->ctx->ref->get_param(This->ctx->ref, PIPE_CAP_CLIP_HALFZ)) {
+        ERR("Warning: Sotware rendering driver doesn't support d3d9 coordinates\n");
+    }
+
+    return D3D_OK;
+}
+
+void
+NineAdapter9_dtor( struct NineAdapter9 *This )
+{
+    struct d3dadapter9_context *ctx = This->ctx;
+
+    DBG("This=%p\n", This);
+
+    NineUnknown_dtor(&This->base);
+
+    /* special case, call backend-specific dtor AFTER destroying this object
+     * completely. */
+    if (ctx) {
+        if (ctx->destroy) { ctx->destroy(ctx); }
+    }
+}
+
+static HRESULT
+NineAdapter9_GetScreen( struct NineAdapter9 *This,
+                        D3DDEVTYPE DevType,
+                        struct pipe_screen **ppScreen )
+{
+    const char *force_sw = getenv("D3D_ALWAYS_SOFTWARE");
+    switch (DevType) {
+        case D3DDEVTYPE_HAL:
+            if (force_sw && !strcmp(force_sw, "1") && This->ctx->ref) {
+                *ppScreen = This->ctx->ref;
+                break;
+            }
+            *ppScreen = This->ctx->hal;
+            break;
+
+        case D3DDEVTYPE_REF:
+        case D3DDEVTYPE_NULLREF:
+        case D3DDEVTYPE_SW:
+            if (force_sw && !strcmp(force_sw, "0")) {
+                *ppScreen = This->ctx->hal;
+                break;
+            }
+            *ppScreen = This->ctx->ref;
+            break;
+
+        default:
+            user_assert(!"Invalid device type", D3DERR_INVALIDCALL);
+    }
+
+    if (!*ppScreen) { return D3DERR_NOTAVAILABLE; }
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineAdapter9_GetAdapterIdentifier( struct NineAdapter9 *This,
+                                   DWORD Flags,
+                                   D3DADAPTER_IDENTIFIER9 *pIdentifier )
+{
+    DBG("This=%p Flags=%x pIdentifier=%p\n", This, Flags, pIdentifier);
+
+    /* regarding flags, MSDN has this to say:
+     *  Flags sets the WHQLLevel member of D3DADAPTER_IDENTIFIER9. Flags can be
+     *  set to either 0 or D3DENUM_WHQL_LEVEL. If D3DENUM_WHQL_LEVEL is
+     *  specified, this call can connect to the Internet to download new
+     *  Microsoft Windows Hardware Quality Labs (WHQL) certificates.
+     * so let's just ignore it. */
+    *pIdentifier = This->ctx->identifier;
+    return D3D_OK;
+}
+
+static INLINE boolean
+backbuffer_format( D3DFORMAT dfmt,
+                   D3DFORMAT bfmt,
+                   boolean win )
+{
+    if (dfmt == D3DFMT_A2R10G10B10 && win) { return FALSE; }
+
+    if ((dfmt == D3DFMT_A2R10G10B10 && bfmt == dfmt) ||
+        (dfmt == D3DFMT_X8R8G8B8 && (bfmt == dfmt ||
+                                     bfmt == D3DFMT_A8R8G8B8)) ||
+        (dfmt == D3DFMT_X1R5G5B5 && (bfmt == dfmt ||
+                                     bfmt == D3DFMT_A1R5G5B5)) ||
+        (dfmt == D3DFMT_R5G6B5 && bfmt == dfmt)) {
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+HRESULT WINAPI
+NineAdapter9_CheckDeviceType( struct NineAdapter9 *This,
+                              D3DDEVTYPE DevType,
+                              D3DFORMAT AdapterFormat,
+                              D3DFORMAT BackBufferFormat,
+                              BOOL bWindowed )
+{
+    struct pipe_screen *screen;
+    enum pipe_format dfmt, bfmt;
+    HRESULT hr;
+
+    DBG("This=%p DevType=%s AdapterFormat=%s BackBufferFormat=%s "
+        "bWindowed=%i\n", This, nine_D3DDEVTYPE_to_str(DevType),
+        d3dformat_to_string(AdapterFormat),
+        d3dformat_to_string(BackBufferFormat), bWindowed);
+
+    user_assert(backbuffer_format(AdapterFormat, BackBufferFormat, bWindowed),
+                D3DERR_NOTAVAILABLE);
+
+    hr = NineAdapter9_GetScreen(This, DevType, &screen);
+    if (FAILED(hr)) { return hr; }
+
+    dfmt = d3d9_to_pipe_format(AdapterFormat);
+    bfmt = d3d9_to_pipe_format(BackBufferFormat);
+    if (dfmt == PIPE_FORMAT_NONE || bfmt == PIPE_FORMAT_NONE) {
+        DBG("Invalid Adapter/BackBufferFormat.\n");
+        return D3DERR_NOTAVAILABLE;
+    }
+
+    if (!screen->is_format_supported(screen, dfmt, PIPE_TEXTURE_2D, 1,
+                                     PIPE_BIND_DISPLAY_TARGET |
+                                     PIPE_BIND_SHARED) ||
+        !screen->is_format_supported(screen, bfmt, PIPE_TEXTURE_2D, 1,
+                                     PIPE_BIND_DISPLAY_TARGET |
+                                     PIPE_BIND_SHARED)) {
+        DBG("Unsupported Adapter/BackBufferFormat.\n");
+        return D3DERR_NOTAVAILABLE;
+    }
+
+    return D3D_OK;
+}
+
+static INLINE boolean
+display_format( D3DFORMAT fmt,
+                boolean win )
+{
+    /* http://msdn.microsoft.com/en-us/library/bb172558(v=VS.85).aspx#BackBuffer_or_Display_Formats */
+    static const D3DFORMAT allowed[] = {
+        D3DFMT_A2R10G10B10,
+        D3DFMT_X8R8G8B8,
+        D3DFMT_X1R5G5B5,
+        D3DFMT_R5G6B5,
+    };
+    unsigned i;
+
+    if (fmt == D3DFMT_A2R10G10B10 && win) { return FALSE; }
+
+    for (i = 0; i < sizeof(allowed)/sizeof(D3DFORMAT); i++) {
+        if (fmt == allowed[i]) { return TRUE; }
+    }
+    return FALSE;
+}
+
+HRESULT WINAPI
+NineAdapter9_CheckDeviceFormat( struct NineAdapter9 *This,
+                                D3DDEVTYPE DeviceType,
+                                D3DFORMAT AdapterFormat,
+                                DWORD Usage,
+                                D3DRESOURCETYPE RType,
+                                D3DFORMAT CheckFormat )
+{
+    struct pipe_screen *screen;
+    HRESULT hr;
+    enum pipe_format pf;
+    enum pipe_texture_target target;
+    unsigned bind = 0;
+
+    /* Check adapter format. */
+
+    /* Nicer output if we only have the line at the end. */
+#if 1
+    DBG("This=%p DeviceType=%s AdapterFormat=%s\n", This,
+        nine_D3DDEVTYPE_to_str(DeviceType), d3dformat_to_string(AdapterFormat));
+#endif
+    user_assert(display_format(AdapterFormat, FALSE), D3DERR_INVALIDCALL);
+
+    hr = NineAdapter9_GetScreen(This, DeviceType, &screen);
+    if (FAILED(hr))
+        return hr;
+    pf = d3d9_to_pipe_format(AdapterFormat);
+    if (pf == PIPE_FORMAT_NONE ||
+        !screen->is_format_supported(screen, pf, PIPE_TEXTURE_2D, 0,
+                                     PIPE_BIND_DISPLAY_TARGET |
+                                     PIPE_BIND_SHARED)) {
+        DBG("AdapterFormat %s not available.\n",
+            d3dformat_to_string(AdapterFormat));
+        return D3DERR_NOTAVAILABLE;
+    }
+
+    /* Check actual format. */
+
+    switch (RType) {
+    case D3DRTYPE_SURFACE:       target = PIPE_TEXTURE_2D; break;
+    case D3DRTYPE_TEXTURE:       target = PIPE_TEXTURE_2D; break;
+    case D3DRTYPE_CUBETEXTURE:   target = PIPE_TEXTURE_CUBE; break;
+    case D3DRTYPE_VOLUME:        target = PIPE_TEXTURE_3D; break;
+    case D3DRTYPE_VOLUMETEXTURE: target = PIPE_TEXTURE_3D; break;
+    case D3DRTYPE_VERTEXBUFFER:  target = PIPE_BUFFER; break;
+    case D3DRTYPE_INDEXBUFFER:   target = PIPE_BUFFER; break;
+    default:
+        user_assert(0, D3DERR_INVALIDCALL);
+    }
+
+    bind = 0;
+    if (Usage & D3DUSAGE_RENDERTARGET) bind |= PIPE_BIND_RENDER_TARGET;
+    if (Usage & D3DUSAGE_DEPTHSTENCIL) bind |= PIPE_BIND_DEPTH_STENCIL;
+
+    /* API hack because setting RT[0] to NULL is forbidden */
+    if (CheckFormat == D3DFMT_NULL && bind == PIPE_BIND_RENDER_TARGET &&
+        (RType == D3DRTYPE_SURFACE ||
+         RType == D3DRTYPE_TEXTURE))
+        return D3D_OK;
+
+    if (Usage & D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING)
+        bind |= PIPE_BIND_BLENDABLE;
+
+    if (Usage & D3DUSAGE_DMAP) {
+        DBG("D3DUSAGE_DMAP not available\n");
+        return D3DERR_NOTAVAILABLE; /* TODO: displacement mapping */
+    }
+
+    switch (RType) {
+    case D3DRTYPE_TEXTURE:       bind |= PIPE_BIND_SAMPLER_VIEW; break;
+    case D3DRTYPE_CUBETEXTURE:   bind |= PIPE_BIND_SAMPLER_VIEW; break;
+    case D3DRTYPE_VOLUMETEXTURE: bind |= PIPE_BIND_SAMPLER_VIEW; break;
+    case D3DRTYPE_VERTEXBUFFER:  bind |= PIPE_BIND_VERTEX_BUFFER; break;
+    case D3DRTYPE_INDEXBUFFER:   bind |= PIPE_BIND_INDEX_BUFFER; break;
+    default:
+        break;
+    }
+
+
+    pf = d3d9_to_pipe_format(CheckFormat);
+    if (Usage & (D3DUSAGE_QUERY_SRGBREAD | D3DUSAGE_QUERY_SRGBWRITE))
+        pf = util_format_srgb(pf);
+
+    DBG("Format=%s/%s Usage/Bind=%x/%d RType/Target=%u/%s\n", // replace %d to %s
+        d3dformat_to_string(CheckFormat), util_format_name(pf),
+        Usage, bind, // temporary simplified for merge, FIXME
+        /* Usage, util_dump_bind_flags(bind), */
+        RType, util_dump_tex_target(target, TRUE));
+
+    if (pf == PIPE_FORMAT_NONE ||
+        !screen->is_format_supported(screen, pf, target, 0, bind)) {
+        DBG("NOT AVAILABLE\n");
+        return D3DERR_NOTAVAILABLE;
+    }
+
+    /* if (Usage & D3DUSAGE_NONSECURE) { don't know the implications of this } */
+    /* if (Usage & D3DUSAGE_SOFTWAREPROCESSING) { we can always support this } */
+
+    if ((Usage & D3DUSAGE_AUTOGENMIPMAP) && !(bind & PIPE_BIND_SAMPLER_VIEW))
+        return D3DOK_NOAUTOGEN;
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineAdapter9_CheckDeviceMultiSampleType( struct NineAdapter9 *This,
+                                         D3DDEVTYPE DeviceType,
+                                         D3DFORMAT SurfaceFormat,
+                                         BOOL Windowed,
+                                         D3DMULTISAMPLE_TYPE MultiSampleType,
+                                         DWORD *pQualityLevels )
+{
+    struct pipe_screen *screen;
+    HRESULT hr;
+    enum pipe_format pf;
+    unsigned bind;
+
+    DBG("This=%p DeviceType=%s SurfaceFormat=%s Windowed=%i MultiSampleType=%u "
+        "pQualityLevels=%p\n", This, nine_D3DDEVTYPE_to_str(DeviceType),
+        d3dformat_to_string(SurfaceFormat), Windowed, MultiSampleType,
+        pQualityLevels);
+
+    hr = NineAdapter9_GetScreen(This, DeviceType, &screen);
+    if (FAILED(hr))
+        return hr;
+
+    pf = d3d9_to_pipe_format(SurfaceFormat);
+    bind = util_format_is_depth_or_stencil(pf) ?
+        PIPE_BIND_DEPTH_STENCIL : PIPE_BIND_RENDER_TARGET;
+
+    if (pf == PIPE_FORMAT_NONE ||
+        !screen->is_format_supported(screen, pf, PIPE_TEXTURE_2D,
+                                     MultiSampleType, bind)) {
+        DBG("%s with %u samples not available.\n",
+            d3dformat_to_string(SurfaceFormat), MultiSampleType);
+        return D3DERR_NOTAVAILABLE;
+    }
+
+    if (pQualityLevels)
+        *pQualityLevels = 1; /* gallium doesn't have quality levels */
+
+    return D3D_OK;
+}
+
+static INLINE boolean
+depth_stencil_format( D3DFORMAT fmt )
+{
+    static D3DFORMAT allowed[] = {
+        D3DFMT_D16_LOCKABLE,
+        D3DFMT_D32,
+        D3DFMT_D15S1,
+        D3DFMT_D24S8,
+        D3DFMT_D24X8,
+        D3DFMT_D24X4S4,
+        D3DFMT_D16,
+        D3DFMT_D32F_LOCKABLE,
+        D3DFMT_D24FS8,
+        D3DFMT_D32_LOCKABLE
+    };
+    unsigned i;
+
+    for (i = 0; i < sizeof(allowed)/sizeof(D3DFORMAT); i++) {
+        if (fmt == allowed[i]) { return TRUE; }
+    }
+    return FALSE;
+}
+
+HRESULT WINAPI
+NineAdapter9_CheckDepthStencilMatch( struct NineAdapter9 *This,
+                                     D3DDEVTYPE DeviceType,
+                                     D3DFORMAT AdapterFormat,
+                                     D3DFORMAT RenderTargetFormat,
+                                     D3DFORMAT DepthStencilFormat )
+{
+    struct pipe_screen *screen;
+    enum pipe_format dfmt, bfmt, zsfmt;
+    HRESULT hr;
+
+    DBG("This=%p DeviceType=%s AdapterFormat=%s "
+        "RenderTargetFormat=%s DepthStencilFormat=%s\n", This,
+        nine_D3DDEVTYPE_to_str(DeviceType), d3dformat_to_string(AdapterFormat),
+        d3dformat_to_string(RenderTargetFormat),
+        d3dformat_to_string(DepthStencilFormat));
+
+    user_assert(display_format(AdapterFormat, FALSE), D3DERR_NOTAVAILABLE);
+    user_assert(depth_stencil_format(DepthStencilFormat), D3DERR_NOTAVAILABLE);
+
+    hr = NineAdapter9_GetScreen(This, DeviceType, &screen);
+    if (FAILED(hr)) { return hr; }
+
+    dfmt = d3d9_to_pipe_format(AdapterFormat);
+    bfmt = d3d9_to_pipe_format(RenderTargetFormat);
+    if (RenderTargetFormat == D3DFMT_NULL)
+        bfmt = dfmt;
+    zsfmt = d3d9_to_pipe_format(DepthStencilFormat);
+    if (dfmt == PIPE_FORMAT_NONE ||
+        bfmt == PIPE_FORMAT_NONE ||
+        zsfmt == PIPE_FORMAT_NONE) {
+        return D3DERR_NOTAVAILABLE;
+    }
+
+    if (!screen->is_format_supported(screen, dfmt, PIPE_TEXTURE_2D, 0,
+                                     PIPE_BIND_DISPLAY_TARGET |
+                                     PIPE_BIND_SHARED) ||
+        !screen->is_format_supported(screen, bfmt, PIPE_TEXTURE_2D, 0,
+                                     PIPE_BIND_RENDER_TARGET) ||
+        !screen->is_format_supported(screen, zsfmt, PIPE_TEXTURE_2D, 0,
+                                     PIPE_BIND_DEPTH_STENCIL)) {
+        return D3DERR_NOTAVAILABLE;
+    }
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineAdapter9_CheckDeviceFormatConversion( struct NineAdapter9 *This,
+                                          D3DDEVTYPE DeviceType,
+                                          D3DFORMAT SourceFormat,
+                                          D3DFORMAT TargetFormat )
+{
+    /* MSDN says this tests whether a certain backbuffer format can be used in
+     * conjunction with a certain front buffer format. It's a little confusing
+     * but some one wiser might be able to figure this one out. XXX */
+    struct pipe_screen *screen;
+    enum pipe_format dfmt, bfmt;
+    HRESULT hr;
+
+    DBG("This=%p DeviceType=%s SourceFormat=%s TargetFormat=%s\n", This,
+        nine_D3DDEVTYPE_to_str(DeviceType),
+        d3dformat_to_string(SourceFormat), d3dformat_to_string(TargetFormat));
+
+    user_assert(backbuffer_format(TargetFormat, SourceFormat, FALSE),
+                D3DERR_NOTAVAILABLE);
+
+    hr = NineAdapter9_GetScreen(This, DeviceType, &screen);
+    if (FAILED(hr)) { return hr; }
+
+    dfmt = d3d9_to_pipe_format(TargetFormat);
+    bfmt = d3d9_to_pipe_format(SourceFormat);
+    if (dfmt == PIPE_FORMAT_NONE || bfmt == PIPE_FORMAT_NONE) {
+        return D3DERR_NOTAVAILABLE;
+    }
+    if (!screen->is_format_supported(screen, dfmt, PIPE_TEXTURE_2D, 1,
+                                     PIPE_BIND_DISPLAY_TARGET |
+                                     PIPE_BIND_SHARED) ||
+        !screen->is_format_supported(screen, bfmt, PIPE_TEXTURE_2D, 1,
+                                     PIPE_BIND_DISPLAY_TARGET |
+                                     PIPE_BIND_SHARED)) {
+        DBG("%s to %s not supported.\n",
+            d3dformat_to_string(SourceFormat),
+            d3dformat_to_string(TargetFormat));
+        return D3DERR_NOTAVAILABLE;
+    }
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineAdapter9_GetDeviceCaps( struct NineAdapter9 *This,
+                            D3DDEVTYPE DeviceType,
+                            D3DCAPS9 *pCaps )
+{
+    struct pipe_screen *screen;
+    boolean sm3, vs;
+    HRESULT hr;
+
+    DBG("This=%p DeviceType=%s pCaps=%p\n", This,
+        nine_D3DDEVTYPE_to_str(DeviceType), pCaps);
+
+    user_assert(pCaps, D3DERR_INVALIDCALL);
+
+    hr = NineAdapter9_GetScreen(This, DeviceType, &screen);
+    if (FAILED(hr)) {
+       DBG("Failed to get pipe_screen.\n");
+       return hr;
+    }
+
+#define D3DPIPECAP(pcap, d3dcap) \
+    (screen->get_param(screen, PIPE_CAP_##pcap) ? (d3dcap) : 0)
+
+#define D3DNPIPECAP(pcap, d3dcap) \
+    (screen->get_param(screen, PIPE_CAP_##pcap) ? 0 : (d3dcap))
+
+    sm3 = screen->get_param(screen, PIPE_CAP_SM3);
+    vs = !!(screen->get_shader_param(screen, PIPE_SHADER_VERTEX,
+                                     PIPE_SHADER_CAP_MAX_INSTRUCTIONS));
+
+    pCaps->DeviceType = DeviceType;
+
+    pCaps->AdapterOrdinal = 0;
+
+    pCaps->Caps = 0;
+
+    pCaps->Caps2 = D3DCAPS2_CANMANAGERESOURCE |
+                /* D3DCAPS2_CANSHARERESOURCE | */
+                /* D3DCAPS2_CANCALIBRATEGAMMA | */
+                   D3DCAPS2_DYNAMICTEXTURES |
+                   D3DCAPS2_FULLSCREENGAMMA |
+                   D3DCAPS2_CANAUTOGENMIPMAP;
+
+    /* Note: D3DCAPS3_ALPHA_FULLSCREEN_FLIP_OR_DISCARD just means the
+     * backbuffer can be ARGB (instead of only XRGB) when we are fullscreen
+     * and in discard mode. */
+    pCaps->Caps3 = D3DCAPS3_ALPHA_FULLSCREEN_FLIP_OR_DISCARD |
+                   D3DCAPS3_COPY_TO_VIDMEM |
+                   D3DCAPS3_COPY_TO_SYSTEMMEM |
+                   D3DCAPS3_LINEAR_TO_SRGB_PRESENTATION;
+
+    pCaps->PresentationIntervals = D3DPRESENT_INTERVAL_DEFAULT |
+                                   D3DPRESENT_INTERVAL_ONE |
+                                   D3DPRESENT_INTERVAL_TWO |
+                                   D3DPRESENT_INTERVAL_THREE |
+                                   D3DPRESENT_INTERVAL_FOUR |
+                                   D3DPRESENT_INTERVAL_IMMEDIATE;
+    pCaps->CursorCaps = D3DCURSORCAPS_COLOR | D3DCURSORCAPS_LOWRES;
+
+    pCaps->DevCaps = D3DDEVCAPS_CANBLTSYSTONONLOCAL |
+                     D3DDEVCAPS_CANRENDERAFTERFLIP |
+                     D3DDEVCAPS_DRAWPRIMITIVES2 |
+                     D3DDEVCAPS_DRAWPRIMITIVES2EX |
+                     D3DDEVCAPS_DRAWPRIMTLVERTEX |
+                     D3DDEVCAPS_EXECUTESYSTEMMEMORY |
+                     D3DDEVCAPS_EXECUTEVIDEOMEMORY |
+                     D3DDEVCAPS_HWRASTERIZATION |
+                     D3DDEVCAPS_HWTRANSFORMANDLIGHT |
+                     /*D3DDEVCAPS_NPATCHES |*/
+                     D3DDEVCAPS_PUREDEVICE |
+                     /*D3DDEVCAPS_QUINTICRTPATCHES |*/
+                     /*D3DDEVCAPS_RTPATCHES |*/
+                     /*D3DDEVCAPS_RTPATCHHANDLEZERO |*/
+                     /*D3DDEVCAPS_SEPARATETEXTUREMEMORIES |*/
+                     /*D3DDEVCAPS_TEXTURENONLOCALVIDMEM |*/
+                     D3DDEVCAPS_TEXTURESYSTEMMEMORY |
+                     D3DDEVCAPS_TEXTUREVIDEOMEMORY |
+                     D3DDEVCAPS_TLVERTEXSYSTEMMEMORY |
+                     D3DDEVCAPS_TLVERTEXVIDEOMEMORY;
+
+    pCaps->PrimitiveMiscCaps = D3DPMISCCAPS_MASKZ |
+                               D3DPMISCCAPS_CULLNONE | /* XXX */
+                               D3DPMISCCAPS_CULLCW |
+                               D3DPMISCCAPS_CULLCCW |
+                               D3DPMISCCAPS_COLORWRITEENABLE |
+                               D3DPMISCCAPS_CLIPPLANESCALEDPOINTS |
+                               D3DPMISCCAPS_CLIPTLVERTS |
+                               D3DPMISCCAPS_TSSARGTEMP |
+                               D3DPMISCCAPS_BLENDOP |
+                               D3DPIPECAP(INDEP_BLEND_ENABLE, D3DPMISCCAPS_INDEPENDENTWRITEMASKS) |
+                               /*D3DPMISCCAPS_PERSTAGECONSTANT |*/
+                               /*D3DPMISCCAPS_POSTBLENDSRGBCONVERT |*/ /* TODO */
+                               D3DPMISCCAPS_FOGANDSPECULARALPHA |
+                               D3DPIPECAP(BLEND_EQUATION_SEPARATE, D3DPMISCCAPS_SEPARATEALPHABLEND) |
+                               D3DPIPECAP(MIXED_COLORBUFFER_FORMATS, D3DPMISCCAPS_MRTINDEPENDENTBITDEPTHS) |
+                               D3DPMISCCAPS_MRTPOSTPIXELSHADERBLENDING |
+                               /*D3DPMISCCAPS_FOGVERTEXCLAMPED*/0;
+
+    pCaps->RasterCaps =
+        D3DPIPECAP(ANISOTROPIC_FILTER, D3DPRASTERCAPS_ANISOTROPY) |
+        /*D3DPRASTERCAPS_COLORPERSPECTIVE |*/
+        D3DPRASTERCAPS_DITHER |
+        D3DPRASTERCAPS_DEPTHBIAS |
+        /*D3DPRASTERCAPS_FOGRANGE |*/
+        /*D3DPRASTERCAPS_FOGTABLE |*/
+        /*D3DPRASTERCAPS_FOGVERTEX |*/
+        D3DPRASTERCAPS_MIPMAPLODBIAS |
+        D3DPRASTERCAPS_MULTISAMPLE_TOGGLE |
+        D3DPRASTERCAPS_SCISSORTEST |
+        D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS |
+        /*D3DPRASTERCAPS_WBUFFER |*/
+        /*D3DPRASTERCAPS_WFOG |*/
+        /*D3DPRASTERCAPS_ZBUFFERLESSHSR |*/
+        /*D3DPRASTERCAPS_ZFOG |*/
+        D3DPRASTERCAPS_ZTEST;
+
+    pCaps->ZCmpCaps = D3DPCMPCAPS_NEVER |
+                      D3DPCMPCAPS_LESS |
+                      D3DPCMPCAPS_EQUAL |
+                      D3DPCMPCAPS_LESSEQUAL |
+                      D3DPCMPCAPS_GREATER |
+                      D3DPCMPCAPS_NOTEQUAL |
+                      D3DPCMPCAPS_GREATEREQUAL |
+                      D3DPCMPCAPS_ALWAYS;
+
+    pCaps->SrcBlendCaps = D3DPBLENDCAPS_ZERO |
+                          D3DPBLENDCAPS_ONE |
+                          D3DPBLENDCAPS_SRCCOLOR |
+                          D3DPBLENDCAPS_INVSRCCOLOR |
+                          D3DPBLENDCAPS_SRCALPHA |
+                          D3DPBLENDCAPS_INVSRCALPHA |
+                          D3DPBLENDCAPS_DESTALPHA |
+                          D3DPBLENDCAPS_INVDESTALPHA |
+                          D3DPBLENDCAPS_DESTCOLOR |
+                          D3DPBLENDCAPS_INVDESTCOLOR |
+                          D3DPBLENDCAPS_SRCALPHASAT |
+                          D3DPBLENDCAPS_BOTHSRCALPHA |
+                          D3DPBLENDCAPS_BOTHINVSRCALPHA |
+                          D3DPBLENDCAPS_BLENDFACTOR |
+                          D3DPIPECAP(MAX_DUAL_SOURCE_RENDER_TARGETS,
+                              D3DPBLENDCAPS_INVSRCCOLOR2 |
+                              D3DPBLENDCAPS_SRCCOLOR2);
+
+    pCaps->DestBlendCaps = pCaps->SrcBlendCaps;
+
+    pCaps->AlphaCmpCaps = D3DPCMPCAPS_LESS |
+                          D3DPCMPCAPS_EQUAL |
+                          D3DPCMPCAPS_LESSEQUAL |
+                          D3DPCMPCAPS_GREATER |
+                          D3DPCMPCAPS_NOTEQUAL |
+                          D3DPCMPCAPS_GREATEREQUAL |
+                          D3DPCMPCAPS_ALWAYS;
+
+    /* FLAT caps not legal for D3D9. */
+    pCaps->ShadeCaps = D3DPSHADECAPS_COLORGOURAUDRGB |
+                       D3DPSHADECAPS_SPECULARGOURAUDRGB |
+                       D3DPSHADECAPS_ALPHAGOURAUDBLEND |
+                       D3DPSHADECAPS_FOGGOURAUD;
+
+    pCaps->TextureCaps =
+        D3DPTEXTURECAPS_ALPHA |
+        D3DPTEXTURECAPS_ALPHAPALETTE |
+        D3DPTEXTURECAPS_PERSPECTIVE |
+        D3DPTEXTURECAPS_PROJECTED |
+        /*D3DPTEXTURECAPS_TEXREPEATNOTSCALEDBYSIZE |*/
+        D3DPTEXTURECAPS_CUBEMAP |
+        D3DPTEXTURECAPS_VOLUMEMAP |
+        D3DNPIPECAP(NPOT_TEXTURES, D3DPTEXTURECAPS_POW2) |
+        D3DNPIPECAP(NPOT_TEXTURES, D3DPTEXTURECAPS_NONPOW2CONDITIONAL) |
+        D3DNPIPECAP(NPOT_TEXTURES, D3DPTEXTURECAPS_CUBEMAP_POW2) |
+        D3DNPIPECAP(NPOT_TEXTURES, D3DPTEXTURECAPS_VOLUMEMAP_POW2) |
+        D3DPIPECAP(MAX_TEXTURE_2D_LEVELS, D3DPTEXTURECAPS_MIPMAP) |
+        D3DPIPECAP(MAX_TEXTURE_3D_LEVELS, D3DPTEXTURECAPS_MIPVOLUMEMAP) |
+        D3DPIPECAP(MAX_TEXTURE_CUBE_LEVELS, D3DPTEXTURECAPS_MIPCUBEMAP);
+
+    pCaps->TextureFilterCaps =
+        D3DPTFILTERCAPS_MINFPOINT |
+        D3DPTFILTERCAPS_MINFLINEAR |
+        D3DPIPECAP(ANISOTROPIC_FILTER, D3DPTFILTERCAPS_MINFANISOTROPIC) |
+        /*D3DPTFILTERCAPS_MINFPYRAMIDALQUAD |*/
+        /*D3DPTFILTERCAPS_MINFGAUSSIANQUAD |*/
+        D3DPTFILTERCAPS_MIPFPOINT |
+        D3DPTFILTERCAPS_MIPFLINEAR |
+        D3DPTFILTERCAPS_MAGFPOINT |
+        D3DPTFILTERCAPS_MAGFLINEAR |
+        D3DPIPECAP(ANISOTROPIC_FILTER, D3DPTFILTERCAPS_MAGFANISOTROPIC) |
+        /*D3DPTFILTERCAPS_MAGFPYRAMIDALQUAD |*/
+        /*D3DPTFILTERCAPS_MAGFGAUSSIANQUAD*/0;
+
+    pCaps->CubeTextureFilterCaps = pCaps->TextureFilterCaps;
+    pCaps->VolumeTextureFilterCaps = pCaps->TextureFilterCaps;
+
+    pCaps->TextureAddressCaps =
+        D3DPTADDRESSCAPS_BORDER |
+        D3DPTADDRESSCAPS_INDEPENDENTUV |
+        D3DPTADDRESSCAPS_WRAP |
+        D3DPTADDRESSCAPS_MIRROR |
+        D3DPTADDRESSCAPS_CLAMP |
+        D3DPIPECAP(TEXTURE_MIRROR_CLAMP, D3DPTADDRESSCAPS_MIRRORONCE);
+
+    pCaps->VolumeTextureAddressCaps = pCaps->TextureAddressCaps;
+
+    pCaps->LineCaps =
+        D3DLINECAPS_ALPHACMP |
+        D3DLINECAPS_BLEND |
+        D3DLINECAPS_TEXTURE |
+        D3DLINECAPS_ZTEST |
+        D3DLINECAPS_FOG;
+    if (screen->get_paramf(screen, PIPE_CAPF_MAX_LINE_WIDTH_AA) > 0.0) {
+        pCaps->LineCaps |= D3DLINECAPS_ANTIALIAS;
+    }
+
+    pCaps->MaxTextureWidth =
+        1 << (screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1);
+    pCaps->MaxTextureHeight = pCaps->MaxTextureWidth;
+    pCaps->MaxVolumeExtent =
+        1 << (screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_3D_LEVELS) - 1);
+    /* XXX values from wine */
+    pCaps->MaxTextureRepeat = 32768;
+    pCaps->MaxTextureAspectRatio = pCaps->MaxTextureWidth;
+
+    pCaps->MaxAnisotropy =
+        (DWORD)screen->get_paramf(screen, PIPE_CAPF_MAX_TEXTURE_ANISOTROPY);
+
+    pCaps->MaxVertexW = 1.0f; /* XXX */
+    pCaps->GuardBandLeft = screen->get_paramf(screen,
+                                              PIPE_CAPF_GUARD_BAND_LEFT);
+    pCaps->GuardBandTop = screen->get_paramf(screen,
+                                             PIPE_CAPF_GUARD_BAND_TOP);
+    pCaps->GuardBandRight = screen->get_paramf(screen,
+                                               PIPE_CAPF_GUARD_BAND_RIGHT);
+    pCaps->GuardBandBottom = screen->get_paramf(screen,
+                                                PIPE_CAPF_GUARD_BAND_BOTTOM);
+    pCaps->ExtentsAdjust = 0.0f;
+
+    pCaps->StencilCaps =
+        D3DSTENCILCAPS_KEEP |
+        D3DSTENCILCAPS_ZERO |
+        D3DSTENCILCAPS_REPLACE |
+        D3DSTENCILCAPS_INCRSAT |
+        D3DSTENCILCAPS_DECRSAT |
+        D3DSTENCILCAPS_INVERT |
+        D3DSTENCILCAPS_INCR |
+        D3DSTENCILCAPS_DECR |
+        D3DPIPECAP(TWO_SIDED_STENCIL, D3DSTENCILCAPS_TWOSIDED);
+
+    pCaps->FVFCaps =
+        (D3DFVFCAPS_TEXCOORDCOUNTMASK & 0xff) |
+        /*D3DFVFCAPS_DONOTSTRIPELEMENTS |*/
+        D3DFVFCAPS_PSIZE;
+
+    /* XXX: Some of these are probably not in SM2.0 so cap them when I figure
+     * them out. For now leave them all enabled. */
+    pCaps->TextureOpCaps = D3DTEXOPCAPS_DISABLE |
+                           D3DTEXOPCAPS_SELECTARG1 |
+                           D3DTEXOPCAPS_SELECTARG2 |
+                           D3DTEXOPCAPS_MODULATE |
+                           D3DTEXOPCAPS_MODULATE2X |
+                           D3DTEXOPCAPS_MODULATE4X |
+                           D3DTEXOPCAPS_ADD |
+                           D3DTEXOPCAPS_ADDSIGNED |
+                           D3DTEXOPCAPS_ADDSIGNED2X |
+                           D3DTEXOPCAPS_SUBTRACT |
+                           D3DTEXOPCAPS_ADDSMOOTH |
+                           D3DTEXOPCAPS_BLENDDIFFUSEALPHA |
+                           D3DTEXOPCAPS_BLENDTEXTUREALPHA |
+                           D3DTEXOPCAPS_BLENDFACTORALPHA |
+                           D3DTEXOPCAPS_BLENDTEXTUREALPHAPM |
+                           D3DTEXOPCAPS_BLENDCURRENTALPHA |
+                           D3DTEXOPCAPS_PREMODULATE |
+                           D3DTEXOPCAPS_MODULATEALPHA_ADDCOLOR |
+                           D3DTEXOPCAPS_MODULATECOLOR_ADDALPHA |
+                           D3DTEXOPCAPS_MODULATEINVALPHA_ADDCOLOR |
+                           D3DTEXOPCAPS_MODULATEINVCOLOR_ADDALPHA |
+                           D3DTEXOPCAPS_BUMPENVMAP |
+                           D3DTEXOPCAPS_BUMPENVMAPLUMINANCE |
+                           D3DTEXOPCAPS_DOTPRODUCT3 |
+                           D3DTEXOPCAPS_MULTIPLYADD |
+                           D3DTEXOPCAPS_LERP;
+
+    pCaps->MaxTextureBlendStages = 8; /* XXX wine */
+        (DWORD)screen->get_param(screen, PIPE_CAP_BLEND_EQUATION_SEPARATE);
+    pCaps->MaxSimultaneousTextures = screen->get_shader_param(screen,
+        PIPE_SHADER_FRAGMENT, PIPE_SHADER_CAP_MAX_TEXTURE_SAMPLERS);
+    if (pCaps->MaxSimultaneousTextures > NINE_MAX_SAMPLERS_PS)
+        pCaps->MaxSimultaneousTextures = NINE_MAX_SAMPLERS_PS;
+
+    pCaps->VertexProcessingCaps = D3DVTXPCAPS_TEXGEN |
+                                  /*D3DVTXPCAPS_TEXGEN_SPHEREMAP |*/
+                                  D3DVTXPCAPS_MATERIALSOURCE7 |
+                                  D3DVTXPCAPS_DIRECTIONALLIGHTS |
+                                  D3DVTXPCAPS_POSITIONALLIGHTS |
+                                  D3DVTXPCAPS_LOCALVIEWER |
+                                  D3DVTXPCAPS_TWEENING |
+                                  /*D3DVTXPCAPS_NO_TEXGEN_NONLOCALVIEWER*/0;
+
+    pCaps->MaxActiveLights = NINE_MAX_LIGHTS_ACTIVE; /* like GL_LIGHTi */
+    pCaps->MaxUserClipPlanes = PIPE_MAX_CLIP_PLANES;
+    pCaps->MaxVertexBlendMatrices = 4; /* 1 vec4 BLENDWEIGHT/INDICES input */
+    pCaps->MaxVertexBlendMatrixIndex = 7; /* D3DTS_WORLDMATRIX(0..7) */
+
+    pCaps->MaxPointSize = screen->get_paramf(screen, PIPE_CAPF_MAX_POINT_WIDTH);
+
+    pCaps->MaxPrimitiveCount = 0xFFFFF; /* <- wine, really 0xFFFFFFFF; */
+    pCaps->MaxVertexIndex = 0xFFFFF; /* <- wine, really 0xFFFFFFFF */
+    pCaps->MaxStreams =
+        _min(screen->get_shader_param(screen,
+                 PIPE_SHADER_VERTEX, PIPE_SHADER_CAP_MAX_INPUTS),
+             16);
+
+    pCaps->MaxStreamStride = screen->get_param(screen,
+            PIPE_CAP_MAX_VERTEX_ATTRIB_STRIDE);
+
+    pCaps->VertexShaderVersion = sm3 ? D3DVS_VERSION(3,0) : D3DVS_VERSION(2,0);
+    if (vs) {
+        /* VS 2 as well as 3.0 supports a minimum of 256 consts, no matter how
+         * much our architecture moans about it. The problem is that D3D9
+         * expects access to 16 int consts (i#), containing 3 components and
+         * 16 booleans (b#), containing only 1 component. This should be packed
+         * into 20 float vectors (16 for i# and 16/4 for b#), since gallium has
+         * removed support for the loop counter/boolean files. */
+        pCaps->MaxVertexShaderConst =
+            _min((screen->get_shader_param(screen, PIPE_SHADER_VERTEX,
+                     PIPE_SHADER_CAP_MAX_CONST_BUFFER_SIZE) /
+                     sizeof(float[4])) - 20,
+                NINE_MAX_CONST_F);
+        /* Fake the minimum cap for Windows. */
+        if (QUIRK(FAKE_CAPS)) {
+            pCaps->MaxVertexShaderConst = 256;
+        }
+    } else {
+        pCaps->MaxVertexShaderConst = 0;
+    }
+
+    pCaps->PixelShaderVersion = sm3 ? D3DPS_VERSION(3,0) : D3DPS_VERSION(2,0);
+    pCaps->PixelShader1xMaxValue = 8.0f; /* XXX: wine */
+
+    pCaps->DevCaps2 = D3DDEVCAPS2_STREAMOFFSET |
+                      D3DDEVCAPS2_VERTEXELEMENTSCANSHARESTREAMOFFSET |
+                      D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES |
+                      /*D3DDEVCAPS2_DMAPNPATCH |*/
+                      /*D3DDEVCAPS2_ADAPTIVETESSRTPATCH |*/
+                      /*D3DDEVCAPS2_ADAPTIVETESSNPATCH |*/
+                      /*D3DDEVCAPS2_PRESAMPLEDDMAPNPATCH*/0;
+
+    pCaps->MasterAdapterOrdinal = 0;
+    pCaps->AdapterOrdinalInGroup = 0;
+    pCaps->NumberOfAdaptersInGroup = 1;
+
+    /* Undocumented ? */
+    pCaps->MaxNpatchTessellationLevel = 0.0f;
+    pCaps->Reserved5 = 0;
+
+    /* XXX: use is_format_supported */
+    pCaps->DeclTypes = D3DDTCAPS_UBYTE4 |
+                       D3DDTCAPS_UBYTE4N |
+                       D3DDTCAPS_SHORT2N |
+                       D3DDTCAPS_SHORT4N |
+                       D3DDTCAPS_USHORT2N |
+                       D3DDTCAPS_USHORT4N |
+                       D3DDTCAPS_UDEC3 |
+                       D3DDTCAPS_DEC3N |
+                       D3DDTCAPS_FLOAT16_2 |
+                       D3DDTCAPS_FLOAT16_4;
+
+    pCaps->NumSimultaneousRTs =
+        screen->get_param(screen, PIPE_CAP_MAX_RENDER_TARGETS);
+    if (pCaps->NumSimultaneousRTs > NINE_MAX_SIMULTANEOUS_RENDERTARGETS)
+        pCaps->NumSimultaneousRTs = NINE_MAX_SIMULTANEOUS_RENDERTARGETS;
+
+    pCaps->StretchRectFilterCaps = D3DPTFILTERCAPS_MINFPOINT |
+                                   D3DPTFILTERCAPS_MINFLINEAR |
+                                   D3DPTFILTERCAPS_MAGFPOINT |
+                                   D3DPTFILTERCAPS_MAGFLINEAR;
+
+
+    pCaps->VS20Caps.Caps = D3DVS20CAPS_PREDICATION;
+    pCaps->VS20Caps.DynamicFlowControlDepth = /* XXX is this dynamic ? */
+        screen->get_shader_param(screen, PIPE_SHADER_VERTEX,
+                                 PIPE_SHADER_CAP_MAX_CONTROL_FLOW_DEPTH);
+    pCaps->VS20Caps.NumTemps =
+        screen->get_shader_param(screen, PIPE_SHADER_VERTEX,
+                                 PIPE_SHADER_CAP_MAX_TEMPS);
+    pCaps->VS20Caps.StaticFlowControlDepth = /* XXX is this static ? */
+        screen->get_shader_param(screen, PIPE_SHADER_VERTEX,
+                                 PIPE_SHADER_CAP_MAX_CONTROL_FLOW_DEPTH);
+
+    /* also check for values < 0, because get_shader_param may return unsigned */
+    if (pCaps->VS20Caps.DynamicFlowControlDepth > D3DVS20_MAX_DYNAMICFLOWCONTROLDEPTH
+        || pCaps->VS20Caps.DynamicFlowControlDepth < 0)
+        pCaps->VS20Caps.DynamicFlowControlDepth = D3DVS20_MAX_DYNAMICFLOWCONTROLDEPTH;
+    if (pCaps->VS20Caps.StaticFlowControlDepth > D3DVS20_MAX_STATICFLOWCONTROLDEPTH
+        || pCaps->VS20Caps.StaticFlowControlDepth < 0)
+        pCaps->VS20Caps.StaticFlowControlDepth = D3DVS20_MAX_STATICFLOWCONTROLDEPTH;
+    if (pCaps->VS20Caps.NumTemps > D3DVS20_MAX_NUMTEMPS)
+        pCaps->VS20Caps.NumTemps = D3DVS20_MAX_NUMTEMPS;
+    assert(pCaps->VS20Caps.DynamicFlowControlDepth >= D3DVS20_MIN_DYNAMICFLOWCONTROLDEPTH);
+    assert(pCaps->VS20Caps.StaticFlowControlDepth >= D3DVS20_MIN_STATICFLOWCONTROLDEPTH);
+    assert(pCaps->VS20Caps.NumTemps >= D3DVS20_MIN_NUMTEMPS);
+
+
+    pCaps->PS20Caps.Caps = D3DPS20CAPS_ARBITRARYSWIZZLE |
+                           D3DPS20CAPS_GRADIENTINSTRUCTIONS |
+                           D3DPS20CAPS_PREDICATION;
+    if (screen->get_shader_param(screen, PIPE_SHADER_FRAGMENT,
+                                 PIPE_SHADER_CAP_MAX_TEX_INSTRUCTIONS) ==
+        screen->get_shader_param(screen, PIPE_SHADER_FRAGMENT,
+                                 PIPE_SHADER_CAP_MAX_INSTRUCTIONS))
+        pCaps->PS20Caps.Caps |= D3DPS20CAPS_NOTEXINSTRUCTIONLIMIT;
+    if (screen->get_shader_param(screen, PIPE_SHADER_FRAGMENT,
+                                 PIPE_SHADER_CAP_MAX_TEX_INSTRUCTIONS) ==
+        screen->get_shader_param(screen, PIPE_SHADER_FRAGMENT,
+                                 PIPE_SHADER_CAP_MAX_TEX_INDIRECTIONS))
+        pCaps->PS20Caps.Caps |= D3DPS20CAPS_NODEPENDENTREADLIMIT;
+    pCaps->PS20Caps.DynamicFlowControlDepth = /* XXX is this dynamic ? */
+        screen->get_shader_param(screen, PIPE_SHADER_FRAGMENT,
+                                 PIPE_SHADER_CAP_MAX_CONTROL_FLOW_DEPTH);
+    pCaps->PS20Caps.NumTemps =
+        screen->get_shader_param(screen, PIPE_SHADER_FRAGMENT,
+                                 PIPE_SHADER_CAP_MAX_TEMPS);
+    pCaps->PS20Caps.StaticFlowControlDepth =  /* XXX is this static ? */
+        screen->get_shader_param(screen, PIPE_SHADER_FRAGMENT,
+                                 PIPE_SHADER_CAP_MAX_CONTROL_FLOW_DEPTH);
+    pCaps->PS20Caps.NumInstructionSlots =
+        screen->get_shader_param(screen, PIPE_SHADER_FRAGMENT,
+                                 PIPE_SHADER_CAP_MAX_INSTRUCTIONS);
+
+    if (pCaps->PS20Caps.DynamicFlowControlDepth > D3DPS20_MAX_DYNAMICFLOWCONTROLDEPTH
+        || pCaps->PS20Caps.DynamicFlowControlDepth < 0)
+        pCaps->PS20Caps.DynamicFlowControlDepth = D3DPS20_MAX_DYNAMICFLOWCONTROLDEPTH;
+    if (pCaps->PS20Caps.StaticFlowControlDepth > D3DPS20_MAX_STATICFLOWCONTROLDEPTH
+        || pCaps->PS20Caps.StaticFlowControlDepth < 0)
+        pCaps->PS20Caps.StaticFlowControlDepth = D3DPS20_MAX_STATICFLOWCONTROLDEPTH;
+    if (pCaps->PS20Caps.NumTemps > D3DPS20_MAX_NUMTEMPS)
+        pCaps->PS20Caps.NumTemps = D3DPS20_MAX_NUMTEMPS;
+    if (pCaps->PS20Caps.NumInstructionSlots > D3DPS20_MAX_NUMINSTRUCTIONSLOTS)
+        pCaps->PS20Caps.NumInstructionSlots = D3DPS20_MAX_NUMINSTRUCTIONSLOTS;
+    assert(pCaps->PS20Caps.DynamicFlowControlDepth >= D3DPS20_MIN_DYNAMICFLOWCONTROLDEPTH);
+    assert(pCaps->PS20Caps.StaticFlowControlDepth >= D3DPS20_MIN_STATICFLOWCONTROLDEPTH);
+    assert(pCaps->PS20Caps.NumTemps >= D3DPS20_MIN_NUMTEMPS);
+    assert(pCaps->PS20Caps.NumInstructionSlots >= D3DPS20_MIN_NUMINSTRUCTIONSLOTS);
+
+
+    if (screen->get_shader_param(screen, PIPE_SHADER_VERTEX,
+                                 PIPE_SHADER_CAP_MAX_TEXTURE_SAMPLERS))
+        pCaps->VertexTextureFilterCaps = pCaps->TextureFilterCaps &
+            ~(D3DPTFILTERCAPS_MIPFPOINT |
+              D3DPTFILTERCAPS_MIPFPOINT); /* XXX */
+    else
+        pCaps->VertexTextureFilterCaps = 0;
+
+    if (sm3) {
+        pCaps->MaxVertexShader30InstructionSlots =
+            screen->get_shader_param(screen, PIPE_SHADER_VERTEX,
+                                     PIPE_SHADER_CAP_MAX_INSTRUCTIONS);
+        pCaps->MaxPixelShader30InstructionSlots =
+            screen->get_shader_param(screen, PIPE_SHADER_FRAGMENT,
+                                     PIPE_SHADER_CAP_MAX_INSTRUCTIONS);
+        if (pCaps->MaxVertexShader30InstructionSlots > D3DMAX30SHADERINSTRUCTIONS)
+            pCaps->MaxVertexShader30InstructionSlots = D3DMAX30SHADERINSTRUCTIONS;
+        if (pCaps->MaxPixelShader30InstructionSlots > D3DMAX30SHADERINSTRUCTIONS)
+            pCaps->MaxPixelShader30InstructionSlots = D3DMAX30SHADERINSTRUCTIONS;
+        assert(pCaps->MaxVertexShader30InstructionSlots >= D3DMIN30SHADERINSTRUCTIONS);
+        assert(pCaps->MaxPixelShader30InstructionSlots >= D3DMIN30SHADERINSTRUCTIONS);
+    } else {
+        pCaps->MaxVertexShader30InstructionSlots = 0;
+        pCaps->MaxPixelShader30InstructionSlots = 0;
+    }
+
+    /* 65535 is required, advertise more for GPUs with >= 2048 instruction slots */
+    pCaps->MaxVShaderInstructionsExecuted = MAX2(65535, pCaps->MaxVertexShader30InstructionSlots * 32);
+    pCaps->MaxPShaderInstructionsExecuted = MAX2(65535, pCaps->MaxPixelShader30InstructionSlots * 32);
+
+    if (debug_get_bool_option("NINE_DUMP_CAPS", FALSE))
+        nine_dump_D3DCAPS9(DBG_CHANNEL, pCaps);
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineAdapter9_CreateDevice( struct NineAdapter9 *This,
+                           UINT RealAdapter,
+                           D3DDEVTYPE DeviceType,
+                           HWND hFocusWindow,
+                           DWORD BehaviorFlags,
+                           D3DPRESENT_PARAMETERS *pPresentationParameters,
+                           IDirect3D9 *pD3D9,
+                           ID3DPresentGroup *pPresentationGroup,
+                           IDirect3DDevice9 **ppReturnedDeviceInterface )
+{
+    struct pipe_screen *screen;
+    D3DDEVICE_CREATION_PARAMETERS params;
+    D3DCAPS9 caps;
+    int major, minor;
+    HRESULT hr;
+
+    DBG("This=%p RealAdapter=%u DeviceType=%s hFocusWindow=%p "
+        "BehaviourFlags=%x " "pD3D9=%p pPresentationGroup=%p "
+        "ppReturnedDeviceInterface=%p\n", This,
+        RealAdapter, nine_D3DDEVTYPE_to_str(DeviceType), hFocusWindow,
+        BehaviorFlags, pD3D9, pPresentationGroup, ppReturnedDeviceInterface);
+
+    ID3DPresentGroup_GetVersion(pPresentationGroup, &major, &minor);
+    if (major != 1) {
+        ERR("Doesn't support the ID3DPresentGroup version %d %d. Expected 1\n",
+            major, minor);
+        return D3DERR_NOTAVAILABLE;
+    }
+
+    hr = NineAdapter9_GetScreen(This, DeviceType, &screen);
+    if (FAILED(hr)) {
+        DBG("Failed to get pipe_screen.\n");
+        return hr;
+    }
+
+    hr = NineAdapter9_GetDeviceCaps(This, DeviceType, &caps);
+    if (FAILED(hr)) {
+        DBG("Failed to get device caps.\n");
+        return hr;
+    }
+
+    params.AdapterOrdinal = RealAdapter;
+    params.DeviceType = DeviceType;
+    params.hFocusWindow = hFocusWindow;
+    params.BehaviorFlags = BehaviorFlags;
+
+    hr = NineDevice9_new(screen, &params, &caps, pPresentationParameters,
+                         pD3D9, pPresentationGroup, This->ctx,
+                         (struct NineDevice9 **)ppReturnedDeviceInterface);
+    if (FAILED(hr)) {
+        DBG("Failed to create device.\n");
+        return hr;
+    }
+    DBG("NineDevice9 created successfully.\n");
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineAdapter9_CreateDeviceEx( struct NineAdapter9 *This,
+                             UINT RealAdapter,
+                             D3DDEVTYPE DeviceType,
+                             HWND hFocusWindow,
+                             DWORD BehaviorFlags,
+                             D3DPRESENT_PARAMETERS *pPresentationParameters,
+                             D3DDISPLAYMODEEX *pFullscreenDisplayMode,
+                             IDirect3D9Ex *pD3D9Ex,
+                             ID3DPresentGroup *pPresentationGroup,
+                             IDirect3DDevice9Ex **ppReturnedDeviceInterface )
+{
+    struct pipe_screen *screen;
+    D3DDEVICE_CREATION_PARAMETERS params;
+    D3DCAPS9 caps;
+    int major, minor;
+    HRESULT hr;
+
+    DBG("This=%p RealAdapter=%u DeviceType=%s hFocusWindow=%p "
+        "BehaviourFlags=%x " "pD3D9Ex=%p pPresentationGroup=%p "
+        "ppReturnedDeviceInterface=%p\n", This,
+        RealAdapter, nine_D3DDEVTYPE_to_str(DeviceType), hFocusWindow,
+        BehaviorFlags, pD3D9Ex, pPresentationGroup, ppReturnedDeviceInterface);
+
+    ID3DPresentGroup_GetVersion(pPresentationGroup, &major, &minor);
+    if (major != 1) {
+        ERR("Doesn't support the ID3DPresentGroup version %d %d. Expected 1\n",
+            major, minor);
+        return D3DERR_NOTAVAILABLE;
+    }
+
+    hr = NineAdapter9_GetScreen(This, DeviceType, &screen);
+    if (FAILED(hr)) {
+        DBG("Failed to get pipe_screen.\n");
+        return hr;
+    }
+
+    hr = NineAdapter9_GetDeviceCaps(This, DeviceType, &caps);
+    if (FAILED(hr)) {
+        DBG("Failed to get device caps.\n");
+        return hr;
+    }
+
+    params.AdapterOrdinal = RealAdapter;
+    params.DeviceType = DeviceType;
+    params.hFocusWindow = hFocusWindow;
+    params.BehaviorFlags = BehaviorFlags;
+
+    hr = NineDevice9Ex_new(screen, &params, &caps, pPresentationParameters,
+                           pFullscreenDisplayMode,
+                           pD3D9Ex, pPresentationGroup, This->ctx,
+                           (struct NineDevice9Ex **)ppReturnedDeviceInterface);
+    if (FAILED(hr)) {
+        DBG("Failed to create device.\n");
+        return hr;
+    }
+    DBG("NineDevice9Ex created successfully.\n");
+
+    return D3D_OK;
+}
+
+ID3DAdapter9Vtbl NineAdapter9_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)NineAdapter9_GetAdapterIdentifier,
+    (void *)NineAdapter9_CheckDeviceType,
+    (void *)NineAdapter9_CheckDeviceFormat,
+    (void *)NineAdapter9_CheckDeviceMultiSampleType,
+    (void *)NineAdapter9_CheckDepthStencilMatch,
+    (void *)NineAdapter9_CheckDeviceFormatConversion,
+    (void *)NineAdapter9_GetDeviceCaps,
+    (void *)NineAdapter9_CreateDevice,
+    (void *)NineAdapter9_CreateDeviceEx
+};
+
+static const GUID *NineAdapter9_IIDs[] = {
+    &IID_ID3D9Adapter,
+    &IID_IUnknown,
+    NULL
+};
+
+HRESULT
+NineAdapter9_new( struct d3dadapter9_context *pCTX,
+                  struct NineAdapter9 **ppOut )
+{
+    NINE_NEW(Adapter9, ppOut, FALSE, /* args */ pCTX);
+}
diff --git a/src/gallium/state_trackers/nine/adapter9.h b/src/gallium/state_trackers/nine/adapter9.h
new file mode 100644 (file)
index 0000000..c743347
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _NINE_ADAPTER9_H_
+#define _NINE_ADAPTER9_H_
+
+#include "iunknown.h"
+
+#include "d3dadapter/d3dadapter9.h"
+
+struct pipe_screen;
+struct pipe_resource;
+
+struct d3dadapter9_context
+{
+    struct pipe_screen *hal, *ref;
+    D3DADAPTER_IDENTIFIER9 identifier;
+    BOOL linear_framebuffer;
+    BOOL throttling;
+    int throttling_value;
+
+    void (*destroy)( struct d3dadapter9_context *ctx );
+};
+
+struct NineAdapter9
+{
+    struct NineUnknown base;
+    
+    struct d3dadapter9_context *ctx;
+};
+static INLINE struct NineAdapter9 *
+NineAdapter9( void *data )
+{
+    return (struct NineAdapter9 *)data;
+}
+
+HRESULT
+NineAdapter9_new( struct d3dadapter9_context *pCTX,
+                  struct NineAdapter9 **ppOut );
+
+HRESULT
+NineAdapter9_ctor( struct NineAdapter9 *This,
+                   struct NineUnknownParams *pParams,
+                   struct d3dadapter9_context *pCTX );
+
+void
+NineAdapter9_dtor( struct NineAdapter9 *This );
+
+HRESULT WINAPI
+NineAdapter9_GetAdapterIdentifier( struct NineAdapter9 *This,
+                                   DWORD Flags,
+                                   D3DADAPTER_IDENTIFIER9 *pIdentifier );
+
+HRESULT WINAPI
+NineAdapter9_CheckDeviceType( struct NineAdapter9 *This,
+                              D3DDEVTYPE DevType,
+                              D3DFORMAT AdapterFormat,
+                              D3DFORMAT BackBufferFormat,
+                              BOOL bWindowed );
+
+HRESULT WINAPI
+NineAdapter9_CheckDeviceFormat( struct NineAdapter9 *This,
+                                D3DDEVTYPE DeviceType,
+                                D3DFORMAT AdapterFormat,
+                                DWORD Usage,
+                                D3DRESOURCETYPE RType,
+                                D3DFORMAT CheckFormat );
+
+HRESULT WINAPI
+NineAdapter9_CheckDeviceMultiSampleType( struct NineAdapter9 *This,
+                                         D3DDEVTYPE DeviceType,
+                                         D3DFORMAT SurfaceFormat,
+                                         BOOL Windowed,
+                                         D3DMULTISAMPLE_TYPE MultiSampleType,
+                                         DWORD *pQualityLevels );
+
+HRESULT WINAPI
+NineAdapter9_CheckDepthStencilMatch( struct NineAdapter9 *This,
+                                     D3DDEVTYPE DeviceType,
+                                     D3DFORMAT AdapterFormat,
+                                     D3DFORMAT RenderTargetFormat,
+                                     D3DFORMAT DepthStencilFormat );
+
+HRESULT WINAPI
+NineAdapter9_CheckDeviceFormatConversion( struct NineAdapter9 *This,
+                                          D3DDEVTYPE DeviceType,
+                                          D3DFORMAT SourceFormat,
+                                          D3DFORMAT TargetFormat );
+
+HRESULT WINAPI
+NineAdapter9_GetDeviceCaps( struct NineAdapter9 *This,
+                            D3DDEVTYPE DeviceType,
+                            D3DCAPS9 *pCaps );
+
+HRESULT WINAPI
+NineAdapter9_CreateDevice( struct NineAdapter9 *This,
+                           UINT RealAdapter,
+                           D3DDEVTYPE DeviceType,
+                           HWND hFocusWindow,
+                           DWORD BehaviorFlags,
+                           D3DPRESENT_PARAMETERS *pPresentationParameters,
+                           IDirect3D9 *pD3D9,
+                           ID3DPresentGroup *pPresentationGroup,
+                           IDirect3DDevice9 **ppReturnedDeviceInterface );
+
+HRESULT WINAPI
+NineAdapter9_CreateDeviceEx( struct NineAdapter9 *This,
+                             UINT RealAdapter,
+                             D3DDEVTYPE DeviceType,
+                             HWND hFocusWindow,
+                             DWORD BehaviorFlags,
+                             D3DPRESENT_PARAMETERS *pPresentationParameters,
+                             D3DDISPLAYMODEEX *pFullscreenDisplayMode,
+                             IDirect3D9Ex *pD3D9Ex,
+                             ID3DPresentGroup *pPresentationGroup,
+                             IDirect3DDevice9Ex **ppReturnedDeviceInterface );
+
+#endif /* _NINE_ADAPTER9_H_ */
diff --git a/src/gallium/state_trackers/nine/authenticatedchannel9.c b/src/gallium/state_trackers/nine/authenticatedchannel9.c
new file mode 100644 (file)
index 0000000..44ad87c
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "authenticatedchannel9.h"
+
+#define DBG_CHANNEL DBG_AUTHENTICATEDCHANNEL
+
+HRESULT WINAPI
+NineAuthenticatedChannel9_GetCertificateSize( struct NineAuthenticatedChannel9 *This,
+                                              UINT *pCertificateSize )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineAuthenticatedChannel9_GetCertificate( struct NineAuthenticatedChannel9 *This,
+                                          UINT CertifacteSize,
+                                          BYTE *ppCertificate )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineAuthenticatedChannel9_NegotiateKeyExchange( struct NineAuthenticatedChannel9 *This,
+                                                UINT DataSize,
+                                                void *pData )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineAuthenticatedChannel9_Query( struct NineAuthenticatedChannel9 *This,
+                                 UINT InputSize,
+                                 const void *pInput,
+                                 UINT OutputSize,
+                                 void *pOutput )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineAuthenticatedChannel9_Configure( struct NineAuthenticatedChannel9 *This,
+                                     UINT InputSize,
+                                     const void *pInput,
+                                     D3DAUTHENTICATEDCHANNEL_CONFIGURE_OUTPUT *pOutput )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+IDirect3DAuthenticatedChannel9Vtbl NineAuthenticatedChannel9_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)NineAuthenticatedChannel9_GetCertificateSize,
+    (void *)NineAuthenticatedChannel9_GetCertificate,
+    (void *)NineAuthenticatedChannel9_NegotiateKeyExchange,
+    (void *)NineAuthenticatedChannel9_Query,
+    (void *)NineAuthenticatedChannel9_Configure
+};
diff --git a/src/gallium/state_trackers/nine/authenticatedchannel9.h b/src/gallium/state_trackers/nine/authenticatedchannel9.h
new file mode 100644 (file)
index 0000000..7d374f6
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _NINE_AUTHENTICATEDCHANNEL9_H_
+#define _NINE_AUTHENTICATEDCHANNEL9_H_
+
+#include "iunknown.h"
+
+struct NineAuthenticatedChannel9
+{
+    struct NineUnknown base;
+};
+static INLINE struct NineAuthenticatedChannel9 *
+NineAuthenticatedChannel9( void *data )
+{
+    return (struct NineAuthenticatedChannel9 *)data;
+}
+
+HRESULT WINAPI
+NineAuthenticatedChannel9_GetCertificateSize( struct NineAuthenticatedChannel9 *This,
+                                              UINT *pCertificateSize );
+
+HRESULT WINAPI
+NineAuthenticatedChannel9_GetCertificate( struct NineAuthenticatedChannel9 *This,
+                                          UINT CertifacteSize,
+                                          BYTE *ppCertificate );
+
+HRESULT WINAPI
+NineAuthenticatedChannel9_NegotiateKeyExchange( struct NineAuthenticatedChannel9 *This,
+                                                UINT DataSize,
+                                                void *pData );
+
+HRESULT WINAPI
+NineAuthenticatedChannel9_Query( struct NineAuthenticatedChannel9 *This,
+                                 UINT InputSize,
+                                 const void *pInput,
+                                 UINT OutputSize,
+                                 void *pOutput );
+
+HRESULT WINAPI
+NineAuthenticatedChannel9_Configure( struct NineAuthenticatedChannel9 *This,
+                                     UINT InputSize,
+                                     const void *pInput,
+                                     D3DAUTHENTICATEDCHANNEL_CONFIGURE_OUTPUT *pOutput );
+
+#endif /* _NINE_AUTHENTICATEDCHANNEL9_H_ */
diff --git a/src/gallium/state_trackers/nine/basetexture9.c b/src/gallium/state_trackers/nine/basetexture9.c
new file mode 100644 (file)
index 0000000..89f6269
--- /dev/null
@@ -0,0 +1,504 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "basetexture9.h"
+#include "device9.h"
+
+/* For UploadSelf: */
+#include "texture9.h"
+#include "cubetexture9.h"
+#include "volumetexture9.h"
+
+#ifdef DEBUG
+#include "nine_pipe.h"
+#include "nine_dump.h"
+#endif
+
+#include "util/u_format.h"
+#include "util/u_gen_mipmap.h"
+
+#define DBG_CHANNEL DBG_BASETEXTURE
+
+HRESULT
+NineBaseTexture9_ctor( struct NineBaseTexture9 *This,
+                       struct NineUnknownParams *pParams,
+                       D3DRESOURCETYPE Type,
+                       D3DPOOL Pool )
+{
+    BOOL alloc = (Pool == D3DPOOL_DEFAULT) && !This->base.resource &&
+        (This->format != D3DFMT_NULL);
+    HRESULT hr;
+    DWORD usage = This->base.usage;
+
+    user_assert(!(usage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)) ||
+                Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL);
+    user_assert(!(usage & D3DUSAGE_DYNAMIC) ||
+                Pool != D3DPOOL_MANAGED, D3DERR_INVALIDCALL);
+
+    hr = NineResource9_ctor(&This->base, pParams, alloc, Type, Pool);
+    if (FAILED(hr))
+        return hr;
+
+    This->pipe = pParams->device->pipe;
+    This->mipfilter = (This->base.usage & D3DUSAGE_AUTOGENMIPMAP) ?
+        D3DTEXF_LINEAR : D3DTEXF_NONE;
+    This->lod = 0;
+    This->lod_resident = -1;
+    This->shadow = This->format != D3DFMT_INTZ && util_format_has_depth(
+        util_format_description(This->base.info.format));
+
+    list_inithead(&This->list);
+
+    return D3D_OK;
+}
+
+void
+NineBaseTexture9_dtor( struct NineBaseTexture9 *This )
+{
+    DBG("This=%p\n", This);
+
+    pipe_sampler_view_reference(&This->view[0], NULL);
+    pipe_sampler_view_reference(&This->view[1], NULL);
+
+    list_del(&This->list),
+
+    NineResource9_dtor(&This->base);
+}
+
+DWORD WINAPI
+NineBaseTexture9_SetLOD( struct NineBaseTexture9 *This,
+                         DWORD LODNew )
+{
+    DWORD old = This->lod;
+
+    user_assert(This->base.pool == D3DPOOL_MANAGED, 0);
+
+    This->lod = MIN2(LODNew, This->base.info.last_level);
+
+    if (This->lod != old && This->bind_count && LIST_IS_EMPTY(&This->list))
+       list_add(&This->list, &This->base.base.device->update_textures);
+
+    return old;
+}
+
+DWORD WINAPI
+NineBaseTexture9_GetLOD( struct NineBaseTexture9 *This )
+{
+    return This->lod;
+}
+
+DWORD WINAPI
+NineBaseTexture9_GetLevelCount( struct NineBaseTexture9 *This )
+{
+    if (This->base.usage & D3DUSAGE_AUTOGENMIPMAP)
+        return 1;
+    return This->base.info.last_level + 1;
+}
+
+HRESULT WINAPI
+NineBaseTexture9_SetAutoGenFilterType( struct NineBaseTexture9 *This,
+                                       D3DTEXTUREFILTERTYPE FilterType )
+{
+    if (!(This->base.usage & D3DUSAGE_AUTOGENMIPMAP))
+        return D3D_OK;
+    user_assert(FilterType != D3DTEXF_NONE, D3DERR_INVALIDCALL);
+
+    This->mipfilter = FilterType;
+
+    return D3D_OK;
+}
+
+D3DTEXTUREFILTERTYPE WINAPI
+NineBaseTexture9_GetAutoGenFilterType( struct NineBaseTexture9 *This )
+{
+    return This->mipfilter;
+}
+
+HRESULT
+NineBaseTexture9_UploadSelf( struct NineBaseTexture9 *This )
+{
+    HRESULT hr;
+    unsigned last_level = This->base.info.last_level;
+    unsigned l;
+
+    DBG("This=%p dirty=%i type=%s\n", This, This->dirty,
+        nine_D3DRTYPE_to_str(This->base.type));
+
+    assert(This->base.pool == D3DPOOL_MANAGED);
+
+    if (This->base.usage & D3DUSAGE_AUTOGENMIPMAP)
+        last_level = 0; /* TODO: What if level 0 is not resident ? */
+
+    if (This->lod_resident != This->lod) {
+        struct pipe_resource *res;
+
+        DBG("updating LOD from %u to %u ...\n", This->lod_resident, This->lod);
+
+        pipe_sampler_view_reference(&This->view[0], NULL);
+        pipe_sampler_view_reference(&This->view[1], NULL);
+
+        if (This->bind_count) {
+            /* mark state dirty */
+            struct nine_state *state = &This->base.base.device->state;
+            unsigned s;
+            for (s = 0; s < NINE_MAX_SAMPLERS; ++s)
+                if (state->texture[s] == This)
+                    state->changed.texture |= 1 << s;
+            if (state->changed.texture)
+                state->changed.group |= NINE_STATE_TEXTURE;
+        }
+
+        hr = NineBaseTexture9_CreatePipeResource(This, This->lod_resident != -1);
+        if (FAILED(hr))
+            return hr;
+        res = This->base.resource;
+
+        if (This->lod_resident == -1) /* no levels were resident */
+            This->lod_resident = This->base.info.last_level + 1;
+
+        if (This->base.type == D3DRTYPE_TEXTURE) {
+            struct NineTexture9 *tex = NineTexture9(This);
+            struct pipe_box box;
+
+            /* Mark uninitialized levels as dirty. */
+            box.x = box.y = box.z = 0;
+            box.depth = 1;
+            for (l = This->lod; l < This->lod_resident; ++l) {
+                box.width = u_minify(This->base.info.width0, l);
+                box.height = u_minify(This->base.info.height0, l);
+                NineSurface9_AddDirtyRect(tex->surfaces[l], &box);
+            }
+            for (l = 0; l < This->lod; ++l)
+                NineSurface9_SetResource(tex->surfaces[l], NULL, -1);
+            for (; l <= This->base.info.last_level; ++l)
+                NineSurface9_SetResource(tex->surfaces[l], res, l - This->lod);
+        } else
+        if (This->base.type == D3DRTYPE_CUBETEXTURE) {
+            struct NineCubeTexture9 *tex = NineCubeTexture9(This);
+            struct pipe_box box;
+            unsigned z;
+
+            /* Mark uninitialized levels as dirty. */
+            box.x = box.y = box.z = 0;
+            box.depth = 1;
+            for (l = This->lod; l < This->lod_resident; ++l) {
+                box.width = u_minify(This->base.info.width0, l);
+                box.height = u_minify(This->base.info.height0, l);
+                for (z = 0; z < 6; ++z)
+                    NineSurface9_AddDirtyRect(tex->surfaces[l * 6 + z], &box);
+            }
+            for (l = 0; l < This->lod; ++l) {
+                for (z = 0; z < 6; ++z)
+                    NineSurface9_SetResource(tex->surfaces[l * 6 + z],
+                                             NULL, -1);
+            }
+            for (; l <= This->base.info.last_level; ++l) {
+                for (z = 0; z < 6; ++z)
+                    NineSurface9_SetResource(tex->surfaces[l * 6 + z],
+                                             res, l - This->lod);
+            }
+        } else
+        if (This->base.type == D3DRTYPE_VOLUMETEXTURE) {
+            struct NineVolumeTexture9 *tex = NineVolumeTexture9(This);
+            struct pipe_box box;
+
+            /* Mark uninitialized levels as dirty. */
+            box.x = box.y = box.z = 0;
+            for (l = This->lod; l < This->lod_resident; ++l) {
+                box.width = u_minify(This->base.info.width0, l);
+                box.height = u_minify(This->base.info.height0, l);
+                box.depth = u_minify(This->base.info.depth0, l);
+                NineVolume9_AddDirtyRegion(tex->volumes[l], &box);
+            }
+            for (l = 0; l < This->lod; ++l)
+                NineVolume9_SetResource(tex->volumes[l], NULL, -1);
+            for (; l <= This->base.info.last_level; ++l)
+                NineVolume9_SetResource(tex->volumes[l], res, l - This->lod);
+        } else {
+            assert(!"invalid texture type");
+        }
+
+        if (This->lod < This->lod_resident)
+            This->dirty = TRUE;
+        This->lod_resident = This->lod;
+    }
+    if (!This->dirty)
+        return D3D_OK;
+
+    if (This->base.type == D3DRTYPE_TEXTURE) {
+        struct NineTexture9 *tex = NineTexture9(This);
+        struct pipe_box box;
+        box.z = 0;
+        box.depth = 1;
+
+        DBG("TEXTURE: dirty rect=(%u,%u) (%ux%u)\n",
+            tex->dirty_rect.x, tex->dirty_rect.y,
+            tex->dirty_rect.width, tex->dirty_rect.height);
+
+        if (tex->dirty_rect.width) {
+            for (l = 0; l <= last_level; ++l) {
+                u_box_minify_2d(&box, &tex->dirty_rect, l);
+                NineSurface9_AddDirtyRect(tex->surfaces[l], &box);
+            }
+            memset(&tex->dirty_rect, 0, sizeof(tex->dirty_rect));
+            tex->dirty_rect.depth = 1;
+        }
+        for (l = This->lod; l <= last_level; ++l)
+            NineSurface9_UploadSelf(tex->surfaces[l]);
+    } else
+    if (This->base.type == D3DRTYPE_CUBETEXTURE) {
+        struct NineCubeTexture9 *tex = NineCubeTexture9(This);
+        unsigned z;
+        struct pipe_box box;
+        box.z = 0;
+        box.depth = 1;
+
+        for (z = 0; z < 6; ++z) {
+            DBG("FACE[%u]: dirty rect=(%u,%u) (%ux%u)\n", z,
+                tex->dirty_rect[z].x, tex->dirty_rect[z].y,
+                tex->dirty_rect[z].width, tex->dirty_rect[z].height);
+
+            if (tex->dirty_rect[z].width) {
+                for (l = 0; l <= last_level; ++l) {
+                    u_box_minify_2d(&box, &tex->dirty_rect[z], l);
+                    NineSurface9_AddDirtyRect(tex->surfaces[l * 6 + z], &box);
+                }
+                memset(&tex->dirty_rect[z], 0, sizeof(tex->dirty_rect[z]));
+                tex->dirty_rect[z].depth = 1;
+            }
+            for (l = This->lod; l <= last_level; ++l)
+                NineSurface9_UploadSelf(tex->surfaces[l * 6 + z]);
+        }
+    } else
+    if (This->base.type == D3DRTYPE_VOLUMETEXTURE) {
+        struct NineVolumeTexture9 *tex = NineVolumeTexture9(This);
+        struct pipe_box box;
+
+        DBG("VOLUME: dirty_box=(%u,%u,%u) (%ux%ux%u)\n",
+            tex->dirty_box.x, tex->dirty_box.y, tex->dirty_box.y,
+            tex->dirty_box.width, tex->dirty_box.height, tex->dirty_box.depth);
+
+        if (tex->dirty_box.width) {
+            for (l = 0; l <= last_level; ++l) {
+                u_box_minify_2d(&box, &tex->dirty_box, l);
+                NineVolume9_AddDirtyRegion(tex->volumes[l], &tex->dirty_box);
+            }
+            memset(&tex->dirty_box, 0, sizeof(tex->dirty_box));
+        }
+        for (l = This->lod; l <= last_level; ++l)
+            NineVolume9_UploadSelf(tex->volumes[l]);
+    } else {
+        assert(!"invalid texture type");
+    }
+    This->dirty = FALSE;
+
+    if (This->base.usage & D3DUSAGE_AUTOGENMIPMAP)
+        This->dirty_mip = TRUE;
+    /* TODO: if dirty only because of lod change, only generate added levels */
+
+    DBG("DONE, generate mip maps = %i\n", This->dirty_mip);
+    return D3D_OK;
+}
+
+void WINAPI
+NineBaseTexture9_GenerateMipSubLevels( struct NineBaseTexture9 *This )
+{
+    struct pipe_resource *resource = This->base.resource;
+
+    unsigned base_level = 0;
+    unsigned last_level = This->base.info.last_level - This->lod;
+    unsigned first_layer = 0;
+    unsigned last_layer;
+    unsigned filter = This->mipfilter == D3DTEXF_POINT ? PIPE_TEX_FILTER_NEAREST
+                                                       : PIPE_TEX_FILTER_LINEAR;
+    DBG("This=%p\n", This);
+
+    if (This->base.pool == D3DPOOL_MANAGED)
+        NineBaseTexture9_UploadSelf(This);
+    if (!This->dirty_mip)
+        return;
+    if (This->lod) {
+        ERR("AUTOGENMIPMAP if level 0 is not resident not supported yet !\n");
+        return;
+    }
+
+    if (!This->view[0])
+        NineBaseTexture9_UpdateSamplerView(This, 0);
+
+    last_layer = util_max_layer(This->view[0]->texture, base_level);
+
+    util_gen_mipmap(This->pipe, resource,
+                    resource->format, base_level, last_level,
+                    first_layer, last_layer, filter);
+
+    This->dirty_mip = FALSE;
+
+    NineDevice9_RestoreNonCSOState(This->base.base.device, ~0x3);
+}
+
+HRESULT
+NineBaseTexture9_CreatePipeResource( struct NineBaseTexture9 *This,
+                                     BOOL CopyData )
+{
+    struct pipe_context *pipe = This->pipe;
+    struct pipe_screen *screen = This->base.info.screen;
+    struct pipe_resource templ;
+    unsigned l, m;
+    struct pipe_resource *res;
+    struct pipe_resource *old = This->base.resource;
+
+    DBG("This=%p lod=%u last_level=%u\n", This,
+        This->lod, This->base.info.last_level);
+
+    assert(This->base.pool == D3DPOOL_MANAGED);
+
+    templ = This->base.info;
+
+    if (This->lod) {
+        templ.width0 = u_minify(templ.width0, This->lod);
+        templ.height0 = u_minify(templ.height0, This->lod);
+        templ.depth0 = u_minify(templ.depth0, This->lod);
+    }
+    templ.last_level = This->base.info.last_level - This->lod;
+
+    if (old) {
+        /* LOD might have changed. */
+        if (old->width0 == templ.width0 &&
+            old->height0 == templ.height0 &&
+            old->depth0 == templ.depth0)
+            return D3D_OK;
+    }
+
+    res = screen->resource_create(screen, &templ);
+    if (!res)
+        return D3DERR_OUTOFVIDEOMEMORY;
+    This->base.resource = res;
+
+    if (old && CopyData) { /* Don't return without releasing old ! */
+        struct pipe_box box;
+        box.x = 0;
+        box.y = 0;
+        box.z = 0;
+
+        l = (This->lod < This->lod_resident) ? This->lod_resident - This->lod : 0;
+        m = (This->lod < This->lod_resident) ? 0 : This->lod - This->lod_resident;
+
+        box.width = u_minify(templ.width0, l);
+        box.height = u_minify(templ.height0, l);
+        box.depth = u_minify(templ.depth0, l);
+
+        for (; l <= templ.last_level; ++l, ++m) {
+            pipe->resource_copy_region(pipe,
+                                       res, l, 0, 0, 0,
+                                       old, m, &box);
+            box.width = u_minify(box.width, 1);
+            box.height = u_minify(box.height, 1);
+            box.depth = u_minify(box.depth, 1);
+        }
+    }
+    pipe_resource_reference(&old, NULL);
+
+    return D3D_OK;
+}
+
+HRESULT
+NineBaseTexture9_UpdateSamplerView( struct NineBaseTexture9 *This,
+                                    const int sRGB )
+{
+    const struct util_format_description *desc;
+    struct pipe_context *pipe = This->pipe;
+    struct pipe_resource *resource = This->base.resource;
+    struct pipe_sampler_view templ;
+    uint8_t swizzle[4];
+
+    if (unlikely(!resource)) {
+       if (unlikely(This->format == D3DFMT_NULL))
+            return D3D_OK;
+        NineBaseTexture9_Dump(This);
+    }
+    assert(resource);
+
+    pipe_sampler_view_reference(&This->view[sRGB], NULL);
+
+    swizzle[0] = PIPE_SWIZZLE_RED;
+    swizzle[1] = PIPE_SWIZZLE_GREEN;
+    swizzle[2] = PIPE_SWIZZLE_BLUE;
+    swizzle[3] = PIPE_SWIZZLE_ALPHA;
+    desc = util_format_description(resource->format);
+    if (desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS) {
+        /* ZZZ1 -> 0Z01 (see end of docs/source/tgsi.rst)
+         * XXX: but it's wrong
+        swizzle[0] = PIPE_SWIZZLE_ZERO;
+        swizzle[2] = PIPE_SWIZZLE_ZERO; */
+    } else
+    if (desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_X &&
+        desc->swizzle[3] == UTIL_FORMAT_SWIZZLE_1) {
+        /* R001/RG01 -> R111/RG11 */
+        if (desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_0)
+            swizzle[1] = PIPE_SWIZZLE_ONE;
+        if (desc->swizzle[2] == UTIL_FORMAT_SWIZZLE_0)
+            swizzle[2] = PIPE_SWIZZLE_ONE;
+    }
+    /* but 000A remains unchanged */
+
+    templ.format = sRGB ? util_format_srgb(resource->format) : resource->format;
+    templ.u.tex.first_layer = 0;
+    templ.u.tex.last_layer = (resource->target == PIPE_TEXTURE_CUBE) ?
+        5 : (This->base.info.depth0 - 1);
+    templ.u.tex.first_level = 0;
+    templ.u.tex.last_level = resource->last_level;
+    templ.swizzle_r = swizzle[0];
+    templ.swizzle_g = swizzle[1];
+    templ.swizzle_b = swizzle[2];
+    templ.swizzle_a = swizzle[3];
+    templ.target = resource->target;
+
+    This->view[sRGB] = pipe->create_sampler_view(pipe, resource, &templ);
+
+    DBG("sampler view = %p(resource = %p)\n", This->view[sRGB], resource);
+
+    return This->view ? D3D_OK : D3DERR_DRIVERINTERNALERROR;
+}
+
+void WINAPI
+NineBaseTexture9_PreLoad( struct NineBaseTexture9 *This )
+{
+    if (This->dirty && This->base.pool == D3DPOOL_MANAGED)
+        NineBaseTexture9_UploadSelf(This);
+}
+
+#ifdef DEBUG
+void
+NineBaseTexture9_Dump( struct NineBaseTexture9 *This )
+{
+    DBG("\nNineBaseTexture9(%p->%p/%p): Pool=%s Type=%s Usage=%s\n"
+        "Format=%s Dims=%ux%ux%u/%u LastLevel=%u Lod=%u(%u)\n", This,
+        This->base.resource, This->base.data,
+        nine_D3DPOOL_to_str(This->base.pool),
+        nine_D3DRTYPE_to_str(This->base.type),
+        nine_D3DUSAGE_to_str(This->base.usage),
+        d3dformat_to_string(This->format),
+        This->base.info.width0, This->base.info.height0, This->base.info.depth0,
+        This->base.info.array_size, This->base.info.last_level,
+        This->lod, This->lod_resident);
+}
+#endif /* DEBUG */
diff --git a/src/gallium/state_trackers/nine/basetexture9.h b/src/gallium/state_trackers/nine/basetexture9.h
new file mode 100644 (file)
index 0000000..d615376
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _NINE_BASETEXTURE9_H_
+#define _NINE_BASETEXTURE9_H_
+
+#include "resource9.h"
+#include "util/u_inlines.h"
+#include "util/u_double_list.h"
+
+struct NineBaseTexture9
+{
+    struct NineResource9 base;
+    struct list_head list;
+
+    /* g3d */
+    struct pipe_context *pipe;
+    struct pipe_sampler_view *view[2]; /* linear and sRGB */
+
+    D3DFORMAT format;
+
+    D3DTEXTUREFILTERTYPE mipfilter;
+    DWORD lod;
+    DWORD lod_resident;
+
+    int16_t bind_count; /* to Device9->state.texture */
+
+    boolean shadow;
+    uint8_t pstype; /* 0: 2D, 1: 1D, 2: CUBE, 3: 3D */
+
+    boolean dirty;
+    boolean dirty_mip;
+};
+static INLINE struct NineBaseTexture9 *
+NineBaseTexture9( void *data )
+{
+    return (struct NineBaseTexture9 *)data;
+}
+
+HRESULT
+NineBaseTexture9_ctor( struct NineBaseTexture9 *This,
+                       struct NineUnknownParams *pParams,
+                       D3DRESOURCETYPE Type,
+                       D3DPOOL Pool );
+
+void
+NineBaseTexture9_dtor( struct NineBaseTexture9 *This );
+
+DWORD WINAPI
+NineBaseTexture9_SetLOD( struct NineBaseTexture9 *This,
+                         DWORD LODNew );
+
+DWORD WINAPI
+NineBaseTexture9_GetLOD( struct NineBaseTexture9 *This );
+
+DWORD WINAPI
+NineBaseTexture9_GetLevelCount( struct NineBaseTexture9 *This );
+
+HRESULT WINAPI
+NineBaseTexture9_SetAutoGenFilterType( struct NineBaseTexture9 *This,
+                                       D3DTEXTUREFILTERTYPE FilterType );
+
+D3DTEXTUREFILTERTYPE WINAPI
+NineBaseTexture9_GetAutoGenFilterType( struct NineBaseTexture9 *This );
+
+void WINAPI
+NineBaseTexture9_GenerateMipSubLevels( struct NineBaseTexture9 *This );
+
+void WINAPI
+NineBaseTexture9_PreLoad( struct NineBaseTexture9 *This );
+
+/* For D3DPOOL_MANAGED only (after SetLOD change): */
+HRESULT
+NineBaseTexture9_CreatePipeResource( struct NineBaseTexture9 *This,
+                                     BOOL CopyData );
+
+/* For D3DPOOL_MANAGED only: */
+HRESULT
+NineBaseTexture9_UploadSelf( struct NineBaseTexture9 *This );
+
+HRESULT
+NineBaseTexture9_UpdateSamplerView( struct NineBaseTexture9 *This,
+                                    const int sRGB );
+
+static INLINE void
+NineBaseTexture9_Validate( struct NineBaseTexture9 *This )
+{
+    DBG_FLAG(DBG_BASETEXTURE, "This=%p dirty=%i dirty_mip=%i lod=%u/%u\n",
+             This, This->dirty, This->dirty_mip, This->lod, This->lod_resident);
+    if ((This->base.pool == D3DPOOL_MANAGED) &&
+        (This->dirty || This->lod != This->lod_resident))
+        NineBaseTexture9_UploadSelf(This);
+    if (This->dirty_mip)
+        NineBaseTexture9_GenerateMipSubLevels(This);
+}
+
+static INLINE struct pipe_sampler_view *
+NineBaseTexture9_GetSamplerView( struct NineBaseTexture9 *This, const int sRGB )
+{
+    if (!This->view[sRGB])
+        NineBaseTexture9_UpdateSamplerView(This, sRGB);
+    return This->view[sRGB];
+}
+
+#ifdef DEBUG
+void
+NineBaseTexture9_Dump( struct NineBaseTexture9 *This );
+#else
+static INLINE void
+NineBaseTexture9_Dump( struct NineBaseTexture9 *This ) { }
+#endif
+
+#define BASETEX_REGISTER_UPDATE(t) do { \
+    if (((t)->dirty | ((t)->dirty_mip)) && (t)->base.base.bind) \
+        if (LIST_IS_EMPTY(&(t)->list)) \
+            list_add(&(t)->list, &(t)->base.base.device->update_textures); \
+    } while(0)
+
+#endif /* _NINE_BASETEXTURE9_H_ */
diff --git a/src/gallium/state_trackers/nine/cryptosession9.c b/src/gallium/state_trackers/nine/cryptosession9.c
new file mode 100644 (file)
index 0000000..2622f2b
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "cryptosession9.h"
+
+#define DBG_CHANNEL DBG_CRYPTOSESSION
+
+HRESULT WINAPI
+NineCryptoSession9_GetCertificateSize( struct NineCryptoSession9 *This,
+                                       UINT *pCertificateSize )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineCryptoSession9_GetCertificate( struct NineCryptoSession9 *This,
+                                   UINT CertifacteSize,
+                                   BYTE *ppCertificate )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineCryptoSession9_NegotiateKeyExchange( struct NineCryptoSession9 *This,
+                                         UINT DataSize,
+                                         void *pData )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineCryptoSession9_EncryptionBlt( struct NineCryptoSession9 *This,
+                                  IDirect3DSurface9 *pSrcSurface,
+                                  IDirect3DSurface9 *pDstSurface,
+                                  UINT DstSurfaceSize,
+                                  void *pIV )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineCryptoSession9_DecryptionBlt( struct NineCryptoSession9 *This,
+                                  IDirect3DSurface9 *pSrcSurface,
+                                  IDirect3DSurface9 *pDstSurface,
+                                  UINT SrcSurfaceSize,
+                                  D3DENCRYPTED_BLOCK_INFO *pEncryptedBlockInfo,
+                                  void *pContentKey,
+                                  void *pIV )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineCryptoSession9_GetSurfacePitch( struct NineCryptoSession9 *This,
+                                    IDirect3DSurface9 *pSrcSurface,
+                                    UINT *pSurfacePitch )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineCryptoSession9_StartSessionKeyRefresh( struct NineCryptoSession9 *This,
+                                           void *pRandomNumber,
+                                           UINT RandomNumberSize )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineCryptoSession9_FinishSessionKeyRefresh( struct NineCryptoSession9 *This )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineCryptoSession9_GetEncryptionBltKey( struct NineCryptoSession9 *This,
+                                        void *pReadbackKey,
+                                        UINT KeySize )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+IDirect3DCryptoSession9Vtbl NineCryptoSession9_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)NineCryptoSession9_GetCertificateSize,
+    (void *)NineCryptoSession9_GetCertificate,
+    (void *)NineCryptoSession9_NegotiateKeyExchange,
+    (void *)NineCryptoSession9_EncryptionBlt,
+    (void *)NineCryptoSession9_DecryptionBlt,
+    (void *)NineCryptoSession9_GetSurfacePitch,
+    (void *)NineCryptoSession9_StartSessionKeyRefresh,
+    (void *)NineCryptoSession9_FinishSessionKeyRefresh,
+    (void *)NineCryptoSession9_GetEncryptionBltKey
+};
diff --git a/src/gallium/state_trackers/nine/cryptosession9.h b/src/gallium/state_trackers/nine/cryptosession9.h
new file mode 100644 (file)
index 0000000..660d246
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _NINE_CRYPTOSESSION9_H_
+#define _NINE_CRYPTOSESSION9_H_
+
+#include "iunknown.h"
+
+struct NineCryptoSession9
+{
+    struct NineUnknown base;
+};
+static INLINE struct NineCryptoSession9 *
+NineCryptoSession9( void *data )
+{
+    return (struct NineCryptoSession9 *)data;
+}
+
+HRESULT WINAPI
+NineCryptoSession9_GetCertificateSize( struct NineCryptoSession9 *This,
+                                       UINT *pCertificateSize );
+
+HRESULT WINAPI
+NineCryptoSession9_GetCertificate( struct NineCryptoSession9 *This,
+                                   UINT CertifacteSize,
+                                   BYTE *ppCertificate );
+
+HRESULT WINAPI
+NineCryptoSession9_NegotiateKeyExchange( struct NineCryptoSession9 *This,
+                                         UINT DataSize,
+                                         void *pData );
+
+HRESULT WINAPI
+NineCryptoSession9_EncryptionBlt( struct NineCryptoSession9 *This,
+                                  IDirect3DSurface9 *pSrcSurface,
+                                  IDirect3DSurface9 *pDstSurface,
+                                  UINT DstSurfaceSize,
+                                  void *pIV );
+
+HRESULT WINAPI
+NineCryptoSession9_DecryptionBlt( struct NineCryptoSession9 *This,
+                                  IDirect3DSurface9 *pSrcSurface,
+                                  IDirect3DSurface9 *pDstSurface,
+                                  UINT SrcSurfaceSize,
+                                  D3DENCRYPTED_BLOCK_INFO *pEncryptedBlockInfo,
+                                  void *pContentKey,
+                                  void *pIV );
+
+HRESULT WINAPI
+NineCryptoSession9_GetSurfacePitch( struct NineCryptoSession9 *This,
+                                    IDirect3DSurface9 *pSrcSurface,
+                                    UINT *pSurfacePitch );
+
+HRESULT WINAPI
+NineCryptoSession9_StartSessionKeyRefresh( struct NineCryptoSession9 *This,
+                                           void *pRandomNumber,
+                                           UINT RandomNumberSize );
+
+HRESULT WINAPI
+NineCryptoSession9_FinishSessionKeyRefresh( struct NineCryptoSession9 *This );
+
+HRESULT WINAPI
+NineCryptoSession9_GetEncryptionBltKey( struct NineCryptoSession9 *This,
+                                        void *pReadbackKey,
+                                        UINT KeySize );
+
+#endif /* _NINE_CRYPTOSESSION9_H_ */
diff --git a/src/gallium/state_trackers/nine/cubetexture9.c b/src/gallium/state_trackers/nine/cubetexture9.c
new file mode 100644 (file)
index 0000000..77802e7
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "device9.h"
+#include "cubetexture9.h"
+#include "nine_helpers.h"
+#include "nine_pipe.h"
+
+#define DBG_CHANNEL DBG_CUBETEXTURE
+
+
+static HRESULT
+NineCubeTexture9_ctor( struct NineCubeTexture9 *This,
+                       struct NineUnknownParams *pParams,
+                       UINT EdgeLength, UINT Levels,
+                       DWORD Usage,
+                       D3DFORMAT Format,
+                       D3DPOOL Pool,
+                       HANDLE *pSharedHandle )
+{
+    struct pipe_resource *info = &This->base.base.info;
+    unsigned i;
+    D3DSURFACE_DESC sfdesc;
+    HRESULT hr;
+
+    user_assert(!(Usage & D3DUSAGE_AUTOGENMIPMAP) ||
+                (Pool != D3DPOOL_SYSTEMMEM && Levels <= 1), D3DERR_INVALIDCALL);
+
+    user_assert(!pSharedHandle, D3DERR_INVALIDCALL); /* TODO */
+
+    if (Usage & D3DUSAGE_AUTOGENMIPMAP)
+        Levels = 0;
+
+    This->base.format = Format;
+    This->base.base.usage = Usage;
+
+    info->screen = pParams->device->screen;
+    info->target = PIPE_TEXTURE_CUBE;
+    info->format = d3d9_to_pipe_format(Format);
+    info->width0 = EdgeLength;
+    info->height0 = EdgeLength;
+    info->depth0 = 1;
+    if (Levels)
+        info->last_level = Levels - 1;
+    else
+        info->last_level = util_logbase2(EdgeLength);
+    info->array_size = 6;
+    info->nr_samples = 0;
+    info->bind = PIPE_BIND_SAMPLER_VIEW;
+    info->usage = PIPE_USAGE_DEFAULT;
+    info->flags = 0;
+
+    if (Usage & D3DUSAGE_RENDERTARGET)
+        info->bind |= PIPE_BIND_RENDER_TARGET;
+    if (Usage & D3DUSAGE_DEPTHSTENCIL)
+        info->bind |= PIPE_BIND_DEPTH_STENCIL;
+
+    if (Usage & D3DUSAGE_DYNAMIC) {
+        info->usage = PIPE_USAGE_DYNAMIC;
+        info->bind |=
+            PIPE_BIND_TRANSFER_READ |
+            PIPE_BIND_TRANSFER_WRITE;
+    }
+
+    This->surfaces = CALLOC(6 * (info->last_level + 1), sizeof(*This->surfaces));
+    if (!This->surfaces)
+        return E_OUTOFMEMORY;
+
+    hr = NineBaseTexture9_ctor(&This->base, pParams, D3DRTYPE_CUBETEXTURE,
+                               Pool);
+    if (FAILED(hr))
+        return hr;
+    This->base.pstype = 2;
+
+    /* Create all the surfaces right away.
+     * They manage backing storage, and transfers (LockRect) are deferred
+     * to them.
+     */
+    sfdesc.Format = Format;
+    sfdesc.Type = D3DRTYPE_SURFACE;
+    sfdesc.Usage = Usage;
+    sfdesc.Pool = Pool;
+    sfdesc.MultiSampleType = D3DMULTISAMPLE_NONE;
+    sfdesc.MultiSampleQuality = 0;
+    for (i = 0; i < (info->last_level + 1) * 6; ++i) {
+        sfdesc.Width = sfdesc.Height = u_minify(EdgeLength, i / 6);
+
+        hr = NineSurface9_new(This->base.base.base.device, NineUnknown(This),
+                              This->base.base.resource, D3DRTYPE_CUBETEXTURE,
+                              i / 6, i % 6,
+                              &sfdesc, &This->surfaces[i]);
+        if (FAILED(hr))
+            return hr;
+    }
+    for (i = 0; i < 6; ++i) /* width = 0 means empty, depth stays 1 */
+        This->dirty_rect[i].depth = 1;
+
+    return D3D_OK;
+}
+
+static void
+NineCubeTexture9_dtor( struct NineCubeTexture9 *This )
+{
+    unsigned i;
+
+    DBG("This=%p\n", This);
+
+    if (This->surfaces) {
+        for (i = 0; i < This->base.base.info.last_level * 6; ++i)
+            NineUnknown_Destroy(&This->surfaces[i]->base.base);
+        FREE(This->surfaces);
+    }
+
+    NineBaseTexture9_dtor(&This->base);
+}
+
+HRESULT WINAPI
+NineCubeTexture9_GetLevelDesc( struct NineCubeTexture9 *This,
+                               UINT Level,
+                               D3DSURFACE_DESC *pDesc )
+{
+    user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL);
+    user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP),
+                D3DERR_INVALIDCALL);
+
+    *pDesc = This->surfaces[Level]->desc;
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineCubeTexture9_GetCubeMapSurface( struct NineCubeTexture9 *This,
+                                    D3DCUBEMAP_FACES FaceType,
+                                    UINT Level,
+                                    IDirect3DSurface9 **ppCubeMapSurface )
+{
+    const unsigned s = Level * 6 + FaceType;
+
+    user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL);
+    user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP),
+                D3DERR_INVALIDCALL);
+    user_assert(FaceType < 6, D3DERR_INVALIDCALL);
+
+    NineUnknown_AddRef(NineUnknown(This->surfaces[s]));
+    *ppCubeMapSurface = (IDirect3DSurface9 *)This->surfaces[s];
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineCubeTexture9_LockRect( struct NineCubeTexture9 *This,
+                           D3DCUBEMAP_FACES FaceType,
+                           UINT Level,
+                           D3DLOCKED_RECT *pLockedRect,
+                           const RECT *pRect,
+                           DWORD Flags )
+{
+    const unsigned s = Level * 6 + FaceType;
+
+    user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL);
+    user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP),
+                D3DERR_INVALIDCALL);
+    user_assert(FaceType < 6, D3DERR_INVALIDCALL);
+
+    return NineSurface9_LockRect(This->surfaces[s], pLockedRect, pRect, Flags);
+}
+
+HRESULT WINAPI
+NineCubeTexture9_UnlockRect( struct NineCubeTexture9 *This,
+                             D3DCUBEMAP_FACES FaceType,
+                             UINT Level )
+{
+    const unsigned s = Level * 6 + FaceType;
+
+    user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL);
+    user_assert(FaceType < 6, D3DERR_INVALIDCALL);
+
+    return NineSurface9_UnlockRect(This->surfaces[s]);
+}
+
+HRESULT WINAPI
+NineCubeTexture9_AddDirtyRect( struct NineCubeTexture9 *This,
+                               D3DCUBEMAP_FACES FaceType,
+                               const RECT *pDirtyRect )
+{
+    user_assert(FaceType < 6, D3DERR_INVALIDCALL);
+
+    if (This->base.base.pool != D3DPOOL_MANAGED) {
+        if (This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP)
+            This->base.dirty_mip = TRUE;
+        return D3D_OK;
+    }
+    This->base.dirty = TRUE;
+
+    BASETEX_REGISTER_UPDATE(&This->base);
+
+    if (!pDirtyRect) {
+        u_box_origin_2d(This->base.base.info.width0,
+                        This->base.base.info.height0,
+                        &This->dirty_rect[FaceType]);
+    } else {
+        struct pipe_box box;
+        rect_to_pipe_box_clamp(&box, pDirtyRect);
+        u_box_union_2d(&This->dirty_rect[FaceType], &This->dirty_rect[FaceType],
+                       &box);
+    }
+    return D3D_OK;
+}
+
+IDirect3DCubeTexture9Vtbl NineCubeTexture9_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */
+    (void *)NineResource9_SetPrivateData,
+    (void *)NineResource9_GetPrivateData,
+    (void *)NineResource9_FreePrivateData,
+    (void *)NineResource9_SetPriority,
+    (void *)NineResource9_GetPriority,
+    (void *)NineBaseTexture9_PreLoad,
+    (void *)NineResource9_GetType,
+    (void *)NineBaseTexture9_SetLOD,
+    (void *)NineBaseTexture9_GetLOD,
+    (void *)NineBaseTexture9_GetLevelCount,
+    (void *)NineBaseTexture9_SetAutoGenFilterType,
+    (void *)NineBaseTexture9_GetAutoGenFilterType,
+    (void *)NineBaseTexture9_GenerateMipSubLevels,
+    (void *)NineCubeTexture9_GetLevelDesc,
+    (void *)NineCubeTexture9_GetCubeMapSurface,
+    (void *)NineCubeTexture9_LockRect,
+    (void *)NineCubeTexture9_UnlockRect,
+    (void *)NineCubeTexture9_AddDirtyRect
+};
+
+static const GUID *NineCubeTexture9_IIDs[] = {
+    &IID_IDirect3DCubeTexture9,
+    &IID_IDirect3DBaseTexture9,
+    &IID_IDirect3DResource9,
+    &IID_IUnknown,
+    NULL
+};
+
+HRESULT
+NineCubeTexture9_new( struct NineDevice9 *pDevice,
+                      UINT EdgeLength, UINT Levels,
+                      DWORD Usage,
+                      D3DFORMAT Format,
+                      D3DPOOL Pool,
+                      struct NineCubeTexture9 **ppOut,
+                      HANDLE *pSharedHandle )
+{
+    NINE_DEVICE_CHILD_NEW(CubeTexture9, ppOut, pDevice,
+                          EdgeLength, Levels,
+                          Usage, Format, Pool, pSharedHandle);
+}
diff --git a/src/gallium/state_trackers/nine/cubetexture9.h b/src/gallium/state_trackers/nine/cubetexture9.h
new file mode 100644 (file)
index 0000000..e8594d3
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _NINE_CUBETEXTURE9_H_
+#define _NINE_CUBETEXTURE9_H_
+
+#include "basetexture9.h"
+#include "surface9.h"
+
+struct NineCubeTexture9
+{
+    struct NineBaseTexture9 base;
+    struct NineSurface9 **surfaces;
+    struct pipe_box dirty_rect[6]; /* covers all mip levels */
+};
+static INLINE struct NineCubeTexture9 *
+NineCubeTexture9( void *data )
+{
+    return (struct NineCubeTexture9 *)data;
+}
+
+HRESULT
+NineCubeTexture9_new( struct NineDevice9 *pDevice,
+                      UINT EdgeLength, UINT Levels,
+                      DWORD Usage,
+                      D3DFORMAT Format,
+                      D3DPOOL Pool,
+                      struct NineCubeTexture9 **ppOut,
+                      HANDLE *pSharedHandle );
+
+HRESULT WINAPI
+NineCubeTexture9_GetLevelDesc( struct NineCubeTexture9 *This,
+                               UINT Level,
+                               D3DSURFACE_DESC *pDesc );
+
+HRESULT WINAPI
+NineCubeTexture9_GetCubeMapSurface( struct NineCubeTexture9 *This,
+                                    D3DCUBEMAP_FACES FaceType,
+                                    UINT Level,
+                                    IDirect3DSurface9 **ppCubeMapSurface );
+
+HRESULT WINAPI
+NineCubeTexture9_LockRect( struct NineCubeTexture9 *This,
+                           D3DCUBEMAP_FACES FaceType,
+                           UINT Level,
+                           D3DLOCKED_RECT *pLockedRect,
+                           const RECT *pRect,
+                           DWORD Flags );
+
+HRESULT WINAPI
+NineCubeTexture9_UnlockRect( struct NineCubeTexture9 *This,
+                             D3DCUBEMAP_FACES FaceType,
+                             UINT Level );
+
+HRESULT WINAPI
+NineCubeTexture9_AddDirtyRect( struct NineCubeTexture9 *This,
+                               D3DCUBEMAP_FACES FaceType,
+                               const RECT *pDirtyRect );
+
+#endif /* _NINE_CUBETEXTURE9_H_ */
diff --git a/src/gallium/state_trackers/nine/device9.c b/src/gallium/state_trackers/nine/device9.c
new file mode 100644 (file)
index 0000000..7d2142d
--- /dev/null
@@ -0,0 +1,3458 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "device9.h"
+#include "stateblock9.h"
+#include "surface9.h"
+#include "swapchain9.h"
+#include "swapchain9ex.h"
+#include "indexbuffer9.h"
+#include "vertexbuffer9.h"
+#include "vertexdeclaration9.h"
+#include "vertexshader9.h"
+#include "pixelshader9.h"
+#include "query9.h"
+#include "texture9.h"
+#include "cubetexture9.h"
+#include "volumetexture9.h"
+#include "nine_helpers.h"
+#include "nine_pipe.h"
+#include "nine_ff.h"
+#include "nine_dump.h"
+
+#include "pipe/p_screen.h"
+#include "pipe/p_context.h"
+#include "util/u_math.h"
+#include "util/u_inlines.h"
+#include "util/u_hash_table.h"
+#include "util/u_format.h"
+#include "util/u_surface.h"
+#include "util/u_upload_mgr.h"
+#include "hud/hud_context.h"
+
+#include "cso_cache/cso_context.h"
+
+#define DBG_CHANNEL DBG_DEVICE
+
+static void
+NineDevice9_SetDefaultState( struct NineDevice9 *This, boolean is_reset )
+{
+    struct NineSurface9 *refSurf = NULL;
+
+    assert(!This->is_recording);
+
+    nine_state_set_defaults(&This->state, &This->caps, is_reset);
+
+    This->state.viewport.X = 0;
+    This->state.viewport.Y = 0;
+    This->state.viewport.Width = 0;
+    This->state.viewport.Height = 0;
+
+    This->state.scissor.minx = 0;
+    This->state.scissor.miny = 0;
+    This->state.scissor.maxx = 0xffff;
+    This->state.scissor.maxy = 0xffff;
+
+    if (This->nswapchains && This->swapchains[0]->params.BackBufferCount)
+        refSurf = This->swapchains[0]->buffers[0];
+
+    if (refSurf) {
+        This->state.viewport.Width = refSurf->desc.Width;
+        This->state.viewport.Height = refSurf->desc.Height;
+        This->state.scissor.maxx = refSurf->desc.Width;
+        This->state.scissor.maxy = refSurf->desc.Height;
+    }
+
+    if (This->nswapchains && This->swapchains[0]->params.EnableAutoDepthStencil)
+        This->state.rs[D3DRS_ZENABLE] = TRUE;
+    if (This->state.rs[D3DRS_ZENABLE])
+        NineDevice9_SetDepthStencilSurface(
+            This, (IDirect3DSurface9 *)This->swapchains[0]->zsbuf);
+}
+
+void
+NineDevice9_RestoreNonCSOState( struct NineDevice9 *This, unsigned mask )
+{
+    struct pipe_context *pipe = This->pipe;
+
+    if (mask & 0x1) {
+        struct pipe_constant_buffer cb;
+        cb.buffer_offset = 0;
+
+        if (This->prefer_user_constbuf) {
+            cb.buffer = NULL;
+            cb.user_buffer = This->state.vs_const_f;
+        } else {
+            cb.buffer = This->constbuf_vs;
+            cb.user_buffer = NULL;
+        }
+        cb.buffer_size = This->constbuf_vs->width0;
+        pipe->set_constant_buffer(pipe, PIPE_SHADER_VERTEX, 0, &cb);
+
+        if (This->prefer_user_constbuf) {
+            cb.user_buffer = This->state.ps_const_f;
+        } else {
+            cb.buffer = This->constbuf_ps;
+        }
+        cb.buffer_size = This->constbuf_ps->width0;
+        pipe->set_constant_buffer(pipe, PIPE_SHADER_FRAGMENT, 0, &cb);
+    }
+
+    if (mask & 0x2) {
+        struct pipe_poly_stipple stipple;
+        memset(&stipple, ~0, sizeof(stipple));
+        pipe->set_polygon_stipple(pipe, &stipple);
+    }
+
+    This->state.changed.group = NINE_STATE_ALL;
+    This->state.changed.vtxbuf = (1ULL << This->caps.MaxStreams) - 1;
+    This->state.changed.ucp = (1 << PIPE_MAX_CLIP_PLANES) - 1;
+    This->state.changed.texture = NINE_PS_SAMPLERS_MASK | NINE_VS_SAMPLERS_MASK;
+}
+
+#define GET_PCAP(n) pScreen->get_param(pScreen, PIPE_CAP_##n)
+HRESULT
+NineDevice9_ctor( struct NineDevice9 *This,
+                  struct NineUnknownParams *pParams,
+                  struct pipe_screen *pScreen,
+                  D3DDEVICE_CREATION_PARAMETERS *pCreationParameters,
+                  D3DCAPS9 *pCaps,
+                  D3DPRESENT_PARAMETERS *pPresentationParameters,
+                  IDirect3D9 *pD3D9,
+                  ID3DPresentGroup *pPresentationGroup,
+                  struct d3dadapter9_context *pCTX )
+{
+    unsigned i;
+    HRESULT hr = NineUnknown_ctor(&This->base, pParams);
+    if (FAILED(hr)) { return hr; }
+
+    list_inithead(&This->update_textures);
+
+    This->screen = pScreen;
+    This->caps = *pCaps;
+    This->d3d9 = pD3D9;
+    This->params = *pCreationParameters;
+    This->present = pPresentationGroup;
+    IDirect3D9_AddRef(This->d3d9);
+    ID3DPresentGroup_AddRef(This->present);
+
+    This->pipe = This->screen->context_create(This->screen, NULL);
+    if (!This->pipe) { return E_OUTOFMEMORY; } /* guess */
+
+    This->cso = cso_create_context(This->pipe);
+    if (!This->cso) { return E_OUTOFMEMORY; } /* also a guess */
+
+    /* Create first, it messes up our state. */
+    This->hud = hud_create(This->pipe, This->cso); /* NULL result is fine */
+
+    /* create implicit swapchains */
+    This->nswapchains = ID3DPresentGroup_GetMultiheadCount(This->present);
+    This->swapchains = CALLOC(This->nswapchains,
+                              sizeof(struct NineSwapChain9 *));
+    if (!This->swapchains) { return E_OUTOFMEMORY; }
+
+    for (i = 0; i < This->nswapchains; ++i) {
+        ID3DPresent *present;
+
+        hr = ID3DPresentGroup_GetPresent(This->present, i, &present);
+        if (FAILED(hr))
+            return hr;
+
+        if (This->ex) {
+            D3DDISPLAYMODEEX *mode = NULL;
+            struct NineSwapChain9Ex **ret =
+                (struct NineSwapChain9Ex **)&This->swapchains[i];
+
+            if (This->pFullscreenDisplayMode) mode = &(This->pFullscreenDisplayMode[i]);
+            /* when this is a Device9Ex, it should create SwapChain9Exs */
+            hr = NineSwapChain9Ex_new(This, TRUE, present,
+                                      &pPresentationParameters[i], pCTX,
+                                      This->params.hFocusWindow, mode, ret);
+        } else {
+            hr = NineSwapChain9_new(This, TRUE, present,
+                                    &pPresentationParameters[i], pCTX,
+                                    This->params.hFocusWindow,
+                                    &This->swapchains[i]);
+        }
+
+        ID3DPresent_Release(present);
+        if (FAILED(hr))
+            return hr;
+        NineUnknown_ConvertRefToBind(NineUnknown(This->swapchains[i]));
+
+        hr = NineSwapChain9_GetBackBuffer(This->swapchains[i], 0,
+                                          D3DBACKBUFFER_TYPE_MONO,
+                                          (IDirect3DSurface9 **)
+                                          &This->state.rt[i]);
+        if (FAILED(hr))
+            return hr;
+        NineUnknown_ConvertRefToBind(NineUnknown(This->state.rt[i]));
+    }
+
+    This->cursor.software = FALSE;
+    This->cursor.hotspot.x = -1;
+    This->cursor.hotspot.y = -1;
+    {
+        struct pipe_resource tmpl;
+        tmpl.target = PIPE_TEXTURE_2D;
+        tmpl.format = PIPE_FORMAT_R8G8B8A8_UNORM;
+        tmpl.width0 = 64;
+        tmpl.height0 = 64;
+        tmpl.depth0 = 1;
+        tmpl.array_size = 1;
+        tmpl.last_level = 0;
+        tmpl.nr_samples = 0;
+        tmpl.usage = PIPE_USAGE_DEFAULT;
+        tmpl.bind = PIPE_BIND_CURSOR | PIPE_BIND_SAMPLER_VIEW;
+        tmpl.flags = 0;
+
+        This->cursor.image = pScreen->resource_create(pScreen, &tmpl);
+        if (!This->cursor.image)
+            return D3DERR_OUTOFVIDEOMEMORY;
+    }
+
+    /* Create constant buffers. */
+    {
+        struct pipe_resource tmpl;
+        unsigned max_const_vs, max_const_ps;
+
+        max_const_vs = _min(pScreen->get_shader_param(pScreen, PIPE_SHADER_VERTEX,
+                                PIPE_SHADER_CAP_MAX_CONST_BUFFER_SIZE) /
+                                sizeof(float[4]),
+                           NINE_MAX_CONST_ALL);
+        max_const_ps = _min(pScreen->get_shader_param(pScreen, PIPE_SHADER_FRAGMENT,
+                                PIPE_SHADER_CAP_MAX_CONST_BUFFER_SIZE) /
+                                sizeof(float[4]),
+                            NINE_MAX_CONST_ALL);
+
+        This->max_vs_const_f = max_const_vs -
+                               (NINE_MAX_CONST_I + NINE_MAX_CONST_B / 4);
+        This->max_ps_const_f = max_const_ps -
+                               (NINE_MAX_CONST_I + NINE_MAX_CONST_B / 4);
+
+        /* Include space for I,B constants for user constbuf. */
+        This->state.vs_const_f = CALLOC(NINE_MAX_CONST_ALL, sizeof(float[4]));
+        This->state.ps_const_f = CALLOC(NINE_MAX_CONST_ALL, sizeof(float[4]));
+        if (!This->state.vs_const_f || !This->state.ps_const_f)
+            return E_OUTOFMEMORY;
+
+        if (strstr(pScreen->get_name(pScreen), "AMD") ||
+            strstr(pScreen->get_name(pScreen), "ATI"))
+            This->prefer_user_constbuf = TRUE;
+
+        tmpl.target = PIPE_BUFFER;
+        tmpl.format = PIPE_FORMAT_R8_UNORM;
+        tmpl.height0 = 1;
+        tmpl.depth0 = 1;
+        tmpl.array_size = 1;
+        tmpl.last_level = 0;
+        tmpl.nr_samples = 0;
+        tmpl.usage = PIPE_USAGE_DYNAMIC;
+        tmpl.bind = PIPE_BIND_CONSTANT_BUFFER;
+        tmpl.flags = 0;
+
+        tmpl.width0 = max_const_vs * sizeof(float[4]);
+        This->constbuf_vs = pScreen->resource_create(pScreen, &tmpl);
+
+        tmpl.width0 = max_const_ps * sizeof(float[4]);
+        This->constbuf_ps = pScreen->resource_create(pScreen, &tmpl);
+
+        if (!This->constbuf_vs || !This->constbuf_ps)
+            return E_OUTOFMEMORY;
+    }
+
+    This->vs_bool_true = pScreen->get_shader_param(pScreen,
+        PIPE_SHADER_VERTEX,
+        PIPE_SHADER_CAP_INTEGERS) ? 0xFFFFFFFF : fui(1.0f);
+    This->ps_bool_true = pScreen->get_shader_param(pScreen,
+        PIPE_SHADER_FRAGMENT,
+        PIPE_SHADER_CAP_INTEGERS) ? 0xFFFFFFFF : fui(1.0f);
+
+    /* Allocate upload helper for drivers that suck (from st pov ;). */
+    {
+        unsigned bind = 0;
+
+        This->driver_caps.user_vbufs = GET_PCAP(USER_VERTEX_BUFFERS);
+        This->driver_caps.user_ibufs = GET_PCAP(USER_INDEX_BUFFERS);
+
+        if (!This->driver_caps.user_vbufs) bind |= PIPE_BIND_VERTEX_BUFFER;
+        if (!This->driver_caps.user_ibufs) bind |= PIPE_BIND_INDEX_BUFFER;
+        if (bind)
+            This->upload = u_upload_create(This->pipe, 1 << 20, 4, bind);
+    }
+
+    This->driver_caps.window_space_position_support = GET_PCAP(TGSI_VS_WINDOW_SPACE_POSITION);
+
+    nine_ff_init(This); /* initialize fixed function code */
+
+    NineDevice9_SetDefaultState(This, FALSE);
+    NineDevice9_RestoreNonCSOState(This, ~0);
+
+    This->update = &This->state;
+    nine_update_state(This, ~0);
+
+    /* Is just used to pass the parameter from NineDevice9Ex_ctor */
+    This->pFullscreenDisplayMode = NULL;
+
+    ID3DPresentGroup_Release(This->present);
+
+    return D3D_OK;
+}
+#undef GET_PCAP
+
+void
+NineDevice9_dtor( struct NineDevice9 *This )
+{
+    unsigned i;
+
+    DBG("This=%p\n", This);
+
+    if (This->pipe && This->cso)
+        nine_pipe_context_clear(This);
+    nine_ff_fini(This);
+    nine_state_clear(&This->state, TRUE);
+
+    if (This->upload)
+        u_upload_destroy(This->upload);
+
+    nine_bind(&This->record, NULL);
+
+    pipe_resource_reference(&This->constbuf_vs, NULL);
+    pipe_resource_reference(&This->constbuf_ps, NULL);
+    FREE(This->state.vs_const_f);
+    FREE(This->state.ps_const_f);
+
+    if (This->swapchains) {
+        for (i = 0; i < This->nswapchains; ++i)
+            NineUnknown_Unbind(NineUnknown(This->swapchains[i]));
+        FREE(This->swapchains);
+    }
+
+    /* state stuff */
+    if (This->pipe) {
+        if (This->cso) {
+            cso_release_all(This->cso);
+            cso_destroy_context(This->cso);
+        }
+        if (This->pipe->destroy) { This->pipe->destroy(This->pipe); }
+    }
+
+    if (This->present) { ID3DPresentGroup_Release(This->present); }
+    if (This->d3d9) { IDirect3D9_Release(This->d3d9); }
+
+    NineUnknown_dtor(&This->base);
+}
+
+struct pipe_screen *
+NineDevice9_GetScreen( struct NineDevice9 *This )
+{
+    return This->screen;
+}
+
+struct pipe_context *
+NineDevice9_GetPipe( struct NineDevice9 *This )
+{
+    return This->pipe;
+}
+
+struct cso_context *
+NineDevice9_GetCSO( struct NineDevice9 *This )
+{
+    return This->cso;
+}
+
+const D3DCAPS9 *
+NineDevice9_GetCaps( struct NineDevice9 *This )
+{
+    return &This->caps;
+}
+
+static INLINE void
+NineDevice9_PauseRecording( struct NineDevice9 *This )
+{
+    if (This->record) {
+        This->update = &This->state;
+        This->is_recording = FALSE;
+    }
+}
+
+static INLINE void
+NineDevice9_ResumeRecording( struct NineDevice9 *This )
+{
+    if (This->record) {
+        This->update = &This->record->state;
+        This->is_recording = TRUE;
+    }
+}
+
+HRESULT WINAPI
+NineDevice9_TestCooperativeLevel( struct NineDevice9 *This )
+{
+    return D3D_OK; /* TODO */
+}
+
+UINT WINAPI
+NineDevice9_GetAvailableTextureMem( struct NineDevice9 *This )
+{
+    return This->screen->get_param(This->screen, PIPE_CAP_VIDEO_MEMORY);
+}
+
+HRESULT WINAPI
+NineDevice9_EvictManagedResources( struct NineDevice9 *This )
+{
+    /* We don't really need to do anything here, but might want to free up
+     * the GPU virtual address space by killing pipe_resources.
+     */
+    STUB(D3D_OK);
+}
+
+HRESULT WINAPI
+NineDevice9_GetDirect3D( struct NineDevice9 *This,
+                         IDirect3D9 **ppD3D9 )
+{
+    user_assert(ppD3D9 != NULL, E_POINTER);
+    IDirect3D9_AddRef(This->d3d9);
+    *ppD3D9 = This->d3d9;
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_GetDeviceCaps( struct NineDevice9 *This,
+                           D3DCAPS9 *pCaps )
+{
+    user_assert(pCaps != NULL, D3DERR_INVALIDCALL);
+    *pCaps = This->caps;
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_GetDisplayMode( struct NineDevice9 *This,
+                            UINT iSwapChain,
+                            D3DDISPLAYMODE *pMode )
+{
+    DBG("This=%p iSwapChain=%u pMode=%p\n", This, iSwapChain, pMode);
+
+    user_assert(iSwapChain < This->nswapchains, D3DERR_INVALIDCALL);
+
+    return NineSwapChain9_GetDisplayMode(This->swapchains[iSwapChain], pMode);
+}
+
+HRESULT WINAPI
+NineDevice9_GetCreationParameters( struct NineDevice9 *This,
+                                   D3DDEVICE_CREATION_PARAMETERS *pParameters )
+{
+    user_assert(pParameters != NULL, D3DERR_INVALIDCALL);
+    *pParameters = This->params;
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_SetCursorProperties( struct NineDevice9 *This,
+                                 UINT XHotSpot,
+                                 UINT YHotSpot,
+                                 IDirect3DSurface9 *pCursorBitmap )
+{
+    /* TODO: hardware cursor */
+    struct NineSurface9 *surf = NineSurface9(pCursorBitmap);
+    struct pipe_context *pipe = This->pipe;
+    struct pipe_box box;
+    struct pipe_transfer *transfer;
+    void *ptr;
+
+    DBG_FLAG(DBG_SWAPCHAIN, "This=%p XHotSpot=%u YHotSpot=%u "
+             "pCursorBitmap=%p\n", This, XHotSpot, YHotSpot, pCursorBitmap);
+
+    user_assert(pCursorBitmap, D3DERR_INVALIDCALL);
+
+    This->cursor.w = MIN2(surf->desc.Width, This->cursor.image->width0);
+    This->cursor.h = MIN2(surf->desc.Height, This->cursor.image->height0);
+
+    u_box_origin_2d(This->cursor.w, This->cursor.h, &box);
+
+    ptr = pipe->transfer_map(pipe, This->cursor.image, 0,
+                             PIPE_TRANSFER_WRITE |
+                             PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE,
+                             &box, &transfer);
+    if (!ptr)
+        ret_err("Failed to update cursor image.\n", D3DERR_DRIVERINTERNALERROR);
+
+    This->cursor.hotspot.x = XHotSpot;
+    This->cursor.hotspot.y = YHotSpot;
+
+    /* Copy cursor image to internal storage. */
+    {
+        D3DLOCKED_RECT lock;
+        HRESULT hr;
+        const struct util_format_description *sfmt =
+            util_format_description(surf->base.info.format);
+        assert(sfmt);
+
+        hr = NineSurface9_LockRect(surf, &lock, NULL, D3DLOCK_READONLY);
+        if (FAILED(hr))
+            ret_err("Failed to map cursor source image.\n",
+                    D3DERR_DRIVERINTERNALERROR);
+
+        sfmt->unpack_rgba_8unorm(ptr, transfer->stride,
+                                 lock.pBits, lock.Pitch,
+                                 This->cursor.w, This->cursor.h);
+
+        if (!This->cursor.software &&
+            This->cursor.w == 32 && This->cursor.h == 32)
+            ID3DPresent_SetCursor(This->swapchains[0]->present,
+                                  lock.pBits, &This->cursor.hotspot,
+                                  This->cursor.visible);
+
+        NineSurface9_UnlockRect(surf);
+    }
+    pipe->transfer_unmap(pipe, transfer);
+
+    return D3D_OK;
+}
+
+void WINAPI
+NineDevice9_SetCursorPosition( struct NineDevice9 *This,
+                               int X,
+                               int Y,
+                               DWORD Flags )
+{
+    struct NineSwapChain9 *swap = This->swapchains[0];
+
+    This->cursor.pos.x = X;
+    This->cursor.pos.y = Y;
+
+    if (!This->cursor.software)
+        ID3DPresent_SetCursorPos(swap->present, &This->cursor.pos);
+}
+
+BOOL WINAPI
+NineDevice9_ShowCursor( struct NineDevice9 *This,
+                        BOOL bShow )
+{
+    BOOL old = This->cursor.visible;
+    This->cursor.visible = bShow && (This->cursor.hotspot.x != -1);
+    if (!This->cursor.software)
+        ID3DPresent_SetCursor(This->swapchains[0]->present, NULL, NULL, bShow);
+
+    return old;
+}
+
+HRESULT WINAPI
+NineDevice9_CreateAdditionalSwapChain( struct NineDevice9 *This,
+                                       D3DPRESENT_PARAMETERS *pPresentationParameters,
+                                       IDirect3DSwapChain9 **pSwapChain )
+{
+    struct NineSwapChain9 *swapchain, *tmplt = This->swapchains[0];
+    ID3DPresent *present;
+    HRESULT hr;
+
+    user_assert(pPresentationParameters, D3DERR_INVALIDCALL);
+
+    hr = ID3DPresentGroup_CreateAdditionalPresent(This->present, pPresentationParameters, &present);
+
+    if (FAILED(hr))
+        return hr;
+
+    hr = NineSwapChain9_new(This, FALSE, present, pPresentationParameters,
+                            tmplt->actx,
+                            tmplt->params.hDeviceWindow,
+                            &swapchain);
+    if (FAILED(hr))
+        return hr;
+
+    *pSwapChain = (IDirect3DSwapChain9 *)swapchain;
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_GetSwapChain( struct NineDevice9 *This,
+                          UINT iSwapChain,
+                          IDirect3DSwapChain9 **pSwapChain )
+{
+    user_assert(pSwapChain != NULL, D3DERR_INVALIDCALL);
+
+    *pSwapChain = NULL;
+    user_assert(iSwapChain < This->nswapchains, D3DERR_INVALIDCALL);
+
+    NineUnknown_AddRef(NineUnknown(This->swapchains[iSwapChain]));
+    *pSwapChain = (IDirect3DSwapChain9 *)This->swapchains[iSwapChain];
+
+    return D3D_OK;
+}
+
+UINT WINAPI
+NineDevice9_GetNumberOfSwapChains( struct NineDevice9 *This )
+{
+    return This->nswapchains;
+}
+
+HRESULT WINAPI
+NineDevice9_Reset( struct NineDevice9 *This,
+                   D3DPRESENT_PARAMETERS *pPresentationParameters )
+{
+    HRESULT hr = D3D_OK;
+    unsigned i;
+
+    DBG("This=%p pPresentationParameters=%p\n", This, pPresentationParameters);
+
+    for (i = 0; i < This->nswapchains; ++i) {
+        D3DPRESENT_PARAMETERS *params = &pPresentationParameters[i];
+        hr = NineSwapChain9_Resize(This->swapchains[i], params, NULL);
+        if (FAILED(hr))
+            return (hr == D3DERR_OUTOFVIDEOMEMORY) ? hr : D3DERR_DEVICELOST;
+    }
+
+    nine_pipe_context_clear(This);
+    nine_state_clear(&This->state, TRUE);
+
+    NineDevice9_SetDefaultState(This, TRUE);
+    NineDevice9_SetRenderTarget(
+        This, 0, (IDirect3DSurface9 *)This->swapchains[0]->buffers[0]);
+    /* XXX: better use GetBackBuffer here ? */
+
+    return hr;
+}
+
+HRESULT WINAPI
+NineDevice9_Present( struct NineDevice9 *This,
+                     const RECT *pSourceRect,
+                     const RECT *pDestRect,
+                     HWND hDestWindowOverride,
+                     const RGNDATA *pDirtyRegion )
+{
+    unsigned i;
+    HRESULT hr;
+
+    /* XXX is this right? */
+    for (i = 0; i < This->nswapchains; ++i) {
+        hr = NineSwapChain9_Present(This->swapchains[i], pSourceRect, pDestRect,
+                                    hDestWindowOverride, pDirtyRegion, 0);
+        if (FAILED(hr)) { return hr; }
+    }
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_GetBackBuffer( struct NineDevice9 *This,
+                           UINT iSwapChain,
+                           UINT iBackBuffer,
+                           D3DBACKBUFFER_TYPE Type,
+                           IDirect3DSurface9 **ppBackBuffer )
+{
+    user_assert(ppBackBuffer != NULL, D3DERR_INVALIDCALL);
+    user_assert(iSwapChain < This->nswapchains, D3DERR_INVALIDCALL);
+
+    return NineSwapChain9_GetBackBuffer(This->swapchains[iSwapChain],
+                                        iBackBuffer, Type, ppBackBuffer);
+}
+
+HRESULT WINAPI
+NineDevice9_GetRasterStatus( struct NineDevice9 *This,
+                             UINT iSwapChain,
+                             D3DRASTER_STATUS *pRasterStatus )
+{
+    user_assert(pRasterStatus != NULL, D3DERR_INVALIDCALL);
+    user_assert(iSwapChain < This->nswapchains, D3DERR_INVALIDCALL);
+
+    return NineSwapChain9_GetRasterStatus(This->swapchains[iSwapChain],
+                                          pRasterStatus);
+}
+
+HRESULT WINAPI
+NineDevice9_SetDialogBoxMode( struct NineDevice9 *This,
+                              BOOL bEnableDialogs )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+void WINAPI
+NineDevice9_SetGammaRamp( struct NineDevice9 *This,
+                          UINT iSwapChain,
+                          DWORD Flags,
+                          const D3DGAMMARAMP *pRamp )
+{
+    DBG("This=%p iSwapChain=%u Flags=%x pRamp=%p\n", This,
+        iSwapChain, Flags, pRamp);
+
+    user_warn(iSwapChain >= This->nswapchains);
+    user_warn(!pRamp);
+
+    if (pRamp && (iSwapChain < This->nswapchains)) {
+        struct NineSwapChain9 *swap = This->swapchains[iSwapChain];
+        swap->gamma = *pRamp;
+        ID3DPresent_SetGammaRamp(swap->present, pRamp, swap->params.hDeviceWindow);
+    }
+}
+
+void WINAPI
+NineDevice9_GetGammaRamp( struct NineDevice9 *This,
+                          UINT iSwapChain,
+                          D3DGAMMARAMP *pRamp )
+{
+    DBG("This=%p iSwapChain=%u pRamp=%p\n", This, iSwapChain, pRamp);
+
+    user_warn(iSwapChain >= This->nswapchains);
+    user_warn(!pRamp);
+
+    if (pRamp && (iSwapChain < This->nswapchains))
+        *pRamp = This->swapchains[iSwapChain]->gamma;
+}
+
+HRESULT WINAPI
+NineDevice9_CreateTexture( struct NineDevice9 *This,
+                           UINT Width,
+                           UINT Height,
+                           UINT Levels,
+                           DWORD Usage,
+                           D3DFORMAT Format,
+                           D3DPOOL Pool,
+                           IDirect3DTexture9 **ppTexture,
+                           HANDLE *pSharedHandle )
+{
+    struct NineTexture9 *tex;
+    HRESULT hr;
+
+    DBG("This=%p Width=%u Height=%u Levels=%u Usage=%s Format=%s Pool=%s "
+        "ppOut=%p pSharedHandle=%p\n", This, Width, Height, Levels,
+        nine_D3DUSAGE_to_str(Usage), d3dformat_to_string(Format),
+        nine_D3DPOOL_to_str(Pool), ppTexture, pSharedHandle);
+
+    Usage &= D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_DEPTHSTENCIL | D3DUSAGE_DMAP |
+             D3DUSAGE_DYNAMIC | D3DUSAGE_NONSECURE | D3DUSAGE_RENDERTARGET |
+             D3DUSAGE_SOFTWAREPROCESSING | D3DUSAGE_TEXTAPI;
+
+    user_assert(Width && Height, D3DERR_INVALIDCALL);
+    user_assert(!pSharedHandle || This->ex, D3DERR_INVALIDCALL);
+    /* When is used shared handle, Pool must be
+     * SYSTEMMEM with Levels 1 or DEFAULT with any Levels */
+    user_assert(!pSharedHandle || Pool != D3DPOOL_SYSTEMMEM || Levels == 1,
+                D3DERR_INVALIDCALL);
+    user_assert(!pSharedHandle || Pool == D3DPOOL_SYSTEMMEM || Pool == D3DPOOL_DEFAULT,
+                D3DERR_INVALIDCALL);
+    user_assert((Usage != D3DUSAGE_AUTOGENMIPMAP || Levels <= 1), D3DERR_INVALIDCALL);
+
+    hr = NineTexture9_new(This, Width, Height, Levels, Usage, Format, Pool,
+                          &tex, pSharedHandle);
+    if (SUCCEEDED(hr))
+        *ppTexture = (IDirect3DTexture9 *)tex;
+
+    return hr;
+}
+
+HRESULT WINAPI
+NineDevice9_CreateVolumeTexture( struct NineDevice9 *This,
+                                 UINT Width,
+                                 UINT Height,
+                                 UINT Depth,
+                                 UINT Levels,
+                                 DWORD Usage,
+                                 D3DFORMAT Format,
+                                 D3DPOOL Pool,
+                                 IDirect3DVolumeTexture9 **ppVolumeTexture,
+                                 HANDLE *pSharedHandle )
+{
+    struct NineVolumeTexture9 *tex;
+    HRESULT hr;
+
+    DBG("This=%p Width=%u Height=%u Depth=%u Levels=%u Usage=%s Format=%s Pool=%s "
+        "ppOut=%p pSharedHandle=%p\n", This, Width, Height, Depth, Levels,
+        nine_D3DUSAGE_to_str(Usage), d3dformat_to_string(Format),
+        nine_D3DPOOL_to_str(Pool), ppVolumeTexture, pSharedHandle);
+
+    Usage &= D3DUSAGE_DYNAMIC | D3DUSAGE_NONSECURE |
+             D3DUSAGE_SOFTWAREPROCESSING;
+
+    user_assert(Width && Height && Depth, D3DERR_INVALIDCALL);
+    user_assert(!pSharedHandle || Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL);
+
+    hr = NineVolumeTexture9_new(This, Width, Height, Depth, Levels,
+                                Usage, Format, Pool, &tex, pSharedHandle);
+    if (SUCCEEDED(hr))
+        *ppVolumeTexture = (IDirect3DVolumeTexture9 *)tex;
+
+    return hr;
+}
+
+HRESULT WINAPI
+NineDevice9_CreateCubeTexture( struct NineDevice9 *This,
+                               UINT EdgeLength,
+                               UINT Levels,
+                               DWORD Usage,
+                               D3DFORMAT Format,
+                               D3DPOOL Pool,
+                               IDirect3DCubeTexture9 **ppCubeTexture,
+                               HANDLE *pSharedHandle )
+{
+    struct NineCubeTexture9 *tex;
+    HRESULT hr;
+
+    DBG("This=%p EdgeLength=%u Levels=%u Usage=%s Format=%s Pool=%s ppOut=%p "
+        "pSharedHandle=%p\n", This, EdgeLength, Levels,
+        nine_D3DUSAGE_to_str(Usage), d3dformat_to_string(Format),
+        nine_D3DPOOL_to_str(Pool), ppCubeTexture, pSharedHandle);
+
+    Usage &= D3DUSAGE_AUTOGENMIPMAP | D3DUSAGE_DEPTHSTENCIL | D3DUSAGE_DYNAMIC |
+             D3DUSAGE_NONSECURE | D3DUSAGE_RENDERTARGET |
+             D3DUSAGE_SOFTWAREPROCESSING;
+
+    user_assert(EdgeLength, D3DERR_INVALIDCALL);
+    user_assert(!pSharedHandle || Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL);
+
+    hr = NineCubeTexture9_new(This, EdgeLength, Levels, Usage, Format, Pool,
+                              &tex, pSharedHandle);
+    if (SUCCEEDED(hr))
+        *ppCubeTexture = (IDirect3DCubeTexture9 *)tex;
+
+    return hr;
+}
+
+HRESULT WINAPI
+NineDevice9_CreateVertexBuffer( struct NineDevice9 *This,
+                                UINT Length,
+                                DWORD Usage,
+                                DWORD FVF,
+                                D3DPOOL Pool,
+                                IDirect3DVertexBuffer9 **ppVertexBuffer,
+                                HANDLE *pSharedHandle )
+{
+    struct NineVertexBuffer9 *buf;
+    HRESULT hr;
+    D3DVERTEXBUFFER_DESC desc;
+
+    DBG("This=%p Length=%u Usage=%x FVF=%x Pool=%u ppOut=%p pSharedHandle=%p\n",
+        This, Length, Usage, FVF, Pool, ppVertexBuffer, pSharedHandle);
+
+    user_assert(!pSharedHandle || Pool == D3DPOOL_DEFAULT, D3DERR_NOTAVAILABLE);
+
+    desc.Format = D3DFMT_VERTEXDATA;
+    desc.Type = D3DRTYPE_VERTEXBUFFER;
+    desc.Usage = Usage &
+        (D3DUSAGE_DONOTCLIP | D3DUSAGE_DYNAMIC | D3DUSAGE_NONSECURE |
+         D3DUSAGE_NPATCHES | D3DUSAGE_POINTS | D3DUSAGE_RTPATCHES |
+         D3DUSAGE_SOFTWAREPROCESSING | D3DUSAGE_TEXTAPI |
+         D3DUSAGE_WRITEONLY);
+    desc.Pool = Pool;
+    desc.Size = Length;
+    desc.FVF = FVF;
+
+    user_assert(!pSharedHandle || Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL);
+    user_assert(desc.Usage == Usage, D3DERR_INVALIDCALL);
+
+    hr = NineVertexBuffer9_new(This, &desc, &buf);
+    if (SUCCEEDED(hr))
+        *ppVertexBuffer = (IDirect3DVertexBuffer9 *)buf;
+    return hr;
+}
+
+HRESULT WINAPI
+NineDevice9_CreateIndexBuffer( struct NineDevice9 *This,
+                               UINT Length,
+                               DWORD Usage,
+                               D3DFORMAT Format,
+                               D3DPOOL Pool,
+                               IDirect3DIndexBuffer9 **ppIndexBuffer,
+                               HANDLE *pSharedHandle )
+{
+    struct NineIndexBuffer9 *buf;
+    HRESULT hr;
+    D3DINDEXBUFFER_DESC desc;
+
+    DBG("This=%p Length=%u Usage=%x Format=%s Pool=%u ppOut=%p "
+        "pSharedHandle=%p\n", This, Length, Usage,
+        d3dformat_to_string(Format), Pool, ppIndexBuffer, pSharedHandle);
+
+    user_assert(!pSharedHandle || Pool == D3DPOOL_DEFAULT, D3DERR_NOTAVAILABLE);
+
+    desc.Format = Format;
+    desc.Type = D3DRTYPE_INDEXBUFFER;
+    desc.Usage = Usage &
+        (D3DUSAGE_DONOTCLIP | D3DUSAGE_DYNAMIC | D3DUSAGE_NONSECURE |
+         D3DUSAGE_NPATCHES | D3DUSAGE_POINTS | D3DUSAGE_RTPATCHES |
+         D3DUSAGE_SOFTWAREPROCESSING | D3DUSAGE_WRITEONLY);
+    desc.Pool = Pool;
+    desc.Size = Length;
+
+    user_assert(!pSharedHandle || Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL);
+    user_assert(desc.Usage == Usage, D3DERR_INVALIDCALL);
+
+    hr = NineIndexBuffer9_new(This, &desc, &buf);
+    if (SUCCEEDED(hr))
+        *ppIndexBuffer = (IDirect3DIndexBuffer9 *)buf;
+    return hr;
+}
+
+static HRESULT
+create_zs_or_rt_surface(struct NineDevice9 *This,
+                        unsigned type, /* 0 = RT, 1 = ZS, 2 = plain */
+                        D3DPOOL Pool,
+                        UINT Width, UINT Height,
+                        D3DFORMAT Format,
+                        D3DMULTISAMPLE_TYPE MultiSample,
+                        DWORD MultisampleQuality,
+                        BOOL Discard_or_Lockable,
+                        IDirect3DSurface9 **ppSurface,
+                        HANDLE *pSharedHandle)
+{
+    struct NineSurface9 *surface;
+    struct pipe_screen *screen = This->screen;
+    struct pipe_resource *resource = NULL;
+    HRESULT hr;
+    D3DSURFACE_DESC desc;
+    struct pipe_resource templ;
+
+    DBG("This=%p type=%u Pool=%s Width=%u Height=%u Format=%s MS=%u Quality=%u "
+        "Discard_or_Lockable=%i ppSurface=%p pSharedHandle=%p\n",
+        This, type, nine_D3DPOOL_to_str(Pool), Width, Height,
+        d3dformat_to_string(Format), MultiSample, MultisampleQuality,
+        Discard_or_Lockable, ppSurface, pSharedHandle);
+
+    if (pSharedHandle)
+      DBG("FIXME Used shared handle! This option isn't probably handled correctly!\n");
+
+    user_assert(Width && Height, D3DERR_INVALIDCALL);
+    user_assert(Pool != D3DPOOL_MANAGED, D3DERR_INVALIDCALL);
+
+    templ.target = PIPE_TEXTURE_2D;
+    templ.format = d3d9_to_pipe_format(Format);
+    templ.width0 = Width;
+    templ.height0 = Height;
+    templ.depth0 = 1;
+    templ.array_size = 1;
+    templ.last_level = 0;
+    templ.nr_samples = (unsigned)MultiSample;
+    templ.usage = PIPE_USAGE_DEFAULT;
+    templ.flags = 0;
+    templ.bind = PIPE_BIND_SAMPLER_VIEW; /* StretchRect */
+    switch (type) {
+    case 0: templ.bind |= PIPE_BIND_RENDER_TARGET; break;
+    case 1: templ.bind |= PIPE_BIND_DEPTH_STENCIL; break;
+    default:
+        assert(type == 2);
+        break;
+    }
+
+    desc.Format = Format;
+    desc.Type = D3DRTYPE_SURFACE;
+    desc.Usage = 0;
+    desc.Pool = Pool;
+    desc.MultiSampleType = MultiSample;
+    desc.MultiSampleQuality = MultisampleQuality;
+    desc.Width = Width;
+    desc.Height = Height;
+    switch (type) {
+    case 0: desc.Usage = D3DUSAGE_RENDERTARGET; break;
+    case 1: desc.Usage = D3DUSAGE_DEPTHSTENCIL; break;
+    default: break;
+    }
+
+    if (Pool == D3DPOOL_DEFAULT && Format != D3DFMT_NULL) {
+        /* resource_create doesn't return an error code, so check format here */
+        user_assert(CHECK_PIPE_RESOURCE_TEMPLATE(templ), D3DERR_INVALIDCALL);
+        resource = screen->resource_create(screen, &templ);
+        user_assert(resource, D3DERR_OUTOFVIDEOMEMORY);
+        if (Discard_or_Lockable && (desc.Usage & D3DUSAGE_RENDERTARGET))
+            resource->flags |= NINE_RESOURCE_FLAG_LOCKABLE;
+    } else {
+        resource = NULL;
+    }
+    hr = NineSurface9_new(This, NULL, resource, 0, 0, 0, &desc, &surface);
+    pipe_resource_reference(&resource, NULL);
+
+    if (SUCCEEDED(hr))
+        *ppSurface = (IDirect3DSurface9 *)surface;
+    return hr;
+}
+
+HRESULT WINAPI
+NineDevice9_CreateRenderTarget( struct NineDevice9 *This,
+                                UINT Width,
+                                UINT Height,
+                                D3DFORMAT Format,
+                                D3DMULTISAMPLE_TYPE MultiSample,
+                                DWORD MultisampleQuality,
+                                BOOL Lockable,
+                                IDirect3DSurface9 **ppSurface,
+                                HANDLE *pSharedHandle )
+{
+    return create_zs_or_rt_surface(This, 0, D3DPOOL_DEFAULT,
+                                   Width, Height, Format,
+                                   MultiSample, MultisampleQuality,
+                                   Lockable, ppSurface, pSharedHandle);
+}
+
+HRESULT WINAPI
+NineDevice9_CreateDepthStencilSurface( struct NineDevice9 *This,
+                                       UINT Width,
+                                       UINT Height,
+                                       D3DFORMAT Format,
+                                       D3DMULTISAMPLE_TYPE MultiSample,
+                                       DWORD MultisampleQuality,
+                                       BOOL Discard,
+                                       IDirect3DSurface9 **ppSurface,
+                                       HANDLE *pSharedHandle )
+{
+    return create_zs_or_rt_surface(This, 1, D3DPOOL_DEFAULT,
+                                   Width, Height, Format,
+                                   MultiSample, MultisampleQuality,
+                                   Discard, ppSurface, pSharedHandle);
+}
+
+HRESULT WINAPI
+NineDevice9_UpdateSurface( struct NineDevice9 *This,
+                           IDirect3DSurface9 *pSourceSurface,
+                           const RECT *pSourceRect,
+                           IDirect3DSurface9 *pDestinationSurface,
+                           const POINT *pDestPoint )
+{
+    struct NineSurface9 *dst = NineSurface9(pDestinationSurface);
+    struct NineSurface9 *src = NineSurface9(pSourceSurface);
+
+    DBG("This=%p pSourceSurface=%p pDestinationSurface=%p "
+        "pSourceRect=%p pDestPoint=%p\n", This,
+        pSourceSurface, pDestinationSurface, pSourceRect, pDestPoint);
+    if (pSourceRect)
+        DBG("pSourceRect = (%u,%u)-(%u,%u)\n",
+            pSourceRect->left, pSourceRect->top,
+            pSourceRect->right, pSourceRect->bottom);
+    if (pDestPoint)
+        DBG("pDestPoint = (%u,%u)\n", pDestPoint->x, pDestPoint->y);
+
+    user_assert(dst->base.pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL);
+    user_assert(src->base.pool == D3DPOOL_SYSTEMMEM, D3DERR_INVALIDCALL);
+
+    user_assert(dst->desc.MultiSampleType == D3DMULTISAMPLE_NONE, D3DERR_INVALIDCALL);
+    user_assert(src->desc.MultiSampleType == D3DMULTISAMPLE_NONE, D3DERR_INVALIDCALL);
+
+    return NineSurface9_CopySurface(dst, src, pDestPoint, pSourceRect);
+}
+
+HRESULT WINAPI
+NineDevice9_UpdateTexture( struct NineDevice9 *This,
+                           IDirect3DBaseTexture9 *pSourceTexture,
+                           IDirect3DBaseTexture9 *pDestinationTexture )
+{
+    struct NineBaseTexture9 *dstb = NineBaseTexture9(pDestinationTexture);
+    struct NineBaseTexture9 *srcb = NineBaseTexture9(pSourceTexture);
+    unsigned l, m;
+    unsigned last_level = dstb->base.info.last_level;
+
+    DBG("This=%p pSourceTexture=%p pDestinationTexture=%p\n", This,
+        pSourceTexture, pDestinationTexture);
+
+    user_assert(pSourceTexture != pDestinationTexture, D3DERR_INVALIDCALL);
+
+    user_assert(dstb->base.pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL);
+    user_assert(srcb->base.pool == D3DPOOL_SYSTEMMEM, D3DERR_INVALIDCALL);
+
+    if (dstb->base.usage & D3DUSAGE_AUTOGENMIPMAP) {
+        /* Only the first level is updated, the others regenerated. */
+        last_level = 0;
+    } else {
+        user_assert(!(srcb->base.usage & D3DUSAGE_AUTOGENMIPMAP), D3DERR_INVALIDCALL);
+    }
+
+    user_assert(dstb->base.type == srcb->base.type, D3DERR_INVALIDCALL);
+
+    /* TODO: We can restrict the update to the dirty portions of the source.
+     * Yes, this seems silly, but it's what MSDN says ...
+     */
+
+    /* Find src level that matches dst level 0: */
+    user_assert(srcb->base.info.width0 >= dstb->base.info.width0 &&
+                srcb->base.info.height0 >= dstb->base.info.height0 &&
+                srcb->base.info.depth0 >= dstb->base.info.depth0,
+                D3DERR_INVALIDCALL);
+    for (m = 0; m <= srcb->base.info.last_level; ++m) {
+        unsigned w = u_minify(srcb->base.info.width0, m);
+        unsigned h = u_minify(srcb->base.info.height0, m);
+        unsigned d = u_minify(srcb->base.info.depth0, m);
+
+        if (w == dstb->base.info.width0 &&
+            h == dstb->base.info.height0 &&
+            d == dstb->base.info.depth0)
+            break;
+    }
+    user_assert(m <= srcb->base.info.last_level, D3DERR_INVALIDCALL);
+
+    last_level = MIN2(last_level, srcb->base.info.last_level - m);
+
+    if (dstb->base.type == D3DRTYPE_TEXTURE) {
+        struct NineTexture9 *dst = NineTexture9(dstb);
+        struct NineTexture9 *src = NineTexture9(srcb);
+
+        for (l = 0; l <= last_level; ++l, ++m)
+            NineSurface9_CopySurface(dst->surfaces[l],
+                                     src->surfaces[m], NULL, NULL);
+    } else
+    if (dstb->base.type == D3DRTYPE_CUBETEXTURE) {
+        struct NineCubeTexture9 *dst = NineCubeTexture9(dstb);
+        struct NineCubeTexture9 *src = NineCubeTexture9(srcb);
+        unsigned z;
+
+        /* GPUs usually have them stored as arrays of mip-mapped 2D textures. */
+        for (z = 0; z < 6; ++z) {
+            for (l = 0; l <= last_level; ++l, ++m) {
+                NineSurface9_CopySurface(dst->surfaces[l * 6 + z],
+                                         src->surfaces[m * 6 + z], NULL, NULL);
+            }
+            m -= l;
+        }
+    } else
+    if (dstb->base.type == D3DRTYPE_VOLUMETEXTURE) {
+        struct NineVolumeTexture9 *dst = NineVolumeTexture9(dstb);
+        struct NineVolumeTexture9 *src = NineVolumeTexture9(srcb);
+
+        for (l = 0; l <= last_level; ++l, ++m)
+            NineVolume9_CopyVolume(dst->volumes[l],
+                                   src->volumes[m], 0, 0, 0, NULL);
+    } else{
+        assert(!"invalid texture type");
+    }
+
+    if (dstb->base.usage & D3DUSAGE_AUTOGENMIPMAP)
+        NineBaseTexture9_GenerateMipSubLevels(dstb);
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_GetRenderTargetData( struct NineDevice9 *This,
+                                 IDirect3DSurface9 *pRenderTarget,
+                                 IDirect3DSurface9 *pDestSurface )
+{
+    struct NineSurface9 *dst = NineSurface9(pDestSurface);
+    struct NineSurface9 *src = NineSurface9(pRenderTarget);
+
+    DBG("This=%p pRenderTarget=%p pDestSurface=%p\n",
+        This, pRenderTarget, pDestSurface);
+
+    user_assert(dst->desc.Pool == D3DPOOL_SYSTEMMEM, D3DERR_INVALIDCALL);
+    user_assert(src->desc.Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL);
+
+    user_assert(dst->desc.MultiSampleType < 2, D3DERR_INVALIDCALL);
+    user_assert(src->desc.MultiSampleType < 2, D3DERR_INVALIDCALL);
+
+    return NineSurface9_CopySurface(dst, src, NULL, NULL);
+}
+
+HRESULT WINAPI
+NineDevice9_GetFrontBufferData( struct NineDevice9 *This,
+                                UINT iSwapChain,
+                                IDirect3DSurface9 *pDestSurface )
+{
+    DBG("This=%p iSwapChain=%u pDestSurface=%p\n", This,
+        iSwapChain, pDestSurface);
+
+    user_assert(pDestSurface != NULL, D3DERR_INVALIDCALL);
+    user_assert(iSwapChain < This->nswapchains, D3DERR_INVALIDCALL);
+
+    return NineSwapChain9_GetFrontBufferData(This->swapchains[iSwapChain],
+                                             pDestSurface);
+}
+
+HRESULT WINAPI
+NineDevice9_StretchRect( struct NineDevice9 *This,
+                         IDirect3DSurface9 *pSourceSurface,
+                         const RECT *pSourceRect,
+                         IDirect3DSurface9 *pDestSurface,
+                         const RECT *pDestRect,
+                         D3DTEXTUREFILTERTYPE Filter )
+{
+    struct pipe_screen *screen = This->screen;
+    struct pipe_context *pipe = This->pipe;
+    struct NineSurface9 *dst = NineSurface9(pDestSurface);
+    struct NineSurface9 *src = NineSurface9(pSourceSurface);
+    struct pipe_resource *dst_res = NineSurface9_GetResource(dst);
+    struct pipe_resource *src_res = NineSurface9_GetResource(src);
+    const boolean zs = util_format_is_depth_or_stencil(dst_res->format);
+    struct pipe_blit_info blit;
+    boolean scaled, clamped, ms, flip_x = FALSE, flip_y = FALSE;
+
+    DBG("This=%p pSourceSurface=%p pSourceRect=%p pDestSurface=%p "
+        "pDestRect=%p Filter=%u\n",
+        This, pSourceSurface, pSourceRect, pDestSurface, pDestRect, Filter);
+    if (pSourceRect)
+        DBG("pSourceRect=(%u,%u)-(%u,%u)\n",
+            pSourceRect->left, pSourceRect->top,
+            pSourceRect->right, pSourceRect->bottom);
+    if (pDestRect)
+        DBG("pSourceRect=(%u,%u)-(%u,%u)\n", pDestRect->left, pDestRect->top,
+            pDestRect->right, pDestRect->bottom);
+
+    user_assert(!zs || !This->in_scene, D3DERR_INVALIDCALL);
+    user_assert(!zs || !pSourceRect ||
+                (pSourceRect->left == 0 &&
+                 pSourceRect->top == 0 &&
+                 pSourceRect->right == src->desc.Width &&
+                 pSourceRect->bottom == src->desc.Height), D3DERR_INVALIDCALL);
+    user_assert(!zs || !pDestRect ||
+                (pDestRect->left == 0 &&
+                 pDestRect->top == 0 &&
+                 pDestRect->right == dst->desc.Width &&
+                 pDestRect->bottom == dst->desc.Height), D3DERR_INVALIDCALL);
+    user_assert(!zs ||
+                (dst->desc.Width == src->desc.Width &&
+                 dst->desc.Height == src->desc.Height), D3DERR_INVALIDCALL);
+    user_assert(zs || !util_format_is_depth_or_stencil(src_res->format),
+                D3DERR_INVALIDCALL);
+    user_assert(!zs || dst->desc.Format == src->desc.Format,
+                D3DERR_INVALIDCALL);
+    user_assert(screen->is_format_supported(screen, src_res->format,
+                                            src_res->target,
+                                            src_res->nr_samples,
+                                            PIPE_BIND_SAMPLER_VIEW),
+                D3DERR_INVALIDCALL);
+    user_assert(dst->base.pool == D3DPOOL_DEFAULT &&
+                src->base.pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL);
+
+    /* We might want to permit these, but wine thinks we shouldn't. */
+    user_assert(!pDestRect ||
+                (pDestRect->left <= pDestRect->right &&
+                 pDestRect->top <= pDestRect->bottom), D3DERR_INVALIDCALL);
+    user_assert(!pSourceRect ||
+                (pSourceRect->left <= pSourceRect->right &&
+                 pSourceRect->top <= pSourceRect->bottom), D3DERR_INVALIDCALL);
+
+    blit.dst.resource = dst_res;
+    blit.dst.level = dst->level;
+    blit.dst.box.z = dst->layer;
+    blit.dst.box.depth = 1;
+    blit.dst.format = dst_res->format;
+    if (pDestRect) {
+        flip_x = pDestRect->left > pDestRect->right;
+        if (flip_x) {
+            blit.dst.box.x = pDestRect->right;
+            blit.dst.box.width = pDestRect->left - pDestRect->right;
+        } else {
+            blit.dst.box.x = pDestRect->left;
+            blit.dst.box.width = pDestRect->right - pDestRect->left;
+        }
+        flip_y = pDestRect->top > pDestRect->bottom;
+        if (flip_y) {
+            blit.dst.box.y = pDestRect->bottom;
+            blit.dst.box.height = pDestRect->top - pDestRect->bottom;
+        } else {
+            blit.dst.box.y = pDestRect->top;
+            blit.dst.box.height = pDestRect->bottom - pDestRect->top;
+        }
+    } else {
+        blit.dst.box.x = 0;
+        blit.dst.box.y = 0;
+        blit.dst.box.width = dst->desc.Width;
+        blit.dst.box.height = dst->desc.Height;
+    }
+    blit.src.resource = src_res;
+    blit.src.level = src->level;
+    blit.src.box.z = src->layer;
+    blit.src.box.depth = 1;
+    blit.src.format = src_res->format;
+    if (pSourceRect) {
+        if (flip_x ^ (pSourceRect->left > pSourceRect->right)) {
+            blit.src.box.x = pSourceRect->right;
+            blit.src.box.width = pSourceRect->left - pSourceRect->right;
+        } else {
+            blit.src.box.x = pSourceRect->left;
+            blit.src.box.width = pSourceRect->right - pSourceRect->left;
+        }
+        if (flip_y ^ (pSourceRect->top > pSourceRect->bottom)) {
+            blit.src.box.y = pSourceRect->bottom;
+            blit.src.box.height = pSourceRect->top - pSourceRect->bottom;
+        } else {
+            blit.src.box.y = pSourceRect->top;
+            blit.src.box.height = pSourceRect->bottom - pSourceRect->top;
+        }
+    } else {
+        blit.src.box.x = flip_x ? src->desc.Width : 0;
+        blit.src.box.y = flip_y ? src->desc.Height : 0;
+        blit.src.box.width = flip_x ? -src->desc.Width : src->desc.Width;
+        blit.src.box.height = flip_y ? -src->desc.Height : src->desc.Height;
+    }
+    blit.mask = zs ? PIPE_MASK_ZS : PIPE_MASK_RGBA;
+    blit.filter = Filter == D3DTEXF_LINEAR ?
+       PIPE_TEX_FILTER_LINEAR : PIPE_TEX_FILTER_NEAREST;
+    blit.scissor_enable = FALSE;
+
+    /* If both of a src and dst dimension are negative, flip them. */
+    if (blit.dst.box.width < 0 && blit.src.box.width < 0) {
+        blit.dst.box.width = -blit.dst.box.width;
+        blit.src.box.width = -blit.src.box.width;
+    }
+    if (blit.dst.box.height < 0 && blit.src.box.height < 0) {
+        blit.dst.box.height = -blit.dst.box.height;
+        blit.src.box.height = -blit.src.box.height;
+    }
+    scaled =
+        blit.dst.box.width != blit.src.box.width ||
+        blit.dst.box.height != blit.src.box.height;
+
+    user_assert(!scaled || dst != src, D3DERR_INVALIDCALL);
+    user_assert(!scaled ||
+                !NineSurface9_IsOffscreenPlain(dst) ||
+                NineSurface9_IsOffscreenPlain(src), D3DERR_INVALIDCALL);
+    user_assert(!scaled ||
+                (!util_format_is_compressed(dst->base.info.format) &&
+                 !util_format_is_compressed(src->base.info.format)),
+                D3DERR_INVALIDCALL);
+
+    user_warn(src == dst &&
+              u_box_test_intersection_2d(&blit.src.box, &blit.dst.box));
+
+    /* Check for clipping/clamping: */
+    {
+        struct pipe_box box;
+        int xy;
+
+        xy = u_box_clip_2d(&box, &blit.dst.box,
+                           dst->desc.Width, dst->desc.Height);
+        if (xy < 0)
+            return D3D_OK;
+        if (xy == 0)
+            xy = u_box_clip_2d(&box, &blit.src.box,
+                               src->desc.Width, src->desc.Height);
+        clamped = !!xy;
+    }
+
+    ms = (dst->desc.MultiSampleType | 1) != (src->desc.MultiSampleType | 1);
+
+    if (clamped || scaled || (blit.dst.format != blit.src.format) || ms) {
+        DBG("using pipe->blit()\n");
+        /* TODO: software scaling */
+        user_assert(screen->is_format_supported(screen, dst_res->format,
+                                                dst_res->target,
+                                                dst_res->nr_samples,
+                                                zs ? PIPE_BIND_DEPTH_STENCIL :
+                                                PIPE_BIND_RENDER_TARGET),
+                    D3DERR_INVALIDCALL);
+
+        pipe->blit(pipe, &blit);
+    } else {
+        assert(blit.dst.box.x >= 0 && blit.dst.box.y >= 0 &&
+               blit.src.box.x >= 0 && blit.src.box.y >= 0 &&
+               blit.dst.box.x + blit.dst.box.width <= dst->desc.Width &&
+               blit.src.box.x + blit.src.box.width <= src->desc.Width &&
+               blit.dst.box.y + blit.dst.box.height <= dst->desc.Height &&
+               blit.src.box.y + blit.src.box.height <= src->desc.Height);
+        /* Or drivers might crash ... */
+        DBG("Using resource_copy_region.\n");
+        pipe->resource_copy_region(pipe,
+            blit.dst.resource, blit.dst.level,
+            blit.dst.box.x, blit.dst.box.y, blit.dst.box.z,
+            blit.src.resource, blit.src.level,
+            &blit.src.box);
+    }
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_ColorFill( struct NineDevice9 *This,
+                       IDirect3DSurface9 *pSurface,
+                       const RECT *pRect,
+                       D3DCOLOR color )
+{
+    struct pipe_context *pipe = This->pipe;
+    struct NineSurface9 *surf = NineSurface9(pSurface);
+    struct pipe_surface *psurf;
+    unsigned x, y, w, h;
+    union pipe_color_union rgba;
+    boolean fallback;
+
+    DBG("This=%p pSurface=%p pRect=%p color=%08x\n", This,
+        pSurface, pRect, color);
+    if (pRect)
+        DBG("pRect=(%u,%u)-(%u,%u)\n", pRect->left, pRect->top,
+            pRect->right, pRect->bottom);
+
+    user_assert(surf->base.pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL);
+
+    user_assert((surf->base.usage & D3DUSAGE_RENDERTARGET) ||
+                NineSurface9_IsOffscreenPlain(surf), D3DERR_INVALIDCALL);
+
+    if (pRect) {
+        x = pRect->left;
+        y = pRect->top;
+        w = pRect->right - pRect->left;
+        h = pRect->bottom - pRect->top;
+    } else{
+        x = 0;
+        y = 0;
+        w = surf->desc.Width;
+        h = surf->desc.Height;
+    }
+    d3dcolor_to_pipe_color_union(&rgba, color);
+
+    fallback =
+        !This->screen->is_format_supported(This->screen, surf->base.info.format,
+                                           surf->base.info.target,
+                                           surf->base.info.nr_samples,
+                                           PIPE_BIND_RENDER_TARGET);
+    if (!fallback) {
+        psurf = NineSurface9_GetSurface(surf, 0);
+        if (!psurf)
+            fallback = TRUE;
+    }
+
+    if (!fallback) {
+        pipe->clear_render_target(pipe, psurf, &rgba, x, y, w, h);
+    } else {
+        D3DLOCKED_RECT lock;
+        union util_color uc;
+        HRESULT hr;
+        /* XXX: lock pRect and fix util_fill_rect */
+        hr = NineSurface9_LockRect(surf, &lock, NULL, 0);
+        if (FAILED(hr))
+            return hr;
+        util_pack_color_ub(color >> 16, color >> 8, color >> 0, color >> 24,
+                           surf->base.info.format, &uc);
+        util_fill_rect(lock.pBits, surf->base.info.format,lock.Pitch,
+                       x, y, w, h, &uc);
+        NineSurface9_UnlockRect(surf);
+    }
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_CreateOffscreenPlainSurface( struct NineDevice9 *This,
+                                         UINT Width,
+                                         UINT Height,
+                                         D3DFORMAT Format,
+                                         D3DPOOL Pool,
+                                         IDirect3DSurface9 **ppSurface,
+                                         HANDLE *pSharedHandle )
+{
+    HRESULT hr;
+
+    DBG("This=%p Width=%u Height=%u Format=%s(0x%x) Pool=%u "
+        "ppSurface=%p pSharedHandle=%p\n", This,
+        Width, Height, d3dformat_to_string(Format), Format, Pool,
+        ppSurface, pSharedHandle);
+
+    user_assert(!pSharedHandle || Pool == D3DPOOL_DEFAULT
+                               || Pool == D3DPOOL_SYSTEMMEM, D3DERR_INVALIDCALL);
+    user_assert(Pool != D3DPOOL_MANAGED, D3DERR_INVALIDCALL);
+
+    /* Can be used with StretchRect and ColorFill. It's also always lockable.
+     */
+    hr = create_zs_or_rt_surface(This, 2, Pool, Width, Height,
+                                 Format,
+                                 D3DMULTISAMPLE_NONE, 0,
+                                 TRUE,
+                                 ppSurface, pSharedHandle);
+    if (FAILED(hr))
+        DBG("Failed to create surface.\n");
+    return hr;
+}
+
+HRESULT WINAPI
+NineDevice9_SetRenderTarget( struct NineDevice9 *This,
+                             DWORD RenderTargetIndex,
+                             IDirect3DSurface9 *pRenderTarget )
+{
+    struct NineSurface9 *rt = NineSurface9(pRenderTarget);
+    const unsigned i = RenderTargetIndex;
+
+    DBG("This=%p RenderTargetIndex=%u pRenderTarget=%p\n", This,
+        RenderTargetIndex, pRenderTarget);
+
+    user_assert(i < This->caps.NumSimultaneousRTs, D3DERR_INVALIDCALL);
+    user_assert(i != 0 || pRenderTarget, D3DERR_INVALIDCALL);
+    user_assert(!pRenderTarget ||
+                rt->desc.Usage & D3DUSAGE_RENDERTARGET, D3DERR_INVALIDCALL);
+
+    if (i == 0) {
+        This->state.viewport.X = 0;
+        This->state.viewport.Y = 0;
+        This->state.viewport.Width = rt->desc.Width;
+        This->state.viewport.Height = rt->desc.Height;
+        This->state.viewport.MinZ = 0.0f;
+        This->state.viewport.MaxZ = 1.0f;
+
+        This->state.scissor.minx = 0;
+        This->state.scissor.miny = 0;
+        This->state.scissor.maxx = rt->desc.Width;
+        This->state.scissor.maxy = rt->desc.Height;
+
+        This->state.changed.group |= NINE_STATE_VIEWPORT | NINE_STATE_SCISSOR;
+    }
+
+    if (This->state.rt[i] != NineSurface9(pRenderTarget)) {
+       nine_bind(&This->state.rt[i], pRenderTarget);
+       This->state.changed.group |= NINE_STATE_FB;
+    }
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_GetRenderTarget( struct NineDevice9 *This,
+                             DWORD RenderTargetIndex,
+                             IDirect3DSurface9 **ppRenderTarget )
+{
+    const unsigned i = RenderTargetIndex;
+
+    user_assert(i < This->caps.NumSimultaneousRTs, D3DERR_INVALIDCALL);
+    user_assert(ppRenderTarget, D3DERR_INVALIDCALL);
+
+    *ppRenderTarget = (IDirect3DSurface9 *)This->state.rt[i];
+    if (!This->state.rt[i])
+        return D3DERR_NOTFOUND;
+
+    NineUnknown_AddRef(NineUnknown(This->state.rt[i]));
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_SetDepthStencilSurface( struct NineDevice9 *This,
+                                    IDirect3DSurface9 *pNewZStencil )
+{
+    DBG("This=%p pNewZStencil=%p\n", This, pNewZStencil);
+
+    if (This->state.ds != NineSurface9(pNewZStencil)) {
+        nine_bind(&This->state.ds, pNewZStencil);
+        This->state.changed.group |= NINE_STATE_FB;
+    }
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_GetDepthStencilSurface( struct NineDevice9 *This,
+                                    IDirect3DSurface9 **ppZStencilSurface )
+{
+    user_assert(ppZStencilSurface, D3DERR_INVALIDCALL);
+
+    *ppZStencilSurface = (IDirect3DSurface9 *)This->state.ds;
+    if (!This->state.ds)
+        return D3DERR_NOTFOUND;
+
+    NineUnknown_AddRef(NineUnknown(This->state.ds));
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_BeginScene( struct NineDevice9 *This )
+{
+    DBG("This=%p\n", This);
+    user_assert(!This->in_scene, D3DERR_INVALIDCALL);
+    This->in_scene = TRUE;
+    /* Do we want to do anything else here ? */
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_EndScene( struct NineDevice9 *This )
+{
+    DBG("This=%p\n", This);
+    user_assert(This->in_scene, D3DERR_INVALIDCALL);
+    This->in_scene = FALSE;
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_Clear( struct NineDevice9 *This,
+                   DWORD Count,
+                   const D3DRECT *pRects,
+                   DWORD Flags,
+                   D3DCOLOR Color,
+                   float Z,
+                   DWORD Stencil )
+{
+    struct pipe_context *pipe = This->pipe;
+    struct NineSurface9 *zsbuf = This->state.ds;
+    unsigned bufs = 0;
+    unsigned r, i;
+    union pipe_color_union rgba;
+    D3DRECT rect;
+
+    DBG("This=%p Count=%u pRects=%p Flags=%x Color=%08x Z=%f Stencil=%x\n",
+        This, Count, pRects, Flags, Color, Z, Stencil);
+
+    user_assert(This->state.ds || !(Flags & NINED3DCLEAR_DEPTHSTENCIL),
+                D3DERR_INVALIDCALL);
+    user_assert(!(Flags & D3DCLEAR_STENCIL) ||
+                (zsbuf &&
+                 util_format_is_depth_and_stencil(zsbuf->base.info.format)),
+                D3DERR_INVALIDCALL);
+#ifdef NINE_STRICT
+    user_assert((Count && pRects) || (!Count && !pRects), D3DERR_INVALIDCALL);
+#else
+    user_warn((pRects && !Count) || (!pRects && Count));
+    if (pRects && !Count)
+        return D3D_OK;
+    if (!pRects)
+        Count = 0;
+#endif
+
+    if (Flags & D3DCLEAR_TARGET) bufs |= PIPE_CLEAR_COLOR;
+    if (Flags & D3DCLEAR_ZBUFFER) bufs |= PIPE_CLEAR_DEPTH;
+    if (Flags & D3DCLEAR_STENCIL) bufs |= PIPE_CLEAR_STENCIL;
+    if (!bufs)
+        return D3D_OK;
+    d3dcolor_to_pipe_color_union(&rgba, Color);
+
+    nine_update_state(This, NINE_STATE_FB);
+
+    rect.x1 = This->state.viewport.X;
+    rect.y1 = This->state.viewport.Y;
+    rect.x2 = This->state.viewport.Width + rect.x1;
+    rect.y2 = This->state.viewport.Height + rect.y1;
+
+    /* Both rectangles apply, which is weird, but that's D3D9. */
+    if (This->state.rs[D3DRS_SCISSORTESTENABLE]) {
+        rect.x1 = MAX2(rect.x1, This->state.scissor.minx);
+        rect.y1 = MAX2(rect.y1, This->state.scissor.miny);
+        rect.x2 = MIN2(rect.x2, This->state.scissor.maxx);
+        rect.y2 = MIN2(rect.y2, This->state.scissor.maxy);
+    }
+
+    if (Count) {
+        /* Maybe apps like to specify a large rect ? */
+        if (pRects[0].x1 <= rect.x1 && pRects[0].x2 >= rect.x2 &&
+            pRects[0].y1 <= rect.y1 && pRects[0].y2 >= rect.y2) {
+            DBG("First rect covers viewport.\n");
+            Count = 0;
+            pRects = NULL;
+        }
+    }
+
+    if (rect.x1 >= This->state.fb.width || rect.y1 >= This->state.fb.height)
+        return D3D_OK;
+    if (!Count &&
+        rect.x1 == 0 && rect.x2 >= This->state.fb.width &&
+        rect.y1 == 0 && rect.y2 >= This->state.fb.height) {
+        /* fast path, clears everything at once */
+        DBG("fast path\n");
+        pipe->clear(pipe, bufs, &rgba, Z, Stencil);
+        return D3D_OK;
+    }
+    rect.x2 = MIN2(rect.x2, This->state.fb.width);
+    rect.y2 = MIN2(rect.y2, This->state.fb.height);
+
+    if (!Count) {
+        Count = 1;
+        pRects = &rect;
+    }
+
+    for (i = 0; (i < This->state.fb.nr_cbufs); ++i) {
+        if (!This->state.fb.cbufs[i] || !(Flags & D3DCLEAR_TARGET))
+            continue; /* save space, compiler should hoist this */
+        for (r = 0; r < Count; ++r) {
+            /* Don't trust users to pass these in the right order. */
+            unsigned x1 = MIN2(pRects[r].x1, pRects[r].x2);
+            unsigned y1 = MIN2(pRects[r].y1, pRects[r].y2);
+            unsigned x2 = MAX2(pRects[r].x1, pRects[r].x2);
+            unsigned y2 = MAX2(pRects[r].y1, pRects[r].y2);
+#ifndef NINE_LAX
+            /* Drop negative rectangles (like wine expects). */
+            if (pRects[r].x1 > pRects[r].x2) continue;
+            if (pRects[r].y1 > pRects[r].y2) continue;
+#endif
+
+            x1 = MAX2(x1, rect.x1);
+            y1 = MAX2(y1, rect.y1);
+            x2 = MIN2(x2, rect.x2);
+            y2 = MIN2(y2, rect.y2);
+
+            DBG("Clearing (%u..%u)x(%u..%u)\n", x1, x2, y1, y2);
+            pipe->clear_render_target(pipe, This->state.fb.cbufs[i], &rgba,
+                                      x1, y1, x2 - x1, y2 - y1);
+        }
+    }
+    if (!(Flags & NINED3DCLEAR_DEPTHSTENCIL))
+        return D3D_OK;
+
+    bufs &= PIPE_CLEAR_DEPTHSTENCIL;
+
+    for (r = 0; r < Count; ++r) {
+        unsigned x1 = MIN2(pRects[r].x1, pRects[r].x2);
+        unsigned y1 = MIN2(pRects[r].y1, pRects[r].y2);
+        unsigned x2 = MAX2(pRects[r].x1, pRects[r].x2);
+        unsigned y2 = MAX2(pRects[r].y1, pRects[r].y2);
+#ifndef NINE_LAX
+        /* Drop negative rectangles. */
+        if (pRects[r].x1 > pRects[r].x2) continue;
+        if (pRects[r].y1 > pRects[r].y2) continue;
+#endif
+
+        x1 = MIN2(x1, rect.x1);
+        y1 = MIN2(y1, rect.y1);
+        x2 = MIN2(x2, rect.x2);
+        y2 = MIN2(y2, rect.y2);
+
+        pipe->clear_depth_stencil(pipe, This->state.fb.zsbuf, bufs, Z, Stencil,
+                                  x1, y1, x2 - x1, y2 - y1);
+    }
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_SetTransform( struct NineDevice9 *This,
+                          D3DTRANSFORMSTATETYPE State,
+                          const D3DMATRIX *pMatrix )
+{
+    struct nine_state *state = This->update;
+    D3DMATRIX *M = nine_state_access_transform(state, State, TRUE);
+    user_assert(M, D3DERR_INVALIDCALL);
+
+    *M = *pMatrix;
+    state->ff.changed.transform[State / 32] |= 1 << (State % 32);
+    state->changed.group |= NINE_STATE_FF;
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_GetTransform( struct NineDevice9 *This,
+                          D3DTRANSFORMSTATETYPE State,
+                          D3DMATRIX *pMatrix )
+{
+    D3DMATRIX *M = nine_state_access_transform(&This->state, State, FALSE);
+    user_assert(M, D3DERR_INVALIDCALL);
+    *pMatrix = *M;
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_MultiplyTransform( struct NineDevice9 *This,
+                               D3DTRANSFORMSTATETYPE State,
+                               const D3DMATRIX *pMatrix )
+{
+    struct nine_state *state = This->update;
+    D3DMATRIX T;
+    D3DMATRIX *M = nine_state_access_transform(state, State, TRUE);
+    user_assert(M, D3DERR_INVALIDCALL);
+
+    nine_d3d_matrix_matrix_mul(&T, pMatrix, M);
+    return NineDevice9_SetTransform(This, State, &T);
+}
+
+HRESULT WINAPI
+NineDevice9_SetViewport( struct NineDevice9 *This,
+                         const D3DVIEWPORT9 *pViewport )
+{
+    struct nine_state *state = This->update;
+
+    DBG("X=%u Y=%u W=%u H=%u MinZ=%f MaxZ=%f\n",
+        pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height,
+        pViewport->MinZ, pViewport->MaxZ);
+
+    state->viewport = *pViewport;
+    state->changed.group |= NINE_STATE_VIEWPORT;
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_GetViewport( struct NineDevice9 *This,
+                         D3DVIEWPORT9 *pViewport )
+{
+    *pViewport = This->state.viewport;
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_SetMaterial( struct NineDevice9 *This,
+                         const D3DMATERIAL9 *pMaterial )
+{
+    struct nine_state *state = This->update;
+
+    DBG("This=%p pMaterial=%p\n", This, pMaterial);
+    if (pMaterial)
+        nine_dump_D3DMATERIAL9(DBG_FF, pMaterial);
+
+    user_assert(pMaterial, E_POINTER);
+
+    state->ff.material = *pMaterial;
+    state->changed.group |= NINE_STATE_FF_MATERIAL;
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_GetMaterial( struct NineDevice9 *This,
+                         D3DMATERIAL9 *pMaterial )
+{
+    user_assert(pMaterial, E_POINTER);
+    *pMaterial = This->state.ff.material;
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_SetLight( struct NineDevice9 *This,
+                      DWORD Index,
+                      const D3DLIGHT9 *pLight )
+{
+    struct nine_state *state = This->update;
+
+    DBG("This=%p Index=%u pLight=%p\n", This, Index, pLight);
+    if (pLight)
+        nine_dump_D3DLIGHT9(DBG_FF, pLight);
+
+    user_assert(pLight, D3DERR_INVALIDCALL);
+    user_assert(pLight->Type < NINED3DLIGHT_INVALID, D3DERR_INVALIDCALL);
+
+    user_assert(Index < NINE_MAX_LIGHTS, D3DERR_INVALIDCALL); /* sanity */
+
+    if (Index >= state->ff.num_lights) {
+        unsigned n = state->ff.num_lights;
+        unsigned N = Index + 1;
+
+        state->ff.light = REALLOC(state->ff.light, n * sizeof(D3DLIGHT9),
+                                                   N * sizeof(D3DLIGHT9));
+        if (!state->ff.light)
+            return E_OUTOFMEMORY;
+        state->ff.num_lights = N;
+
+        for (; n < Index; ++n)
+            state->ff.light[n].Type = (D3DLIGHTTYPE)NINED3DLIGHT_INVALID;
+    }
+    state->ff.light[Index] = *pLight;
+
+    if (pLight->Type == D3DLIGHT_SPOT && pLight->Theta >= pLight->Phi) {
+        DBG("Warning: clamping D3DLIGHT9.Theta\n");
+        state->ff.light[Index].Theta = state->ff.light[Index].Phi;
+    }
+    if (pLight->Type != D3DLIGHT_DIRECTIONAL &&
+        pLight->Attenuation0 == 0.0f &&
+        pLight->Attenuation1 == 0.0f &&
+        pLight->Attenuation2 == 0.0f) {
+        DBG("Warning: all D3DLIGHT9.Attenuation[i] are 0\n");
+    }
+
+    state->changed.group |= NINE_STATE_FF_LIGHTING;
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_GetLight( struct NineDevice9 *This,
+                      DWORD Index,
+                      D3DLIGHT9 *pLight )
+{
+    const struct nine_state *state = &This->state;
+
+    user_assert(pLight, D3DERR_INVALIDCALL);
+    user_assert(Index < state->ff.num_lights, D3DERR_INVALIDCALL);
+    user_assert(state->ff.light[Index].Type < NINED3DLIGHT_INVALID,
+                D3DERR_INVALIDCALL);
+
+    *pLight = state->ff.light[Index];
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_LightEnable( struct NineDevice9 *This,
+                         DWORD Index,
+                         BOOL Enable )
+{
+    struct nine_state *state = This->update;
+    unsigned i;
+
+    DBG("This=%p Index=%u Enable=%i\n", This, Index, Enable);
+
+    if (Index >= state->ff.num_lights ||
+        state->ff.light[Index].Type == NINED3DLIGHT_INVALID) {
+        /* This should create a default light. */
+        D3DLIGHT9 light;
+        memset(&light, 0, sizeof(light));
+        light.Type = D3DLIGHT_DIRECTIONAL;
+        light.Diffuse.r = 1.0f;
+        light.Diffuse.g = 1.0f;
+        light.Diffuse.b = 1.0f;
+        light.Direction.z = 1.0f;
+        NineDevice9_SetLight(This, Index, &light);
+    }
+    user_assert(Index < state->ff.num_lights, D3DERR_INVALIDCALL);
+
+    for (i = 0; i < state->ff.num_lights_active; ++i) {
+        if (state->ff.active_light[i] == Index)
+            break;
+    }
+
+    if (Enable) {
+        if (i < state->ff.num_lights_active)
+            return D3D_OK;
+        /* XXX wine thinks this should still succeed:
+         */
+        user_assert(i < NINE_MAX_LIGHTS_ACTIVE, D3DERR_INVALIDCALL);
+
+        state->ff.active_light[i] = Index;
+        state->ff.num_lights_active++;
+    } else {
+        if (i == state->ff.num_lights_active)
+            return D3D_OK;
+        --state->ff.num_lights_active;
+        for (; i < state->ff.num_lights_active; ++i)
+            state->ff.active_light[i] = state->ff.active_light[i + 1];
+    }
+    state->changed.group |= NINE_STATE_FF_LIGHTING;
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_GetLightEnable( struct NineDevice9 *This,
+                            DWORD Index,
+                            BOOL *pEnable )
+{
+    const struct nine_state *state = &This->state;
+    unsigned i;
+
+    user_assert(Index < state->ff.num_lights, D3DERR_INVALIDCALL);
+    user_assert(state->ff.light[Index].Type < NINED3DLIGHT_INVALID,
+                D3DERR_INVALIDCALL);
+
+    for (i = 0; i < state->ff.num_lights_active; ++i)
+        if (state->ff.active_light[i] == Index)
+            break;
+    *pEnable = i != state->ff.num_lights_active;
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_SetClipPlane( struct NineDevice9 *This,
+                          DWORD Index,
+                          const float *pPlane )
+{
+    struct nine_state *state = This->update;
+
+    DBG("This=%p Index=%u pPlane=%p(%f %f %f %f)\n", This, Index, pPlane,
+        pPlane ? pPlane[0] : 0.0f, pPlane ? pPlane[1] : 0.0f,
+        pPlane ? pPlane[2] : 0.0f, pPlane ? pPlane[3] : 0.0f);
+
+    user_assert(Index < PIPE_MAX_CLIP_PLANES, D3DERR_INVALIDCALL);
+
+    memcpy(&state->clip.ucp[Index][0], pPlane, sizeof(state->clip.ucp[0]));
+    state->changed.ucp |= 1 << Index;
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_GetClipPlane( struct NineDevice9 *This,
+                          DWORD Index,
+                          float *pPlane )
+{
+    const struct nine_state *state = &This->state;
+
+    user_assert(Index < PIPE_MAX_CLIP_PLANES, D3DERR_INVALIDCALL);
+
+    memcpy(pPlane, &state->clip.ucp[Index][0], sizeof(state->clip.ucp[0]));
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_SetRenderState( struct NineDevice9 *This,
+                            D3DRENDERSTATETYPE State,
+                            DWORD Value )
+{
+    struct nine_state *state = This->update;
+
+    DBG("This=%p State=%u(%s) Value=%08x\n", This,
+        State, nine_d3drs_to_string(State), Value);
+
+    user_assert(State < Elements(state->rs), D3DERR_INVALIDCALL);
+
+    if (likely(state->rs[State] != Value) || unlikely(This->is_recording)) {
+        state->rs[State] = Value;
+        state->changed.rs[State / 32] |= 1 << (State % 32);
+        state->changed.group |= nine_render_state_group[State];
+    }
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_GetRenderState( struct NineDevice9 *This,
+                            D3DRENDERSTATETYPE State,
+                            DWORD *pValue )
+{
+    user_assert(State < Elements(This->state.rs), D3DERR_INVALIDCALL);
+
+    *pValue = This->state.rs[State];
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_CreateStateBlock( struct NineDevice9 *This,
+                              D3DSTATEBLOCKTYPE Type,
+                              IDirect3DStateBlock9 **ppSB )
+{
+    struct NineStateBlock9 *nsb;
+    struct nine_state *dst;
+    HRESULT hr;
+    enum nine_stateblock_type type;
+    unsigned s;
+
+    DBG("This=%p Type=%u ppSB=%p\n", This, Type, ppSB);
+
+    user_assert(Type == D3DSBT_ALL ||
+                Type == D3DSBT_VERTEXSTATE ||
+                Type == D3DSBT_PIXELSTATE, D3DERR_INVALIDCALL);
+
+    switch (Type) {
+    case D3DSBT_VERTEXSTATE: type = NINESBT_VERTEXSTATE; break;
+    case D3DSBT_PIXELSTATE:  type = NINESBT_PIXELSTATE; break;
+    default:
+       type = NINESBT_ALL;
+       break;
+    }
+
+    hr = NineStateBlock9_new(This, &nsb, type);
+    if (FAILED(hr))
+       return hr;
+    *ppSB = (IDirect3DStateBlock9 *)nsb;
+    dst = &nsb->state;
+
+    dst->changed.group =
+       NINE_STATE_TEXTURE |
+       NINE_STATE_SAMPLER;
+
+    if (Type == D3DSBT_ALL || Type == D3DSBT_VERTEXSTATE) {
+       dst->changed.group |=
+           NINE_STATE_FF_LIGHTING |
+           NINE_STATE_VS | NINE_STATE_VS_CONST |
+           NINE_STATE_VDECL;
+       /* TODO: texture/sampler state */
+       memcpy(dst->changed.rs,
+              nine_render_states_vertex, sizeof(dst->changed.rs));
+       nine_ranges_insert(&dst->changed.vs_const_f, 0, This->max_vs_const_f,
+                          &This->range_pool);
+       dst->changed.vs_const_i = 0xffff;
+       dst->changed.vs_const_b = 0xffff;
+       for (s = 0; s < NINE_MAX_SAMPLERS; ++s)
+           dst->changed.sampler[s] |= 1 << D3DSAMP_DMAPOFFSET;
+       if (This->state.ff.num_lights) {
+           dst->ff.num_lights = This->state.ff.num_lights;
+           /* zero'd -> light type won't be NINED3DLIGHT_INVALID, so
+            * all currently existing lights will be captured
+            */
+           dst->ff.light = CALLOC(This->state.ff.num_lights,
+                                  sizeof(D3DLIGHT9));
+           if (!dst->ff.light) {
+               nine_bind(ppSB, NULL);
+               return E_OUTOFMEMORY;
+           }
+       }
+    }
+    if (Type == D3DSBT_ALL || Type == D3DSBT_PIXELSTATE) {
+       dst->changed.group |=
+          NINE_STATE_PS | NINE_STATE_PS_CONST;
+       /* TODO: texture/sampler state */
+       memcpy(dst->changed.rs,
+              nine_render_states_pixel, sizeof(dst->changed.rs));
+       nine_ranges_insert(&dst->changed.ps_const_f, 0, This->max_ps_const_f,
+                          &This->range_pool);
+       dst->changed.ps_const_i = 0xffff;
+       dst->changed.ps_const_b = 0xffff;
+       for (s = 0; s < NINE_MAX_SAMPLERS; ++s)
+           dst->changed.sampler[s] |= 0x1ffe;
+    }
+    if (Type == D3DSBT_ALL) {
+       dst->changed.group |=
+          NINE_STATE_VIEWPORT |
+          NINE_STATE_SCISSOR |
+          NINE_STATE_RASTERIZER |
+          NINE_STATE_BLEND |
+          NINE_STATE_DSA |
+          NINE_STATE_IDXBUF |
+          NINE_STATE_MATERIAL |
+          NINE_STATE_BLEND_COLOR |
+          NINE_STATE_SAMPLE_MASK;
+       memset(dst->changed.rs, ~0, (D3DRS_COUNT / 32) * sizeof(uint32_t));
+       dst->changed.rs[D3DRS_LAST / 32] |= (1 << (D3DRS_COUNT % 32)) - 1;
+       dst->changed.vtxbuf = (1ULL << This->caps.MaxStreams) - 1;
+       dst->changed.stream_freq = dst->changed.vtxbuf;
+       dst->changed.ucp = (1 << PIPE_MAX_CLIP_PLANES) - 1;
+       dst->changed.texture = (1 << NINE_MAX_SAMPLERS) - 1;
+    }
+    NineStateBlock9_Capture(NineStateBlock9(*ppSB));
+
+    /* TODO: fixed function state */
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_BeginStateBlock( struct NineDevice9 *This )
+{
+    HRESULT hr;
+
+    DBG("This=%p\n", This);
+
+    user_assert(!This->record, D3DERR_INVALIDCALL);
+
+    hr = NineStateBlock9_new(This, &This->record, NINESBT_CUSTOM);
+    if (FAILED(hr))
+        return hr;
+    NineUnknown_ConvertRefToBind(NineUnknown(This->record));
+
+    This->update = &This->record->state;
+    This->is_recording = TRUE;
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_EndStateBlock( struct NineDevice9 *This,
+                           IDirect3DStateBlock9 **ppSB )
+{
+    DBG("This=%p ppSB=%p\n", This, ppSB);
+
+    user_assert(This->record, D3DERR_INVALIDCALL);
+
+    This->update = &This->state;
+    This->is_recording = FALSE;
+
+    NineUnknown_AddRef(NineUnknown(This->record));
+    *ppSB = (IDirect3DStateBlock9 *)This->record;
+    NineUnknown_Unbind(NineUnknown(This->record));
+    This->record = NULL;
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_SetClipStatus( struct NineDevice9 *This,
+                           const D3DCLIPSTATUS9 *pClipStatus )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineDevice9_GetClipStatus( struct NineDevice9 *This,
+                           D3DCLIPSTATUS9 *pClipStatus )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineDevice9_GetTexture( struct NineDevice9 *This,
+                        DWORD Stage,
+                        IDirect3DBaseTexture9 **ppTexture )
+{
+    user_assert(Stage < This->caps.MaxSimultaneousTextures ||
+                Stage == D3DDMAPSAMPLER ||
+                (Stage >= D3DVERTEXTEXTURESAMPLER0 &&
+                 Stage <= D3DVERTEXTEXTURESAMPLER3), D3DERR_INVALIDCALL);
+    user_assert(ppTexture, D3DERR_INVALIDCALL);
+
+    if (Stage >= D3DDMAPSAMPLER)
+        Stage = Stage - D3DDMAPSAMPLER + NINE_MAX_SAMPLERS_PS;
+
+    *ppTexture = (IDirect3DBaseTexture9 *)This->state.texture[Stage];
+
+    if (This->state.texture[Stage])
+        NineUnknown_AddRef(NineUnknown(This->state.texture[Stage]));
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_SetTexture( struct NineDevice9 *This,
+                        DWORD Stage,
+                        IDirect3DBaseTexture9 *pTexture )
+{
+    struct nine_state *state = This->update;
+
+    DBG("This=%p Stage=%u pTexture=%p\n", This, Stage, pTexture);
+
+    user_assert(Stage < This->caps.MaxSimultaneousTextures ||
+                Stage == D3DDMAPSAMPLER ||
+                (Stage >= D3DVERTEXTEXTURESAMPLER0 &&
+                 Stage <= D3DVERTEXTEXTURESAMPLER3), D3DERR_INVALIDCALL);
+
+    if (Stage >= D3DDMAPSAMPLER)
+        Stage = Stage - D3DDMAPSAMPLER + NINE_MAX_SAMPLERS_PS;
+
+    if (!This->is_recording) {
+        struct NineBaseTexture9 *tex = NineBaseTexture9(pTexture);
+        struct NineBaseTexture9 *old = state->texture[Stage];
+        if (old == tex)
+            return D3D_OK;
+
+        state->samplers_shadow &= ~(1 << Stage);
+        if (tex) {
+            state->samplers_shadow |= tex->shadow << Stage;
+
+            if ((tex->dirty | tex->dirty_mip) && LIST_IS_EMPTY(&tex->list))
+                list_add(&tex->list, &This->update_textures);
+
+            tex->bind_count++;
+        }
+        if (old)
+            old->bind_count--;
+    }
+    nine_bind(&state->texture[Stage], pTexture);
+
+    state->changed.texture |= 1 << Stage;
+    state->changed.group |= NINE_STATE_TEXTURE;
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_GetTextureStageState( struct NineDevice9 *This,
+                                  DWORD Stage,
+                                  D3DTEXTURESTAGESTATETYPE Type,
+                                  DWORD *pValue )
+{
+    const struct nine_state *state = &This->state;
+
+    user_assert(Stage < Elements(state->ff.tex_stage), D3DERR_INVALIDCALL);
+    user_assert(Type < Elements(state->ff.tex_stage[0]), D3DERR_INVALIDCALL);
+
+    *pValue = state->ff.tex_stage[Stage][Type];
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_SetTextureStageState( struct NineDevice9 *This,
+                                  DWORD Stage,
+                                  D3DTEXTURESTAGESTATETYPE Type,
+                                  DWORD Value )
+{
+    struct nine_state *state = This->update;
+
+    DBG("Stage=%u Type=%u Value=%08x\n", Stage, Type, Value);
+    nine_dump_D3DTSS_value(DBG_FF, Type, Value);
+
+    user_assert(Stage < Elements(state->ff.tex_stage), D3DERR_INVALIDCALL);
+    user_assert(Type < Elements(state->ff.tex_stage[0]), D3DERR_INVALIDCALL);
+
+    state->ff.tex_stage[Stage][Type] = Value;
+
+    state->changed.group |= NINE_STATE_FF_PSSTAGES;
+    state->ff.changed.tex_stage[Stage][Type / 32] |= 1 << (Type % 32);
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_GetSamplerState( struct NineDevice9 *This,
+                             DWORD Sampler,
+                             D3DSAMPLERSTATETYPE Type,
+                             DWORD *pValue )
+{
+    user_assert(Sampler < This->caps.MaxSimultaneousTextures ||
+                Sampler == D3DDMAPSAMPLER ||
+                (Sampler >= D3DVERTEXTEXTURESAMPLER0 &&
+                 Sampler <= D3DVERTEXTEXTURESAMPLER3), D3DERR_INVALIDCALL);
+
+    if (Sampler >= D3DDMAPSAMPLER)
+        Sampler = Sampler - D3DDMAPSAMPLER + NINE_MAX_SAMPLERS_PS;
+
+    *pValue = This->state.samp[Sampler][Type];
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_SetSamplerState( struct NineDevice9 *This,
+                             DWORD Sampler,
+                             D3DSAMPLERSTATETYPE Type,
+                             DWORD Value )
+{
+    struct nine_state *state = This->update;
+
+    DBG("This=%p Sampler=%u Type=%s Value=%08x\n", This,
+        Sampler, nine_D3DSAMP_to_str(Type), Value);
+
+    user_assert(Sampler < This->caps.MaxSimultaneousTextures ||
+                Sampler == D3DDMAPSAMPLER ||
+                (Sampler >= D3DVERTEXTEXTURESAMPLER0 &&
+                 Sampler <= D3DVERTEXTEXTURESAMPLER3), D3DERR_INVALIDCALL);
+
+    if (Sampler >= D3DDMAPSAMPLER)
+        Sampler = Sampler - D3DDMAPSAMPLER + NINE_MAX_SAMPLERS_PS;
+
+    state->samp[Sampler][Type] = Value;
+    state->changed.group |= NINE_STATE_SAMPLER;
+    state->changed.sampler[Sampler] |= 1 << Type;
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_ValidateDevice( struct NineDevice9 *This,
+                            DWORD *pNumPasses )
+{
+    const struct nine_state *state = &This->state;
+    unsigned i;
+    unsigned w = 0, h = 0;
+
+    DBG("This=%p pNumPasses=%p\n", This, pNumPasses);
+
+    for (i = 0; i < Elements(state->samp); ++i) {
+        if (state->samp[i][D3DSAMP_MINFILTER] == D3DTEXF_NONE ||
+            state->samp[i][D3DSAMP_MAGFILTER] == D3DTEXF_NONE)
+            return D3DERR_UNSUPPORTEDTEXTUREFILTER;
+    }
+
+    for (i = 0; i < This->caps.NumSimultaneousRTs; ++i) {
+        if (!state->rt[i])
+            continue;
+        if (w == 0) {
+            w = state->rt[i]->desc.Width;
+            h = state->rt[i]->desc.Height;
+        } else
+        if (state->rt[i]->desc.Width != w || state->rt[i]->desc.Height != h) {
+            return D3DERR_CONFLICTINGRENDERSTATE;
+        }
+    }
+    if (state->ds &&
+        (state->rs[D3DRS_ZENABLE] || state->rs[D3DRS_STENCILENABLE])) {
+        if (w != 0 &&
+            (state->ds->desc.Width != w || state->ds->desc.Height != h))
+            return D3DERR_CONFLICTINGRENDERSTATE;
+    }
+
+    if (pNumPasses)
+        *pNumPasses = 1;
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_SetPaletteEntries( struct NineDevice9 *This,
+                               UINT PaletteNumber,
+                               const PALETTEENTRY *pEntries )
+{
+    STUB(D3D_OK); /* like wine */
+}
+
+HRESULT WINAPI
+NineDevice9_GetPaletteEntries( struct NineDevice9 *This,
+                               UINT PaletteNumber,
+                               PALETTEENTRY *pEntries )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineDevice9_SetCurrentTexturePalette( struct NineDevice9 *This,
+                                      UINT PaletteNumber )
+{
+    STUB(D3D_OK); /* like wine */
+}
+
+HRESULT WINAPI
+NineDevice9_GetCurrentTexturePalette( struct NineDevice9 *This,
+                                      UINT *PaletteNumber )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineDevice9_SetScissorRect( struct NineDevice9 *This,
+                            const RECT *pRect )
+{
+    struct nine_state *state = This->update;
+
+    DBG("x=(%u..%u) y=(%u..%u)\n",
+        pRect->left, pRect->top, pRect->right, pRect->bottom);
+
+    state->scissor.minx = pRect->left;
+    state->scissor.miny = pRect->top;
+    state->scissor.maxx = pRect->right;
+    state->scissor.maxy = pRect->bottom;
+
+    state->changed.group |= NINE_STATE_SCISSOR;
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_GetScissorRect( struct NineDevice9 *This,
+                            RECT *pRect )
+{
+    pRect->left   = This->state.scissor.minx;
+    pRect->top    = This->state.scissor.miny;
+    pRect->right  = This->state.scissor.maxx;
+    pRect->bottom = This->state.scissor.maxy;
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_SetSoftwareVertexProcessing( struct NineDevice9 *This,
+                                         BOOL bSoftware )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+BOOL WINAPI
+NineDevice9_GetSoftwareVertexProcessing( struct NineDevice9 *This )
+{
+    return !!(This->params.BehaviorFlags & D3DCREATE_SOFTWARE_VERTEXPROCESSING);
+}
+
+HRESULT WINAPI
+NineDevice9_SetNPatchMode( struct NineDevice9 *This,
+                           float nSegments )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+float WINAPI
+NineDevice9_GetNPatchMode( struct NineDevice9 *This )
+{
+    STUB(0);
+}
+
+static INLINE void
+init_draw_info(struct pipe_draw_info *info,
+               struct NineDevice9 *dev, D3DPRIMITIVETYPE type, UINT count)
+{
+    info->mode = d3dprimitivetype_to_pipe_prim(type);
+    info->count = prim_count_to_vertex_count(type, count);
+    info->start_instance = 0;
+    info->instance_count = 1;
+    if (dev->state.stream_instancedata_mask & dev->state.stream_usage_mask)
+        info->instance_count = MAX2(dev->state.stream_freq[0] & 0x7FFFFF, 1);
+    info->primitive_restart = FALSE;
+    info->restart_index = 0;
+    info->count_from_stream_output = NULL;
+    info->indirect = NULL;
+}
+
+HRESULT WINAPI
+NineDevice9_DrawPrimitive( struct NineDevice9 *This,
+                           D3DPRIMITIVETYPE PrimitiveType,
+                           UINT StartVertex,
+                           UINT PrimitiveCount )
+{
+    struct pipe_draw_info info;
+
+    DBG("iface %p, PrimitiveType %u, StartVertex %u, PrimitiveCount %u\n",
+        This, PrimitiveType, StartVertex, PrimitiveCount);
+
+    nine_update_state(This, ~0);
+
+    init_draw_info(&info, This, PrimitiveType, PrimitiveCount);
+    info.indexed = FALSE;
+    info.start = StartVertex;
+    info.index_bias = 0;
+    info.min_index = info.start;
+    info.max_index = info.count - 1;
+
+    This->pipe->draw_vbo(This->pipe, &info);
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_DrawIndexedPrimitive( struct NineDevice9 *This,
+                                  D3DPRIMITIVETYPE PrimitiveType,
+                                  INT BaseVertexIndex,
+                                  UINT MinVertexIndex,
+                                  UINT NumVertices,
+                                  UINT StartIndex,
+                                  UINT PrimitiveCount )
+{
+    struct pipe_draw_info info;
+
+    DBG("iface %p, PrimitiveType %u, BaseVertexIndex %u, MinVertexIndex %u "
+        "NumVertices %u, StartIndex %u, PrimitiveCount %u\n",
+        This, PrimitiveType, BaseVertexIndex, MinVertexIndex, NumVertices,
+        StartIndex, PrimitiveCount);
+
+    user_assert(This->state.idxbuf, D3DERR_INVALIDCALL);
+    user_assert(This->state.vdecl, D3DERR_INVALIDCALL);
+
+    nine_update_state(This, ~0);
+
+    init_draw_info(&info, This, PrimitiveType, PrimitiveCount);
+    info.indexed = TRUE;
+    info.start = StartIndex;
+    info.index_bias = BaseVertexIndex;
+    /* These don't include index bias: */
+    info.min_index = MinVertexIndex;
+    info.max_index = MinVertexIndex + NumVertices - 1;
+
+    This->pipe->draw_vbo(This->pipe, &info);
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_DrawPrimitiveUP( struct NineDevice9 *This,
+                             D3DPRIMITIVETYPE PrimitiveType,
+                             UINT PrimitiveCount,
+                             const void *pVertexStreamZeroData,
+                             UINT VertexStreamZeroStride )
+{
+    struct pipe_vertex_buffer vtxbuf;
+    struct pipe_draw_info info;
+
+    DBG("iface %p, PrimitiveType %u, PrimitiveCount %u, data %p, stride %u\n",
+        This, PrimitiveType, PrimitiveCount,
+        pVertexStreamZeroData, VertexStreamZeroStride);
+
+    user_assert(pVertexStreamZeroData && VertexStreamZeroStride,
+                D3DERR_INVALIDCALL);
+
+    nine_update_state(This, ~0);
+
+    init_draw_info(&info, This, PrimitiveType, PrimitiveCount);
+    info.indexed = FALSE;
+    info.start = 0;
+    info.index_bias = 0;
+    info.min_index = 0;
+    info.max_index = info.count - 1;
+
+    vtxbuf.stride = VertexStreamZeroStride;
+    vtxbuf.buffer_offset = 0;
+    vtxbuf.buffer = NULL;
+    vtxbuf.user_buffer = pVertexStreamZeroData;
+
+    if (!This->driver_caps.user_vbufs)
+        u_upload_data(This->upload,
+                      0,
+                      (info.max_index + 1) * VertexStreamZeroStride, /* XXX */
+                      vtxbuf.user_buffer,
+                      &vtxbuf.buffer_offset,
+                      &vtxbuf.buffer);
+
+    This->pipe->set_vertex_buffers(This->pipe, 0, 1, &vtxbuf);
+
+    This->pipe->draw_vbo(This->pipe, &info);
+
+    NineDevice9_PauseRecording(This);
+    NineDevice9_SetStreamSource(This, 0, NULL, 0, 0);
+    NineDevice9_ResumeRecording(This);
+
+    pipe_resource_reference(&vtxbuf.buffer, NULL);
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_DrawIndexedPrimitiveUP( struct NineDevice9 *This,
+                                    D3DPRIMITIVETYPE PrimitiveType,
+                                    UINT MinVertexIndex,
+                                    UINT NumVertices,
+                                    UINT PrimitiveCount,
+                                    const void *pIndexData,
+                                    D3DFORMAT IndexDataFormat,
+                                    const void *pVertexStreamZeroData,
+                                    UINT VertexStreamZeroStride )
+{
+    struct pipe_draw_info info;
+    struct pipe_vertex_buffer vbuf;
+    struct pipe_index_buffer ibuf;
+
+    DBG("iface %p, PrimitiveType %u, MinVertexIndex %u, NumVertices %u "
+        "PrimitiveCount %u, pIndexData %p, IndexDataFormat %u "
+        "pVertexStreamZeroData %p, VertexStreamZeroStride %u\n",
+        This, PrimitiveType, MinVertexIndex, NumVertices, PrimitiveCount,
+        pIndexData, IndexDataFormat,
+        pVertexStreamZeroData, VertexStreamZeroStride);
+
+    user_assert(pIndexData && pVertexStreamZeroData, D3DERR_INVALIDCALL);
+    user_assert(VertexStreamZeroStride, D3DERR_INVALIDCALL);
+    user_assert(IndexDataFormat == D3DFMT_INDEX16 ||
+                IndexDataFormat == D3DFMT_INDEX32, D3DERR_INVALIDCALL);
+
+    nine_update_state(This, ~0);
+
+    init_draw_info(&info, This, PrimitiveType, PrimitiveCount);
+    info.indexed = TRUE;
+    info.start = 0;
+    info.index_bias = 0;
+    info.min_index = MinVertexIndex;
+    info.max_index = MinVertexIndex + NumVertices - 1;
+
+    vbuf.stride = VertexStreamZeroStride;
+    vbuf.buffer_offset = 0;
+    vbuf.buffer = NULL;
+    vbuf.user_buffer = pVertexStreamZeroData;
+
+    ibuf.index_size = (IndexDataFormat == D3DFMT_INDEX16) ? 2 : 4;
+    ibuf.offset = 0;
+    ibuf.buffer = NULL;
+    ibuf.user_buffer = pIndexData;
+
+    if (!This->driver_caps.user_vbufs) {
+        const unsigned base = info.min_index * VertexStreamZeroStride;
+        u_upload_data(This->upload,
+                      base,
+                      (info.max_index -
+                       info.min_index + 1) * VertexStreamZeroStride, /* XXX */
+                      (const uint8_t *)vbuf.user_buffer + base,
+                      &vbuf.buffer_offset,
+                      &vbuf.buffer);
+        /* Won't be used: */
+        vbuf.buffer_offset -= base;
+    }
+    if (!This->driver_caps.user_ibufs)
+        u_upload_data(This->upload,
+                      0,
+                      info.count * ibuf.index_size,
+                      ibuf.user_buffer,
+                      &ibuf.offset,
+                      &ibuf.buffer);
+
+    This->pipe->set_vertex_buffers(This->pipe, 0, 1, &vbuf);
+    This->pipe->set_index_buffer(This->pipe, &ibuf);
+
+    This->pipe->draw_vbo(This->pipe, &info);
+
+    pipe_resource_reference(&vbuf.buffer, NULL);
+    pipe_resource_reference(&ibuf.buffer, NULL);
+
+    NineDevice9_PauseRecording(This);
+    NineDevice9_SetIndices(This, NULL);
+    NineDevice9_SetStreamSource(This, 0, NULL, 0, 0);
+    NineDevice9_ResumeRecording(This);
+
+    return D3D_OK;
+}
+
+/* TODO: Write to pDestBuffer directly if vertex declaration contains
+ * only f32 formats.
+ */
+HRESULT WINAPI
+NineDevice9_ProcessVertices( struct NineDevice9 *This,
+                             UINT SrcStartIndex,
+                             UINT DestIndex,
+                             UINT VertexCount,
+                             IDirect3DVertexBuffer9 *pDestBuffer,
+                             IDirect3DVertexDeclaration9 *pVertexDecl,
+                             DWORD Flags )
+{
+    struct pipe_screen *screen = This->screen;
+    struct NineVertexDeclaration9 *vdecl = NineVertexDeclaration9(pVertexDecl);
+    struct NineVertexShader9 *vs;
+    struct pipe_resource *resource;
+    struct pipe_stream_output_target *target;
+    struct pipe_draw_info draw;
+    HRESULT hr;
+    unsigned buffer_offset, buffer_size;
+
+    if (!screen->get_param(screen, PIPE_CAP_MAX_STREAM_OUTPUT_BUFFERS))
+        STUB(D3DERR_INVALIDCALL);
+
+    nine_update_state(This, ~0);
+
+    /* TODO: Create shader with stream output. */
+    STUB(D3DERR_INVALIDCALL);
+    struct NineVertexBuffer9 *dst = NineVertexBuffer9(pDestBuffer);
+
+    vs = This->state.vs ? This->state.vs : This->ff.vs;
+
+    buffer_size = VertexCount * vs->so->stride[0];
+    if (1) {
+        struct pipe_resource templ;
+
+        templ.target = PIPE_BUFFER;
+        templ.format = PIPE_FORMAT_R8_UNORM;
+        templ.width0 = buffer_size;
+        templ.flags = 0;
+        templ.bind = PIPE_BIND_STREAM_OUTPUT;
+        templ.usage = PIPE_USAGE_STREAM;
+        templ.height0 = templ.depth0 = templ.array_size = 1;
+        templ.last_level = templ.nr_samples = 0;
+
+        resource = This->screen->resource_create(This->screen, &templ);
+        if (!resource)
+            return E_OUTOFMEMORY;
+        buffer_offset = 0;
+    } else {
+        /* SO matches vertex declaration */
+        resource = dst->base.resource;
+        buffer_offset = DestIndex * vs->so->stride[0];
+    }
+    target = This->pipe->create_stream_output_target(This->pipe, resource,
+                                                     buffer_offset,
+                                                     buffer_size);
+    if (!target) {
+        pipe_resource_reference(&resource, NULL);
+        return D3DERR_DRIVERINTERNALERROR;
+    }
+
+    if (!vdecl) {
+        hr = NineVertexDeclaration9_new_from_fvf(This, dst->desc.FVF, &vdecl);
+        if (FAILED(hr))
+            goto out;
+    }
+
+    init_draw_info(&draw, This, D3DPT_POINTLIST, VertexCount);
+    draw.instance_count = 1;
+    draw.indexed = FALSE;
+    draw.start = SrcStartIndex;
+    draw.index_bias = 0;
+    draw.min_index = SrcStartIndex;
+    draw.max_index = SrcStartIndex + VertexCount - 1;
+
+    This->pipe->set_stream_output_targets(This->pipe, 1, &target, 0);
+    This->pipe->draw_vbo(This->pipe, &draw);
+    This->pipe->set_stream_output_targets(This->pipe, 0, NULL, 0);
+    This->pipe->stream_output_target_destroy(This->pipe, target);
+
+    hr = NineVertexDeclaration9_ConvertStreamOutput(vdecl,
+                                                    dst, DestIndex, VertexCount,
+                                                    resource, vs->so);
+out:
+    pipe_resource_reference(&resource, NULL);
+    if (!pVertexDecl)
+        NineUnknown_Release(NineUnknown(vdecl));
+    return hr;
+}
+
+HRESULT WINAPI
+NineDevice9_CreateVertexDeclaration( struct NineDevice9 *This,
+                                     const D3DVERTEXELEMENT9 *pVertexElements,
+                                     IDirect3DVertexDeclaration9 **ppDecl )
+{
+    struct NineVertexDeclaration9 *vdecl;
+
+    HRESULT hr = NineVertexDeclaration9_new(This, pVertexElements, &vdecl);
+    if (SUCCEEDED(hr))
+        *ppDecl = (IDirect3DVertexDeclaration9 *)vdecl;
+
+    return hr;
+}
+
+HRESULT WINAPI
+NineDevice9_SetVertexDeclaration( struct NineDevice9 *This,
+                                  IDirect3DVertexDeclaration9 *pDecl )
+{
+    struct nine_state *state = This->update;
+
+    DBG("This=%p pDecl=%p\n", This, pDecl);
+
+    if (likely(!This->is_recording) && state->vdecl == NineVertexDeclaration9(pDecl))
+        return D3D_OK;
+    nine_bind(&state->vdecl, pDecl);
+
+    state->changed.group |= NINE_STATE_VDECL;
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_GetVertexDeclaration( struct NineDevice9 *This,
+                                  IDirect3DVertexDeclaration9 **ppDecl )
+{
+    user_assert(ppDecl, D3DERR_INVALIDCALL);
+
+    *ppDecl = (IDirect3DVertexDeclaration9 *)This->state.vdecl;
+    if (*ppDecl)
+        NineUnknown_AddRef(NineUnknown(*ppDecl));
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_SetFVF( struct NineDevice9 *This,
+                    DWORD FVF )
+{
+    struct NineVertexDeclaration9 *vdecl;
+    HRESULT hr;
+
+    DBG("FVF = %08x\n", FVF);
+    if (!FVF)
+        return D3D_OK; /* like wine */
+
+    vdecl = util_hash_table_get(This->ff.ht_fvf, &FVF);
+    if (!vdecl) {
+        hr = NineVertexDeclaration9_new_from_fvf(This, FVF, &vdecl);
+        if (FAILED(hr))
+            return hr;
+        vdecl->fvf = FVF;
+        util_hash_table_set(This->ff.ht_fvf, &vdecl->fvf, vdecl);
+        NineUnknown_ConvertRefToBind(NineUnknown(vdecl));
+    }
+    return NineDevice9_SetVertexDeclaration(
+        This, (IDirect3DVertexDeclaration9 *)vdecl);
+}
+
+HRESULT WINAPI
+NineDevice9_GetFVF( struct NineDevice9 *This,
+                    DWORD *pFVF )
+{
+    *pFVF = This->state.vdecl ? This->state.vdecl->fvf : 0;
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_CreateVertexShader( struct NineDevice9 *This,
+                                const DWORD *pFunction,
+                                IDirect3DVertexShader9 **ppShader )
+{
+    struct NineVertexShader9 *vs;
+    HRESULT hr;
+
+    hr = NineVertexShader9_new(This, &vs, pFunction, NULL);
+    if (FAILED(hr))
+        return hr;
+    *ppShader = (IDirect3DVertexShader9 *)vs;
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_SetVertexShader( struct NineDevice9 *This,
+                             IDirect3DVertexShader9 *pShader )
+{
+    struct nine_state *state = This->update;
+
+    DBG("This=%p pShader=%p\n", This, pShader);
+
+    nine_bind(&state->vs, pShader);
+
+    state->changed.group |= NINE_STATE_VS;
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_GetVertexShader( struct NineDevice9 *This,
+                             IDirect3DVertexShader9 **ppShader )
+{
+    user_assert(ppShader, D3DERR_INVALIDCALL);
+    nine_reference_set(ppShader, This->state.vs);
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_SetVertexShaderConstantF( struct NineDevice9 *This,
+                                      UINT StartRegister,
+                                      const float *pConstantData,
+                                      UINT Vector4fCount )
+{
+    struct nine_state *state = This->update;
+
+    DBG("This=%p StartRegister=%u pConstantData=%p Vector4fCount=%u\n",
+        This, StartRegister, pConstantData, Vector4fCount);
+
+    user_assert(StartRegister                  < This->caps.MaxVertexShaderConst, D3DERR_INVALIDCALL);
+    user_assert(StartRegister + Vector4fCount <= This->caps.MaxVertexShaderConst, D3DERR_INVALIDCALL);
+
+    if (!Vector4fCount)
+       return D3D_OK;
+    user_assert(pConstantData, D3DERR_INVALIDCALL);
+
+    memcpy(&state->vs_const_f[StartRegister * 4],
+           pConstantData,
+           Vector4fCount * 4 * sizeof(state->vs_const_f[0]));
+
+    nine_ranges_insert(&state->changed.vs_const_f,
+                       StartRegister, StartRegister + Vector4fCount,
+                       &This->range_pool);
+
+    state->changed.group |= NINE_STATE_VS_CONST;
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_GetVertexShaderConstantF( struct NineDevice9 *This,
+                                      UINT StartRegister,
+                                      float *pConstantData,
+                                      UINT Vector4fCount )
+{
+    const struct nine_state *state = &This->state;
+
+    user_assert(StartRegister                  < This->caps.MaxVertexShaderConst, D3DERR_INVALIDCALL);
+    user_assert(StartRegister + Vector4fCount <= This->caps.MaxVertexShaderConst, D3DERR_INVALIDCALL);
+    user_assert(pConstantData, D3DERR_INVALIDCALL);
+
+    memcpy(pConstantData,
+           &state->vs_const_f[StartRegister * 4],
+           Vector4fCount * 4 * sizeof(state->vs_const_f[0]));
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_SetVertexShaderConstantI( struct NineDevice9 *This,
+                                      UINT StartRegister,
+                                      const int *pConstantData,
+                                      UINT Vector4iCount )
+{
+    struct nine_state *state = This->update;
+
+    DBG("This=%p StartRegister=%u pConstantData=%p Vector4iCount=%u\n",
+        This, StartRegister, pConstantData, Vector4iCount);
+
+    user_assert(StartRegister                  < NINE_MAX_CONST_I, D3DERR_INVALIDCALL);
+    user_assert(StartRegister + Vector4iCount <= NINE_MAX_CONST_I, D3DERR_INVALIDCALL);
+    user_assert(pConstantData, D3DERR_INVALIDCALL);
+
+    memcpy(&state->vs_const_i[StartRegister][0],
+           pConstantData,
+           Vector4iCount * sizeof(state->vs_const_i[0]));
+
+    state->changed.vs_const_i |= ((1 << Vector4iCount) - 1) << StartRegister;
+    state->changed.group |= NINE_STATE_VS_CONST;
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_GetVertexShaderConstantI( struct NineDevice9 *This,
+                                      UINT StartRegister,
+                                      int *pConstantData,
+                                      UINT Vector4iCount )
+{
+    const struct nine_state *state = &This->state;
+
+    user_assert(StartRegister                  < NINE_MAX_CONST_I, D3DERR_INVALIDCALL);
+    user_assert(StartRegister + Vector4iCount <= NINE_MAX_CONST_I, D3DERR_INVALIDCALL);
+    user_assert(pConstantData, D3DERR_INVALIDCALL);
+
+    memcpy(pConstantData,
+           &state->vs_const_i[StartRegister][0],
+           Vector4iCount * sizeof(state->vs_const_i[0]));
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_SetVertexShaderConstantB( struct NineDevice9 *This,
+                                      UINT StartRegister,
+                                      const BOOL *pConstantData,
+                                      UINT BoolCount )
+{
+    struct nine_state *state = This->update;
+
+    DBG("This=%p StartRegister=%u pConstantData=%p BoolCount=%u\n",
+        This, StartRegister, pConstantData, BoolCount);
+
+    user_assert(StartRegister              < NINE_MAX_CONST_B, D3DERR_INVALIDCALL);
+    user_assert(StartRegister + BoolCount <= NINE_MAX_CONST_B, D3DERR_INVALIDCALL);
+    user_assert(pConstantData, D3DERR_INVALIDCALL);
+
+    memcpy(&state->vs_const_b[StartRegister],
+           pConstantData,
+           BoolCount * sizeof(state->vs_const_b[0]));
+
+    state->changed.vs_const_b |= ((1 << BoolCount) - 1) << StartRegister;
+    state->changed.group |= NINE_STATE_VS_CONST;
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_GetVertexShaderConstantB( struct NineDevice9 *This,
+                                      UINT StartRegister,
+                                      BOOL *pConstantData,
+                                      UINT BoolCount )
+{
+    const struct nine_state *state = &This->state;
+
+    user_assert(StartRegister              < NINE_MAX_CONST_B, D3DERR_INVALIDCALL);
+    user_assert(StartRegister + BoolCount <= NINE_MAX_CONST_B, D3DERR_INVALIDCALL);
+    user_assert(pConstantData, D3DERR_INVALIDCALL);
+
+    memcpy(pConstantData,
+           &state->vs_const_b[StartRegister],
+           BoolCount * sizeof(state->vs_const_b[0]));
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_SetStreamSource( struct NineDevice9 *This,
+                             UINT StreamNumber,
+                             IDirect3DVertexBuffer9 *pStreamData,
+                             UINT OffsetInBytes,
+                             UINT Stride )
+{
+    struct nine_state *state = This->update;
+    struct NineVertexBuffer9 *pVBuf9 = NineVertexBuffer9(pStreamData);
+    const unsigned i = StreamNumber;
+
+    user_assert(StreamNumber < This->caps.MaxStreams, D3DERR_INVALIDCALL);
+    user_assert(Stride <= This->caps.MaxStreamStride, D3DERR_INVALIDCALL);
+
+    if (likely(!This->is_recording)) {
+        if (state->stream[i] == NineVertexBuffer9(pStreamData) &&
+            state->vtxbuf[i].stride == Stride &&
+            state->vtxbuf[i].buffer_offset == OffsetInBytes)
+            return D3D_OK;
+    }
+    nine_bind(&state->stream[i], pStreamData);
+
+    state->changed.vtxbuf |= 1 << StreamNumber;
+
+    if (pStreamData) {
+        state->vtxbuf[i].stride = Stride;
+        state->vtxbuf[i].buffer_offset = OffsetInBytes;
+    }
+    state->vtxbuf[i].buffer = pStreamData ? pVBuf9->base.resource : NULL;
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_GetStreamSource( struct NineDevice9 *This,
+                             UINT StreamNumber,
+                             IDirect3DVertexBuffer9 **ppStreamData,
+                             UINT *pOffsetInBytes,
+                             UINT *pStride )
+{
+    const struct nine_state *state = &This->state;
+    const unsigned i = StreamNumber;
+
+    user_assert(StreamNumber < This->caps.MaxStreams, D3DERR_INVALIDCALL);
+    user_assert(ppStreamData, D3DERR_INVALIDCALL);
+
+    nine_reference_set(ppStreamData, state->stream[i]);
+    *pStride = state->vtxbuf[i].stride;
+    *pOffsetInBytes = state->vtxbuf[i].buffer_offset;
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_SetStreamSourceFreq( struct NineDevice9 *This,
+                                 UINT StreamNumber,
+                                 UINT Setting )
+{
+    struct nine_state *state = This->update;
+    /* const UINT freq = Setting & 0x7FFFFF; */
+
+    DBG("This=%p StreamNumber=%u FrequencyParameter=0x%x\n", This,
+        StreamNumber, Setting);
+
+    user_assert(StreamNumber < This->caps.MaxStreams, D3DERR_INVALIDCALL);
+    user_assert(StreamNumber != 0 || !(Setting & D3DSTREAMSOURCE_INSTANCEDATA),
+                D3DERR_INVALIDCALL);
+    user_assert(!((Setting & D3DSTREAMSOURCE_INSTANCEDATA) &&
+                  (Setting & D3DSTREAMSOURCE_INDEXEDDATA)), D3DERR_INVALIDCALL);
+    user_assert(Setting, D3DERR_INVALIDCALL);
+
+    state->stream_freq[StreamNumber] = Setting;
+
+    if (Setting & D3DSTREAMSOURCE_INSTANCEDATA)
+        state->stream_instancedata_mask |= 1 << StreamNumber;
+    else
+        state->stream_instancedata_mask &= ~(1 << StreamNumber);
+
+    state->changed.stream_freq |= 1 << StreamNumber;
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_GetStreamSourceFreq( struct NineDevice9 *This,
+                                 UINT StreamNumber,
+                                 UINT *pSetting )
+{
+    user_assert(StreamNumber < This->caps.MaxStreams, D3DERR_INVALIDCALL);
+    *pSetting = This->state.stream_freq[StreamNumber];
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_SetIndices( struct NineDevice9 *This,
+                        IDirect3DIndexBuffer9 *pIndexData )
+{
+    struct nine_state *state = This->update;
+
+    if (likely(!This->is_recording))
+        if (state->idxbuf == NineIndexBuffer9(pIndexData))
+            return D3D_OK;
+    nine_bind(&state->idxbuf, pIndexData);
+
+    state->changed.group |= NINE_STATE_IDXBUF;
+
+    return D3D_OK;
+}
+
+/* XXX: wine/d3d9 doesn't have pBaseVertexIndex, and it doesn't make sense
+ * here because it's an argument passed to the Draw calls.
+ */
+HRESULT WINAPI
+NineDevice9_GetIndices( struct NineDevice9 *This,
+                        IDirect3DIndexBuffer9 **ppIndexData /*,
+                        UINT *pBaseVertexIndex */ )
+{
+    user_assert(ppIndexData, D3DERR_INVALIDCALL);
+    nine_reference_set(ppIndexData, This->state.idxbuf);
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_CreatePixelShader( struct NineDevice9 *This,
+                               const DWORD *pFunction,
+                               IDirect3DPixelShader9 **ppShader )
+{
+    struct NinePixelShader9 *ps;
+    HRESULT hr;
+
+    hr = NinePixelShader9_new(This, &ps, pFunction, NULL);
+    if (FAILED(hr))
+        return hr;
+    *ppShader = (IDirect3DPixelShader9 *)ps;
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_SetPixelShader( struct NineDevice9 *This,
+                            IDirect3DPixelShader9 *pShader )
+{
+    struct nine_state *state = This->update;
+
+    DBG("This=%p pShader=%p\n", This, pShader);
+
+    nine_bind(&state->ps, pShader);
+
+    state->changed.group |= NINE_STATE_PS;
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_GetPixelShader( struct NineDevice9 *This,
+                            IDirect3DPixelShader9 **ppShader )
+{
+    user_assert(ppShader, D3DERR_INVALIDCALL);
+    nine_reference_set(ppShader, This->state.ps);
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_SetPixelShaderConstantF( struct NineDevice9 *This,
+                                     UINT StartRegister,
+                                     const float *pConstantData,
+                                     UINT Vector4fCount )
+{
+    struct nine_state *state = This->update;
+
+    DBG("This=%p StartRegister=%u pConstantData=%p Vector4fCount=%u\n",
+        This, StartRegister, pConstantData, Vector4fCount);
+
+    user_assert(StartRegister                  < NINE_MAX_CONST_F, D3DERR_INVALIDCALL);
+    user_assert(StartRegister + Vector4fCount <= NINE_MAX_CONST_F, D3DERR_INVALIDCALL);
+
+    if (!Vector4fCount)
+       return D3D_OK;
+    user_assert(pConstantData, D3DERR_INVALIDCALL);
+
+    memcpy(&state->ps_const_f[StartRegister * 4],
+           pConstantData,
+           Vector4fCount * 4 * sizeof(state->ps_const_f[0]));
+
+    nine_ranges_insert(&state->changed.ps_const_f,
+                       StartRegister, StartRegister + Vector4fCount,
+                       &This->range_pool);
+
+    state->changed.group |= NINE_STATE_PS_CONST;
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_GetPixelShaderConstantF( struct NineDevice9 *This,
+                                     UINT StartRegister,
+                                     float *pConstantData,
+                                     UINT Vector4fCount )
+{
+    const struct nine_state *state = &This->state;
+
+    user_assert(StartRegister                  < NINE_MAX_CONST_F, D3DERR_INVALIDCALL);
+    user_assert(StartRegister + Vector4fCount <= NINE_MAX_CONST_F, D3DERR_INVALIDCALL);
+    user_assert(pConstantData, D3DERR_INVALIDCALL);
+
+    memcpy(pConstantData,
+           &state->ps_const_f[StartRegister * 4],
+           Vector4fCount * 4 * sizeof(state->ps_const_f[0]));
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_SetPixelShaderConstantI( struct NineDevice9 *This,
+                                     UINT StartRegister,
+                                     const int *pConstantData,
+                                     UINT Vector4iCount )
+{
+    struct nine_state *state = This->update;
+
+    DBG("This=%p StartRegister=%u pConstantData=%p Vector4iCount=%u\n",
+        This, StartRegister, pConstantData, Vector4iCount);
+
+    user_assert(StartRegister                  < NINE_MAX_CONST_I, D3DERR_INVALIDCALL);
+    user_assert(StartRegister + Vector4iCount <= NINE_MAX_CONST_I, D3DERR_INVALIDCALL);
+    user_assert(pConstantData, D3DERR_INVALIDCALL);
+
+    memcpy(&state->ps_const_i[StartRegister][0],
+           pConstantData,
+           Vector4iCount * sizeof(state->ps_const_i[0]));
+
+    state->changed.ps_const_i |= ((1 << Vector4iCount) - 1) << StartRegister;
+    state->changed.group |= NINE_STATE_PS_CONST;
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_GetPixelShaderConstantI( struct NineDevice9 *This,
+                                     UINT StartRegister,
+                                     int *pConstantData,
+                                     UINT Vector4iCount )
+{
+    const struct nine_state *state = &This->state;
+
+    user_assert(StartRegister                  < NINE_MAX_CONST_I, D3DERR_INVALIDCALL);
+    user_assert(StartRegister + Vector4iCount <= NINE_MAX_CONST_I, D3DERR_INVALIDCALL);
+    user_assert(pConstantData, D3DERR_INVALIDCALL);
+
+    memcpy(pConstantData,
+           &state->ps_const_i[StartRegister][0],
+           Vector4iCount * sizeof(state->ps_const_i[0]));
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_SetPixelShaderConstantB( struct NineDevice9 *This,
+                                     UINT StartRegister,
+                                     const BOOL *pConstantData,
+                                     UINT BoolCount )
+{
+    struct nine_state *state = This->update;
+
+    DBG("This=%p StartRegister=%u pConstantData=%p BoolCount=%u\n",
+        This, StartRegister, pConstantData, BoolCount);
+
+    user_assert(StartRegister              < NINE_MAX_CONST_B, D3DERR_INVALIDCALL);
+    user_assert(StartRegister + BoolCount <= NINE_MAX_CONST_B, D3DERR_INVALIDCALL);
+    user_assert(pConstantData, D3DERR_INVALIDCALL);
+
+    memcpy(&state->ps_const_b[StartRegister],
+           pConstantData,
+           BoolCount * sizeof(state->ps_const_b[0]));
+
+    state->changed.ps_const_b |= ((1 << BoolCount) - 1) << StartRegister;
+    state->changed.group |= NINE_STATE_PS_CONST;
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_GetPixelShaderConstantB( struct NineDevice9 *This,
+                                     UINT StartRegister,
+                                     BOOL *pConstantData,
+                                     UINT BoolCount )
+{
+    const struct nine_state *state = &This->state;
+
+    user_assert(StartRegister              < NINE_MAX_CONST_B, D3DERR_INVALIDCALL);
+    user_assert(StartRegister + BoolCount <= NINE_MAX_CONST_B, D3DERR_INVALIDCALL);
+    user_assert(pConstantData, D3DERR_INVALIDCALL);
+
+    memcpy(pConstantData,
+           &state->ps_const_b[StartRegister],
+           BoolCount * sizeof(state->ps_const_b[0]));
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9_DrawRectPatch( struct NineDevice9 *This,
+                           UINT Handle,
+                           const float *pNumSegs,
+                           const D3DRECTPATCH_INFO *pRectPatchInfo )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineDevice9_DrawTriPatch( struct NineDevice9 *This,
+                          UINT Handle,
+                          const float *pNumSegs,
+                          const D3DTRIPATCH_INFO *pTriPatchInfo )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineDevice9_DeletePatch( struct NineDevice9 *This,
+                         UINT Handle )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineDevice9_CreateQuery( struct NineDevice9 *This,
+                         D3DQUERYTYPE Type,
+                         IDirect3DQuery9 **ppQuery )
+{
+    struct NineQuery9 *query;
+    HRESULT hr;
+
+    if (!ppQuery)
+        return nine_is_query_supported(Type);
+
+    hr = NineQuery9_new(This, &query, Type);
+    if (FAILED(hr))
+        return hr;
+    *ppQuery = (IDirect3DQuery9 *)query;
+    return D3D_OK;
+}
+
+IDirect3DDevice9Vtbl NineDevice9_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)NineDevice9_TestCooperativeLevel,
+    (void *)NineDevice9_GetAvailableTextureMem,
+    (void *)NineDevice9_EvictManagedResources,
+    (void *)NineDevice9_GetDirect3D,
+    (void *)NineDevice9_GetDeviceCaps,
+    (void *)NineDevice9_GetDisplayMode,
+    (void *)NineDevice9_GetCreationParameters,
+    (void *)NineDevice9_SetCursorProperties,
+    (void *)NineDevice9_SetCursorPosition,
+    (void *)NineDevice9_ShowCursor,
+    (void *)NineDevice9_CreateAdditionalSwapChain,
+    (void *)NineDevice9_GetSwapChain,
+    (void *)NineDevice9_GetNumberOfSwapChains,
+    (void *)NineDevice9_Reset,
+    (void *)NineDevice9_Present,
+    (void *)NineDevice9_GetBackBuffer,
+    (void *)NineDevice9_GetRasterStatus,
+    (void *)NineDevice9_SetDialogBoxMode,
+    (void *)NineDevice9_SetGammaRamp,
+    (void *)NineDevice9_GetGammaRamp,
+    (void *)NineDevice9_CreateTexture,
+    (void *)NineDevice9_CreateVolumeTexture,
+    (void *)NineDevice9_CreateCubeTexture,
+    (void *)NineDevice9_CreateVertexBuffer,
+    (void *)NineDevice9_CreateIndexBuffer,
+    (void *)NineDevice9_CreateRenderTarget,
+    (void *)NineDevice9_CreateDepthStencilSurface,
+    (void *)NineDevice9_UpdateSurface,
+    (void *)NineDevice9_UpdateTexture,
+    (void *)NineDevice9_GetRenderTargetData,
+    (void *)NineDevice9_GetFrontBufferData,
+    (void *)NineDevice9_StretchRect,
+    (void *)NineDevice9_ColorFill,
+    (void *)NineDevice9_CreateOffscreenPlainSurface,
+    (void *)NineDevice9_SetRenderTarget,
+    (void *)NineDevice9_GetRenderTarget,
+    (void *)NineDevice9_SetDepthStencilSurface,
+    (void *)NineDevice9_GetDepthStencilSurface,
+    (void *)NineDevice9_BeginScene,
+    (void *)NineDevice9_EndScene,
+    (void *)NineDevice9_Clear,
+    (void *)NineDevice9_SetTransform,
+    (void *)NineDevice9_GetTransform,
+    (void *)NineDevice9_MultiplyTransform,
+    (void *)NineDevice9_SetViewport,
+    (void *)NineDevice9_GetViewport,
+    (void *)NineDevice9_SetMaterial,
+    (void *)NineDevice9_GetMaterial,
+    (void *)NineDevice9_SetLight,
+    (void *)NineDevice9_GetLight,
+    (void *)NineDevice9_LightEnable,
+    (void *)NineDevice9_GetLightEnable,
+    (void *)NineDevice9_SetClipPlane,
+    (void *)NineDevice9_GetClipPlane,
+    (void *)NineDevice9_SetRenderState,
+    (void *)NineDevice9_GetRenderState,
+    (void *)NineDevice9_CreateStateBlock,
+    (void *)NineDevice9_BeginStateBlock,
+    (void *)NineDevice9_EndStateBlock,
+    (void *)NineDevice9_SetClipStatus,
+    (void *)NineDevice9_GetClipStatus,
+    (void *)NineDevice9_GetTexture,
+    (void *)NineDevice9_SetTexture,
+    (void *)NineDevice9_GetTextureStageState,
+    (void *)NineDevice9_SetTextureStageState,
+    (void *)NineDevice9_GetSamplerState,
+    (void *)NineDevice9_SetSamplerState,
+    (void *)NineDevice9_ValidateDevice,
+    (void *)NineDevice9_SetPaletteEntries,
+    (void *)NineDevice9_GetPaletteEntries,
+    (void *)NineDevice9_SetCurrentTexturePalette,
+    (void *)NineDevice9_GetCurrentTexturePalette,
+    (void *)NineDevice9_SetScissorRect,
+    (void *)NineDevice9_GetScissorRect,
+    (void *)NineDevice9_SetSoftwareVertexProcessing,
+    (void *)NineDevice9_GetSoftwareVertexProcessing,
+    (void *)NineDevice9_SetNPatchMode,
+    (void *)NineDevice9_GetNPatchMode,
+    (void *)NineDevice9_DrawPrimitive,
+    (void *)NineDevice9_DrawIndexedPrimitive,
+    (void *)NineDevice9_DrawPrimitiveUP,
+    (void *)NineDevice9_DrawIndexedPrimitiveUP,
+    (void *)NineDevice9_ProcessVertices,
+    (void *)NineDevice9_CreateVertexDeclaration,
+    (void *)NineDevice9_SetVertexDeclaration,
+    (void *)NineDevice9_GetVertexDeclaration,
+    (void *)NineDevice9_SetFVF,
+    (void *)NineDevice9_GetFVF,
+    (void *)NineDevice9_CreateVertexShader,
+    (void *)NineDevice9_SetVertexShader,
+    (void *)NineDevice9_GetVertexShader,
+    (void *)NineDevice9_SetVertexShaderConstantF,
+    (void *)NineDevice9_GetVertexShaderConstantF,
+    (void *)NineDevice9_SetVertexShaderConstantI,
+    (void *)NineDevice9_GetVertexShaderConstantI,
+    (void *)NineDevice9_SetVertexShaderConstantB,
+    (void *)NineDevice9_GetVertexShaderConstantB,
+    (void *)NineDevice9_SetStreamSource,
+    (void *)NineDevice9_GetStreamSource,
+    (void *)NineDevice9_SetStreamSourceFreq,
+    (void *)NineDevice9_GetStreamSourceFreq,
+    (void *)NineDevice9_SetIndices,
+    (void *)NineDevice9_GetIndices,
+    (void *)NineDevice9_CreatePixelShader,
+    (void *)NineDevice9_SetPixelShader,
+    (void *)NineDevice9_GetPixelShader,
+    (void *)NineDevice9_SetPixelShaderConstantF,
+    (void *)NineDevice9_GetPixelShaderConstantF,
+    (void *)NineDevice9_SetPixelShaderConstantI,
+    (void *)NineDevice9_GetPixelShaderConstantI,
+    (void *)NineDevice9_SetPixelShaderConstantB,
+    (void *)NineDevice9_GetPixelShaderConstantB,
+    (void *)NineDevice9_DrawRectPatch,
+    (void *)NineDevice9_DrawTriPatch,
+    (void *)NineDevice9_DeletePatch,
+    (void *)NineDevice9_CreateQuery
+};
+
+static const GUID *NineDevice9_IIDs[] = {
+    &IID_IDirect3DDevice9,
+    &IID_IUnknown,
+    NULL
+};
+
+HRESULT
+NineDevice9_new( struct pipe_screen *pScreen,
+                 D3DDEVICE_CREATION_PARAMETERS *pCreationParameters,
+                 D3DCAPS9 *pCaps,
+                 D3DPRESENT_PARAMETERS *pPresentationParameters,
+                 IDirect3D9 *pD3D9,
+                 ID3DPresentGroup *pPresentationGroup,
+                 struct d3dadapter9_context *pCTX,
+                 struct NineDevice9 **ppOut )
+{
+    BOOL lock;
+    lock = !!(pCreationParameters->BehaviorFlags & D3DCREATE_MULTITHREADED);
+
+    NINE_NEW(Device9, ppOut, lock, /* args */
+             pScreen, pCreationParameters, pCaps,
+             pPresentationParameters, pD3D9, pPresentationGroup, pCTX);
+}
diff --git a/src/gallium/state_trackers/nine/device9.h b/src/gallium/state_trackers/nine/device9.h
new file mode 100644 (file)
index 0000000..9dc248e
--- /dev/null
@@ -0,0 +1,801 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _NINE_DEVICE9_H_
+#define _NINE_DEVICE9_H_
+
+#include "d3dadapter/d3dadapter9.h"
+
+#include "iunknown.h"
+#include "adapter9.h"
+
+#include "nine_helpers.h"
+#include "nine_state.h"
+
+struct gen_mipmap_state;
+struct util_hash_table;
+struct pipe_screen;
+struct pipe_context;
+struct cso_context;
+struct hud_context;
+struct u_upload_mgr;
+
+struct NineSwapChain9;
+struct NineStateBlock9;
+
+#include "util/u_double_list.h"
+
+struct NineDevice9
+{
+    struct NineUnknown base;
+    boolean ex;
+    D3DDISPLAYMODEEX *pFullscreenDisplayMode;
+
+    /* G3D context */
+    struct pipe_screen *screen;
+    struct pipe_context *pipe;
+    struct cso_context *cso;
+
+    /* creation parameters */
+    D3DCAPS9 caps;
+    D3DDEVICE_CREATION_PARAMETERS params;
+    IDirect3D9 *d3d9;
+
+    /* swapchain stuff */
+    ID3DPresentGroup *present;
+    struct NineSwapChain9 **swapchains;
+    unsigned nswapchains;
+
+    struct NineStateBlock9 *record;
+    struct nine_state *update; /* state to update (&state / &record->state) */
+    struct nine_state state;   /* device state */
+
+    struct list_head update_textures;
+
+    boolean is_recording;
+    boolean in_scene;
+
+    boolean prefer_user_constbuf;
+
+    struct pipe_resource *constbuf_vs;
+    struct pipe_resource *constbuf_ps;
+    uint16_t max_vs_const_f;
+    uint16_t max_ps_const_f;
+    uint32_t vs_bool_true;
+    uint32_t ps_bool_true;
+
+    struct gen_mipmap_state *gen_mipmap;
+
+    struct {
+        struct util_hash_table *ht_vs;
+        struct util_hash_table *ht_ps;
+        struct NineVertexShader9 *vs;
+        struct NinePixelShader9 *ps;
+        unsigned num_vs;
+        unsigned num_ps;
+        float *vs_const;
+        float *ps_const;
+
+        struct util_hash_table *ht_fvf;
+    } ff;
+
+    struct {
+        struct pipe_resource *image;
+        unsigned w;
+        unsigned h;
+        POINT hotspot; /* -1, -1 if no cursor image set */
+        POINT pos;
+        BOOL visible;
+        boolean software;
+    } cursor;
+
+    struct {
+        boolean user_vbufs;
+        boolean user_ibufs;
+        boolean window_space_position_support;
+    } driver_caps;
+
+    struct u_upload_mgr *upload;
+
+    struct nine_range_pool range_pool;
+
+    struct hud_context *hud; /* NULL if hud is disabled */
+};
+static INLINE struct NineDevice9 *
+NineDevice9( void *data )
+{
+    return (struct NineDevice9 *)data;
+}
+
+HRESULT
+NineDevice9_new( struct pipe_screen *pScreen,
+                 D3DDEVICE_CREATION_PARAMETERS *pCreationParameters,
+                 D3DCAPS9 *pCaps,
+                 D3DPRESENT_PARAMETERS *pPresentationParameters,
+                 IDirect3D9 *pD3D9,
+                 ID3DPresentGroup *pPresentationGroup,
+                 struct d3dadapter9_context *pCTX,
+                 struct NineDevice9 **ppOut );
+
+HRESULT
+NineDevice9_ctor( struct NineDevice9 *This,
+                  struct NineUnknownParams *pParams,
+                  struct pipe_screen *pScreen,
+                  D3DDEVICE_CREATION_PARAMETERS *pCreationParameters,
+                  D3DCAPS9 *pCaps,
+                  D3DPRESENT_PARAMETERS *pPresentationParameters,
+                  IDirect3D9 *pD3D9,
+                  ID3DPresentGroup *pPresentationGroup,
+                  struct d3dadapter9_context *pCTX );
+
+void
+NineDevice9_dtor( struct NineDevice9 *This );
+
+/*** Nine private ***/
+
+struct pipe_screen *
+NineDevice9_GetScreen( struct NineDevice9 *This );
+
+struct pipe_context *
+NineDevice9_GetPipe( struct NineDevice9 *This );
+
+struct cso_context *
+NineDevice9_GetCSO( struct NineDevice9 *This );
+
+const D3DCAPS9 *
+NineDevice9_GetCaps( struct NineDevice9 *This );
+
+/* Mask: 0x1 = constant buffers, 0x2 = stipple */
+void
+NineDevice9_RestoreNonCSOState( struct NineDevice9 *This, unsigned mask );
+
+/*** Direct3D public ***/
+
+HRESULT WINAPI
+NineDevice9_TestCooperativeLevel( struct NineDevice9 *This );
+
+UINT WINAPI
+NineDevice9_GetAvailableTextureMem( struct NineDevice9 *This );
+
+HRESULT WINAPI
+NineDevice9_EvictManagedResources( struct NineDevice9 *This );
+
+HRESULT WINAPI
+NineDevice9_GetDirect3D( struct NineDevice9 *This,
+                         IDirect3D9 **ppD3D9 );
+
+HRESULT WINAPI
+NineDevice9_GetDeviceCaps( struct NineDevice9 *This,
+                           D3DCAPS9 *pCaps );
+
+HRESULT WINAPI
+NineDevice9_GetDisplayMode( struct NineDevice9 *This,
+                            UINT iSwapChain,
+                            D3DDISPLAYMODE *pMode );
+
+HRESULT WINAPI
+NineDevice9_GetCreationParameters( struct NineDevice9 *This,
+                                   D3DDEVICE_CREATION_PARAMETERS *pParameters );
+
+HRESULT WINAPI
+NineDevice9_SetCursorProperties( struct NineDevice9 *This,
+                                 UINT XHotSpot,
+                                 UINT YHotSpot,
+                                 IDirect3DSurface9 *pCursorBitmap );
+
+void WINAPI
+NineDevice9_SetCursorPosition( struct NineDevice9 *This,
+                               int X,
+                               int Y,
+                               DWORD Flags );
+
+BOOL WINAPI
+NineDevice9_ShowCursor( struct NineDevice9 *This,
+                        BOOL bShow );
+
+HRESULT WINAPI
+NineDevice9_CreateAdditionalSwapChain( struct NineDevice9 *This,
+                                       D3DPRESENT_PARAMETERS *pPresentationParameters,
+                                       IDirect3DSwapChain9 **pSwapChain );
+
+HRESULT WINAPI
+NineDevice9_GetSwapChain( struct NineDevice9 *This,
+                          UINT iSwapChain,
+                          IDirect3DSwapChain9 **pSwapChain );
+
+UINT WINAPI
+NineDevice9_GetNumberOfSwapChains( struct NineDevice9 *This );
+
+HRESULT WINAPI
+NineDevice9_Reset( struct NineDevice9 *This,
+                   D3DPRESENT_PARAMETERS *pPresentationParameters );
+
+HRESULT WINAPI
+NineDevice9_Present( struct NineDevice9 *This,
+                     const RECT *pSourceRect,
+                     const RECT *pDestRect,
+                     HWND hDestWindowOverride,
+                     const RGNDATA *pDirtyRegion );
+
+HRESULT WINAPI
+NineDevice9_GetBackBuffer( struct NineDevice9 *This,
+                           UINT iSwapChain,
+                           UINT iBackBuffer,
+                           D3DBACKBUFFER_TYPE Type,
+                           IDirect3DSurface9 **ppBackBuffer );
+
+HRESULT WINAPI
+NineDevice9_GetRasterStatus( struct NineDevice9 *This,
+                             UINT iSwapChain,
+                             D3DRASTER_STATUS *pRasterStatus );
+
+HRESULT WINAPI
+NineDevice9_SetDialogBoxMode( struct NineDevice9 *This,
+                              BOOL bEnableDialogs );
+
+void WINAPI
+NineDevice9_SetGammaRamp( struct NineDevice9 *This,
+                          UINT iSwapChain,
+                          DWORD Flags,
+                          const D3DGAMMARAMP *pRamp );
+
+void WINAPI
+NineDevice9_GetGammaRamp( struct NineDevice9 *This,
+                          UINT iSwapChain,
+                          D3DGAMMARAMP *pRamp );
+
+HRESULT WINAPI
+NineDevice9_CreateTexture( struct NineDevice9 *This,
+                           UINT Width,
+                           UINT Height,
+                           UINT Levels,
+                           DWORD Usage,
+                           D3DFORMAT Format,
+                           D3DPOOL Pool,
+                           IDirect3DTexture9 **ppTexture,
+                           HANDLE *pSharedHandle );
+
+HRESULT WINAPI
+NineDevice9_CreateVolumeTexture( struct NineDevice9 *This,
+                                 UINT Width,
+                                 UINT Height,
+                                 UINT Depth,
+                                 UINT Levels,
+                                 DWORD Usage,
+                                 D3DFORMAT Format,
+                                 D3DPOOL Pool,
+                                 IDirect3DVolumeTexture9 **ppVolumeTexture,
+                                 HANDLE *pSharedHandle );
+
+HRESULT WINAPI
+NineDevice9_CreateCubeTexture( struct NineDevice9 *This,
+                               UINT EdgeLength,
+                               UINT Levels,
+                               DWORD Usage,
+                               D3DFORMAT Format,
+                               D3DPOOL Pool,
+                               IDirect3DCubeTexture9 **ppCubeTexture,
+                               HANDLE *pSharedHandle );
+
+HRESULT WINAPI
+NineDevice9_CreateVertexBuffer( struct NineDevice9 *This,
+                                UINT Length,
+                                DWORD Usage,
+                                DWORD FVF,
+                                D3DPOOL Pool,
+                                IDirect3DVertexBuffer9 **ppVertexBuffer,
+                                HANDLE *pSharedHandle );
+
+HRESULT WINAPI
+NineDevice9_CreateIndexBuffer( struct NineDevice9 *This,
+                               UINT Length,
+                               DWORD Usage,
+                               D3DFORMAT Format,
+                               D3DPOOL Pool,
+                               IDirect3DIndexBuffer9 **ppIndexBuffer,
+                               HANDLE *pSharedHandle );
+
+HRESULT WINAPI
+NineDevice9_CreateRenderTarget( struct NineDevice9 *This,
+                                UINT Width,
+                                UINT Height,
+                                D3DFORMAT Format,
+                                D3DMULTISAMPLE_TYPE MultiSample,
+                                DWORD MultisampleQuality,
+                                BOOL Lockable,
+                                IDirect3DSurface9 **ppSurface,
+                                HANDLE *pSharedHandle );
+
+HRESULT WINAPI
+NineDevice9_CreateDepthStencilSurface( struct NineDevice9 *This,
+                                       UINT Width,
+                                       UINT Height,
+                                       D3DFORMAT Format,
+                                       D3DMULTISAMPLE_TYPE MultiSample,
+                                       DWORD MultisampleQuality,
+                                       BOOL Discard,
+                                       IDirect3DSurface9 **ppSurface,
+                                       HANDLE *pSharedHandle );
+
+HRESULT WINAPI
+NineDevice9_UpdateSurface( struct NineDevice9 *This,
+                           IDirect3DSurface9 *pSourceSurface,
+                           const RECT *pSourceRect,
+                           IDirect3DSurface9 *pDestinationSurface,
+                           const POINT *pDestPoint );
+
+HRESULT WINAPI
+NineDevice9_UpdateTexture( struct NineDevice9 *This,
+                           IDirect3DBaseTexture9 *pSourceTexture,
+                           IDirect3DBaseTexture9 *pDestinationTexture );
+
+HRESULT WINAPI
+NineDevice9_GetRenderTargetData( struct NineDevice9 *This,
+                                 IDirect3DSurface9 *pRenderTarget,
+                                 IDirect3DSurface9 *pDestSurface );
+
+HRESULT WINAPI
+NineDevice9_GetFrontBufferData( struct NineDevice9 *This,
+                                UINT iSwapChain,
+                                IDirect3DSurface9 *pDestSurface );
+
+HRESULT WINAPI
+NineDevice9_StretchRect( struct NineDevice9 *This,
+                         IDirect3DSurface9 *pSourceSurface,
+                         const RECT *pSourceRect,
+                         IDirect3DSurface9 *pDestSurface,
+                         const RECT *pDestRect,
+                         D3DTEXTUREFILTERTYPE Filter );
+
+HRESULT WINAPI
+NineDevice9_ColorFill( struct NineDevice9 *This,
+                       IDirect3DSurface9 *pSurface,
+                       const RECT *pRect,
+                       D3DCOLOR color );
+
+HRESULT WINAPI
+NineDevice9_CreateOffscreenPlainSurface( struct NineDevice9 *This,
+                                         UINT Width,
+                                         UINT Height,
+                                         D3DFORMAT Format,
+                                         D3DPOOL Pool,
+                                         IDirect3DSurface9 **ppSurface,
+                                         HANDLE *pSharedHandle );
+
+HRESULT WINAPI
+NineDevice9_SetRenderTarget( struct NineDevice9 *This,
+                             DWORD RenderTargetIndex,
+                             IDirect3DSurface9 *pRenderTarget );
+
+HRESULT WINAPI
+NineDevice9_GetRenderTarget( struct NineDevice9 *This,
+                             DWORD RenderTargetIndex,
+                             IDirect3DSurface9 **ppRenderTarget );
+
+HRESULT WINAPI
+NineDevice9_SetDepthStencilSurface( struct NineDevice9 *This,
+                                    IDirect3DSurface9 *pNewZStencil );
+
+HRESULT WINAPI
+NineDevice9_GetDepthStencilSurface( struct NineDevice9 *This,
+                                    IDirect3DSurface9 **ppZStencilSurface );
+
+HRESULT WINAPI
+NineDevice9_BeginScene( struct NineDevice9 *This );
+
+HRESULT WINAPI
+NineDevice9_EndScene( struct NineDevice9 *This );
+
+HRESULT WINAPI
+NineDevice9_Clear( struct NineDevice9 *This,
+                   DWORD Count,
+                   const D3DRECT *pRects,
+                   DWORD Flags,
+                   D3DCOLOR Color,
+                   float Z,
+                   DWORD Stencil );
+
+HRESULT WINAPI
+NineDevice9_SetTransform( struct NineDevice9 *This,
+                          D3DTRANSFORMSTATETYPE State,
+                          const D3DMATRIX *pMatrix );
+
+HRESULT WINAPI
+NineDevice9_GetTransform( struct NineDevice9 *This,
+                          D3DTRANSFORMSTATETYPE State,
+                          D3DMATRIX *pMatrix );
+
+HRESULT WINAPI
+NineDevice9_MultiplyTransform( struct NineDevice9 *This,
+                               D3DTRANSFORMSTATETYPE State,
+                               const D3DMATRIX *pMatrix );
+
+HRESULT WINAPI
+NineDevice9_SetViewport( struct NineDevice9 *This,
+                         const D3DVIEWPORT9 *pViewport );
+
+HRESULT WINAPI
+NineDevice9_GetViewport( struct NineDevice9 *This,
+                         D3DVIEWPORT9 *pViewport );
+
+HRESULT WINAPI
+NineDevice9_SetMaterial( struct NineDevice9 *This,
+                         const D3DMATERIAL9 *pMaterial );
+
+HRESULT WINAPI
+NineDevice9_GetMaterial( struct NineDevice9 *This,
+                         D3DMATERIAL9 *pMaterial );
+
+HRESULT WINAPI
+NineDevice9_SetLight( struct NineDevice9 *This,
+                      DWORD Index,
+                      const D3DLIGHT9 *pLight );
+
+HRESULT WINAPI
+NineDevice9_GetLight( struct NineDevice9 *This,
+                      DWORD Index,
+                      D3DLIGHT9 *pLight );
+
+HRESULT WINAPI
+NineDevice9_LightEnable( struct NineDevice9 *This,
+                         DWORD Index,
+                         BOOL Enable );
+
+HRESULT WINAPI
+NineDevice9_GetLightEnable( struct NineDevice9 *This,
+                            DWORD Index,
+                            BOOL *pEnable );
+
+HRESULT WINAPI
+NineDevice9_SetClipPlane( struct NineDevice9 *This,
+                          DWORD Index,
+                          const float *pPlane );
+
+HRESULT WINAPI
+NineDevice9_GetClipPlane( struct NineDevice9 *This,
+                          DWORD Index,
+                          float *pPlane );
+
+HRESULT WINAPI
+NineDevice9_SetRenderState( struct NineDevice9 *This,
+                            D3DRENDERSTATETYPE State,
+                            DWORD Value );
+
+HRESULT WINAPI
+NineDevice9_GetRenderState( struct NineDevice9 *This,
+                            D3DRENDERSTATETYPE State,
+                            DWORD *pValue );
+
+HRESULT WINAPI
+NineDevice9_CreateStateBlock( struct NineDevice9 *This,
+                              D3DSTATEBLOCKTYPE Type,
+                              IDirect3DStateBlock9 **ppSB );
+
+HRESULT WINAPI
+NineDevice9_BeginStateBlock( struct NineDevice9 *This );
+
+HRESULT WINAPI
+NineDevice9_EndStateBlock( struct NineDevice9 *This,
+                           IDirect3DStateBlock9 **ppSB );
+
+HRESULT WINAPI
+NineDevice9_SetClipStatus( struct NineDevice9 *This,
+                           const D3DCLIPSTATUS9 *pClipStatus );
+
+HRESULT WINAPI
+NineDevice9_GetClipStatus( struct NineDevice9 *This,
+                           D3DCLIPSTATUS9 *pClipStatus );
+
+HRESULT WINAPI
+NineDevice9_GetTexture( struct NineDevice9 *This,
+                        DWORD Stage,
+                        IDirect3DBaseTexture9 **ppTexture );
+
+HRESULT WINAPI
+NineDevice9_SetTexture( struct NineDevice9 *This,
+                        DWORD Stage,
+                        IDirect3DBaseTexture9 *pTexture );
+
+HRESULT WINAPI
+NineDevice9_GetTextureStageState( struct NineDevice9 *This,
+                                  DWORD Stage,
+                                  D3DTEXTURESTAGESTATETYPE Type,
+                                  DWORD *pValue );
+
+HRESULT WINAPI
+NineDevice9_SetTextureStageState( struct NineDevice9 *This,
+                                  DWORD Stage,
+                                  D3DTEXTURESTAGESTATETYPE Type,
+                                  DWORD Value );
+
+HRESULT WINAPI
+NineDevice9_GetSamplerState( struct NineDevice9 *This,
+                             DWORD Sampler,
+                             D3DSAMPLERSTATETYPE Type,
+                             DWORD *pValue );
+
+HRESULT WINAPI
+NineDevice9_SetSamplerState( struct NineDevice9 *This,
+                             DWORD Sampler,
+                             D3DSAMPLERSTATETYPE Type,
+                             DWORD Value );
+
+HRESULT WINAPI
+NineDevice9_ValidateDevice( struct NineDevice9 *This,
+                            DWORD *pNumPasses );
+
+HRESULT WINAPI
+NineDevice9_SetPaletteEntries( struct NineDevice9 *This,
+                               UINT PaletteNumber,
+                               const PALETTEENTRY *pEntries );
+
+HRESULT WINAPI
+NineDevice9_GetPaletteEntries( struct NineDevice9 *This,
+                               UINT PaletteNumber,
+                               PALETTEENTRY *pEntries );
+
+HRESULT WINAPI
+NineDevice9_SetCurrentTexturePalette( struct NineDevice9 *This,
+                                      UINT PaletteNumber );
+
+HRESULT WINAPI
+NineDevice9_GetCurrentTexturePalette( struct NineDevice9 *This,
+                                      UINT *PaletteNumber );
+
+HRESULT WINAPI
+NineDevice9_SetScissorRect( struct NineDevice9 *This,
+                            const RECT *pRect );
+
+HRESULT WINAPI
+NineDevice9_GetScissorRect( struct NineDevice9 *This,
+                            RECT *pRect );
+
+HRESULT WINAPI
+NineDevice9_SetSoftwareVertexProcessing( struct NineDevice9 *This,
+                                         BOOL bSoftware );
+
+BOOL WINAPI
+NineDevice9_GetSoftwareVertexProcessing( struct NineDevice9 *This );
+
+HRESULT WINAPI
+NineDevice9_SetNPatchMode( struct NineDevice9 *This,
+                           float nSegments );
+
+float WINAPI
+NineDevice9_GetNPatchMode( struct NineDevice9 *This );
+
+HRESULT WINAPI
+NineDevice9_DrawPrimitive( struct NineDevice9 *This,
+                           D3DPRIMITIVETYPE PrimitiveType,
+                           UINT StartVertex,
+                           UINT PrimitiveCount );
+
+HRESULT WINAPI
+NineDevice9_DrawIndexedPrimitive( struct NineDevice9 *This,
+                                  D3DPRIMITIVETYPE PrimitiveType,
+                                  INT BaseVertexIndex,
+                                  UINT MinVertexIndex,
+                                  UINT NumVertices,
+                                  UINT startIndex,
+                                  UINT primCount );
+
+HRESULT WINAPI
+NineDevice9_DrawPrimitiveUP( struct NineDevice9 *This,
+                             D3DPRIMITIVETYPE PrimitiveType,
+                             UINT PrimitiveCount,
+                             const void *pVertexStreamZeroData,
+                             UINT VertexStreamZeroStride );
+
+HRESULT WINAPI
+NineDevice9_DrawIndexedPrimitiveUP( struct NineDevice9 *This,
+                                    D3DPRIMITIVETYPE PrimitiveType,
+                                    UINT MinVertexIndex,
+                                    UINT NumVertices,
+                                    UINT PrimitiveCount,
+                                    const void *pIndexData,
+                                    D3DFORMAT IndexDataFormat,
+                                    const void *pVertexStreamZeroData,
+                                    UINT VertexStreamZeroStride );
+
+HRESULT WINAPI
+NineDevice9_ProcessVertices( struct NineDevice9 *This,
+                             UINT SrcStartIndex,
+                             UINT DestIndex,
+                             UINT VertexCount,
+                             IDirect3DVertexBuffer9 *pDestBuffer,
+                             IDirect3DVertexDeclaration9 *pVertexDecl,
+                             DWORD Flags );
+
+HRESULT WINAPI
+NineDevice9_CreateVertexDeclaration( struct NineDevice9 *This,
+                                     const D3DVERTEXELEMENT9 *pVertexElements,
+                                     IDirect3DVertexDeclaration9 **ppDecl );
+
+HRESULT WINAPI
+NineDevice9_SetVertexDeclaration( struct NineDevice9 *This,
+                                  IDirect3DVertexDeclaration9 *pDecl );
+
+HRESULT WINAPI
+NineDevice9_GetVertexDeclaration( struct NineDevice9 *This,
+                                  IDirect3DVertexDeclaration9 **ppDecl );
+
+HRESULT WINAPI
+NineDevice9_SetFVF( struct NineDevice9 *This,
+                    DWORD FVF );
+
+HRESULT WINAPI
+NineDevice9_GetFVF( struct NineDevice9 *This,
+                    DWORD *pFVF );
+
+HRESULT WINAPI
+NineDevice9_CreateVertexShader( struct NineDevice9 *This,
+                                const DWORD *pFunction,
+                                IDirect3DVertexShader9 **ppShader );
+
+HRESULT WINAPI
+NineDevice9_SetVertexShader( struct NineDevice9 *This,
+                             IDirect3DVertexShader9 *pShader );
+
+HRESULT WINAPI
+NineDevice9_GetVertexShader( struct NineDevice9 *This,
+                             IDirect3DVertexShader9 **ppShader );
+
+HRESULT WINAPI
+NineDevice9_SetVertexShaderConstantF( struct NineDevice9 *This,
+                                      UINT StartRegister,
+                                      const float *pConstantData,
+                                      UINT Vector4fCount );
+
+HRESULT WINAPI
+NineDevice9_GetVertexShaderConstantF( struct NineDevice9 *This,
+                                      UINT StartRegister,
+                                      float *pConstantData,
+                                      UINT Vector4fCount );
+
+HRESULT WINAPI
+NineDevice9_SetVertexShaderConstantI( struct NineDevice9 *This,
+                                      UINT StartRegister,
+                                      const int *pConstantData,
+                                      UINT Vector4iCount );
+
+HRESULT WINAPI
+NineDevice9_GetVertexShaderConstantI( struct NineDevice9 *This,
+                                      UINT StartRegister,
+                                      int *pConstantData,
+                                      UINT Vector4iCount );
+
+HRESULT WINAPI
+NineDevice9_SetVertexShaderConstantB( struct NineDevice9 *This,
+                                      UINT StartRegister,
+                                      const BOOL *pConstantData,
+                                      UINT BoolCount );
+
+HRESULT WINAPI
+NineDevice9_GetVertexShaderConstantB( struct NineDevice9 *This,
+                                      UINT StartRegister,
+                                      BOOL *pConstantData,
+                                      UINT BoolCount );
+
+HRESULT WINAPI
+NineDevice9_SetStreamSource( struct NineDevice9 *This,
+                             UINT StreamNumber,
+                             IDirect3DVertexBuffer9 *pStreamData,
+                             UINT OffsetInBytes,
+                             UINT Stride );
+
+HRESULT WINAPI
+NineDevice9_GetStreamSource( struct NineDevice9 *This,
+                             UINT StreamNumber,
+                             IDirect3DVertexBuffer9 **ppStreamData,
+                             UINT *pOffsetInBytes,
+                             UINT *pStride );
+
+HRESULT WINAPI
+NineDevice9_SetStreamSourceFreq( struct NineDevice9 *This,
+                                 UINT StreamNumber,
+                                 UINT Setting );
+
+HRESULT WINAPI
+NineDevice9_GetStreamSourceFreq( struct NineDevice9 *This,
+                                 UINT StreamNumber,
+                                 UINT *pSetting );
+
+HRESULT WINAPI
+NineDevice9_SetIndices( struct NineDevice9 *This,
+                        IDirect3DIndexBuffer9 *pIndexData );
+
+HRESULT WINAPI
+NineDevice9_GetIndices( struct NineDevice9 *This,
+                        IDirect3DIndexBuffer9 **ppIndexData /*,
+                        UINT *pBaseVertexIndex */ );
+
+HRESULT WINAPI
+NineDevice9_CreatePixelShader( struct NineDevice9 *This,
+                               const DWORD *pFunction,
+                               IDirect3DPixelShader9 **ppShader );
+
+HRESULT WINAPI
+NineDevice9_SetPixelShader( struct NineDevice9 *This,
+                            IDirect3DPixelShader9 *pShader );
+
+HRESULT WINAPI
+NineDevice9_GetPixelShader( struct NineDevice9 *This,
+                            IDirect3DPixelShader9 **ppShader );
+
+HRESULT WINAPI
+NineDevice9_SetPixelShaderConstantF( struct NineDevice9 *This,
+                                     UINT StartRegister,
+                                     const float *pConstantData,
+                                     UINT Vector4fCount );
+
+HRESULT WINAPI
+NineDevice9_GetPixelShaderConstantF( struct NineDevice9 *This,
+                                     UINT StartRegister,
+                                     float *pConstantData,
+                                     UINT Vector4fCount );
+
+HRESULT WINAPI
+NineDevice9_SetPixelShaderConstantI( struct NineDevice9 *This,
+                                     UINT StartRegister,
+                                     const int *pConstantData,
+                                     UINT Vector4iCount );
+
+HRESULT WINAPI
+NineDevice9_GetPixelShaderConstantI( struct NineDevice9 *This,
+                                     UINT StartRegister,
+                                     int *pConstantData,
+                                     UINT Vector4iCount );
+
+HRESULT WINAPI
+NineDevice9_SetPixelShaderConstantB( struct NineDevice9 *This,
+                                     UINT StartRegister,
+                                     const BOOL *pConstantData,
+                                     UINT BoolCount );
+
+HRESULT WINAPI
+NineDevice9_GetPixelShaderConstantB( struct NineDevice9 *This,
+                                     UINT StartRegister,
+                                     BOOL *pConstantData,
+                                     UINT BoolCount );
+
+HRESULT WINAPI
+NineDevice9_DrawRectPatch( struct NineDevice9 *This,
+                           UINT Handle,
+                           const float *pNumSegs,
+                           const D3DRECTPATCH_INFO *pRectPatchInfo );
+
+HRESULT WINAPI
+NineDevice9_DrawTriPatch( struct NineDevice9 *This,
+                          UINT Handle,
+                          const float *pNumSegs,
+                          const D3DTRIPATCH_INFO *pTriPatchInfo );
+
+HRESULT WINAPI
+NineDevice9_DeletePatch( struct NineDevice9 *This,
+                         UINT Handle );
+
+HRESULT WINAPI
+NineDevice9_CreateQuery( struct NineDevice9 *This,
+                         D3DQUERYTYPE Type,
+                         IDirect3DQuery9 **ppQuery );
+
+#endif /* _NINE_DEVICE9_H_ */
diff --git a/src/gallium/state_trackers/nine/device9ex.c b/src/gallium/state_trackers/nine/device9ex.c
new file mode 100644 (file)
index 0000000..00d460b
--- /dev/null
@@ -0,0 +1,400 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "device9ex.h"
+#include "swapchain9ex.h"
+
+#include "nine_helpers.h"
+
+#define DBG_CHANNEL DBG_DEVICE
+
+static HRESULT
+NineDevice9Ex_ctor( struct NineDevice9Ex *This,
+                    struct NineUnknownParams *pParams,
+                    struct pipe_screen *pScreen,
+                    D3DDEVICE_CREATION_PARAMETERS *pCreationParameters,
+                    D3DCAPS9 *pCaps,
+                    D3DPRESENT_PARAMETERS *pPresentationParameters,
+                    D3DDISPLAYMODEEX *pFullscreenDisplayMode,
+                    IDirect3D9Ex *pD3D9Ex,
+                    ID3DPresentGroup *pPresentationGroup,
+                    struct d3dadapter9_context *pCTX )
+{
+    This->base.ex = TRUE;
+    This->base.pFullscreenDisplayMode = pFullscreenDisplayMode;
+
+    return NineDevice9_ctor(&This->base, pParams,
+                            pScreen, pCreationParameters, pCaps,
+                            pPresentationParameters,
+                            (IDirect3D9 *)pD3D9Ex, pPresentationGroup, pCTX);
+}
+
+static void
+NineDevice9Ex_dtor( struct NineDevice9Ex *This )
+{
+    NineDevice9_dtor(&This->base);
+}
+
+HRESULT WINAPI
+NineDevice9Ex_SetConvolutionMonoKernel( struct NineDevice9Ex *This,
+                                        UINT width,
+                                        UINT height,
+                                        float *rows,
+                                        float *columns )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineDevice9Ex_ComposeRects( struct NineDevice9Ex *This,
+                            IDirect3DSurface9 *pSrc,
+                            IDirect3DSurface9 *pDst,
+                            IDirect3DVertexBuffer9 *pSrcRectDescs,
+                            UINT NumRects,
+                            IDirect3DVertexBuffer9 *pDstRectDescs,
+                            D3DCOMPOSERECTSOP Operation,
+                            int Xoffset,
+                            int Yoffset )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineDevice9Ex_PresentEx( struct NineDevice9Ex *This,
+                         const RECT *pSourceRect,
+                         const RECT *pDestRect,
+                         HWND hDestWindowOverride,
+                         const RGNDATA *pDirtyRegion,
+                         DWORD dwFlags )
+{
+    unsigned i;
+    HRESULT hr;
+
+    for (i = 0; i < This->base.nswapchains; i++) {
+        hr = NineSwapChain9_Present(This->base.swapchains[i], pSourceRect, pDestRect,
+                                    hDestWindowOverride, pDirtyRegion, dwFlags);
+        if (FAILED(hr)) { return hr; }
+    }
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9Ex_GetGPUThreadPriority( struct NineDevice9Ex *This,
+                                    INT *pPriority )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineDevice9Ex_SetGPUThreadPriority( struct NineDevice9Ex *This,
+                                    INT Priority )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineDevice9Ex_WaitForVBlank( struct NineDevice9Ex *This,
+                             UINT iSwapChain )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineDevice9Ex_CheckResourceResidency( struct NineDevice9Ex *This,
+                                      IDirect3DResource9 **pResourceArray,
+                                      UINT32 NumResources )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineDevice9Ex_SetMaximumFrameLatency( struct NineDevice9Ex *This,
+                                      UINT MaxLatency )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineDevice9Ex_GetMaximumFrameLatency( struct NineDevice9Ex *This,
+                                      UINT *pMaxLatency )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineDevice9Ex_CheckDeviceState( struct NineDevice9Ex *This,
+                                HWND hDestinationWindow )
+{
+    DBG("This=%p hDestinationWindow=%p\n",
+        This, hDestinationWindow);
+
+    /* TODO: handle the other return values */
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineDevice9Ex_CreateRenderTargetEx( struct NineDevice9Ex *This,
+                                    UINT Width,
+                                    UINT Height,
+                                    D3DFORMAT Format,
+                                    D3DMULTISAMPLE_TYPE MultiSample,
+                                    DWORD MultisampleQuality,
+                                    BOOL Lockable,
+                                    IDirect3DSurface9 **ppSurface,
+                                    HANDLE *pSharedHandle,
+                                    DWORD Usage )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineDevice9Ex_CreateOffscreenPlainSurfaceEx( struct NineDevice9Ex *This,
+                                             UINT Width,
+                                             UINT Height,
+                                             D3DFORMAT Format,
+                                             D3DPOOL Pool,
+                                             IDirect3DSurface9 **ppSurface,
+                                             HANDLE *pSharedHandle,
+                                             DWORD Usage )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineDevice9Ex_CreateDepthStencilSurfaceEx( struct NineDevice9Ex *This,
+                                           UINT Width,
+                                           UINT Height,
+                                           D3DFORMAT Format,
+                                           D3DMULTISAMPLE_TYPE MultiSample,
+                                           DWORD MultisampleQuality,
+                                           BOOL Discard,
+                                           IDirect3DSurface9 **ppSurface,
+                                           HANDLE *pSharedHandle,
+                                           DWORD Usage )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineDevice9Ex_ResetEx( struct NineDevice9Ex *This,
+                       D3DPRESENT_PARAMETERS *pPresentationParameters,
+                       D3DDISPLAYMODEEX *pFullscreenDisplayMode )
+{
+    HRESULT hr = D3D_OK;
+    unsigned i;
+
+    DBG("This=%p pPresentationParameters=%p pFullscreenDisplayMode=%p\n", This, pPresentationParameters, pFullscreenDisplayMode);
+
+    for (i = 0; i < This->base.nswapchains; ++i) {
+        D3DDISPLAYMODEEX *mode = NULL;
+        D3DPRESENT_PARAMETERS *params = &pPresentationParameters[i];
+        if (pFullscreenDisplayMode) mode = &(pFullscreenDisplayMode[i]);
+        hr = NineSwapChain9_Resize(This->base.swapchains[i], params, mode);
+        if (FAILED(hr))
+            return (hr == D3DERR_OUTOFVIDEOMEMORY) ? hr : D3DERR_DEVICELOST;
+    }
+
+    NineDevice9_SetRenderTarget(
+        (struct NineDevice9 *)This, 0, (IDirect3DSurface9 *)This->base.swapchains[0]->buffers[0]);
+
+
+    return hr;
+}
+
+HRESULT WINAPI
+NineDevice9Ex_GetDisplayModeEx( struct NineDevice9Ex *This,
+                                UINT iSwapChain,
+                                D3DDISPLAYMODEEX *pMode,
+                                D3DDISPLAYROTATION *pRotation )
+{
+    struct NineSwapChain9Ex *swapchain;
+
+    user_assert(iSwapChain < This->base.nswapchains, D3DERR_INVALIDCALL);
+
+    swapchain = NineSwapChain9Ex(This->base.swapchains[iSwapChain]);
+    return NineSwapChain9Ex_GetDisplayModeEx(swapchain, pMode, pRotation);
+}
+
+IDirect3DDevice9ExVtbl NineDevice9Ex_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)NineDevice9_TestCooperativeLevel,
+    (void *)NineDevice9_GetAvailableTextureMem,
+    (void *)NineDevice9_EvictManagedResources,
+    (void *)NineDevice9_GetDirect3D,
+    (void *)NineDevice9_GetDeviceCaps,
+    (void *)NineDevice9_GetDisplayMode,
+    (void *)NineDevice9_GetCreationParameters,
+    (void *)NineDevice9_SetCursorProperties,
+    (void *)NineDevice9_SetCursorPosition,
+    (void *)NineDevice9_ShowCursor,
+    (void *)NineDevice9_CreateAdditionalSwapChain,
+    (void *)NineDevice9_GetSwapChain,
+    (void *)NineDevice9_GetNumberOfSwapChains,
+    (void *)NineDevice9_Reset,
+    (void *)NineDevice9_Present,
+    (void *)NineDevice9_GetBackBuffer,
+    (void *)NineDevice9_GetRasterStatus,
+    (void *)NineDevice9_SetDialogBoxMode,
+    (void *)NineDevice9_SetGammaRamp,
+    (void *)NineDevice9_GetGammaRamp,
+    (void *)NineDevice9_CreateTexture,
+    (void *)NineDevice9_CreateVolumeTexture,
+    (void *)NineDevice9_CreateCubeTexture,
+    (void *)NineDevice9_CreateVertexBuffer,
+    (void *)NineDevice9_CreateIndexBuffer,
+    (void *)NineDevice9_CreateRenderTarget,
+    (void *)NineDevice9_CreateDepthStencilSurface,
+    (void *)NineDevice9_UpdateSurface,
+    (void *)NineDevice9_UpdateTexture,
+    (void *)NineDevice9_GetRenderTargetData,
+    (void *)NineDevice9_GetFrontBufferData,
+    (void *)NineDevice9_StretchRect,
+    (void *)NineDevice9_ColorFill,
+    (void *)NineDevice9_CreateOffscreenPlainSurface,
+    (void *)NineDevice9_SetRenderTarget,
+    (void *)NineDevice9_GetRenderTarget,
+    (void *)NineDevice9_SetDepthStencilSurface,
+    (void *)NineDevice9_GetDepthStencilSurface,
+    (void *)NineDevice9_BeginScene,
+    (void *)NineDevice9_EndScene,
+    (void *)NineDevice9_Clear,
+    (void *)NineDevice9_SetTransform,
+    (void *)NineDevice9_GetTransform,
+    (void *)NineDevice9_MultiplyTransform,
+    (void *)NineDevice9_SetViewport,
+    (void *)NineDevice9_GetViewport,
+    (void *)NineDevice9_SetMaterial,
+    (void *)NineDevice9_GetMaterial,
+    (void *)NineDevice9_SetLight,
+    (void *)NineDevice9_GetLight,
+    (void *)NineDevice9_LightEnable,
+    (void *)NineDevice9_GetLightEnable,
+    (void *)NineDevice9_SetClipPlane,
+    (void *)NineDevice9_GetClipPlane,
+    (void *)NineDevice9_SetRenderState,
+    (void *)NineDevice9_GetRenderState,
+    (void *)NineDevice9_CreateStateBlock,
+    (void *)NineDevice9_BeginStateBlock,
+    (void *)NineDevice9_EndStateBlock,
+    (void *)NineDevice9_SetClipStatus,
+    (void *)NineDevice9_GetClipStatus,
+    (void *)NineDevice9_GetTexture,
+    (void *)NineDevice9_SetTexture,
+    (void *)NineDevice9_GetTextureStageState,
+    (void *)NineDevice9_SetTextureStageState,
+    (void *)NineDevice9_GetSamplerState,
+    (void *)NineDevice9_SetSamplerState,
+    (void *)NineDevice9_ValidateDevice,
+    (void *)NineDevice9_SetPaletteEntries,
+    (void *)NineDevice9_GetPaletteEntries,
+    (void *)NineDevice9_SetCurrentTexturePalette,
+    (void *)NineDevice9_GetCurrentTexturePalette,
+    (void *)NineDevice9_SetScissorRect,
+    (void *)NineDevice9_GetScissorRect,
+    (void *)NineDevice9_SetSoftwareVertexProcessing,
+    (void *)NineDevice9_GetSoftwareVertexProcessing,
+    (void *)NineDevice9_SetNPatchMode,
+    (void *)NineDevice9_GetNPatchMode,
+    (void *)NineDevice9_DrawPrimitive,
+    (void *)NineDevice9_DrawIndexedPrimitive,
+    (void *)NineDevice9_DrawPrimitiveUP,
+    (void *)NineDevice9_DrawIndexedPrimitiveUP,
+    (void *)NineDevice9_ProcessVertices,
+    (void *)NineDevice9_CreateVertexDeclaration,
+    (void *)NineDevice9_SetVertexDeclaration,
+    (void *)NineDevice9_GetVertexDeclaration,
+    (void *)NineDevice9_SetFVF,
+    (void *)NineDevice9_GetFVF,
+    (void *)NineDevice9_CreateVertexShader,
+    (void *)NineDevice9_SetVertexShader,
+    (void *)NineDevice9_GetVertexShader,
+    (void *)NineDevice9_SetVertexShaderConstantF,
+    (void *)NineDevice9_GetVertexShaderConstantF,
+    (void *)NineDevice9_SetVertexShaderConstantI,
+    (void *)NineDevice9_GetVertexShaderConstantI,
+    (void *)NineDevice9_SetVertexShaderConstantB,
+    (void *)NineDevice9_GetVertexShaderConstantB,
+    (void *)NineDevice9_SetStreamSource,
+    (void *)NineDevice9_GetStreamSource,
+    (void *)NineDevice9_SetStreamSourceFreq,
+    (void *)NineDevice9_GetStreamSourceFreq,
+    (void *)NineDevice9_SetIndices,
+    (void *)NineDevice9_GetIndices,
+    (void *)NineDevice9_CreatePixelShader,
+    (void *)NineDevice9_SetPixelShader,
+    (void *)NineDevice9_GetPixelShader,
+    (void *)NineDevice9_SetPixelShaderConstantF,
+    (void *)NineDevice9_GetPixelShaderConstantF,
+    (void *)NineDevice9_SetPixelShaderConstantI,
+    (void *)NineDevice9_GetPixelShaderConstantI,
+    (void *)NineDevice9_SetPixelShaderConstantB,
+    (void *)NineDevice9_GetPixelShaderConstantB,
+    (void *)NineDevice9_DrawRectPatch,
+    (void *)NineDevice9_DrawTriPatch,
+    (void *)NineDevice9_DeletePatch,
+    (void *)NineDevice9_CreateQuery,
+    (void *)NineDevice9Ex_SetConvolutionMonoKernel,
+    (void *)NineDevice9Ex_ComposeRects,
+    (void *)NineDevice9Ex_PresentEx,
+    (void *)NineDevice9Ex_GetGPUThreadPriority,
+    (void *)NineDevice9Ex_SetGPUThreadPriority,
+    (void *)NineDevice9Ex_WaitForVBlank,
+    (void *)NineDevice9Ex_CheckResourceResidency,
+    (void *)NineDevice9Ex_SetMaximumFrameLatency,
+    (void *)NineDevice9Ex_GetMaximumFrameLatency,
+    (void *)NineDevice9Ex_CheckDeviceState,
+    (void *)NineDevice9Ex_CreateRenderTargetEx,
+    (void *)NineDevice9Ex_CreateOffscreenPlainSurfaceEx,
+    (void *)NineDevice9Ex_CreateDepthStencilSurfaceEx,
+    (void *)NineDevice9Ex_ResetEx,
+    (void *)NineDevice9Ex_GetDisplayModeEx
+};
+
+static const GUID *NineDevice9Ex_IIDs[] = {
+    &IID_IDirect3DDevice9Ex,
+    &IID_IDirect3DDevice9,
+    &IID_IUnknown,
+    NULL
+};
+
+HRESULT
+NineDevice9Ex_new( struct pipe_screen *pScreen,
+                   D3DDEVICE_CREATION_PARAMETERS *pCreationParameters,
+                   D3DCAPS9 *pCaps,
+                   D3DPRESENT_PARAMETERS *pPresentationParameters,
+                   D3DDISPLAYMODEEX *pFullscreenDisplayMode,
+                   IDirect3D9Ex *pD3D9Ex,
+                   ID3DPresentGroup *pPresentationGroup,
+                   struct d3dadapter9_context *pCTX,
+                   struct NineDevice9Ex **ppOut )
+{
+    BOOL lock;
+    lock = !!(pCreationParameters->BehaviorFlags & D3DCREATE_MULTITHREADED);
+
+    NINE_NEW(Device9Ex, ppOut, lock,
+             pScreen, pCreationParameters, pCaps, pPresentationParameters,
+             pFullscreenDisplayMode, pD3D9Ex, pPresentationGroup, pCTX);
+}
+
diff --git a/src/gallium/state_trackers/nine/device9ex.h b/src/gallium/state_trackers/nine/device9ex.h
new file mode 100644 (file)
index 0000000..a31c720
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _NINE_DEVICE9EX_H_
+#define _NINE_DEVICE9EX_H_
+
+#include "device9.h"
+
+struct NineDevice9Ex
+{
+    struct NineDevice9 base;
+};
+static INLINE struct NineDevice9Ex *
+NineDevice9Ex( void *data )
+{
+    return (struct NineDevice9Ex *)data;
+}
+
+HRESULT
+NineDevice9Ex_new( struct pipe_screen *pScreen,
+                   D3DDEVICE_CREATION_PARAMETERS *pCreationParameters,
+                   D3DCAPS9 *pCaps,
+                   D3DPRESENT_PARAMETERS *pPresentationParameters,
+                   D3DDISPLAYMODEEX *pFullscreenDisplayMode,
+                   IDirect3D9Ex *pD3D9Ex,
+                   ID3DPresentGroup *pPresentationGroup,
+                   struct d3dadapter9_context *pCTX,
+                   struct NineDevice9Ex **ppOut );
+
+HRESULT WINAPI
+NineDevice9Ex_SetConvolutionMonoKernel( struct NineDevice9Ex *This,
+                                        UINT width,
+                                        UINT height,
+                                        float *rows,
+                                        float *columns );
+
+HRESULT WINAPI
+NineDevice9Ex_ComposeRects( struct NineDevice9Ex *This,
+                            IDirect3DSurface9 *pSrc,
+                            IDirect3DSurface9 *pDst,
+                            IDirect3DVertexBuffer9 *pSrcRectDescs,
+                            UINT NumRects,
+                            IDirect3DVertexBuffer9 *pDstRectDescs,
+                            D3DCOMPOSERECTSOP Operation,
+                            int Xoffset,
+                            int Yoffset );
+
+HRESULT WINAPI
+NineDevice9Ex_PresentEx( struct NineDevice9Ex *This,
+                         const RECT *pSourceRect,
+                         const RECT *pDestRect,
+                         HWND hDestWindowOverride,
+                         const RGNDATA *pDirtyRegion,
+                         DWORD dwFlags );
+
+HRESULT WINAPI
+NineDevice9Ex_GetGPUThreadPriority( struct NineDevice9Ex *This,
+                                    INT *pPriority );
+
+HRESULT WINAPI
+NineDevice9Ex_SetGPUThreadPriority( struct NineDevice9Ex *This,
+                                    INT Priority );
+
+HRESULT WINAPI
+NineDevice9Ex_WaitForVBlank( struct NineDevice9Ex *This,
+                             UINT iSwapChain );
+
+HRESULT WINAPI
+NineDevice9Ex_CheckResourceResidency( struct NineDevice9Ex *This,
+                                      IDirect3DResource9 **pResourceArray,
+                                      UINT32 NumResources );
+
+HRESULT WINAPI
+NineDevice9Ex_SetMaximumFrameLatency( struct NineDevice9Ex *This,
+                                      UINT MaxLatency );
+
+HRESULT WINAPI
+NineDevice9Ex_GetMaximumFrameLatency( struct NineDevice9Ex *This,
+                                      UINT *pMaxLatency );
+
+HRESULT WINAPI
+NineDevice9Ex_CheckDeviceState( struct NineDevice9Ex *This,
+                                HWND hDestinationWindow );
+
+HRESULT WINAPI
+NineDevice9Ex_CreateRenderTargetEx( struct NineDevice9Ex *This,
+                                    UINT Width,
+                                    UINT Height,
+                                    D3DFORMAT Format,
+                                    D3DMULTISAMPLE_TYPE MultiSample,
+                                    DWORD MultisampleQuality,
+                                    BOOL Lockable,
+                                    IDirect3DSurface9 **ppSurface,
+                                    HANDLE *pSharedHandle,
+                                    DWORD Usage );
+
+HRESULT WINAPI
+NineDevice9Ex_CreateOffscreenPlainSurfaceEx( struct NineDevice9Ex *This,
+                                             UINT Width,
+                                             UINT Height,
+                                             D3DFORMAT Format,
+                                             D3DPOOL Pool,
+                                             IDirect3DSurface9 **ppSurface,
+                                             HANDLE *pSharedHandle,
+                                             DWORD Usage );
+
+HRESULT WINAPI
+NineDevice9Ex_CreateDepthStencilSurfaceEx( struct NineDevice9Ex *This,
+                                           UINT Width,
+                                           UINT Height,
+                                           D3DFORMAT Format,
+                                           D3DMULTISAMPLE_TYPE MultiSample,
+                                           DWORD MultisampleQuality,
+                                           BOOL Discard,
+                                           IDirect3DSurface9 **ppSurface,
+                                           HANDLE *pSharedHandle,
+                                           DWORD Usage );
+
+HRESULT WINAPI
+NineDevice9Ex_ResetEx( struct NineDevice9Ex *This,
+                       D3DPRESENT_PARAMETERS *pPresentationParameters,
+                       D3DDISPLAYMODEEX *pFullscreenDisplayMode );
+
+HRESULT WINAPI
+NineDevice9Ex_GetDisplayModeEx( struct NineDevice9Ex *This,
+                                UINT iSwapChain,
+                                D3DDISPLAYMODEEX *pMode,
+                                D3DDISPLAYROTATION *pRotation );
+
+#endif /* _NINE_DEVICE9EX_H_ */
diff --git a/src/gallium/state_trackers/nine/device9video.c b/src/gallium/state_trackers/nine/device9video.c
new file mode 100644 (file)
index 0000000..65cc6a0
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "device9video.h"
+
+#define DBG_CHANNEL DBG_DEVICEVIDEO
+
+HRESULT WINAPI
+NineDevice9Video_GetContentProtectionCaps( struct NineDevice9Video *This,
+                                           const GUID *pCryptoType,
+                                           const GUID *pDecodeProfile,
+                                           D3DCONTENTPROTECTIONCAPS *pCaps )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineDevice9Video_CreateAuthenticatedChannel( struct NineDevice9Video *This,
+                                             D3DAUTHENTICATEDCHANNELTYPE ChannelType,
+                                             IDirect3DAuthenticatedChannel9 **ppAuthenticatedChannel,
+                                             HANDLE *pChannelHandle )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineDevice9Video_CreateCryptoSession( struct NineDevice9Video *This,
+                                      const GUID *pCryptoType,
+                                      const GUID *pDecodeProfile,
+                                      IDirect3DCryptoSession9 **ppCryptoSession,
+                                      HANDLE *pCryptoHandle )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+IDirect3DDevice9VideoVtbl NineDevice9Video_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)NineDevice9Video_GetContentProtectionCaps,
+    (void *)NineDevice9Video_CreateAuthenticatedChannel,
+    (void *)NineDevice9Video_CreateCryptoSession
+};
diff --git a/src/gallium/state_trackers/nine/device9video.h b/src/gallium/state_trackers/nine/device9video.h
new file mode 100644 (file)
index 0000000..ca041e5
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _NINE_DEVICE9VIDEO_H_
+#define _NINE_DEVICE9VIDEO_H_
+
+#include "iunknown.h"
+
+struct NineDevice9Video
+{
+    struct NineUnknown base;
+};
+static INLINE struct NineDevice9Video *
+NineDevice9Video( void *data )
+{
+    return (struct NineDevice9Video *)data;
+}
+
+HRESULT WINAPI
+NineDevice9Video_GetContentProtectionCaps( struct NineDevice9Video *This,
+                                           const GUID *pCryptoType,
+                                           const GUID *pDecodeProfile,
+                                           D3DCONTENTPROTECTIONCAPS *pCaps );
+
+HRESULT WINAPI
+NineDevice9Video_CreateAuthenticatedChannel( struct NineDevice9Video *This,
+                                             D3DAUTHENTICATEDCHANNELTYPE ChannelType,
+                                             IDirect3DAuthenticatedChannel9 **ppAuthenticatedChannel,
+                                             HANDLE *pChannelHandle );
+
+HRESULT WINAPI
+NineDevice9Video_CreateCryptoSession( struct NineDevice9Video *This,
+                                      const GUID *pCryptoType,
+                                      const GUID *pDecodeProfile,
+                                      IDirect3DCryptoSession9 **ppCryptoSession,
+                                      HANDLE *pCryptoHandle );
+
+#endif /* _NINE_DEVICE9VIDEO_H_ */
diff --git a/src/gallium/state_trackers/nine/guid.c b/src/gallium/state_trackers/nine/guid.c
new file mode 100644 (file)
index 0000000..5034feb
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "guid.h"
+
+const GUID IID_IUnknown = { 0x00000000, 0x0000, 0x0000, { 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } };
+const GUID IID_ID3D9Adapter = { 0xBF6C7B9A, 0xF0BE, 0x11DF, { 0x81, 0xE3, 0x7F, 0x57, 0xDF, 0xD7, 0x20, 0x85 } };
+const GUID IID_IDirect3D9ExOverlayExtension = { 0x187AEB13, 0xAAF5, 0x4C59, { 0x87, 0x6D, 0xE0, 0x59, 0x08, 0x8C, 0x0D, 0xF8 } };
+const GUID IID_IDirect3DAuthenticatedChannel9 = { 0xFF24BEEE, 0xDA21, 0x4BEB, { 0x98, 0xB5, 0xD2, 0xF8, 0x99, 0xF9, 0x8A, 0xF9 } };
+const GUID IID_IDirect3DBaseTexture9 = { 0x580CA87E, 0x1D3C, 0x4D54, { 0x99, 0x1D, 0xB7, 0xD3, 0xE3, 0xC2, 0x98, 0xCE } };
+const GUID IID_IDirect3DCryptoSession9 = { 0xFA0AB799, 0x7A9C, 0x48CA, { 0x8C, 0x5B, 0x23, 0x7E, 0x71, 0xA5, 0x44, 0x34 } };
+const GUID IID_IDirect3DCubeTexture9 = { 0xFFF32F81, 0xD953, 0x473A, { 0x92, 0x23, 0x93, 0xD6, 0x52, 0xAB, 0xA9, 0x3F } };
+const GUID IID_IDirect3DDevice9 = { 0xD0223B96, 0xBF7A, 0x43FD, { 0x92, 0xBD, 0xA4, 0x3B, 0x0D, 0x82, 0xB9, 0xEB } };
+const GUID IID_IDirect3DDevice9Ex = { 0xB18B10CE, 0x2649, 0x405A, { 0x87, 0x0F, 0x95, 0xF7, 0x77, 0xD4, 0x31, 0x3A } };
+const GUID IID_IDirect3DDevice9Video = { 0x26DC4561, 0xA1EE, 0x4AE7, { 0x96, 0xDA, 0x11, 0x8A, 0x36, 0xC0, 0xEC, 0x95 } };
+const GUID IID_IDirect3DIndexBuffer9 = { 0x7C9DD65E, 0xD3F7, 0x4529, { 0xAC, 0xEE, 0x78, 0x58, 0x30, 0xAC, 0xDE, 0x35 } };
+const GUID IID_IDirect3DPixelShader9 = { 0x6D3BDBDC, 0x5B02, 0x4415, { 0xB8, 0x52, 0xCE, 0x5E, 0x8B, 0xCC, 0xB2, 0x89 } };
+const GUID IID_IDirect3DQuery9 = { 0xD9771460, 0xA695, 0x4F26, { 0xBB, 0xD3, 0x27, 0xB8, 0x40, 0xB5, 0x41, 0xCC } };
+const GUID IID_IDirect3DResource9 = { 0x05EEC05D, 0x8F7D, 0x4362, { 0xB9, 0x99, 0xD1, 0xBA, 0xF3, 0x57, 0xC7, 0x4 } };
+const GUID IID_IDirect3DStateBlock9 = { 0xB07C4FE5, 0x310D, 0x4BA8, { 0xA2, 0x3C, 0x4F, 0x0F, 0x20, 0x6F, 0x21, 0x8B } };
+const GUID IID_IDirect3DSurface9 = { 0x0CFBAF3A, 0x9FF6, 0x429A, { 0x99, 0xB3, 0xA2, 0x79, 0x6A, 0xF8, 0xB8, 0x9B } };
+const GUID IID_IDirect3DSwapChain9 = { 0x794950F2, 0xADFC, 0x458A, { 0x90, 0x5E, 0x10, 0xA1, 0x0B, 0x0B, 0x50, 0x3B } };
+const GUID IID_IDirect3DSwapChain9Ex = { 0x91886CAF, 0x1C3D, 0x4D2E, { 0xA0, 0xAB, 0x3E, 0x4C, 0x7D, 0x8D, 0x33, 0x3 } };
+const GUID IID_IDirect3DTexture9 = { 0x85C31227, 0x3DE5, 0x4F00, { 0x9B, 0x3A, 0xF1, 0x1A, 0xC3, 0x8C, 0x18, 0xB5 } };
+const GUID IID_IDirect3DVertexBuffer9 = { 0xB64BB1B5, 0xFD70, 0x4DF6, { 0xBF, 0x91, 0x19, 0xD0, 0xA1, 0x24, 0x55, 0xE3 } };
+const GUID IID_IDirect3DVertexDeclaration9 = { 0xDD13C59C, 0x36FA, 0x4098, { 0xA8, 0xFB, 0xC7, 0xED, 0x39, 0xDC, 0x85, 0x46 } };
+const GUID IID_IDirect3DVertexShader9 = { 0xEFC5557E, 0x6265, 0x4613, { 0x8A, 0x94, 0x43, 0x85, 0x78, 0x89, 0xEB, 0x36 } };
+const GUID IID_IDirect3DVolume9 = { 0x24F416E6, 0x1F67, 0x4AA7, { 0xB8, 0x8E, 0xD3, 0x3F, 0x6F, 0x31, 0x28, 0xA1 } };
+const GUID IID_IDirect3DVolumeTexture9 = { 0x2518526C, 0xE789, 0x4111, { 0xA7, 0xB9, 0x47, 0xEF, 0x32, 0x8D, 0x13, 0xE6 } };
+
+boolean
+GUID_equal( const GUID *a,
+            const GUID *b )
+{
+    unsigned i;
+
+    if (!a || !b)
+        return FALSE;
+
+    if (a->Data1 != b->Data1 ||
+        a->Data2 != b->Data2 ||
+        a->Data3 != b->Data3) { return FALSE; }
+    for (i = 0; i < 8; i++) {
+        if (a->Data4[i] != b->Data4[i]) { return FALSE; }
+    }
+    return TRUE;
+}
diff --git a/src/gallium/state_trackers/nine/guid.h b/src/gallium/state_trackers/nine/guid.h
new file mode 100644 (file)
index 0000000..1f9ff00
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _NINE_GUID_H_
+#define _NINE_GUID_H_
+
+#include "pipe/p_compiler.h"
+
+#include "d3d9types.h"
+
+extern const GUID IID_ID3D9Adapter;
+
+boolean
+GUID_equal( const GUID *a,
+            const GUID *b );
+
+#endif /* _NINE_GUID_H_ */
diff --git a/src/gallium/state_trackers/nine/indexbuffer9.c b/src/gallium/state_trackers/nine/indexbuffer9.c
new file mode 100644 (file)
index 0000000..c5606f1
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "indexbuffer9.h"
+#include "device9.h"
+#include "nine_helpers.h"
+#include "nine_pipe.h"
+#include "nine_dump.h"
+
+#include "pipe/p_screen.h"
+#include "pipe/p_context.h"
+#include "pipe/p_state.h"
+#include "pipe/p_defines.h"
+#include "pipe/p_format.h"
+#include "util/u_box.h"
+
+#define DBG_CHANNEL DBG_INDEXBUFFER
+
+HRESULT
+NineIndexBuffer9_ctor( struct NineIndexBuffer9 *This,
+                       struct NineUnknownParams *pParams,
+                       D3DINDEXBUFFER_DESC *pDesc )
+{
+    struct pipe_resource *info = &This->base.info;
+    HRESULT hr;
+    DBG("This=%p pParams=%p pDesc=%p Usage=%s\n",
+         This, pParams, pDesc, nine_D3DUSAGE_to_str(pDesc->Usage));
+
+    This->pipe = pParams->device->pipe;
+
+    info->screen = pParams->device->screen;
+    info->target = PIPE_BUFFER;
+    info->format = PIPE_FORMAT_R8_UNORM;
+    info->width0 = pDesc->Size;
+    info->flags = 0;
+
+    info->bind = PIPE_BIND_INDEX_BUFFER | PIPE_BIND_TRANSFER_WRITE;
+    if (!(pDesc->Usage & D3DUSAGE_WRITEONLY))
+        info->bind |= PIPE_BIND_TRANSFER_READ;
+
+    info->usage = PIPE_USAGE_DEFAULT;
+    if (pDesc->Usage & D3DUSAGE_DYNAMIC)
+        info->usage = PIPE_USAGE_STREAM;
+    if (pDesc->Pool == D3DPOOL_SYSTEMMEM)
+        info->usage = PIPE_USAGE_STAGING;
+
+    /* if (This->desc.Usage & D3DUSAGE_DONOTCLIP) { } */
+    /* if (This->desc.Usage & D3DUSAGE_NONSECURE) { } */
+    /* if (This->desc.Usage & D3DUSAGE_NPATCHES) { } */
+    /* if (This->desc.Usage & D3DUSAGE_POINTS) { } */
+    /* if (This->desc.Usage & D3DUSAGE_RTPATCHES) { } */
+    /* if (This->desc.Usage & D3DUSAGE_SOFTWAREPROCESSING) { } */
+
+    info->height0 = 1;
+    info->depth0 = 1;
+    info->array_size = 1;
+    info->last_level = 0;
+    info->nr_samples = 0;
+
+    hr = NineResource9_ctor(&This->base, pParams, TRUE, D3DRTYPE_INDEXBUFFER,
+                            pDesc->Pool);
+    if (FAILED(hr))
+        return hr;
+
+    This->buffer.buffer = This->base.resource;
+    This->buffer.offset = 0;
+    This->map_count = 0;
+
+    switch (pDesc->Format) {
+    case D3DFMT_INDEX16: This->buffer.index_size = 2; break;
+    case D3DFMT_INDEX32: This->buffer.index_size = 4; break;
+    default:
+        user_assert(!"Invalid index format.", D3DERR_INVALIDCALL);
+        break;
+    }
+    This->buffer.user_buffer = NULL;
+
+    pDesc->Type = D3DRTYPE_INDEXBUFFER;
+    This->desc = *pDesc;
+
+    return D3D_OK;
+}
+
+void
+NineIndexBuffer9_dtor( struct NineIndexBuffer9 *This )
+{
+    if (This->transfer) { NineIndexBuffer9_Unlock(This); }
+
+    NineResource9_dtor(&This->base);
+}
+
+const struct pipe_index_buffer *
+NineIndexBuffer9_GetBuffer( struct NineIndexBuffer9 *This )
+{
+    return &This->buffer;
+}
+
+HRESULT WINAPI
+NineIndexBuffer9_Lock( struct NineIndexBuffer9 *This,
+                       UINT OffsetToLock,
+                       UINT SizeToLock,
+                       void **ppbData,
+                       DWORD Flags )
+{
+    struct pipe_box box;
+    void *data;
+    UINT count;
+    const unsigned usage = d3dlock_buffer_to_pipe_transfer_usage(Flags);
+
+    DBG("This=%p OffsetToLock=%u SizeToLock=%u ppbData=%p Flags=%i "
+        "transfer=%p map_count=%u\n", This, OffsetToLock,
+       SizeToLock, ppbData, Flags, This->transfer, This->map_count);
+
+    count = ++This->map_count;
+
+    if (SizeToLock == 0) {
+        SizeToLock = This->desc.Size - OffsetToLock;
+        user_warn(OffsetToLock != 0);
+    }
+
+    u_box_1d(OffsetToLock, SizeToLock, &box);
+
+    if (unlikely(count != 1)) {
+        DBG("Lock has been called on already locked buffer."
+           "Unmapping before mapping again.");
+        This->pipe->transfer_unmap(This->pipe, This->transfer);
+    }
+    data = This->pipe->transfer_map(This->pipe, This->base.resource, 0,
+                                    usage, &box, &This->transfer);
+    if (!This->transfer) {
+        DBG("pipe::transfer_map failed\n"
+            " usage = %u\n"
+            " box.x = %u\n"
+            " box.width = %u\n",
+            usage, box.x, box.width);
+    }
+    *ppbData = data;
+    DBG("Returning memory at %p at address %p\n", *ppbData, ppbData);
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineIndexBuffer9_Unlock( struct NineIndexBuffer9 *This )
+{
+    DBG("This=%p\n", This);
+    if (!This->map_count) {
+        DBG("Unmap called without a previous map call.\n");
+        return D3D_OK;
+    }
+    if (--This->map_count) {
+        DBG("Ignoring unmap.\n");
+       return D3D_OK;
+    }
+    This->pipe->transfer_unmap(This->pipe, This->transfer);
+    This->transfer = NULL;
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineIndexBuffer9_GetDesc( struct NineIndexBuffer9 *This,
+                          D3DINDEXBUFFER_DESC *pDesc )
+{
+    user_assert(pDesc, E_POINTER);
+    *pDesc = This->desc;
+    return D3D_OK;
+}
+
+IDirect3DIndexBuffer9Vtbl NineIndexBuffer9_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */
+    (void *)NineResource9_SetPrivateData,
+    (void *)NineResource9_GetPrivateData,
+    (void *)NineResource9_FreePrivateData,
+    (void *)NineResource9_SetPriority,
+    (void *)NineResource9_GetPriority,
+    (void *)NineResource9_PreLoad,
+    (void *)NineResource9_GetType,
+    (void *)NineIndexBuffer9_Lock,
+    (void *)NineIndexBuffer9_Unlock,
+    (void *)NineIndexBuffer9_GetDesc
+};
+
+static const GUID *NineIndexBuffer9_IIDs[] = {
+    &IID_IDirect3DIndexBuffer9,
+    &IID_IDirect3DResource9,
+    &IID_IUnknown,
+    NULL
+};
+
+HRESULT
+NineIndexBuffer9_new( struct NineDevice9 *pDevice,
+                      D3DINDEXBUFFER_DESC *pDesc,
+                      struct NineIndexBuffer9 **ppOut )
+{
+    NINE_DEVICE_CHILD_NEW(IndexBuffer9, ppOut, /* args */ pDevice, pDesc);
+}
diff --git a/src/gallium/state_trackers/nine/indexbuffer9.h b/src/gallium/state_trackers/nine/indexbuffer9.h
new file mode 100644 (file)
index 0000000..0982a93
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _NINE_INDEXBUFFER9_H_
+#define _NINE_INDEXBUFFER9_H_
+
+#include "resource9.h"
+
+#include "pipe/p_state.h"
+
+struct pipe_screen;
+struct pipe_context;
+struct pipe_index_buffer;
+struct pipe_transfer;
+struct NineDevice9;
+
+struct NineIndexBuffer9
+{
+    struct NineResource9 base;
+
+    /* g3d stuff */
+    struct pipe_context *pipe;
+    struct pipe_index_buffer buffer;
+    struct pipe_transfer *transfer;
+    UINT map_count;
+
+    D3DINDEXBUFFER_DESC desc;
+};
+static INLINE struct NineIndexBuffer9 *
+NineIndexBuffer9( void *data )
+{
+    return (struct NineIndexBuffer9 *)data;
+}
+
+HRESULT
+NineIndexBuffer9_new( struct NineDevice9 *pDevice,
+                      D3DINDEXBUFFER_DESC *pDesc,
+                      struct NineIndexBuffer9 **ppOut );
+
+HRESULT
+NineIndexBuffer9_ctor( struct NineIndexBuffer9 *This,
+                       struct NineUnknownParams *pParams,
+                       D3DINDEXBUFFER_DESC *pDesc );
+
+void
+NineIndexBuffer9_dtor( struct NineIndexBuffer9 *This );
+
+/*** Nine private ***/
+
+const struct pipe_index_buffer *
+NineIndexBuffer9_GetBuffer( struct NineIndexBuffer9 *This );
+
+/*** Direct3D public ***/
+
+HRESULT WINAPI
+NineIndexBuffer9_Lock( struct NineIndexBuffer9 *This,
+                       UINT OffsetToLock,
+                       UINT SizeToLock,
+                       void **ppbData,
+                       DWORD Flags );
+
+HRESULT WINAPI
+NineIndexBuffer9_Unlock( struct NineIndexBuffer9 *This );
+
+HRESULT WINAPI
+NineIndexBuffer9_GetDesc( struct NineIndexBuffer9 *This,
+                          D3DINDEXBUFFER_DESC *pDesc );
+
+#endif /* _NINE_INDEXBUFFER9_H_ */
diff --git a/src/gallium/state_trackers/nine/iunknown.c b/src/gallium/state_trackers/nine/iunknown.c
new file mode 100644 (file)
index 0000000..aff8041
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "iunknown.h"
+#include "util/u_atomic.h"
+#include "nine_helpers.h"
+
+#define DBG_CHANNEL DBG_UNKNOWN
+
+HRESULT
+NineUnknown_ctor( struct NineUnknown *This,
+                  struct NineUnknownParams *pParams )
+{
+    This->refs = pParams->container ? 0 : 1;
+    This->bind = 0;
+    This->forward = !This->refs;
+    This->container = pParams->container;
+    This->device = pParams->device;
+    if (This->refs && This->device)
+        NineUnknown_AddRef(NineUnknown(This->device));
+
+    This->vtable = pParams->vtable;
+    This->guids = pParams->guids;
+    This->dtor = pParams->dtor;
+
+    return D3D_OK;
+}
+
+void
+NineUnknown_dtor( struct NineUnknown *This )
+{
+    FREE(This);
+}
+
+HRESULT WINAPI
+NineUnknown_QueryInterface( struct NineUnknown *This,
+                            REFIID riid,
+                            void **ppvObject )
+{
+    unsigned i = 0;
+
+    if (!ppvObject) return E_POINTER;
+
+    do {
+        if (GUID_equal(This->guids[i], riid)) {
+            *ppvObject = This;
+            assert(This->refs);
+            NineUnknown_AddRef(This);
+            return S_OK;
+        }
+    } while (This->guids[++i]);
+
+    *ppvObject = NULL;
+    return E_NOINTERFACE;
+}
+
+ULONG WINAPI
+NineUnknown_AddRef( struct NineUnknown *This )
+{
+    ULONG r;
+    if (This->forward)
+        return NineUnknown_AddRef(This->container);
+    else
+        r = p_atomic_inc_return(&This->refs);
+
+    if (r == 1) {
+        if (This->device)
+            NineUnknown_AddRef(NineUnknown(This->device));
+        /* This shouldn't be necessary:
+        if (This->container)
+            NineUnknown_Bind(NineUnknown(This->container)); */
+    }
+    return r;
+}
+
+ULONG WINAPI
+NineUnknown_Release( struct NineUnknown *This )
+{
+    if (This->forward)
+        return NineUnknown_Release(This->container);
+
+    ULONG r = p_atomic_dec_return(&This->refs);
+
+    if (r == 0) {
+        if (This->device) {
+            if (NineUnknown_Release(NineUnknown(This->device)) == 0)
+                return r; /* everything's gone */
+        }
+        if (This->container) {
+            /* NineUnknown_Unbind(NineUnknown(This->container)); */
+        } else
+        if (This->bind == 0) {
+            This->dtor(This);
+        }
+    }
+    return r;
+}
+
+HRESULT WINAPI
+NineUnknown_GetDevice( struct NineUnknown *This,
+                       IDirect3DDevice9 **ppDevice )
+{
+    user_assert(ppDevice, E_POINTER);
+    NineUnknown_AddRef(NineUnknown(This->device));
+    *ppDevice = (IDirect3DDevice9 *)This->device;
+    return D3D_OK;
+}
diff --git a/src/gallium/state_trackers/nine/iunknown.h b/src/gallium/state_trackers/nine/iunknown.h
new file mode 100644 (file)
index 0000000..4c83ddd
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _NINE_IUNKNOWN_H_
+#define _NINE_IUNKNOWN_H_
+
+#include "pipe/p_compiler.h"
+
+#include "util/u_memory.h"
+
+#include "guid.h"
+#include "nine_debug.h"
+#include "nine_quirk.h"
+
+#include "d3d9.h"
+
+struct Nine9;
+struct NineDevice9;
+
+struct NineUnknown
+{
+    /* pointer to vtable  */
+    void *vtable;
+
+    int32_t refs; /* external reference count */
+    int32_t bind; /* internal bind count */
+    boolean forward; /* whether to forward references to the container */
+
+    struct NineUnknown *container; /* referenced if (refs | bind) */
+    struct NineDevice9 *device;    /* referenced if (refs) */
+
+    const GUID **guids; /* for QueryInterface */
+
+    void (*dtor)(void *data); /* top-level dtor */
+};
+static INLINE struct NineUnknown *
+NineUnknown( void *data )
+{
+    return (struct NineUnknown *)data;
+}
+
+/* Use this instead of a shitload of arguments: */
+struct NineUnknownParams
+{
+    void *vtable;
+    const GUID **guids;
+    void (*dtor)(void *data);
+    struct NineUnknown *container;
+    struct NineDevice9 *device;
+};
+
+HRESULT
+NineUnknown_ctor( struct NineUnknown *This,
+                  struct NineUnknownParams *pParams );
+
+void
+NineUnknown_dtor( struct NineUnknown *This );
+
+/*** Direct3D public methods ***/
+
+HRESULT WINAPI
+NineUnknown_QueryInterface( struct NineUnknown *This,
+                            REFIID riid,
+                            void **ppvObject );
+
+ULONG WINAPI
+NineUnknown_AddRef( struct NineUnknown *This );
+
+ULONG WINAPI
+NineUnknown_Release( struct NineUnknown *This );
+
+HRESULT WINAPI
+NineUnknown_GetDevice( struct NineUnknown *This,
+                       IDirect3DDevice9 **ppDevice );
+
+/*** Nine private methods ***/
+
+static INLINE void
+NineUnknown_Destroy( struct NineUnknown *This )
+{
+    assert(!(This->refs | This->bind));
+    This->dtor(This);
+}
+
+static INLINE UINT
+NineUnknown_Bind( struct NineUnknown *This )
+{
+    UINT b = ++This->bind;
+    assert(b);
+    if (b == 1 && This->container) {
+        if (This->container != NineUnknown(This->device))
+            NineUnknown_Bind(This->container);
+    }
+    return b;
+}
+
+static INLINE UINT
+NineUnknown_Unbind( struct NineUnknown *This )
+{
+    UINT b = --This->bind;
+    if (!b) {
+        if (This->container) {
+            if (This->container != NineUnknown(This->device))
+                NineUnknown_Unbind(This->container);
+        } else
+        if (This->refs == 0) {
+            This->dtor(This);
+        }
+    }
+    return b;
+}
+
+static INLINE void
+NineUnknown_ConvertRefToBind( struct NineUnknown *This )
+{
+    NineUnknown_Bind(This);
+    NineUnknown_Release(This);
+}
+
+/* Detach from container. */
+static INLINE void
+NineUnknown_Detach( struct NineUnknown *This )
+{
+    assert(This->container && !This->forward);
+    if (This->refs)
+        NineUnknown_Unbind(This->container);
+    if (This->bind)
+        NineUnknown_Unbind(This->container);
+    This->container = NULL;
+    if (!(This->refs | This->bind))
+        This->dtor(This);
+}
+
+#endif /* _NINE_IUNKNOWN_H_ */
diff --git a/src/gallium/state_trackers/nine/nine_debug.c b/src/gallium/state_trackers/nine/nine_debug.c
new file mode 100644 (file)
index 0000000..4779192
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "nine_debug.h"
+
+#include <ctype.h>
+
+static const struct debug_named_value nine_debug_flags[] = {
+    { "unknown", DBG_UNKNOWN,              "IUnknown implementation." },
+    { "adapter", DBG_ADAPTER,              "ID3D9Adapter implementation." },
+    { "overlay", DBG_OVERLAYEXTENSION,     "IDirect3D9ExOverlayExtension implementation." },
+    { "auth",    DBG_AUTHENTICATEDCHANNEL, "IDirect3DAuthenticatedChannel9 implementation." },
+    { "basetex", DBG_BASETEXTURE,          "IDirect3DBaseTexture9 implementation." },
+    { "crypto",  DBG_CRYPTOSESSION,        "IDirect3DCryptoSession9 implementation." },
+    { "cubetex", DBG_CUBETEXTURE,          "IDirect3DCubeTexture9 implementation." },
+    { "device",  DBG_DEVICE,               "IDirect3DDevice9(Ex) implementation." },
+    { "video",   DBG_DEVICEVIDEO,          "IDirect3DDeviceVideo9 implementation." },
+    { "ibuf",    DBG_INDEXBUFFER,          "IDirect3DIndexBuffer9 implementation." },
+    { "ps",      DBG_PIXELSHADER,          "IDirect3DPixelShader9 implementation." },
+    { "query",   DBG_QUERY,                "IDirect3DQuery9 implementation." },
+    { "res",     DBG_RESOURCE,             "IDirect3DResource9 implementation." },
+    { "state",   DBG_STATEBLOCK,           "IDirect3DStateBlock9 implementation." },
+    { "surf",    DBG_SURFACE,              "IDirect3DSurface9 implementation." },
+    { "swap",    DBG_SWAPCHAIN,            "IDirect3DSwapChain9(Ex) implementation." },
+    { "tex",     DBG_TEXTURE,              "IDirect3DTexture9 implementation." },
+    { "vbuf",    DBG_VERTEXBUFFER,         "IDirect3DVertexBuffer9 implementation." },
+    { "vdecl",   DBG_VERTEXDECLARATION,    "IDirect3DVertexDeclaration9 implementation." },
+    { "vs",      DBG_VERTEXSHADER,         "IDirect3DVertexShader9 implementation." },
+    { "3dsurf",  DBG_VOLUME,               "IDirect3DVolume9 implementation." },
+    { "3dtex",   DBG_VOLUMETEXTURE,        "IDirect3DVolumeTexture9 implementation." },
+    { "shader",  DBG_SHADER,               "Shader token stream translator." },
+    { "ff",      DBG_FF,                   "Fixed function emulation." },
+    { "user",    DBG_USER,                 "User errors, both fixable and unfixable." },
+    { "error",   DBG_ERROR,                "Driver errors, always visible." },
+    { "warn",    DBG_WARN,                 "Driver warnings, always visible in debug builds." },
+    DEBUG_NAMED_VALUE_END
+};
+
+void
+_nine_debug_printf( unsigned long flag,
+                    const char *func,
+                    const char *fmt,
+                    ... )
+{
+    static boolean first = TRUE;
+    static unsigned long dbg_flags = DBG_ERROR | DBG_WARN;
+
+    if (first) {
+        first = FALSE;
+        dbg_flags |= debug_get_flags_option("NINE_DEBUG", nine_debug_flags, 0);
+    }
+    if (dbg_flags & flag) {
+        const char *f = func ? strrchr(func, '_') : NULL;
+        va_list ap;
+
+        /* inside a class this will print nine:classinlowercase:func: while
+         * outside a class (rarely used) it will just print nine:func:
+         * the reason for lower case is simply to match the filenames, as it
+         * will also strip off the "Nine" */
+        if (f && strncmp(func, "Nine", 4) == 0) {
+            char klass[96]; /* no class name is this long */
+            char *ptr = klass;
+            for (func += 4; func != f; ++func) { *ptr++ = tolower(*func); }
+            *ptr = '\0';
+
+            debug_printf("nine:%s:%s: ", klass, ++f);
+        } else if (func) {
+            debug_printf("nine:%s: ", func);
+        }
+
+        va_start(ap, fmt);
+        debug_vprintf(fmt, ap);
+        va_end(ap);
+    }
+}
+
+void
+_nine_stub( const char *file,
+            const char *func,
+            unsigned line )
+{
+    const char *r = strrchr(file, '/');
+    if (r == NULL) { r = strrchr(file, '\\'); }
+    debug_printf("nine:%s:%d: %s STUB!\n", r ? ++r : file, line, func);
+}
diff --git a/src/gallium/state_trackers/nine/nine_debug.h b/src/gallium/state_trackers/nine/nine_debug.h
new file mode 100644 (file)
index 0000000..4c017ea
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _NINE_DEBUG_H_
+#define _NINE_DEBUG_H_
+
+#include "util/u_debug.h"
+
+void
+_nine_debug_printf( unsigned long flag,
+                    const char *func,
+                    const char *fmt,
+                    ... ) _util_printf_format(3,4);
+
+#define ERR(fmt, ...) _nine_debug_printf(DBG_ERROR, __FUNCTION__, fmt, ## __VA_ARGS__)
+
+#ifdef DEBUG
+#define WARN(fmt, ...) _nine_debug_printf(DBG_WARN, __FUNCTION__, fmt, ## __VA_ARGS__)
+#define WARN_ONCE(fmt, ...) \
+    do { \
+        static boolean once = TRUE; \
+        if (once) { \
+            once = FALSE; \
+            _nine_debug_printf(DBG_WARN, __FUNCTION__, fmt, ## __VA_ARGS__); \
+        } \
+    } while(0)
+#else
+#define WARN(fmt, ...)
+#define WARN_ONCE(fmt, ...)
+#endif
+
+#ifdef DEBUG
+#define DBG_FLAG(flag, fmt, ...) \
+    _nine_debug_printf(flag, __FUNCTION__, fmt, ## __VA_ARGS__)
+#else
+#define DBG_FLAG(flag, fmt, ...)
+#endif
+#define DBG(fmt, ...) DBG_FLAG(DBG_CHANNEL, fmt, ## __VA_ARGS__)
+
+#define DBG_UNKNOWN              (1<< 0)
+#define DBG_ADAPTER              (1<< 1)
+#define DBG_OVERLAYEXTENSION     (1<< 2)
+#define DBG_AUTHENTICATEDCHANNEL (1<< 3)
+#define DBG_BASETEXTURE          (1<< 4)
+#define DBG_CRYPTOSESSION        (1<< 5)
+#define DBG_CUBETEXTURE          (1<< 6)
+#define DBG_DEVICE               (1<< 7)
+#define DBG_DEVICEVIDEO          (1<< 8)
+#define DBG_INDEXBUFFER          (1<< 9)
+#define DBG_PIXELSHADER          (1<<10)
+#define DBG_QUERY                (1<<11)
+#define DBG_RESOURCE             (1<<12)
+#define DBG_STATEBLOCK           (1<<13)
+#define DBG_SURFACE              (1<<14)
+#define DBG_SWAPCHAIN            (1<<15)
+#define DBG_TEXTURE              (1<<16)
+#define DBG_VERTEXBUFFER         (1<<17)
+#define DBG_VERTEXDECLARATION    (1<<18)
+#define DBG_VERTEXSHADER         (1<<19)
+#define DBG_VOLUME               (1<<20)
+#define DBG_VOLUMETEXTURE        (1<<21)
+#define DBG_SHADER               (1<<22)
+#define DBG_FF                   (1<<23)
+#define DBG_USER                 (1<<24)
+#define DBG_ERROR                (1<<25)
+#define DBG_WARN                 (1<<26)
+
+void
+_nine_stub( const char *file,
+            const char *func,
+            unsigned line );
+
+#ifdef DEBUG
+#define STUB(ret) \
+    do { \
+        _nine_stub(__FILE__, __FUNCTION__, __LINE__); \
+        return ret; \
+    } while (0)
+#else
+#define STUB(ret) do { return ret; } while (0)
+#endif
+
+/* the expression for this macro is equivalent of that to assert, however this
+ * macro is designed to be used in conditionals ala
+ * if (user_error(required condition)) { assertion failed }
+ * It also prints debug message if the assertion fails. */
+#ifdef DEBUG
+#define user_error(x) \
+    (!(x) ? (DBG_FLAG(DBG_USER, "User assertion failed: `%s'\n", #x), TRUE) \
+          : FALSE)
+#else
+#define user_error(x) (!(x) ? TRUE : FALSE)
+#endif
+
+#ifdef DEBUG
+#define user_warn(x) \
+    if ((x)) { DBG_FLAG(DBG_USER, "User warning: `%s'\n", #x); }
+#else
+#define user_warn(x)
+#endif
+
+/* nonfatal assert */
+#define user_assert(x, r) \
+    do { \
+        if (user_error(x)) { \
+            return r; \
+        } \
+    } while (0)
+
+#define ret_err(x, r) \
+    do { \
+        ERR(x); \
+        return r; \
+    } while(0)
+
+#endif /* _NINE_DEBUG_H_ */
diff --git a/src/gallium/state_trackers/nine/nine_defines.h b/src/gallium/state_trackers/nine/nine_defines.h
new file mode 100644 (file)
index 0000000..aa3b257
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _NINE_DEFINES_H_
+#define _NINE_DEFINES_H_
+
+#include "pipe/p_defines.h"
+
+
+#define NINE_RESOURCE_FLAG_LOCKABLE (PIPE_RESOURCE_FLAG_ST_PRIV << 1)
+#define NINE_RESOURCE_FLAG_DUMMY    (PIPE_RESOURCE_FLAG_ST_PRIV << 2)
+
+/* vertexdeclaration9.c */
+unsigned nine_d3d9_to_nine_declusage(unsigned usage, unsigned index);
+
+#define NINE_DECLUSAGE_POSITION(i)     ( 0 + (i))
+#define NINE_DECLUSAGE_BLENDWEIGHT(i)  ( 5 + (i))
+#define NINE_DECLUSAGE_BLENDINDICES(i) ( 9 + (i))
+#define NINE_DECLUSAGE_NORMAL(i)       (13 + (i))
+#define NINE_DECLUSAGE_PSIZE            15
+#define NINE_DECLUSAGE_TEXCOORD(i)     (16 + (i))
+#define NINE_DECLUSAGE_TANGENT(i)      (32 + (i))
+#define NINE_DECLUSAGE_BINORMAL(i)     (34 + (i))
+#define NINE_DECLUSAGE_TESSFACTOR       36
+#define NINE_DECLUSAGE_POSITIONT        37
+#define NINE_DECLUSAGE_COLOR(i)        (38 + (i))
+#define NINE_DECLUSAGE_DEPTH            43
+#define NINE_DECLUSAGE_FOG              44
+#define NINE_DECLUSAGE_SAMPLE           45
+#define NINE_DECLUSAGE_NONE             46
+#define NINE_DECLUSAGE_LAST             NINE_DECLUSAGE_NONE
+#define NINE_DECLUSAGE_COUNT           (NINE_DECLUSAGE_LAST + 1)
+
+#define NINED3DCLEAR_DEPTHSTENCIL   (D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL)
+
+#endif /* _NINE_DEFINES_H_ */
diff --git a/src/gallium/state_trackers/nine/nine_dump.c b/src/gallium/state_trackers/nine/nine_dump.c
new file mode 100644 (file)
index 0000000..1ca5505
--- /dev/null
@@ -0,0 +1,813 @@
+
+#include "nine_debug.h"
+#include "nine_pipe.h"
+
+#include <stdio.h>
+#include "util/u_memory.h"
+#include "util/u_math.h"
+
+#include "nine_dump.h"
+
+#ifdef DEBUG
+
+static char __thread tls[128];
+
+const char *nine_D3DDEVTYPE_to_str(D3DDEVTYPE type)
+{
+    switch (type) {
+    case D3DDEVTYPE_HAL: return "HAL";
+    case D3DDEVTYPE_NULLREF: return "NULLREF";
+    case D3DDEVTYPE_REF: return "REF";
+    case D3DDEVTYPE_SW: return "SW";
+    default:
+       return "(D3DDEVTYPE_?)";
+    }
+}
+
+const char *nine_D3DPOOL_to_str(D3DPOOL pool)
+{
+    switch (pool) {
+    case D3DPOOL_DEFAULT: return "DEFAULT";
+    case D3DPOOL_MANAGED: return "MANAGED";
+    case D3DPOOL_SYSTEMMEM: return "SYSTEMMEM";
+    case D3DPOOL_SCRATCH: return "SCRATCH";
+    default:
+        return "(D3DPOOL_?)";
+    }
+}
+
+const char *nine_D3DSAMP_to_str(DWORD samp)
+{
+    switch (samp) {
+    case D3DSAMP_ADDRESSU: return "ADDRESSU";
+    case D3DSAMP_ADDRESSV: return "ADDRESSV";
+    case D3DSAMP_ADDRESSW: return "ADDRESSW";
+    case D3DSAMP_BORDERCOLOR: return "BORDERCOLOR";
+    case D3DSAMP_MAGFILTER: return "MAGFILTER";
+    case D3DSAMP_MINFILTER: return "MINFILTER";
+    case D3DSAMP_MIPFILTER: return "MIPFILTER";
+    case D3DSAMP_MIPMAPLODBIAS: return "MIPMAPLODBIAS";
+    case D3DSAMP_MAXMIPLEVEL: return "MAXMIPLEVEL";
+    case D3DSAMP_MAXANISOTROPY: return "MAXANISOTROPY";
+    case D3DSAMP_SRGBTEXTURE: return "SRGBTEXTURE";
+    case D3DSAMP_ELEMENTINDEX: return "ELEMENTINDEX";
+    case D3DSAMP_DMAPOFFSET: return "DMAPOFFSET";
+    default:
+        return "(D3DSAMP_?)";
+    }
+}
+
+#define C2S(n,s) \
+    do { \
+        if (usage & D3DUSAGE_##n) p += snprintf(&tls[p], sizeof(tls) - p, s); \
+    } while(0)
+const char *nine_D3DUSAGE_to_str(DWORD usage)
+{
+    int p = 0;
+    tls[0] = 0;
+    C2S(AUTOGENMIPMAP, "MIPGEN");
+    C2S(WRITEONLY, "WO");
+    C2S(DYNAMIC, "DYNAMIC");
+    C2S(DEPTHSTENCIL, "DS");
+    C2S(RENDERTARGET, "RT");
+    C2S(SOFTWAREPROCESSING, "SW");
+    C2S(DONOTCLIP, "NOCLIP");
+    C2S(POINTS, "POINTS");
+    C2S(DMAP, "DMAP");
+    C2S(NPATCHES, "NPATCHES");
+    C2S(RTPATCHES, "RTPATCHES");
+    C2S(TEXTAPI, "TEXTAPI");
+    C2S(NONSECURE, "NONSECURE");
+    C2S(RESTRICTED_CONTENT, "RESTRICTED_CONTENT");
+    C2S(RESTRICT_SHARED_RESOURCE, "RESTRICT_SHARED_RESOURCE");
+    C2S(RESTRICT_SHARED_RESOURCE_DRIVER, "RESTRICT_SHARED_RESOURCE_DRIVER");
+    return tls;
+}
+#undef C2S
+
+#define C2S(n) \
+    do { \
+        if (flags & D3DPRESENTFLAG_##n) \
+            p += snprintf(&tls[p], sizeof(tls) - p, #n); \
+    } while(0)
+const char *nine_D3DPRESENTFLAG_to_str(DWORD flags)
+{
+    int p = 0;
+    tls[0] = 0;
+    C2S(DEVICECLIP);
+    C2S(DISCARD_DEPTHSTENCIL);
+    C2S(LOCKABLE_BACKBUFFER);
+    C2S(NOAUTOROTATE);
+    C2S(UNPRUNEDMODE);
+    C2S(VIDEO);
+    C2S(OVERLAY_LIMITEDRGB);
+    C2S(OVERLAY_YCbCr_BT709);
+    C2S(OVERLAY_YCbCr_xvYCC);
+    C2S(RESTRICTED_CONTENT);
+    C2S(RESTRICT_SHARED_RESOURCE_DRIVER);
+    return tls;
+}
+#undef C2S
+
+#define C2S(n) \
+    do { \
+        if (lock & D3DLOCK_##n) p += snprintf(&tls[p], sizeof(tls) - p, #n"|"); \
+    } while(0)
+const char *nine_D3DLOCK_to_str(DWORD lock)
+{
+    int p = 0;
+    tls[0] = 0;
+    C2S(DISCARD);
+    C2S(DONOTWAIT);
+    C2S(NO_DIRTY_UPDATE);
+    C2S(NOOVERWRITE);
+    C2S(NOSYSLOCK);
+    C2S(READONLY);
+    return tls;
+}
+#undef C2S
+
+const char *nine_D3DRTYPE_to_str(D3DRESOURCETYPE type)
+{
+    switch (type) {
+    case D3DRTYPE_SURFACE: return "SURFACE";
+    case D3DRTYPE_VOLUME: return "VOLUME";
+    case D3DRTYPE_TEXTURE: return "TEXTURE";
+    case D3DRTYPE_VOLUMETEXTURE: return "VOLUMETEXTURE";
+    case D3DRTYPE_CUBETEXTURE: return "CUBETEXTURE";
+    case D3DRTYPE_VERTEXBUFFER: return "VERTEXBUFFER";
+    case D3DRTYPE_INDEXBUFFER: return "INDEXBUFFER";
+    default:
+        return "(D3DRTYPE_?)";
+    }
+}
+
+const char *nine_D3DQUERYTYPE_to_str(D3DQUERYTYPE type)
+{
+    switch (type) {
+    case D3DQUERYTYPE_VCACHE: return "VCACHE";
+    case D3DQUERYTYPE_RESOURCEMANAGER: return "RESOURCEMANAGER";
+    case D3DQUERYTYPE_VERTEXSTATS: return "VERTEXSTATS";
+    case D3DQUERYTYPE_EVENT: return "EVENT";
+    case D3DQUERYTYPE_OCCLUSION: return "OCCLUSION";
+    case D3DQUERYTYPE_TIMESTAMP: return "TIMESTAMP";
+    case D3DQUERYTYPE_TIMESTAMPDISJOINT: return "TIMESTAMPDISJOINT";
+    case D3DQUERYTYPE_TIMESTAMPFREQ: return "TIMESTAMPFREQ";
+    case D3DQUERYTYPE_PIPELINETIMINGS: return "PIPELINETIMINGS";
+    case D3DQUERYTYPE_INTERFACETIMINGS: return "INTERFACETIMINGS";
+    case D3DQUERYTYPE_VERTEXTIMINGS: return "VERTEXTIMINGS";
+    case D3DQUERYTYPE_PIXELTIMINGS: return "PIXELTIMINGS";
+    case D3DQUERYTYPE_BANDWIDTHTIMINGS: return "BANDWIDTHTIMINGS";
+    case D3DQUERYTYPE_CACHEUTILIZATION: return "CACHEUTILIZATION";
+    default:
+        return "(D3DQUERYTYPE_?)";
+    }
+}
+
+const char *nine_D3DTSS_to_str(D3DTEXTURESTAGESTATETYPE type)
+{
+    switch (type) {
+    case D3DTSS_COLOROP: return "COLOROP";
+    case D3DTSS_ALPHAOP: return "ALPHAOP";
+    case D3DTSS_COLORARG0: return "COLORARG0";
+    case D3DTSS_COLORARG1: return "COLORARG1";
+    case D3DTSS_COLORARG2: return "COLORARG2";
+    case D3DTSS_ALPHAARG0: return "ALPHAARG0";
+    case D3DTSS_ALPHAARG1: return "ALPHAARG1";
+    case D3DTSS_ALPHAARG2: return "ALPHAARG2";
+    case D3DTSS_RESULTARG: return "RESULTARG";
+    case D3DTSS_BUMPENVMAT00: return "BUMPENVMAT00";
+    case D3DTSS_BUMPENVMAT01: return "BUMPENVMAT01";
+    case D3DTSS_BUMPENVMAT10: return "BUMPENVMAT10";
+    case D3DTSS_BUMPENVMAT11: return "BUMPENVMAT11";
+    case D3DTSS_BUMPENVLSCALE: return "BUMPENVLSCALE";
+    case D3DTSS_BUMPENVLOFFSET: return "BUMPENVLOFFSET";
+    case D3DTSS_TEXCOORDINDEX: return "TEXCOORDINDEX";
+    case D3DTSS_TEXTURETRANSFORMFLAGS: return "TEXTURETRANSFORMFLAGS";
+    case D3DTSS_CONSTANT: return "CONSTANT";
+    default:
+        return "(D3DTSS_?)";
+    }
+}
+
+#define D3DTOP_TO_STR_CASE(n) case D3DTOP_##n: return #n
+const char *nine_D3DTOP_to_str(D3DTEXTUREOP top)
+{
+    switch (top) {
+    D3DTOP_TO_STR_CASE(DISABLE);
+    D3DTOP_TO_STR_CASE(SELECTARG1);
+    D3DTOP_TO_STR_CASE(SELECTARG2);
+    D3DTOP_TO_STR_CASE(MODULATE);
+    D3DTOP_TO_STR_CASE(MODULATE2X);
+    D3DTOP_TO_STR_CASE(MODULATE4X);
+    D3DTOP_TO_STR_CASE(ADD);
+    D3DTOP_TO_STR_CASE(ADDSIGNED);
+    D3DTOP_TO_STR_CASE(ADDSIGNED2X);
+    D3DTOP_TO_STR_CASE(SUBTRACT);
+    D3DTOP_TO_STR_CASE(ADDSMOOTH);
+    D3DTOP_TO_STR_CASE(BLENDDIFFUSEALPHA);
+    D3DTOP_TO_STR_CASE(BLENDTEXTUREALPHA);
+    D3DTOP_TO_STR_CASE(BLENDFACTORALPHA);
+    D3DTOP_TO_STR_CASE(BLENDTEXTUREALPHAPM);
+    D3DTOP_TO_STR_CASE(BLENDCURRENTALPHA);
+    D3DTOP_TO_STR_CASE(PREMODULATE);
+    D3DTOP_TO_STR_CASE(MODULATEALPHA_ADDCOLOR);
+    D3DTOP_TO_STR_CASE(MODULATECOLOR_ADDALPHA);
+    D3DTOP_TO_STR_CASE(MODULATEINVALPHA_ADDCOLOR);
+    D3DTOP_TO_STR_CASE(MODULATEINVCOLOR_ADDALPHA);
+    D3DTOP_TO_STR_CASE(BUMPENVMAP);
+    D3DTOP_TO_STR_CASE(BUMPENVMAPLUMINANCE);
+    D3DTOP_TO_STR_CASE(DOTPRODUCT3);
+    D3DTOP_TO_STR_CASE(MULTIPLYADD);
+    D3DTOP_TO_STR_CASE(LERP);
+    default:
+        return "(D3DTOP_?)";
+    }
+}
+
+static const char *
+nine_D3DLIGHTTYPE_to_str(D3DLIGHTTYPE type)
+{
+    switch (type) {
+    case D3DLIGHT_POINT: return "POINT";
+    case D3DLIGHT_SPOT: return "SPOT";
+    case D3DLIGHT_DIRECTIONAL: return "DIRECTIONAL";
+    default:
+        return "(D3DLIGHT_?)";
+    }
+}
+
+static const char *
+nine_D3DTA_to_str(DWORD value)
+{
+    switch (value & D3DTA_SELECTMASK) {
+    case D3DTA_DIFFUSE: return "DIFFUSE";
+    case D3DTA_CURRENT: return "CURRENT";
+    case D3DTA_TEXTURE: return "TEXTURE";
+    case D3DTA_TFACTOR: return "TFACTOR";
+    case D3DTA_SPECULAR: return "SPECULAR";
+    case D3DTA_TEMP: return "TEMP";
+    case D3DTA_CONSTANT: return "CONSTANT";
+    default:
+        return "(D3DTA_?)";
+    }
+}
+
+static const char *
+nine_D3DTSS_TCI_to_str(DWORD value)
+{
+    switch (value & 0xf0000) {
+    case D3DTSS_TCI_PASSTHRU: return "PASSTHRU";
+    case D3DTSS_TCI_CAMERASPACENORMAL: return "CAMERASPACENORMAL";
+    case D3DTSS_TCI_CAMERASPACEPOSITION: return "CAMERASPACEPOSITION";
+    case D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
+        return "CAMERASPACEREFLECTIONVECTOR";
+    case D3DTSS_TCI_SPHEREMAP: return "SPHEREMAP";
+    default:
+        return "(D3DTSS_TCI_?)";
+    }
+}
+
+static const char *
+nine_D3DTTFF_to_str(DWORD value)
+{
+    switch (value) {
+    case D3DTTFF_DISABLE: return "DISABLE";
+    case D3DTTFF_COUNT1: return "COUNT1";
+    case D3DTTFF_COUNT2: return "COUNT2";
+    case D3DTTFF_COUNT3: return "COUNT3";
+    case D3DTTFF_COUNT4: return "COUNT4";
+    case D3DTTFF_PROJECTED: return "PROJECTED";
+    default:
+        return "(D3DTTFF_?)";
+    }
+}
+
+void
+nine_dump_D3DLIGHT9(unsigned ch, const D3DLIGHT9 *lit)
+{
+    DBG_FLAG(ch, "D3DLIGHT9(%p):\n"
+             "Type: %s\n"
+             "Diffuse: (%f %f %f %f)\n"
+             "Specular: (%f %f %f %f)\n"
+             "Ambient: (%f %f %f %f)\n"
+             "Position: (%f %f %f)\n"
+             "Direction: (%f %f %f)\n"
+             "Range: %f\n"
+             "Falloff: %f\n"
+             "Attenuation: %f + %f * d + %f * d^2\n"
+             "Theta: %f deg\n"
+             "Phi: %f deg\n", lit,
+             nine_D3DLIGHTTYPE_to_str(lit->Type),
+             lit->Diffuse.r,lit->Diffuse.r,lit->Diffuse.g,lit->Diffuse.a,
+             lit->Specular.r,lit->Specular.r,lit->Specular.g,lit->Specular.a,
+             lit->Ambient.r,lit->Ambient.r,lit->Ambient.g,lit->Ambient.a,
+             lit->Position.x,lit->Position.y,lit->Position.z,
+             lit->Direction.x,lit->Direction.y,lit->Direction.z,
+             lit->Range,lit->Falloff,
+             lit->Attenuation0,lit->Attenuation1,lit->Attenuation2,
+             lit->Theta * 360.0f / M_PI,lit->Phi * 360.0f / M_PI);
+}
+
+void
+nine_dump_D3DMATERIAL9(unsigned ch, const D3DMATERIAL9 *mat)
+{
+    DBG_FLAG(ch, "D3DMATERIAL9(%p):\n"
+             "Diffuse: (%f %f %f %f)\n"
+             "Specular: (%f %f %f %f)\n"
+             "Ambient: (%f %f %f %f)\n"
+             "Emissive: (%f %f %f %f)\n"
+             "Power: %f\n", mat,
+             mat->Diffuse.r,mat->Diffuse.r,mat->Diffuse.g,mat->Diffuse.a,
+             mat->Specular.r,mat->Specular.r,mat->Specular.g,mat->Specular.a,
+             mat->Ambient.r,mat->Ambient.r,mat->Ambient.g,mat->Ambient.a,
+             mat->Emissive.r,mat->Emissive.r,mat->Emissive.g,mat->Emissive.a,
+             mat->Power);
+}
+
+void
+nine_dump_D3DTSS_value(unsigned ch, D3DTEXTURESTAGESTATETYPE type, DWORD value)
+{
+    float rgba[4];
+
+    switch (type) {
+    case D3DTSS_COLOROP:
+    case D3DTSS_ALPHAOP:
+        DBG_FLAG(ch, "D3DTSS_%s = %s\n",
+                 nine_D3DTSS_to_str(type), nine_D3DTOP_to_str(value));
+        break;
+    case D3DTSS_COLORARG0:
+    case D3DTSS_COLORARG1:
+    case D3DTSS_COLORARG2:
+    case D3DTSS_ALPHAARG0:
+    case D3DTSS_ALPHAARG1:
+    case D3DTSS_ALPHAARG2:
+    case D3DTSS_RESULTARG:
+        DBG_FLAG(ch, "D3DTSS_%s = %s%s%s\n",
+                 nine_D3DTSS_to_str(type),
+                 (value & D3DTA_COMPLEMENT) ? "COMPLEMENT " : "",
+                 (value & D3DTA_ALPHAREPLICATE) ? "ALPHAREPLICATE " : "",
+                 nine_D3DTA_to_str(value));
+        break;
+    case D3DTSS_BUMPENVMAT00:
+    case D3DTSS_BUMPENVMAT01:
+    case D3DTSS_BUMPENVMAT10:
+    case D3DTSS_BUMPENVMAT11:
+    case D3DTSS_BUMPENVLSCALE:
+    case D3DTSS_BUMPENVLOFFSET:
+        DBG_FLAG(ch, "D3DTSS_%s = %f\n",
+                 nine_D3DTSS_to_str(type), asfloat(value));
+        break;
+    case D3DTSS_TEXCOORDINDEX:
+        DBG_FLAG(ch, "D3DTSS_TEXCOORDINDEX = %s %u\n",
+                 nine_D3DTSS_TCI_to_str(value),
+                 value & 0xffff);
+        break;
+    case D3DTSS_TEXTURETRANSFORMFLAGS:
+        DBG_FLAG(ch, "D3DTSS_TEXTURETRANSFORMFLAGS = %s\n",
+                 nine_D3DTTFF_to_str(value));
+        break;
+    case D3DTSS_CONSTANT:
+        d3dcolor_to_rgba(rgba, value);
+        DBG_FLAG(ch, "D3DTSS_CONSTANT = %f %f %f %F\n",
+                 rgba[0],rgba[1],rgba[2],rgba[3]);
+        break;
+    default:
+        DBG_FLAG(ch, "D3DTSS_? = 0x%08x\n", value);
+        break;
+    }
+}
+
+void
+nine_dump_D3DADAPTER_IDENTIFIER9(unsigned ch, const D3DADAPTER_IDENTIFIER9 *id)
+{
+    DBG_FLAG(ch, "D3DADAPTER_IDENTIFIER9(%p):\n"
+             "Driver: %s\n"
+             "Description: %s\n"
+             "DeviceName: %s\n"
+             "DriverVersion: %08x.%08x\n"
+             "VendorId: %x\n"
+             "DeviceId: %x\n"
+             "SubSysId: %x\n"
+             "Revision: %u\n"
+             "GUID: %08x.%04x.%04x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x\n"
+             "WHQLLevel: %u\n", id, id->Driver, id->Description,
+             id->DeviceName,
+             id->DriverVersionLowPart, id->DriverVersionHighPart,
+             id->VendorId, id->DeviceId, id->SubSysId,
+             id->Revision,
+             id->DeviceIdentifier.Data1,
+             id->DeviceIdentifier.Data2,
+             id->DeviceIdentifier.Data3,
+             id->DeviceIdentifier.Data4[0],
+             id->DeviceIdentifier.Data4[1],
+             id->DeviceIdentifier.Data4[2],
+             id->DeviceIdentifier.Data4[3],
+             id->DeviceIdentifier.Data4[4],
+             id->DeviceIdentifier.Data4[5],
+             id->DeviceIdentifier.Data4[6],
+             id->DeviceIdentifier.Data4[7],
+             id->WHQLLevel);
+}
+
+#define C2S(args...) p += snprintf(&s[p],c-p,args)
+
+#define CAP_CASE(m,p,n) \
+    do {                     \
+        if (caps->m & p##_##n) \
+            C2S(" "#n); \
+        else \
+            C2S(" ("#n")"); \
+    } while(0)
+
+void
+nine_dump_D3DCAPS9(unsigned ch, const D3DCAPS9 *caps)
+{
+    const int c = 1 << 17;
+    int p = 0;
+    char *s = (char *)MALLOC(c);
+
+    if (!s) {
+        DBG_FLAG(ch, "D3DCAPS9(%p): (out of memory)\n", caps);
+        return;
+    }
+
+    C2S("DeviceType: %s\n", nine_D3DDEVTYPE_to_str(caps->DeviceType));
+
+    C2S("AdapterOrdinal: %u\nCaps:", caps->AdapterOrdinal);
+    if (caps->Caps & 0x20000)
+        C2S(" READ_SCANLINE");
+    if (caps->Caps & ~0x20000)
+        C2S(" %x", caps->Caps & ~0x20000);
+
+    C2S("\nCaps2:");
+    CAP_CASE(Caps2, D3DCAPS2, CANAUTOGENMIPMAP);
+    CAP_CASE(Caps2, D3DCAPS2, CANCALIBRATEGAMMA);
+    CAP_CASE(Caps2, D3DCAPS2, CANSHARERESOURCE);
+    CAP_CASE(Caps2, D3DCAPS2, CANMANAGERESOURCE);
+    CAP_CASE(Caps2, D3DCAPS2, DYNAMICTEXTURES);
+    CAP_CASE(Caps2, D3DCAPS2, FULLSCREENGAMMA);
+
+    C2S("\nCaps3:");
+    CAP_CASE(Caps3, D3DCAPS3, ALPHA_FULLSCREEN_FLIP_OR_DISCARD);
+    CAP_CASE(Caps3, D3DCAPS3, COPY_TO_VIDMEM);
+    CAP_CASE(Caps3, D3DCAPS3, COPY_TO_SYSTEMMEM);
+    CAP_CASE(Caps3, D3DCAPS3, DXVAHD);
+    CAP_CASE(Caps3, D3DCAPS3, LINEAR_TO_SRGB_PRESENTATION);
+
+    C2S("\nPresentationIntervals:");
+    CAP_CASE(PresentationIntervals, D3DPRESENT_INTERVAL, ONE);
+    CAP_CASE(PresentationIntervals, D3DPRESENT_INTERVAL, TWO);
+    CAP_CASE(PresentationIntervals, D3DPRESENT_INTERVAL, THREE);
+    CAP_CASE(PresentationIntervals, D3DPRESENT_INTERVAL, FOUR);
+    CAP_CASE(PresentationIntervals, D3DPRESENT_INTERVAL, IMMEDIATE);
+
+    C2S("\nCursorCaps:");
+    CAP_CASE(CursorCaps, D3DCURSORCAPS, COLOR);
+    CAP_CASE(CursorCaps, D3DCURSORCAPS, LOWRES);
+
+    C2S("\nDevCaps:");
+    CAP_CASE(DevCaps, D3DDEVCAPS, CANBLTSYSTONONLOCAL);
+    CAP_CASE(DevCaps, D3DDEVCAPS, CANRENDERAFTERFLIP);
+    CAP_CASE(DevCaps, D3DDEVCAPS, DRAWPRIMITIVES2);
+    CAP_CASE(DevCaps, D3DDEVCAPS, DRAWPRIMITIVES2EX);
+    CAP_CASE(DevCaps, D3DDEVCAPS, DRAWPRIMTLVERTEX);
+    CAP_CASE(DevCaps, D3DDEVCAPS, EXECUTESYSTEMMEMORY);
+    CAP_CASE(DevCaps, D3DDEVCAPS, EXECUTEVIDEOMEMORY);
+    CAP_CASE(DevCaps, D3DDEVCAPS, HWRASTERIZATION);
+    CAP_CASE(DevCaps, D3DDEVCAPS, HWTRANSFORMANDLIGHT);
+    CAP_CASE(DevCaps, D3DDEVCAPS, NPATCHES);
+    CAP_CASE(DevCaps, D3DDEVCAPS, PUREDEVICE);
+    CAP_CASE(DevCaps, D3DDEVCAPS, QUINTICRTPATCHES);
+    CAP_CASE(DevCaps, D3DDEVCAPS, RTPATCHES);
+    CAP_CASE(DevCaps, D3DDEVCAPS, RTPATCHHANDLEZERO);
+    CAP_CASE(DevCaps, D3DDEVCAPS, SEPARATETEXTUREMEMORIES);
+    CAP_CASE(DevCaps, D3DDEVCAPS, TEXTURENONLOCALVIDMEM);
+    CAP_CASE(DevCaps, D3DDEVCAPS, TEXTURESYSTEMMEMORY);
+    CAP_CASE(DevCaps, D3DDEVCAPS, TEXTUREVIDEOMEMORY);
+    CAP_CASE(DevCaps, D3DDEVCAPS, TLVERTEXSYSTEMMEMORY);
+    CAP_CASE(DevCaps, D3DDEVCAPS, TLVERTEXVIDEOMEMORY);
+
+    C2S("\nPrimitiveMiscCaps:");
+    CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, MASKZ);
+    CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, CULLNONE);
+    CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, CULLCW);
+    CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, CULLCCW);
+    CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, COLORWRITEENABLE);
+    CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, CLIPPLANESCALEDPOINTS);
+    CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, CLIPTLVERTS);
+    CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, TSSARGTEMP);
+    CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, BLENDOP);
+    CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, NULLREFERENCE);
+    CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, INDEPENDENTWRITEMASKS);
+    CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, PERSTAGECONSTANT);
+    CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, POSTBLENDSRGBCONVERT);
+    CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, FOGANDSPECULARALPHA);
+    CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, SEPARATEALPHABLEND);
+    CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, MRTINDEPENDENTBITDEPTHS);
+    CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, MRTPOSTPIXELSHADERBLENDING);
+    CAP_CASE(PrimitiveMiscCaps, D3DPMISCCAPS, FOGVERTEXCLAMPED);
+
+    C2S("\nRasterCaps:");
+    CAP_CASE(RasterCaps, D3DPRASTERCAPS, ANISOTROPY);
+    CAP_CASE(RasterCaps, D3DPRASTERCAPS, COLORPERSPECTIVE);
+    CAP_CASE(RasterCaps, D3DPRASTERCAPS, DITHER);
+    CAP_CASE(RasterCaps, D3DPRASTERCAPS, DEPTHBIAS);
+    CAP_CASE(RasterCaps, D3DPRASTERCAPS, FOGRANGE);
+    CAP_CASE(RasterCaps, D3DPRASTERCAPS, FOGTABLE);
+    CAP_CASE(RasterCaps, D3DPRASTERCAPS, FOGVERTEX);
+    CAP_CASE(RasterCaps, D3DPRASTERCAPS, MIPMAPLODBIAS);
+    CAP_CASE(RasterCaps, D3DPRASTERCAPS, MULTISAMPLE_TOGGLE);
+    CAP_CASE(RasterCaps, D3DPRASTERCAPS, SCISSORTEST);
+    CAP_CASE(RasterCaps, D3DPRASTERCAPS, SLOPESCALEDEPTHBIAS);
+    CAP_CASE(RasterCaps, D3DPRASTERCAPS, WBUFFER);
+    CAP_CASE(RasterCaps, D3DPRASTERCAPS, WFOG);
+    CAP_CASE(RasterCaps, D3DPRASTERCAPS, ZBUFFERLESSHSR);
+    CAP_CASE(RasterCaps, D3DPRASTERCAPS, ZFOG);
+    CAP_CASE(RasterCaps, D3DPRASTERCAPS, ZTEST);
+
+    C2S("\nZCmpCaps:");
+    CAP_CASE(ZCmpCaps, D3DPCMPCAPS, ALWAYS);
+    CAP_CASE(ZCmpCaps, D3DPCMPCAPS, EQUAL);
+    CAP_CASE(ZCmpCaps, D3DPCMPCAPS, GREATER);
+    CAP_CASE(ZCmpCaps, D3DPCMPCAPS, GREATEREQUAL);
+    CAP_CASE(ZCmpCaps, D3DPCMPCAPS, LESS);
+    CAP_CASE(ZCmpCaps, D3DPCMPCAPS, LESSEQUAL);
+    CAP_CASE(ZCmpCaps, D3DPCMPCAPS, NEVER);
+    CAP_CASE(ZCmpCaps, D3DPCMPCAPS, NOTEQUAL);
+
+    C2S("\nSrcBlendCaps");
+    CAP_CASE(SrcBlendCaps, D3DPBLENDCAPS, BLENDFACTOR);
+    CAP_CASE(SrcBlendCaps, D3DPBLENDCAPS, BOTHINVSRCALPHA);
+    CAP_CASE(SrcBlendCaps, D3DPBLENDCAPS, BOTHSRCALPHA);
+    CAP_CASE(SrcBlendCaps, D3DPBLENDCAPS, DESTALPHA);
+    CAP_CASE(SrcBlendCaps, D3DPBLENDCAPS, DESTCOLOR);
+    CAP_CASE(SrcBlendCaps, D3DPBLENDCAPS, INVDESTALPHA);
+    CAP_CASE(SrcBlendCaps, D3DPBLENDCAPS, INVDESTCOLOR);
+    CAP_CASE(SrcBlendCaps, D3DPBLENDCAPS, INVSRCALPHA);
+    CAP_CASE(SrcBlendCaps, D3DPBLENDCAPS, INVSRCCOLOR);
+    CAP_CASE(SrcBlendCaps, D3DPBLENDCAPS, INVSRCCOLOR2);
+    CAP_CASE(SrcBlendCaps, D3DPBLENDCAPS, ONE);
+    CAP_CASE(SrcBlendCaps, D3DPBLENDCAPS, SRCALPHA);
+    CAP_CASE(SrcBlendCaps, D3DPBLENDCAPS, SRCALPHASAT);
+    CAP_CASE(SrcBlendCaps, D3DPBLENDCAPS, SRCCOLOR);
+    CAP_CASE(SrcBlendCaps, D3DPBLENDCAPS, SRCCOLOR2);
+    CAP_CASE(SrcBlendCaps, D3DPBLENDCAPS, ZERO);
+
+    C2S("\nDestBlendCaps");
+    CAP_CASE(DestBlendCaps, D3DPBLENDCAPS, BLENDFACTOR);
+    CAP_CASE(DestBlendCaps, D3DPBLENDCAPS, BOTHINVSRCALPHA);
+    CAP_CASE(DestBlendCaps, D3DPBLENDCAPS, BOTHSRCALPHA);
+    CAP_CASE(DestBlendCaps, D3DPBLENDCAPS, DESTALPHA);
+    CAP_CASE(DestBlendCaps, D3DPBLENDCAPS, DESTCOLOR);
+    CAP_CASE(DestBlendCaps, D3DPBLENDCAPS, INVDESTALPHA);
+    CAP_CASE(DestBlendCaps, D3DPBLENDCAPS, INVDESTCOLOR);
+    CAP_CASE(DestBlendCaps, D3DPBLENDCAPS, INVSRCALPHA);
+    CAP_CASE(DestBlendCaps, D3DPBLENDCAPS, INVSRCCOLOR);
+    CAP_CASE(DestBlendCaps, D3DPBLENDCAPS, INVSRCCOLOR2);
+    CAP_CASE(DestBlendCaps, D3DPBLENDCAPS, ONE);
+    CAP_CASE(DestBlendCaps, D3DPBLENDCAPS, SRCALPHA);
+    CAP_CASE(DestBlendCaps, D3DPBLENDCAPS, SRCALPHASAT);
+    CAP_CASE(DestBlendCaps, D3DPBLENDCAPS, SRCCOLOR);
+    CAP_CASE(DestBlendCaps, D3DPBLENDCAPS, SRCCOLOR2);
+    CAP_CASE(DestBlendCaps, D3DPBLENDCAPS, ZERO);
+
+    C2S("\nAlphaCmpCaps:");
+    CAP_CASE(AlphaCmpCaps, D3DPCMPCAPS, ALWAYS);
+    CAP_CASE(AlphaCmpCaps, D3DPCMPCAPS, EQUAL);
+    CAP_CASE(AlphaCmpCaps, D3DPCMPCAPS, GREATER);
+    CAP_CASE(AlphaCmpCaps, D3DPCMPCAPS, GREATEREQUAL);
+    CAP_CASE(AlphaCmpCaps, D3DPCMPCAPS, LESS);
+    CAP_CASE(AlphaCmpCaps, D3DPCMPCAPS, LESSEQUAL);
+    CAP_CASE(AlphaCmpCaps, D3DPCMPCAPS, NEVER);
+    CAP_CASE(AlphaCmpCaps, D3DPCMPCAPS, NOTEQUAL);
+
+    C2S("\nShadeCaps:");
+    CAP_CASE(ShadeCaps, D3DPSHADECAPS, ALPHAGOURAUDBLEND);
+    CAP_CASE(ShadeCaps, D3DPSHADECAPS, COLORGOURAUDRGB);
+    CAP_CASE(ShadeCaps, D3DPSHADECAPS, FOGGOURAUD);
+    CAP_CASE(ShadeCaps, D3DPSHADECAPS, SPECULARGOURAUDRGB);
+
+    C2S("\nTextureCaps:");
+    CAP_CASE(TextureCaps, D3DPTEXTURECAPS, ALPHA);
+    CAP_CASE(TextureCaps, D3DPTEXTURECAPS, ALPHAPALETTE);
+    CAP_CASE(TextureCaps, D3DPTEXTURECAPS, CUBEMAP);
+    CAP_CASE(TextureCaps, D3DPTEXTURECAPS, CUBEMAP_POW2);
+    CAP_CASE(TextureCaps, D3DPTEXTURECAPS, MIPCUBEMAP);
+    CAP_CASE(TextureCaps, D3DPTEXTURECAPS, MIPMAP);
+    CAP_CASE(TextureCaps, D3DPTEXTURECAPS, MIPVOLUMEMAP);
+    CAP_CASE(TextureCaps, D3DPTEXTURECAPS, NONPOW2CONDITIONAL);
+    CAP_CASE(TextureCaps, D3DPTEXTURECAPS, NOPROJECTEDBUMPENV);
+    CAP_CASE(TextureCaps, D3DPTEXTURECAPS, PERSPECTIVE);
+    CAP_CASE(TextureCaps, D3DPTEXTURECAPS, POW2);
+    CAP_CASE(TextureCaps, D3DPTEXTURECAPS, PROJECTED);
+    CAP_CASE(TextureCaps, D3DPTEXTURECAPS, SQUAREONLY);
+    CAP_CASE(TextureCaps, D3DPTEXTURECAPS, TEXREPEATNOTSCALEDBYSIZE);
+    CAP_CASE(TextureCaps, D3DPTEXTURECAPS, VOLUMEMAP);
+    CAP_CASE(TextureCaps, D3DPTEXTURECAPS, VOLUMEMAP_POW2);
+
+    C2S("\nTextureFilterCaps:");
+ /* CAP_CASE(TextureFilterCaps, D3DPTFILTERCAPS, CONVOLUTIONMONO); */
+    CAP_CASE(TextureFilterCaps, D3DPTFILTERCAPS, MAGFPOINT);
+    CAP_CASE(TextureFilterCaps, D3DPTFILTERCAPS, MAGFLINEAR);
+    CAP_CASE(TextureFilterCaps, D3DPTFILTERCAPS, MAGFANISOTROPIC);
+    CAP_CASE(TextureFilterCaps, D3DPTFILTERCAPS, MAGFPYRAMIDALQUAD);
+    CAP_CASE(TextureFilterCaps, D3DPTFILTERCAPS, MAGFGAUSSIANQUAD);
+    CAP_CASE(TextureFilterCaps, D3DPTFILTERCAPS, MINFPOINT);
+    CAP_CASE(TextureFilterCaps, D3DPTFILTERCAPS, MINFLINEAR);
+    CAP_CASE(TextureFilterCaps, D3DPTFILTERCAPS, MINFANISOTROPIC);
+    CAP_CASE(TextureFilterCaps, D3DPTFILTERCAPS, MINFPYRAMIDALQUAD);
+    CAP_CASE(TextureFilterCaps, D3DPTFILTERCAPS, MINFGAUSSIANQUAD);
+    CAP_CASE(TextureFilterCaps, D3DPTFILTERCAPS, MIPFPOINT);
+    CAP_CASE(TextureFilterCaps, D3DPTFILTERCAPS, MIPFLINEAR);
+
+    C2S("\nCubeTextureFilterCaps:");
+ /* CAP_CASE(CubeTextureFilterCaps, D3DPTFILTERCAPS, CONVOLUTIONMONO); */
+    CAP_CASE(CubeTextureFilterCaps, D3DPTFILTERCAPS, MAGFPOINT);
+    CAP_CASE(CubeTextureFilterCaps, D3DPTFILTERCAPS, MAGFLINEAR);
+    CAP_CASE(CubeTextureFilterCaps, D3DPTFILTERCAPS, MAGFANISOTROPIC);
+    CAP_CASE(CubeTextureFilterCaps, D3DPTFILTERCAPS, MAGFPYRAMIDALQUAD);
+    CAP_CASE(CubeTextureFilterCaps, D3DPTFILTERCAPS, MAGFGAUSSIANQUAD);
+    CAP_CASE(CubeTextureFilterCaps, D3DPTFILTERCAPS, MINFPOINT);
+    CAP_CASE(CubeTextureFilterCaps, D3DPTFILTERCAPS, MINFLINEAR);
+    CAP_CASE(CubeTextureFilterCaps, D3DPTFILTERCAPS, MINFANISOTROPIC);
+    CAP_CASE(CubeTextureFilterCaps, D3DPTFILTERCAPS, MINFPYRAMIDALQUAD);
+    CAP_CASE(CubeTextureFilterCaps, D3DPTFILTERCAPS, MINFGAUSSIANQUAD);
+    CAP_CASE(CubeTextureFilterCaps, D3DPTFILTERCAPS, MIPFPOINT);
+    CAP_CASE(CubeTextureFilterCaps, D3DPTFILTERCAPS, MIPFLINEAR);
+
+    C2S("\nVolumeTextureFilterCaps:");
+ /* CAP_CASE(VolumeTextureFilterCaps, D3DPTFILTERCAPS, CONVOLUTIONMONO); */
+    CAP_CASE(VolumeTextureFilterCaps, D3DPTFILTERCAPS, MAGFPOINT);
+    CAP_CASE(VolumeTextureFilterCaps, D3DPTFILTERCAPS, MAGFLINEAR);
+    CAP_CASE(VolumeTextureFilterCaps, D3DPTFILTERCAPS, MAGFANISOTROPIC);
+    CAP_CASE(VolumeTextureFilterCaps, D3DPTFILTERCAPS, MAGFPYRAMIDALQUAD);
+    CAP_CASE(VolumeTextureFilterCaps, D3DPTFILTERCAPS, MAGFGAUSSIANQUAD);
+    CAP_CASE(VolumeTextureFilterCaps, D3DPTFILTERCAPS, MINFPOINT);
+    CAP_CASE(VolumeTextureFilterCaps, D3DPTFILTERCAPS, MINFLINEAR);
+    CAP_CASE(VolumeTextureFilterCaps, D3DPTFILTERCAPS, MINFANISOTROPIC);
+    CAP_CASE(VolumeTextureFilterCaps, D3DPTFILTERCAPS, MINFPYRAMIDALQUAD);
+    CAP_CASE(VolumeTextureFilterCaps, D3DPTFILTERCAPS, MINFGAUSSIANQUAD);
+    CAP_CASE(VolumeTextureFilterCaps, D3DPTFILTERCAPS, MIPFPOINT);
+    CAP_CASE(VolumeTextureFilterCaps, D3DPTFILTERCAPS, MIPFLINEAR);
+
+    C2S("\nTextureAddressCaps:");
+    CAP_CASE(TextureAddressCaps, D3DPTADDRESSCAPS, BORDER);
+    CAP_CASE(TextureAddressCaps, D3DPTADDRESSCAPS, CLAMP);
+    CAP_CASE(TextureAddressCaps, D3DPTADDRESSCAPS, INDEPENDENTUV);
+    CAP_CASE(TextureAddressCaps, D3DPTADDRESSCAPS, MIRROR);
+    CAP_CASE(TextureAddressCaps, D3DPTADDRESSCAPS, MIRRORONCE);
+    CAP_CASE(TextureAddressCaps, D3DPTADDRESSCAPS, WRAP);
+
+    C2S("\nVolumeTextureAddressCaps:");
+    CAP_CASE(VolumeTextureAddressCaps, D3DPTADDRESSCAPS, BORDER);
+    CAP_CASE(VolumeTextureAddressCaps, D3DPTADDRESSCAPS, CLAMP);
+    CAP_CASE(VolumeTextureAddressCaps, D3DPTADDRESSCAPS, INDEPENDENTUV);
+    CAP_CASE(VolumeTextureAddressCaps, D3DPTADDRESSCAPS, MIRROR);
+    CAP_CASE(VolumeTextureAddressCaps, D3DPTADDRESSCAPS, MIRRORONCE);
+    CAP_CASE(VolumeTextureAddressCaps, D3DPTADDRESSCAPS, WRAP);
+
+    C2S("\nLineCaps:");
+    CAP_CASE(LineCaps, D3DLINECAPS, ALPHACMP);
+    CAP_CASE(LineCaps, D3DLINECAPS, ANTIALIAS);
+    CAP_CASE(LineCaps, D3DLINECAPS, BLEND);
+    CAP_CASE(LineCaps, D3DLINECAPS, FOG);
+    CAP_CASE(LineCaps, D3DLINECAPS, TEXTURE);
+    CAP_CASE(LineCaps, D3DLINECAPS, ZTEST);
+
+    C2S("\nMaxTextureWidth: %u", caps->MaxTextureWidth);
+    C2S("\nMaxTextureHeight: %u", caps->MaxTextureHeight);
+    C2S("\nMaxVolumeExtent: %u", caps->MaxVolumeExtent);
+    C2S("\nMaxTextureRepeat: %u", caps->MaxTextureRepeat);
+    C2S("\nMaxTextureAspectRatio: %u", caps->MaxTextureAspectRatio);
+    C2S("\nMaxAnisotropy: %u", caps->MaxAnisotropy);
+    C2S("\nMaxVertexW: %f", caps->MaxVertexW);
+
+    C2S("\nGuardBandLef,Top,Right,Bottom: %f %f %f %f",
+        caps->GuardBandLeft, caps->GuardBandTop,
+        caps->GuardBandRight, caps->GuardBandBottom);
+
+    C2S("\nExtentsAdjust: %f", caps->ExtentsAdjust);
+
+    C2S("\nStencilCaps:");
+    CAP_CASE(StencilCaps, D3DSTENCILCAPS, KEEP);
+    CAP_CASE(StencilCaps, D3DSTENCILCAPS, ZERO);
+    CAP_CASE(StencilCaps, D3DSTENCILCAPS, REPLACE);
+    CAP_CASE(StencilCaps, D3DSTENCILCAPS, INCRSAT);
+    CAP_CASE(StencilCaps, D3DSTENCILCAPS, DECRSAT);
+    CAP_CASE(StencilCaps, D3DSTENCILCAPS, INVERT);
+    CAP_CASE(StencilCaps, D3DSTENCILCAPS, INCR);
+    CAP_CASE(StencilCaps, D3DSTENCILCAPS, DECR);
+    CAP_CASE(StencilCaps, D3DSTENCILCAPS, TWOSIDED);
+
+    C2S("\nFVFCaps:");
+    CAP_CASE(FVFCaps, D3DFVFCAPS, DONOTSTRIPELEMENTS);
+    CAP_CASE(FVFCaps, D3DFVFCAPS, PSIZE);
+    CAP_CASE(FVFCaps, D3DFVFCAPS, TEXCOORDCOUNTMASK);
+
+    C2S("\nTextureOpCaps:");
+    CAP_CASE(TextureOpCaps, D3DTEXOPCAPS, ADD);
+    CAP_CASE(TextureOpCaps, D3DTEXOPCAPS, ADDSIGNED);
+    C2S(" ...");
+
+    C2S("\nMaxTextureBlendStages: %u", caps->MaxTextureBlendStages);
+    C2S("\nMaxSimultaneousTextures: %u", caps->MaxTextureBlendStages);
+
+    C2S("\nVertexProcessingCaps:");
+    CAP_CASE(VertexProcessingCaps, D3DVTXPCAPS, DIRECTIONALLIGHTS);
+    CAP_CASE(VertexProcessingCaps, D3DVTXPCAPS, LOCALVIEWER);
+    CAP_CASE(VertexProcessingCaps, D3DVTXPCAPS, MATERIALSOURCE7);
+    CAP_CASE(VertexProcessingCaps, D3DVTXPCAPS, NO_TEXGEN_NONLOCALVIEWER);
+    CAP_CASE(VertexProcessingCaps, D3DVTXPCAPS, POSITIONALLIGHTS);
+    CAP_CASE(VertexProcessingCaps, D3DVTXPCAPS, TEXGEN);
+    CAP_CASE(VertexProcessingCaps, D3DVTXPCAPS, TEXGEN_SPHEREMAP);
+    CAP_CASE(VertexProcessingCaps, D3DVTXPCAPS, TWEENING);
+
+    C2S("\nMaxActiveLights: %u", caps->MaxActiveLights);
+    C2S("\nMaxUserClipPlanes: %u", caps->MaxUserClipPlanes);
+    C2S("\nMaxVertexBlendMatrices: %u", caps->MaxVertexBlendMatrices);
+    C2S("\nMaxVertexBlendMatrixIndex: %u", caps->MaxVertexBlendMatrixIndex);
+    C2S("\nMaxPointSize: %f", caps->MaxPointSize);
+    C2S("\nMaxPrimitiveCount: 0x%x", caps->MaxPrimitiveCount);
+    C2S("\nMaxVertexIndex: 0x%x", caps->MaxVertexIndex);
+    C2S("\nMaxStreams: %u", caps->MaxStreams);
+    C2S("\nMaxStreamStride: 0x%x", caps->MaxStreamStride);
+
+    C2S("\nVertexShaderVersion: %08x", caps->VertexShaderVersion);
+    C2S("\nMaxVertexShaderConst: %u", caps->MaxVertexShaderConst);
+    C2S("\nPixelShaderVersion: %08x", caps->PixelShaderVersion);
+    C2S("\nPixelShader1xMaxValue: %f", caps->PixelShader1xMaxValue);
+
+    DBG_FLAG(ch, "D3DCAPS9(%p) part 1:\n%s\n", caps, s);
+    p = 0;
+
+    C2S("DevCaps2:");
+    CAP_CASE(DevCaps2, D3DDEVCAPS2, ADAPTIVETESSRTPATCH);
+    CAP_CASE(DevCaps2, D3DDEVCAPS2, ADAPTIVETESSNPATCH);
+    CAP_CASE(DevCaps2, D3DDEVCAPS2, CAN_STRETCHRECT_FROM_TEXTURES);
+    CAP_CASE(DevCaps2, D3DDEVCAPS2, DMAPNPATCH);
+    CAP_CASE(DevCaps2, D3DDEVCAPS2, PRESAMPLEDDMAPNPATCH);
+    CAP_CASE(DevCaps2, D3DDEVCAPS2, STREAMOFFSET);
+    CAP_CASE(DevCaps2, D3DDEVCAPS2, VERTEXELEMENTSCANSHARESTREAMOFFSET);
+
+    C2S("\nMasterAdapterOrdinal: %u", caps->MasterAdapterOrdinal);
+    C2S("\nAdapterOrdinalInGroup: %u", caps->AdapterOrdinalInGroup);
+    C2S("\nNumberOfAdaptersInGroup: %u", caps->NumberOfAdaptersInGroup);
+
+    C2S("\nDeclTypes:");
+    CAP_CASE(DeclTypes, D3DDTCAPS, UBYTE4);
+    CAP_CASE(DeclTypes, D3DDTCAPS, UBYTE4N);
+    CAP_CASE(DeclTypes, D3DDTCAPS, SHORT2N);
+    CAP_CASE(DeclTypes, D3DDTCAPS, SHORT4N);
+    CAP_CASE(DeclTypes, D3DDTCAPS, USHORT2N);
+    CAP_CASE(DeclTypes, D3DDTCAPS, USHORT4N);
+    CAP_CASE(DeclTypes, D3DDTCAPS, UDEC3);
+    CAP_CASE(DeclTypes, D3DDTCAPS, DEC3N);
+    CAP_CASE(DeclTypes, D3DDTCAPS, FLOAT16_2);
+    CAP_CASE(DeclTypes, D3DDTCAPS, FLOAT16_4);
+
+    C2S("\nNumSimultaneousRTs: %u", caps->NumSimultaneousRTs);
+
+    C2S("\nStretchRectFilterCaps:");
+    CAP_CASE(StretchRectFilterCaps, D3DPTFILTERCAPS, MINFPOINT);
+    CAP_CASE(StretchRectFilterCaps, D3DPTFILTERCAPS, MINFLINEAR);
+    CAP_CASE(StretchRectFilterCaps, D3DPTFILTERCAPS, MAGFPOINT);
+    CAP_CASE(StretchRectFilterCaps, D3DPTFILTERCAPS, MAGFLINEAR);
+
+    C2S("\nVS20Caps.Caps: Predication=%s", caps->VS20Caps.Caps ? "yes" : "no");
+    C2S("\nVS20Caps.DynamicFlowControlDepth: %u", caps->VS20Caps.DynamicFlowControlDepth);
+    C2S("\nVS20Caps.NumTemps: %u", caps->VS20Caps.NumTemps);
+    C2S("\nVS20Caps.StaticFlowControlDepth: %u", caps->VS20Caps.StaticFlowControlDepth);
+
+    C2S("\nPS20Caps.Caps: Predication=%s", caps->VS20Caps.Caps ? "yes" : "no");
+    C2S("\nPS20Caps.DynamicFlowControlDepth: %u", caps->PS20Caps.DynamicFlowControlDepth);
+    C2S("\nPS20Caps.NumTemps: %u", caps->PS20Caps.NumTemps);
+    C2S("\nPS20Caps.StaticFlowControlDepth: %u", caps->PS20Caps.StaticFlowControlDepth);
+    C2S("\nPS20Caps.NumInstructionSlots: %u", caps->PS20Caps.NumInstructionSlots);
+
+    C2S("\nVertexTextureFilterCaps");
+ /* CAP_CASE(VertexTextureFilterCaps, D3DPTFILTERCAPS, CONVOLUTIONMONO); */
+    CAP_CASE(VertexTextureFilterCaps, D3DPTFILTERCAPS, MAGFPOINT);
+    CAP_CASE(VertexTextureFilterCaps, D3DPTFILTERCAPS, MAGFLINEAR);
+    CAP_CASE(VertexTextureFilterCaps, D3DPTFILTERCAPS, MAGFANISOTROPIC);
+    CAP_CASE(VertexTextureFilterCaps, D3DPTFILTERCAPS, MAGFPYRAMIDALQUAD);
+    CAP_CASE(VertexTextureFilterCaps, D3DPTFILTERCAPS, MAGFGAUSSIANQUAD);
+    CAP_CASE(VertexTextureFilterCaps, D3DPTFILTERCAPS, MINFPOINT);
+    CAP_CASE(VertexTextureFilterCaps, D3DPTFILTERCAPS, MINFLINEAR);
+    CAP_CASE(VertexTextureFilterCaps, D3DPTFILTERCAPS, MINFANISOTROPIC);
+    CAP_CASE(VertexTextureFilterCaps, D3DPTFILTERCAPS, MINFPYRAMIDALQUAD);
+    CAP_CASE(VertexTextureFilterCaps, D3DPTFILTERCAPS, MINFGAUSSIANQUAD);
+    CAP_CASE(VertexTextureFilterCaps, D3DPTFILTERCAPS, MIPFPOINT);
+    CAP_CASE(VertexTextureFilterCaps, D3DPTFILTERCAPS, MIPFLINEAR);
+
+    C2S("\nMaxVShaderInstructionsExecuted: %u", caps->MaxVShaderInstructionsExecuted);
+    C2S("\nMaxPShaderInstructionsExecuted: %u", caps->MaxPShaderInstructionsExecuted);
+    C2S("\nMaxVertexShader30InstructionSlots: %u >= 512", caps->MaxVertexShader30InstructionSlots);
+    C2S("\nMaxPixelShader30InstructionSlots: %u >= 512", caps->MaxPixelShader30InstructionSlots);
+
+    DBG_FLAG(ch, "D3DCAPS9(%p) part 2:\n%s\n", caps, s);
+
+    FREE(s);
+}
+
+#endif /* DEBUG */
diff --git a/src/gallium/state_trackers/nine/nine_dump.h b/src/gallium/state_trackers/nine/nine_dump.h
new file mode 100644 (file)
index 0000000..d0d4a9e
--- /dev/null
@@ -0,0 +1,52 @@
+
+#ifndef _NINE_DUMP_H_
+#define _NINE_DUMP_H_
+
+#include "d3d9types.h"
+#include "d3d9caps.h"
+
+const char *nine_D3DDEVTYPE_to_str(D3DDEVTYPE);
+const char *nine_D3DQUERYTYPE_to_str(D3DQUERYTYPE);
+const char *nine_D3DTSS_to_str(D3DTEXTURESTAGESTATETYPE);
+const char *nine_D3DTOP_to_str(D3DTEXTUREOP);
+const char *nine_D3DPOOL_to_str(D3DPOOL);
+const char *nine_D3DRTYPE_to_str(D3DRESOURCETYPE);
+const char *nine_D3DUSAGE_to_str(DWORD);
+const char *nine_D3DPRESENTFLAG_to_str(DWORD);
+const char *nine_D3DLOCK_to_str(DWORD);
+const char *nine_D3DSAMP_to_str(DWORD);
+
+#ifdef DEBUG
+
+void
+nine_dump_D3DADAPTER_IDENTIFIER9(unsigned, const D3DADAPTER_IDENTIFIER9 *);
+void
+nine_dump_D3DCAPS9(unsigned, const D3DCAPS9 *);
+void
+nine_dump_D3DLIGHT9(unsigned, const D3DLIGHT9 *);
+void
+nine_dump_D3DMATERIAL9(unsigned, const D3DMATERIAL9 *);
+void
+nine_dump_D3DTSS_value(unsigned, D3DTEXTURESTAGESTATETYPE, DWORD);
+
+#else /* !DEBUG */
+
+static INLINE void
+nine_dump_D3DADAPTER_IDENTIFIER9(unsigned ch, const D3DADAPTER_IDENTIFIER9 *id)
+{ }
+static INLINE void
+nine_dump_D3DCAPS9(unsigned ch, const D3DCAPS9 *caps)
+{ }
+static INLINE void
+nine_dump_D3DLIGHT9(unsigned ch, const D3DLIGHT9 *light)
+{ }
+static INLINE void
+nine_dump_D3DMATERIAL9(unsigned ch, const D3DMATERIAL9 *mat)
+{ }
+static INLINE void
+nine_dump_D3DTSS_value(unsigned ch, D3DTEXTURESTAGESTATETYPE tss, DWORD value)
+{ }
+
+#endif /* DEBUG */
+
+#endif /* _NINE_DUMP_H_H_ */
diff --git a/src/gallium/state_trackers/nine/nine_ff.c b/src/gallium/state_trackers/nine/nine_ff.c
new file mode 100644 (file)
index 0000000..6890933
--- /dev/null
@@ -0,0 +1,2257 @@
+
+/* FF is big and ugly so feel free to write lines as long as you like.
+ * Aieeeeeeeee !
+ *
+ * Let me make that clearer:
+ * Aieeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee ! !! !!!
+ */
+
+#include "device9.h"
+#include "basetexture9.h"
+#include "vertexdeclaration9.h"
+#include "vertexshader9.h"
+#include "pixelshader9.h"
+#include "nine_ff.h"
+#include "nine_defines.h"
+#include "nine_helpers.h"
+#include "nine_pipe.h"
+#include "nine_dump.h"
+
+#include "pipe/p_context.h"
+#include "tgsi/tgsi_ureg.h"
+#include "tgsi/tgsi_dump.h"
+#include "util/u_box.h"
+#include "util/u_hash_table.h"
+
+#define NINE_TGSI_LAZY_DEVS 1
+
+#define DBG_CHANNEL DBG_FF
+
+#define NINE_FF_NUM_VS_CONST 256
+#define NINE_FF_NUM_PS_CONST 24
+
+#define NINED3DTSS_TCI_DISABLE                       0
+#define NINED3DTSS_TCI_PASSTHRU                      1
+#define NINED3DTSS_TCI_CAMERASPACENORMAL             2
+#define NINED3DTSS_TCI_CAMERASPACEPOSITION           3
+#define NINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR   4
+#define NINED3DTSS_TCI_SPHEREMAP                     5
+
+struct fvec4
+{
+    float x, y, z, w;
+};
+
+struct nine_ff_vs_key
+{
+    union {
+        struct {
+            uint32_t position_t : 1;
+            uint32_t lighting   : 1;
+            uint32_t darkness   : 1; /* lighting enabled but no active lights */
+            uint32_t localviewer : 1;
+            uint32_t vertexpointsize : 1;
+            uint32_t pointscale : 1;
+            uint32_t vertexblend : 3;
+            uint32_t vertexblend_indexed : 1;
+            uint32_t vertextween : 1;
+            uint32_t mtl_diffuse : 2; /* 0 = material, 1 = color1, 2 = color2 */
+            uint32_t mtl_ambient : 2;
+            uint32_t mtl_specular : 2;
+            uint32_t mtl_emissive : 2;
+            uint32_t fog_mode : 2;
+            uint32_t fog_range : 1;
+            uint32_t color0in_one : 1;
+            uint32_t color1in_one : 1;
+            uint32_t pad1 : 8;
+            uint32_t tc_gen : 24; /* 8 * 3 bits */
+            uint32_t pad2 : 8;
+            uint32_t tc_idx : 24;
+            uint32_t pad3 : 8;
+            uint32_t tc_dim : 24; /* 8 * 3 bits */
+            uint32_t pad4 : 8;
+        };
+        uint64_t value64[2]; /* don't forget to resize VertexShader9.ff_key */
+        uint32_t value32[4];
+    };
+};
+
+/* Texture stage state:
+ *
+ * COLOROP       D3DTOP 5 bit
+ * ALPHAOP       D3DTOP 5 bit
+ * COLORARG0     D3DTA  3 bit
+ * COLORARG1     D3DTA  3 bit
+ * COLORARG2     D3DTA  3 bit
+ * ALPHAARG0     D3DTA  3 bit
+ * ALPHAARG1     D3DTA  3 bit
+ * ALPHAARG2     D3DTA  3 bit
+ * RESULTARG     D3DTA  1 bit (CURRENT:0 or TEMP:1)
+ * TEXCOORDINDEX 0 - 7  3 bit
+ * ===========================
+ *                     32 bit per stage
+ */
+struct nine_ff_ps_key
+{
+    union {
+        struct {
+            struct {
+                uint32_t colorop   : 5;
+                uint32_t alphaop   : 5;
+                uint32_t colorarg0 : 3;
+                uint32_t colorarg1 : 3;
+                uint32_t colorarg2 : 3;
+                uint32_t alphaarg0 : 3;
+                uint32_t alphaarg1 : 3;
+                uint32_t alphaarg2 : 3;
+                uint32_t resultarg : 1; /* CURRENT:0 or TEMP:1 */
+                uint32_t textarget : 2; /* 1D/2D/3D/CUBE */
+                uint32_t projected : 1;
+                /* that's 32 bit exactly */
+            } ts[8];
+            uint32_t fog : 1; /* for vFog with programmable VS */
+            uint32_t fog_mode : 2;
+            uint32_t specular : 1; /* 9 32-bit words with this */
+            uint8_t colorarg_b4[3];
+            uint8_t colorarg_b5[3];
+            uint8_t alphaarg_b4[3]; /* 11 32-bit words plus a byte */
+        };
+        uint64_t value64[6]; /* don't forget to resize PixelShader9.ff_key */
+        uint32_t value32[12];
+    };
+};
+
+static unsigned nine_ff_vs_key_hash(void *key)
+{
+    struct nine_ff_vs_key *vs = key;
+    unsigned i;
+    uint32_t hash = vs->value32[0];
+    for (i = 1; i < Elements(vs->value32); ++i)
+        hash ^= vs->value32[i];
+    return hash;
+}
+static int nine_ff_vs_key_comp(void *key1, void *key2)
+{
+    struct nine_ff_vs_key *a = (struct nine_ff_vs_key *)key1;
+    struct nine_ff_vs_key *b = (struct nine_ff_vs_key *)key2;
+
+    return memcmp(a->value64, b->value64, sizeof(a->value64));
+}
+static unsigned nine_ff_ps_key_hash(void *key)
+{
+    struct nine_ff_ps_key *ps = key;
+    unsigned i;
+    uint32_t hash = ps->value32[0];
+    for (i = 1; i < Elements(ps->value32); ++i)
+        hash ^= ps->value32[i];
+    return hash;
+}
+static int nine_ff_ps_key_comp(void *key1, void *key2)
+{
+    struct nine_ff_ps_key *a = (struct nine_ff_ps_key *)key1;
+    struct nine_ff_ps_key *b = (struct nine_ff_ps_key *)key2;
+
+    return memcmp(a->value64, b->value64, sizeof(a->value64));
+}
+static unsigned nine_ff_fvf_key_hash(void *key)
+{
+    return *(DWORD *)key;
+}
+static int nine_ff_fvf_key_comp(void *key1, void *key2)
+{
+    return *(DWORD *)key1 != *(DWORD *)key2;
+}
+
+static void nine_ff_prune_vs(struct NineDevice9 *);
+static void nine_ff_prune_ps(struct NineDevice9 *);
+
+static void nine_ureg_tgsi_dump(struct ureg_program *ureg, boolean override)
+{
+    if (debug_get_bool_option("NINE_FF_DUMP", FALSE) || override) {
+        unsigned count;
+        const struct tgsi_token *toks = ureg_get_tokens(ureg, &count);
+        tgsi_dump(toks, 0);
+        ureg_free_tokens(toks);
+    }
+}
+
+#define _X(r) ureg_scalar(ureg_src(r), TGSI_SWIZZLE_X)
+#define _Y(r) ureg_scalar(ureg_src(r), TGSI_SWIZZLE_Y)
+#define _Z(r) ureg_scalar(ureg_src(r), TGSI_SWIZZLE_Z)
+#define _W(r) ureg_scalar(ureg_src(r), TGSI_SWIZZLE_W)
+
+#define _XXXX(r) ureg_scalar(r, TGSI_SWIZZLE_X)
+#define _YYYY(r) ureg_scalar(r, TGSI_SWIZZLE_Y)
+#define _ZZZZ(r) ureg_scalar(r, TGSI_SWIZZLE_Z)
+#define _WWWW(r) ureg_scalar(r, TGSI_SWIZZLE_W)
+
+#define _XYZW(r) (r)
+
+/* AL should contain base address of lights table. */
+#define LIGHT_CONST(i)                                                \
+    ureg_src_indirect(ureg_src_register(TGSI_FILE_CONSTANT, (i)), _X(AL))
+
+#define MATERIAL_CONST(i) \
+    ureg_src_register(TGSI_FILE_CONSTANT, 19 + (i))
+
+#define MISC_CONST(i) \
+    ureg_src_register(TGSI_FILE_CONSTANT, (i))
+
+#define _CONST(n) ureg_DECL_constant(ureg, n)
+
+/* VS FF constants layout:
+ *
+ * CONST[ 0.. 3] D3DTS_WORLD * D3DTS_VIEW * D3DTS_PROJECTION
+ * CONST[ 4.. 7] D3DTS_WORLD * D3DTS_VIEW
+ * CONST[ 8..11] D3DTS_VIEW * D3DTS_PROJECTION
+ * CONST[12..15] D3DTS_VIEW
+ * CONST[16..18] Normal matrix
+ *
+ * CONST[19]      MATERIAL.Emissive + Material.Ambient * RS.Ambient
+ * CONST[20]      MATERIAL.Diffuse
+ * CONST[21]      MATERIAL.Ambient
+ * CONST[22]      MATERIAL.Specular
+ * CONST[23].x___ MATERIAL.Power
+ * CONST[24]      MATERIAL.Emissive
+ * CONST[25]      RS.Ambient
+ *
+ * CONST[26].x___ RS.PointSizeMin
+ * CONST[26]._y__ RS.PointSizeMax
+ * CONST[26].__z_ RS.PointSize
+ * CONST[26].___w RS.PointScaleA
+ * CONST[27].x___ RS.PointScaleB
+ * CONST[27]._y__ RS.PointScaleC
+ *
+ * CONST[28].x___ RS.FogEnd
+ * CONST[28]._y__ 1.0f / (RS.FogEnd - RS.FogStart)
+ * CONST[28].__z_ RS.FogDensity
+ * CONST[29]      RS.FogColor
+
+ * CONST[30].x___ TWEENFACTOR
+ *
+ * CONST[32].x___ LIGHT[0].Type
+ * CONST[32]._yzw LIGHT[0].Attenuation0,1,2
+ * CONST[33]      LIGHT[0].Diffuse
+ * CONST[34]      LIGHT[0].Specular
+ * CONST[35]      LIGHT[0].Ambient
+ * CONST[36].xyz_ LIGHT[0].Position
+ * CONST[36].___w LIGHT[0].Range
+ * CONST[37].xyz_ LIGHT[0].Direction
+ * CONST[37].___w LIGHT[0].Falloff
+ * CONST[38].x___ cos(LIGHT[0].Theta / 2)
+ * CONST[38]._y__ cos(LIGHT[0].Phi / 2)
+ * CONST[38].__z_ 1.0f / (cos(LIGHT[0].Theta / 2) - cos(Light[0].Phi / 2))
+ * CONST[39].xyz_ LIGHT[0].HalfVector (for directional lights)
+ * CONST[39].___w 1 if this is the last active light, 0 if not
+ * CONST[40]      LIGHT[1]
+ * CONST[48]      LIGHT[2]
+ * CONST[56]      LIGHT[3]
+ * CONST[64]      LIGHT[4]
+ * CONST[72]      LIGHT[5]
+ * CONST[80]      LIGHT[6]
+ * CONST[88]      LIGHT[7]
+ * NOTE: no lighting code is generated if there are no active lights
+ *
+ * CONST[100].x___ Viewport 2/width
+ * CONST[100]._y__ Viewport 2/height
+ * CONST[100].__z_ Viewport 1/(zmax - zmin)
+ * CONST[101].x___ Viewport x0
+ * CONST[101]._y__ Viewport y0
+ * CONST[101].__z_ Viewport z0
+ *
+ * CONST[128..131] D3DTS_TEXTURE0
+ * CONST[132..135] D3DTS_TEXTURE1
+ * CONST[136..139] D3DTS_TEXTURE2
+ * CONST[140..143] D3DTS_TEXTURE3
+ * CONST[144..147] D3DTS_TEXTURE4
+ * CONST[148..151] D3DTS_TEXTURE5
+ * CONST[152..155] D3DTS_TEXTURE6
+ * CONST[156..159] D3DTS_TEXTURE7
+ *
+ * CONST[224] D3DTS_WORLDMATRIX[0]
+ * CONST[228] D3DTS_WORLDMATRIX[1]
+ * ...
+ * CONST[252] D3DTS_WORLDMATRIX[7]
+ */
+struct vs_build_ctx
+{
+    struct ureg_program *ureg;
+    const struct nine_ff_vs_key *key;
+
+    unsigned input[PIPE_MAX_ATTRIBS];
+    unsigned num_inputs;
+
+    struct ureg_src aVtx;
+    struct ureg_src aNrm;
+    struct ureg_src aCol[2];
+    struct ureg_src aTex[8];
+    struct ureg_src aPsz;
+    struct ureg_src aInd;
+    struct ureg_src aWgt;
+
+    struct ureg_src aVtx1; /* tweening */
+    struct ureg_src aNrm1;
+
+    struct ureg_src mtlA;
+    struct ureg_src mtlD;
+    struct ureg_src mtlS;
+    struct ureg_src mtlE;
+};
+
+static INLINE unsigned
+get_texcoord_sn(struct pipe_screen *screen)
+{
+    if (screen->get_param(screen, PIPE_CAP_TGSI_TEXCOORD))
+        return TGSI_SEMANTIC_TEXCOORD;
+    return TGSI_SEMANTIC_GENERIC;
+}
+
+static INLINE struct ureg_src
+build_vs_add_input(struct vs_build_ctx *vs, unsigned ndecl)
+{
+    const unsigned i = vs->num_inputs++;
+    assert(i < PIPE_MAX_ATTRIBS);
+    vs->input[i] = ndecl;
+    return ureg_DECL_vs_input(vs->ureg, i);
+}
+
+/* NOTE: dst may alias src */
+static INLINE void
+ureg_normalize3(struct ureg_program *ureg,
+                struct ureg_dst dst, struct ureg_src src,
+                struct ureg_dst tmp)
+{
+#ifdef NINE_TGSI_LAZY_DEVS
+    struct ureg_dst tmp_x = ureg_writemask(tmp, TGSI_WRITEMASK_X);
+
+    ureg_DP3(ureg, tmp_x, src, src);
+    ureg_RSQ(ureg, tmp_x, _X(tmp));
+    ureg_MUL(ureg, dst, src, _X(tmp));
+#else
+    ureg_NRM(ureg, dst, src);
+#endif
+}
+
+static void *
+nine_ff_build_vs(struct NineDevice9 *device, struct vs_build_ctx *vs)
+{
+    const struct nine_ff_vs_key *key = vs->key;
+    struct ureg_program *ureg = ureg_create(TGSI_PROCESSOR_VERTEX);
+    struct ureg_dst oPos, oCol[2], oTex[8], oPsz, oFog;
+    struct ureg_dst rCol[2]; /* oCol if no fog, TEMP otherwise */
+    struct ureg_dst rVtx, rNrm;
+    struct ureg_dst r[8];
+    struct ureg_dst AR;
+    struct ureg_dst tmp, tmp_x, tmp_z;
+    unsigned i, c;
+    unsigned label[32], l = 0;
+    unsigned num_r = 8;
+    boolean need_rNrm = key->lighting || key->pointscale;
+    boolean need_rVtx = key->lighting || key->fog_mode;
+    const unsigned texcoord_sn = get_texcoord_sn(device->screen);
+
+    vs->ureg = ureg;
+
+    /* Check which inputs we should transform. */
+    for (i = 0; i < 8 * 3; i += 3) {
+        switch ((key->tc_gen >> i) & 0x3) {
+        case NINED3DTSS_TCI_CAMERASPACENORMAL:
+            need_rNrm = TRUE;
+            break;
+        case NINED3DTSS_TCI_CAMERASPACEPOSITION:
+            need_rVtx = TRUE;
+            break;
+        case NINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
+            need_rVtx = need_rNrm = TRUE;
+            break;
+        default:
+            break;
+        }
+    }
+
+    /* Declare and record used inputs (needed for linkage with vertex format):
+     * (texture coordinates handled later)
+     */
+    vs->aVtx = build_vs_add_input(vs,
+        key->position_t ? NINE_DECLUSAGE_POSITIONT : NINE_DECLUSAGE_POSITION(0));
+
+    if (need_rNrm)
+        vs->aNrm = build_vs_add_input(vs, NINE_DECLUSAGE_NORMAL(0));
+
+    vs->aCol[0] = ureg_imm1f(ureg, 1.0f);
+    vs->aCol[1] = ureg_imm1f(ureg, 1.0f);
+
+    if (key->lighting || key->darkness) {
+        const unsigned mask = key->mtl_diffuse | key->mtl_specular |
+                              key->mtl_ambient | key->mtl_emissive;
+        if ((mask & 0x1) && !key->color0in_one)
+            vs->aCol[0] = build_vs_add_input(vs, NINE_DECLUSAGE_COLOR(0));
+        if ((mask & 0x2) && !key->color1in_one)
+            vs->aCol[1] = build_vs_add_input(vs, NINE_DECLUSAGE_COLOR(1));
+
+        vs->mtlD = MATERIAL_CONST(1);
+        vs->mtlA = MATERIAL_CONST(2);
+        vs->mtlS = MATERIAL_CONST(3);
+        vs->mtlE = MATERIAL_CONST(5);
+        if (key->mtl_diffuse  == 1) vs->mtlD = vs->aCol[0]; else
+        if (key->mtl_diffuse  == 2) vs->mtlD = vs->aCol[1];
+        if (key->mtl_ambient  == 1) vs->mtlA = vs->aCol[0]; else
+        if (key->mtl_ambient  == 2) vs->mtlA = vs->aCol[1];
+        if (key->mtl_specular == 1) vs->mtlS = vs->aCol[0]; else
+        if (key->mtl_specular == 2) vs->mtlS = vs->aCol[1];
+        if (key->mtl_emissive == 1) vs->mtlE = vs->aCol[0]; else
+        if (key->mtl_emissive == 2) vs->mtlE = vs->aCol[1];
+    } else {
+        if (!key->color0in_one) vs->aCol[0] = build_vs_add_input(vs, NINE_DECLUSAGE_COLOR(0));
+        if (!key->color1in_one) vs->aCol[1] = build_vs_add_input(vs, NINE_DECLUSAGE_COLOR(1));
+    }
+
+    if (key->vertexpointsize)
+        vs->aPsz = build_vs_add_input(vs, NINE_DECLUSAGE_PSIZE);
+
+    if (key->vertexblend_indexed)
+        vs->aInd = build_vs_add_input(vs, NINE_DECLUSAGE_BLENDINDICES(0));
+    if (key->vertexblend)
+        vs->aWgt = build_vs_add_input(vs, NINE_DECLUSAGE_BLENDWEIGHT(0));
+    if (key->vertextween) {
+        vs->aVtx1 = build_vs_add_input(vs, NINE_DECLUSAGE_POSITION(1));
+        vs->aNrm1 = build_vs_add_input(vs, NINE_DECLUSAGE_NORMAL(1));
+    }
+
+    /* Declare outputs:
+     */
+    oPos = ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 0); /* HPOS */
+    oCol[0] = ureg_saturate(ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0));
+    oCol[1] = ureg_saturate(ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 1));
+
+    if (key->vertexpointsize || key->pointscale) {
+        oPsz = ureg_DECL_output_masked(ureg, TGSI_SEMANTIC_PSIZE, 0, TGSI_WRITEMASK_X);
+        oPsz = ureg_writemask(oPsz, TGSI_WRITEMASK_X);
+    }
+    if (key->fog_mode) {
+        /* We apply fog to the vertex colors, oFog is for programmable shaders only ?
+         */
+        oFog = ureg_DECL_output_masked(ureg, TGSI_SEMANTIC_FOG, 0, TGSI_WRITEMASK_X);
+        oFog = ureg_writemask(oFog, TGSI_WRITEMASK_X);
+    }
+
+    /* Declare TEMPs:
+     */
+    for (i = 0; i < num_r; ++i)
+        r[i] = ureg_DECL_local_temporary(ureg);
+    tmp = r[0];
+    tmp_x = ureg_writemask(tmp, TGSI_WRITEMASK_X);
+    tmp_z = ureg_writemask(tmp, TGSI_WRITEMASK_Z);
+    if (key->lighting || key->vertexblend)
+        AR = ureg_DECL_address(ureg);
+
+    if (key->fog_mode) {
+        rCol[0] = r[2];
+        rCol[1] = r[3];
+    } else {
+        rCol[0] = oCol[0];
+        rCol[1] = oCol[1];
+    }
+
+    rVtx = ureg_writemask(r[1], TGSI_WRITEMASK_XYZ);
+    rNrm = ureg_writemask(r[2], TGSI_WRITEMASK_XYZ);
+
+    /* === Vertex transformation / vertex blending:
+     */
+    if (key->vertextween) {
+        assert(!key->vertexblend);
+        ureg_LRP(ureg, r[2], _XXXX(_CONST(30)), vs->aVtx, vs->aVtx1);
+        if (need_rNrm)
+            ureg_LRP(ureg, r[3], _XXXX(_CONST(30)), vs->aNrm, vs->aNrm1);
+        vs->aVtx = ureg_src(r[2]);
+        vs->aNrm = ureg_src(r[3]);
+    }
+
+    if (key->vertexblend) {
+        struct ureg_src cWM[4];
+
+        for (i = 224; i <= 255; ++i)
+            ureg_DECL_constant(ureg, i);
+
+        /* translate world matrix index to constant file index */
+        if (key->vertexblend_indexed) {
+            ureg_MAD(ureg, tmp, vs->aInd, ureg_imm1f(ureg, 4.0f), ureg_imm1f(ureg, 224.0f));
+            ureg_ARL(ureg, AR, ureg_src(tmp));
+        }
+        for (i = 0; i < key->vertexblend; ++i) {
+            for (c = 0; c < 4; ++c) {
+                cWM[c] = ureg_src_register(TGSI_FILE_CONSTANT, (224 + i * 4) * !key->vertexblend_indexed + c);
+                if (key->vertexblend_indexed)
+                    cWM[c] = ureg_src_indirect(cWM[c], ureg_scalar(ureg_src(AR), i));
+            }
+            /* multiply by WORLD(index) */
+            ureg_MUL(ureg, r[0], _XXXX(vs->aVtx), cWM[0]);
+            ureg_MAD(ureg, r[0], _YYYY(vs->aVtx), cWM[1], ureg_src(r[0]));
+            ureg_MAD(ureg, r[0], _ZZZZ(vs->aVtx), cWM[2], ureg_src(r[0]));
+            ureg_MAD(ureg, r[0], _WWWW(vs->aVtx), cWM[3], ureg_src(r[0]));
+
+            /* accumulate weighted position value */
+            if (i)
+                ureg_MAD(ureg, r[2], ureg_src(r[0]), ureg_scalar(vs->aWgt, i), ureg_src(r[2]));
+            else
+                ureg_MUL(ureg, r[2], ureg_src(r[0]), ureg_scalar(vs->aWgt, 0));
+        }
+        /* multiply by VIEW_PROJ */
+        ureg_MUL(ureg, r[0], _X(r[2]), _CONST(8));
+        ureg_MAD(ureg, r[0], _Y(r[2]), _CONST(9),  ureg_src(r[0]));
+        ureg_MAD(ureg, r[0], _Z(r[2]), _CONST(10), ureg_src(r[0]));
+        ureg_MAD(ureg, oPos, _W(r[2]), _CONST(11), ureg_src(r[0]));
+
+        if (need_rVtx)
+            vs->aVtx = ureg_src(r[2]);
+    } else
+    if (key->position_t && device->driver_caps.window_space_position_support) {
+        ureg_MOV(ureg, oPos, vs->aVtx);
+    } else if (key->position_t) {
+        /* vs->aVtx contains the coordinates buffer wise.
+        * later in the pipeline, clipping, viewport and division
+        * by w (rhw = 1/w) are going to be applied, so do the reverse
+        * of these transformations (except clipping) to have the good
+        * position at the end.*/
+        ureg_MOV(ureg, tmp, vs->aVtx);
+        /* X from [X_min, X_min + width] to [-1, 1], same for Y. Z to [0, 1] */
+        ureg_SUB(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_XYZ), ureg_src(tmp), _CONST(101));
+        ureg_MUL(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_XYZ), ureg_src(tmp), _CONST(100));
+        ureg_SUB(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_XY), ureg_src(tmp), ureg_imm1f(ureg, 1.0f));
+        /* Y needs to be reversed */
+        ureg_MOV(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_Y), ureg_negate(ureg_src(tmp)));
+        /* inverse rhw */
+        ureg_RCP(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_W), _W(tmp));
+        /* multiply X, Y, Z by w */
+        ureg_MUL(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_XYZ), ureg_src(tmp), _W(tmp));
+        ureg_MOV(ureg, oPos, ureg_src(tmp));
+    } else {
+        /* position = vertex * WORLD_VIEW_PROJ */
+        ureg_MUL(ureg, r[0], _XXXX(vs->aVtx), _CONST(0));
+        ureg_MAD(ureg, r[0], _YYYY(vs->aVtx), _CONST(1), ureg_src(r[0]));
+        ureg_MAD(ureg, r[0], _ZZZZ(vs->aVtx), _CONST(2), ureg_src(r[0]));
+        ureg_MAD(ureg, oPos, _WWWW(vs->aVtx), _CONST(3), ureg_src(r[0]));
+    }
+
+    if (need_rVtx) {
+        ureg_MUL(ureg, rVtx, _XXXX(vs->aVtx), _CONST(4));
+        ureg_MAD(ureg, rVtx, _YYYY(vs->aVtx), _CONST(5), ureg_src(rVtx));
+        ureg_MAD(ureg, rVtx, _ZZZZ(vs->aVtx), _CONST(6), ureg_src(rVtx));
+        ureg_MAD(ureg, rVtx, _WWWW(vs->aVtx), _CONST(7), ureg_src(rVtx));
+    }
+    if (need_rNrm) {
+        ureg_MUL(ureg, rNrm, _XXXX(vs->aNrm), _CONST(16));
+        ureg_MAD(ureg, rNrm, _YYYY(vs->aNrm), _CONST(17), ureg_src(rNrm));
+        ureg_MAD(ureg, rNrm, _ZZZZ(vs->aNrm), _CONST(18), ureg_src(rNrm));
+        ureg_normalize3(ureg, rNrm, ureg_src(rNrm), tmp);
+    }
+    /* NOTE: don't use vs->aVtx, vs->aNrm after this line */
+
+    /* === Process point size:
+     */
+    if (key->vertexpointsize) {
+        struct ureg_src cPsz1 = ureg_DECL_constant(ureg, 26);
+#ifdef NINE_TGSI_LAZY_DEVS
+        struct ureg_dst tmp_clamp = ureg_DECL_temporary(ureg);
+
+        ureg_MAX(ureg, tmp_clamp, vs->aPsz, _XXXX(cPsz1));
+        ureg_MIN(ureg, oPsz, ureg_src(tmp_clamp), _YYYY(cPsz1));
+        ureg_release_temporary(ureg, tmp_clamp);
+#else
+        ureg_CLAMP(ureg, oPsz, vs->aPsz, _XXXX(cPsz1), _YYYY(cPsz1));
+#endif
+    } else if (key->pointscale) {
+        struct ureg_dst tmp_x = ureg_writemask(tmp, TGSI_WRITEMASK_X);
+        struct ureg_dst tmp_y = ureg_writemask(tmp, TGSI_WRITEMASK_Y);
+        struct ureg_src cPsz1 = ureg_DECL_constant(ureg, 26);
+        struct ureg_src cPsz2 = ureg_DECL_constant(ureg, 27);
+
+        ureg_DP3(ureg, tmp_x, ureg_src(r[1]), ureg_src(r[1]));
+        ureg_SQRT(ureg, tmp_y, _X(tmp));
+        ureg_MAD(ureg, tmp_x, _Y(tmp), _YYYY(cPsz2), _XXXX(cPsz2));
+        ureg_MAD(ureg, tmp_x, _Y(tmp), _X(tmp), _WWWW(cPsz1));
+        ureg_RCP(ureg, tmp_x, ureg_src(tmp));
+        ureg_MUL(ureg, tmp_x, ureg_src(tmp), _ZZZZ(cPsz1));
+#ifdef NINE_TGSI_LAZY_DEVS
+        struct ureg_dst tmp_clamp = ureg_DECL_temporary(ureg);
+
+        ureg_MAX(ureg, tmp_clamp, _X(tmp), _XXXX(cPsz1));
+        ureg_MIN(ureg, oPsz, ureg_src(tmp_clamp), _YYYY(cPsz1));
+        ureg_release_temporary(ureg, tmp_clamp);
+#else
+        ureg_CLAMP(ureg, oPsz, _X(tmp), _XXXX(cPsz1), _YYYY(cPsz1));
+#endif
+    }
+
+    /* Texture coordinate generation:
+     * XXX: D3DTTFF_PROJECTED, transform matrix
+     */
+    for (i = 0; i < 8; ++i) {
+        struct ureg_dst dst[5];
+        struct ureg_src src;
+        unsigned c;
+        const unsigned tci = (key->tc_gen >> (i * 3)) & 0x7;
+        const unsigned idx = (key->tc_idx >> (i * 3)) & 0x7;
+        const unsigned dim = (key->tc_dim >> (i * 3)) & 0x7;
+
+        if (tci == NINED3DTSS_TCI_DISABLE)
+            continue;
+        oTex[i] = ureg_DECL_output(ureg, texcoord_sn, i);
+
+        if (tci == NINED3DTSS_TCI_PASSTHRU)
+            vs->aTex[idx] = build_vs_add_input(vs, NINE_DECLUSAGE_TEXCOORD(idx));
+
+        if (!dim) {
+            dst[c = 4] = oTex[i];
+        } else {
+            dst[4] = r[5];
+            src = ureg_src(dst[4]);
+            for (c = 0; c < (dim - 1); ++c)
+                dst[c] = ureg_writemask(tmp, (1 << dim) - 1);
+            dst[c] = ureg_writemask(oTex[i], (1 << dim) - 1);
+        }
+
+        switch (tci) {
+        case NINED3DTSS_TCI_PASSTHRU:
+            ureg_MOV(ureg, dst[4], vs->aTex[idx]);
+            break;
+        case NINED3DTSS_TCI_CAMERASPACENORMAL:
+            assert(dim <= 3);
+            ureg_MOV(ureg, ureg_writemask(dst[4], TGSI_WRITEMASK_XYZ), ureg_src(rNrm));
+            ureg_MOV(ureg, ureg_writemask(dst[4], TGSI_WRITEMASK_W), ureg_imm1f(ureg, 1.0f));
+            break;
+        case NINED3DTSS_TCI_CAMERASPACEPOSITION:
+            ureg_MOV(ureg, ureg_writemask(dst[4], TGSI_WRITEMASK_XYZ), ureg_src(rVtx));
+            ureg_MOV(ureg, ureg_writemask(dst[4], TGSI_WRITEMASK_W), ureg_imm1f(ureg, 1.0f));
+            break;
+        case NINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
+            tmp.WriteMask = TGSI_WRITEMASK_XYZ;
+            ureg_DP3(ureg, tmp_x, ureg_src(rVtx), ureg_src(rNrm));
+            ureg_MUL(ureg, tmp, ureg_src(rNrm), _X(tmp));
+            ureg_ADD(ureg, tmp, ureg_src(tmp), ureg_src(tmp));
+            ureg_SUB(ureg, ureg_writemask(dst[4], TGSI_WRITEMASK_XYZ), ureg_src(rVtx), ureg_src(tmp));
+            ureg_MOV(ureg, ureg_writemask(dst[4], TGSI_WRITEMASK_W), ureg_imm1f(ureg, 1.0f));
+            tmp.WriteMask = TGSI_WRITEMASK_XYZW;
+            break;
+        case NINED3DTSS_TCI_SPHEREMAP:
+            assert(!"TODO");
+            break;
+        default:
+            break;
+        }
+        if (!dim)
+            continue;
+        dst[c].WriteMask = ~dst[c].WriteMask;
+        if (dst[c].WriteMask)
+            ureg_MOV(ureg, dst[c], src); /* store untransformed components */
+        dst[c].WriteMask = ~dst[c].WriteMask;
+        if (dim > 0) ureg_MUL(ureg, dst[0], _XXXX(src), _CONST(128 + i * 4));
+        if (dim > 1) ureg_MAD(ureg, dst[1], _YYYY(src), _CONST(129 + i * 4), ureg_src(tmp));
+        if (dim > 2) ureg_MAD(ureg, dst[2], _ZZZZ(src), _CONST(130 + i * 4), ureg_src(tmp));
+        if (dim > 3) ureg_MAD(ureg, dst[3], _WWWW(src), _CONST(131 + i * 4), ureg_src(tmp));
+    }
+
+    /* === Lighting:
+     *
+     * DIRECTIONAL:  Light at infinite distance, parallel rays, no attenuation.
+     * POINT: Finite distance to scene, divergent rays, isotropic, attenuation.
+     * SPOT: Finite distance, divergent rays, angular dependence, attenuation.
+     *
+     * vec3 normal = normalize(in.Normal * NormalMatrix);
+     * vec3 hitDir = light.direction;
+     * float atten = 1.0;
+     *
+     * if (light.type != DIRECTIONAL)
+     * {
+     *     vec3 hitVec = light.position - eyeVertex;
+     *     float d = length(hitVec);
+     *     hitDir = hitVec / d;
+     *     atten = 1 / ((light.atten2 * d + light.atten1) * d + light.atten0);
+     * }
+     *
+     * if (light.type == SPOTLIGHT)
+     * {
+     *     float rho = dp3(-hitVec, light.direction);
+     *     if (rho < cos(light.phi / 2))
+     *         atten = 0;
+     *     if (rho < cos(light.theta / 2))
+     *         atten *= pow(some_func(rho), light.falloff);
+     * }
+     *
+     * float nDotHit = dp3_sat(normal, hitVec);
+     * float powFact = 0.0;
+     *
+     * if (nDotHit > 0.0)
+     * {
+     *     vec3 midVec = normalize(hitDir + eye);
+     *     float nDotMid = dp3_sat(normal, midVec);
+     *     pFact = pow(nDotMid, material.power);
+     * }
+     *
+     * ambient += light.ambient * atten;
+     * diffuse += light.diffuse * atten * nDotHit;
+     * specular += light.specular * atten * powFact;
+     */
+    if (key->lighting) {
+        struct ureg_dst tmp_y = ureg_writemask(tmp, TGSI_WRITEMASK_Y);
+
+        struct ureg_dst rAtt = ureg_writemask(r[1], TGSI_WRITEMASK_W);
+        struct ureg_dst rHit = ureg_writemask(r[3], TGSI_WRITEMASK_XYZ);
+        struct ureg_dst rMid = ureg_writemask(r[4], TGSI_WRITEMASK_XYZ);
+
+        struct ureg_dst rCtr = ureg_writemask(r[2], TGSI_WRITEMASK_W);
+
+        struct ureg_dst AL = ureg_writemask(AR, TGSI_WRITEMASK_X);
+
+        /* Light.*.Alpha is not used. */
+        struct ureg_dst rD = ureg_writemask(r[5], TGSI_WRITEMASK_XYZ);
+        struct ureg_dst rA = ureg_writemask(r[6], TGSI_WRITEMASK_XYZ);
+        struct ureg_dst rS = ureg_writemask(r[7], TGSI_WRITEMASK_XYZ);
+
+        struct ureg_src mtlP = _XXXX(MATERIAL_CONST(4));
+
+        struct ureg_src cLKind = _XXXX(LIGHT_CONST(0));
+        struct ureg_src cLAtt0 = _YYYY(LIGHT_CONST(0));
+        struct ureg_src cLAtt1 = _ZZZZ(LIGHT_CONST(0));
+        struct ureg_src cLAtt2 = _WWWW(LIGHT_CONST(0));
+        struct ureg_src cLColD = _XYZW(LIGHT_CONST(1));
+        struct ureg_src cLColS = _XYZW(LIGHT_CONST(2));
+        struct ureg_src cLColA = _XYZW(LIGHT_CONST(3));
+        struct ureg_src cLPos  = _XYZW(LIGHT_CONST(4));
+        struct ureg_src cLRng  = _WWWW(LIGHT_CONST(4));
+        struct ureg_src cLDir  = _XYZW(LIGHT_CONST(5));
+        struct ureg_src cLFOff = _WWWW(LIGHT_CONST(5));
+        struct ureg_src cLTht  = _XXXX(LIGHT_CONST(6));
+        struct ureg_src cLPhi  = _YYYY(LIGHT_CONST(6));
+        struct ureg_src cLSDiv = _ZZZZ(LIGHT_CONST(6));
+        struct ureg_src cLLast = _WWWW(LIGHT_CONST(7));
+
+        const unsigned loop_label = l++;
+
+        ureg_MOV(ureg, rCtr, ureg_imm1f(ureg, 32.0f)); /* &lightconst(0) */
+        ureg_MOV(ureg, rD, ureg_imm1f(ureg, 0.0f));
+        ureg_MOV(ureg, rA, ureg_imm1f(ureg, 0.0f));
+        ureg_MOV(ureg, rS, ureg_imm1f(ureg, 0.0f));
+        rD = ureg_saturate(rD);
+        rA = ureg_saturate(rA);
+        rS = ureg_saturate(rS);
+
+
+        /* loop management */
+        ureg_BGNLOOP(ureg, &label[loop_label]);
+        ureg_ARL(ureg, AL, _W(rCtr));
+
+        /* if (not DIRECTIONAL light): */
+        ureg_SNE(ureg, tmp_x, cLKind, ureg_imm1f(ureg, D3DLIGHT_DIRECTIONAL));
+        ureg_MOV(ureg, rHit, ureg_negate(cLDir));
+        ureg_MOV(ureg, rAtt, ureg_imm1f(ureg, 1.0f));
+        ureg_IF(ureg, _X(tmp), &label[l++]);
+        {
+            /* hitDir = light.position - eyeVtx
+             * d = length(hitDir)
+             * hitDir /= d
+             */
+            ureg_SUB(ureg, rHit, cLPos, ureg_src(rVtx));
+            ureg_DP3(ureg, tmp_x, ureg_src(rHit), ureg_src(rHit));
+            ureg_RSQ(ureg, tmp_y, _X(tmp));
+            ureg_MUL(ureg, rHit, ureg_src(rHit), _Y(tmp)); /* normalize */
+            ureg_MUL(ureg, tmp_x, _X(tmp), _Y(tmp)); /* length */
+
+            /* att = 1.0 / (light.att0 + (light.att1 + light.att2 * d) * d) */
+            ureg_MAD(ureg, rAtt, _X(tmp), cLAtt2, cLAtt1);
+            ureg_MAD(ureg, rAtt, _X(tmp), _W(rAtt), cLAtt0);
+            ureg_RCP(ureg, rAtt, _W(rAtt));
+            /* cut-off if distance exceeds Light.Range */
+            ureg_SLT(ureg, tmp_x, _X(tmp), cLRng);
+            ureg_MUL(ureg, rAtt, _W(rAtt), _X(tmp));
+        }
+        ureg_fixup_label(ureg, label[l-1], ureg_get_instruction_number(ureg));
+        ureg_ENDIF(ureg);
+
+        /* if (SPOT light) */
+        ureg_SEQ(ureg, tmp_x, cLKind, ureg_imm1f(ureg, D3DLIGHT_SPOT));
+        ureg_IF(ureg, _X(tmp), &label[l++]);
+        {
+            /* rho = dp3(-hitDir, light.spotDir)
+             *
+             * if (rho  > light.ctht2) NOTE: 0 <= phi <= pi, 0 <= theta <= phi
+             *     spotAtt = 1
+             * else
+             * if (rho <= light.cphi2)
+             *     spotAtt = 0
+             * else
+             *     spotAtt = (rho - light.cphi2) / (light.ctht2 - light.cphi2) ^ light.falloff
+             */
+            ureg_DP3(ureg, tmp_y, ureg_negate(ureg_src(rHit)), cLDir); /* rho */
+            ureg_SUB(ureg, tmp_x, _Y(tmp), cLPhi);
+            ureg_MUL(ureg, tmp_x, _X(tmp), cLSDiv);
+            ureg_POW(ureg, tmp_x, _X(tmp), cLFOff); /* spotAtten */
+            ureg_SGE(ureg, tmp_z, _Y(tmp), cLTht); /* if inside theta && phi */
+            ureg_SGE(ureg, tmp_y, _Y(tmp), cLPhi); /* if inside phi */
+            ureg_MAD(ureg, ureg_saturate(tmp_x), _X(tmp), _Y(tmp), _Z(tmp));
+            ureg_MUL(ureg, rAtt, _W(rAtt), _X(tmp));
+        }
+        ureg_fixup_label(ureg, label[l-1], ureg_get_instruction_number(ureg));
+        ureg_ENDIF(ureg);
+
+        /* directional factors, let's not use LIT because of clarity */
+        ureg_DP3(ureg, ureg_saturate(tmp_x), ureg_src(rNrm), ureg_src(rHit));
+        ureg_MOV(ureg, tmp_y, ureg_imm1f(ureg, 0.0f));
+        ureg_IF(ureg, _X(tmp), &label[l++]);
+        {
+            /* midVec = normalize(hitDir + eyeDir) */
+            if (key->localviewer) {
+                ureg_normalize3(ureg, rMid, ureg_src(rVtx), tmp);
+                ureg_ADD(ureg, rMid, ureg_src(rHit), ureg_negate(ureg_src(rMid)));
+            } else {
+                ureg_ADD(ureg, rMid, ureg_src(rHit), ureg_imm3f(ureg, 0.0f, 0.0f, 1.0f));
+            }
+            ureg_normalize3(ureg, rMid, ureg_src(rMid), tmp);
+            ureg_DP3(ureg, ureg_saturate(tmp_y), ureg_src(rNrm), ureg_src(rMid));
+            ureg_POW(ureg, tmp_y, _Y(tmp), mtlP);
+
+            ureg_MUL(ureg, tmp_x, _W(rAtt), _X(tmp)); /* dp3(normal,hitDir) * att */
+            ureg_MUL(ureg, tmp_y, _W(rAtt), _Y(tmp)); /* power factor * att */
+            ureg_MAD(ureg, rD, cLColD, _X(tmp), ureg_src(rD)); /* accumulate diffuse */
+            ureg_MAD(ureg, rS, cLColS, _Y(tmp), ureg_src(rS)); /* accumulate specular */
+        }
+        ureg_fixup_label(ureg, label[l-1], ureg_get_instruction_number(ureg));
+        ureg_ENDIF(ureg);
+
+        ureg_MAD(ureg, rA, cLColA, _W(rAtt), ureg_src(rA)); /* accumulate ambient */
+
+        /* break if this was the last light */
+        ureg_IF(ureg, cLLast, &label[l++]);
+        ureg_BRK(ureg);
+        ureg_ENDIF(ureg);
+        ureg_fixup_label(ureg, label[l-1], ureg_get_instruction_number(ureg));
+
+        ureg_ADD(ureg, rCtr, _W(rCtr), ureg_imm1f(ureg, 8.0f));
+        ureg_fixup_label(ureg, label[loop_label], ureg_get_instruction_number(ureg));
+        ureg_ENDLOOP(ureg, &label[loop_label]);
+
+        /* Set alpha factors of illumination to 1.0 for the multiplications. */
+        rD.WriteMask = TGSI_WRITEMASK_W; rD.Saturate = 0;
+        rS.WriteMask = TGSI_WRITEMASK_W; rS.Saturate = 0;
+        rA.WriteMask = TGSI_WRITEMASK_W; rA.Saturate = 0;
+        ureg_MOV(ureg, rD, ureg_imm1f(ureg, 1.0f));
+        ureg_MOV(ureg, rS, ureg_imm1f(ureg, 1.0f));
+
+        /* Apply to material:
+         *
+         * oCol[0] = (material.emissive + material.ambient * rs.ambient) +
+         *           material.ambient * ambient +
+         *           material.diffuse * diffuse +
+         * oCol[1] = material.specular * specular;
+         */
+        if (key->mtl_emissive == 0 && key->mtl_ambient == 0) {
+            ureg_MOV(ureg, rA, ureg_imm1f(ureg, 1.0f));
+            ureg_MAD(ureg, tmp, ureg_src(rA), vs->mtlA, _CONST(19));
+        } else {
+            ureg_ADD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_XYZ), ureg_src(rA), _CONST(25));
+            ureg_MAD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_XYZ), vs->mtlA, ureg_src(tmp), vs->mtlE);
+            ureg_ADD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_W  ), vs->mtlA, vs->mtlE);
+        }
+        ureg_MAD(ureg, rCol[0], ureg_src(rD), vs->mtlD, ureg_src(tmp));
+        ureg_MUL(ureg, rCol[1], ureg_src(rS), vs->mtlS);
+    } else
+    /* COLOR */
+    if (key->darkness) {
+        if (key->mtl_emissive == 0 && key->mtl_ambient == 0) {
+            ureg_MAD(ureg, rCol[0], vs->mtlD, ureg_imm4f(ureg, 0.0f, 0.0f, 0.0f, 1.0f), _CONST(19));
+        } else {
+            ureg_MAD(ureg, ureg_writemask(rCol[0], TGSI_WRITEMASK_XYZ), vs->mtlA, _CONST(25), vs->mtlE);
+            ureg_ADD(ureg, ureg_writemask(tmp,     TGSI_WRITEMASK_W), vs->mtlA, vs->mtlE);
+            ureg_ADD(ureg, ureg_writemask(rCol[0], TGSI_WRITEMASK_W), vs->mtlD, _W(tmp));
+        }
+        ureg_MUL(ureg, rCol[1], ureg_imm4f(ureg, 0.0f, 0.0f, 0.0f, 1.0f), vs->mtlS);
+    } else {
+        ureg_MOV(ureg, rCol[0], vs->aCol[0]);
+        ureg_MOV(ureg, rCol[1], vs->aCol[1]);
+    }
+
+    /* === Process fog.
+     *
+     * exp(x) = ex2(log2(e) * x)
+     */
+    if (key->fog_mode) {
+        /* Fog doesn't affect alpha, TODO: combine with light code output */
+        ureg_MOV(ureg, ureg_writemask(oCol[0], TGSI_WRITEMASK_W), _W(rCol[0]));
+        ureg_MOV(ureg, ureg_writemask(oCol[1], TGSI_WRITEMASK_W), _W(rCol[1]));
+
+        if (key->position_t) {
+            ureg_MOV(ureg, ureg_saturate(tmp_x), ureg_scalar(vs->aCol[1], TGSI_SWIZZLE_W));
+        } else
+        if (key->fog_range) {
+            ureg_DP3(ureg, tmp_x, ureg_src(rVtx), ureg_src(rVtx));
+            ureg_RSQ(ureg, tmp_z, _X(tmp));
+            ureg_MUL(ureg, tmp_z, _Z(tmp), _X(tmp));
+        } else {
+            ureg_MOV(ureg, tmp_z, ureg_abs(_Z(rVtx)));
+        }
+
+        if (key->fog_mode == D3DFOG_EXP) {
+            ureg_MUL(ureg, tmp_x, _Z(tmp), _ZZZZ(_CONST(28)));
+            ureg_MUL(ureg, tmp_x, _X(tmp), ureg_imm1f(ureg, -1.442695f));
+            ureg_EX2(ureg, tmp_x, _X(tmp));
+        } else
+        if (key->fog_mode == D3DFOG_EXP2) {
+            ureg_MUL(ureg, tmp_x, _Z(tmp), _ZZZZ(_CONST(28)));
+            ureg_MUL(ureg, tmp_x, _X(tmp), _X(tmp));
+            ureg_MUL(ureg, tmp_x, _X(tmp), ureg_imm1f(ureg, -1.442695f));
+            ureg_EX2(ureg, tmp_x, _X(tmp));
+        } else
+        if (key->fog_mode == D3DFOG_LINEAR && !key->position_t) {
+            ureg_SUB(ureg, tmp_x, _XXXX(_CONST(28)), _Z(tmp));
+            ureg_MUL(ureg, ureg_saturate(tmp_x), _X(tmp), _YYYY(_CONST(28)));
+        }
+        ureg_MOV(ureg, oFog, _X(tmp));
+        ureg_LRP(ureg, ureg_writemask(oCol[0], TGSI_WRITEMASK_XYZ), _X(tmp), ureg_src(rCol[0]), _CONST(29));
+        ureg_LRP(ureg, ureg_writemask(oCol[1], TGSI_WRITEMASK_XYZ), _X(tmp), ureg_src(rCol[1]), _CONST(29));
+    }
+
+    if (key->position_t && device->driver_caps.window_space_position_support)
+        ureg_property(ureg, TGSI_PROPERTY_VS_WINDOW_SPACE_POSITION, TRUE);
+
+    ureg_END(ureg);
+    nine_ureg_tgsi_dump(ureg, FALSE);
+    return ureg_create_shader_and_destroy(ureg, device->pipe);
+}
+
+/* PS FF constants layout:
+ *
+ * CONST[ 0.. 7]      stage[i].D3DTSS_CONSTANT
+ * CONST[ 8..15].x___ stage[i].D3DTSS_BUMPENVMAT00
+ * CONST[ 8..15]._y__ stage[i].D3DTSS_BUMPENVMAT01
+ * CONST[ 8..15].__z_ stage[i].D3DTSS_BUMPENVMAT10
+ * CONST[ 8..15].___w stage[i].D3DTSS_BUMPENVMAT11
+ * CONST[16..19].x_z_ stage[i].D3DTSS_BUMPENVLSCALE
+ * CONST[17..19]._y_w stage[i].D3DTSS_BUMPENVLOFFSET
+ *
+ * CONST[20] D3DRS_TEXTUREFACTOR
+ * CONST[21] D3DRS_FOGCOLOR
+ * CONST[22].x___ RS.FogEnd
+ * CONST[22]._y__ 1.0f / (RS.FogEnd - RS.FogStart)
+ * CONST[22].__z_ RS.FogDensity
+ */
+struct ps_build_ctx
+{
+    struct ureg_program *ureg;
+
+    struct ureg_src vC[2]; /* DIFFUSE, SPECULAR */
+    struct ureg_src vT[8]; /* TEXCOORD[i] */
+    struct ureg_dst r[6];  /* TEMPs */
+    struct ureg_dst rCur; /* D3DTA_CURRENT */
+    struct ureg_dst rMod;
+    struct ureg_src rCurSrc;
+    struct ureg_dst rTmp; /* D3DTA_TEMP */
+    struct ureg_src rTmpSrc;
+    struct ureg_dst rTex;
+    struct ureg_src rTexSrc;
+    struct ureg_src cBEM[8];
+    struct ureg_src s[8];
+
+    struct {
+        unsigned index;
+        unsigned index_pre_mod;
+        unsigned num_regs;
+    } stage;
+};
+
+static struct ureg_src
+ps_get_ts_arg(struct ps_build_ctx *ps, unsigned ta)
+{
+    struct ureg_src reg;
+
+    switch (ta & D3DTA_SELECTMASK) {
+    case D3DTA_CONSTANT:
+        reg = ureg_DECL_constant(ps->ureg, ps->stage.index);
+        break;
+    case D3DTA_CURRENT:
+        reg = (ps->stage.index == ps->stage.index_pre_mod) ? ureg_src(ps->rMod) : ps->rCurSrc;
+        break;
+    case D3DTA_DIFFUSE:
+        reg = ureg_DECL_fs_input(ps->ureg, TGSI_SEMANTIC_COLOR, 0, TGSI_INTERPOLATE_PERSPECTIVE);
+        break;
+    case D3DTA_SPECULAR:
+        reg = ureg_DECL_fs_input(ps->ureg, TGSI_SEMANTIC_COLOR, 1, TGSI_INTERPOLATE_PERSPECTIVE);
+        break;
+    case D3DTA_TEMP:
+        reg = ps->rTmpSrc;
+        break;
+    case D3DTA_TEXTURE:
+        reg = ps->rTexSrc;
+        break;
+    case D3DTA_TFACTOR:
+        reg = ureg_DECL_constant(ps->ureg, 20);
+        break;
+    default:
+        assert(0);
+        reg = ureg_src_undef();
+        break;
+    }
+    if (ta & D3DTA_COMPLEMENT) {
+        struct ureg_dst dst = ps->r[ps->stage.num_regs++];
+        ureg_SUB(ps->ureg, dst, ureg_imm1f(ps->ureg, 1.0f), reg);
+        reg = ureg_src(dst);
+    }
+    if (ta & D3DTA_ALPHAREPLICATE)
+        reg = _WWWW(reg);
+    return reg;
+}
+
+static struct ureg_dst
+ps_get_ts_dst(struct ps_build_ctx *ps, unsigned ta)
+{
+    assert(!(ta & (D3DTA_COMPLEMENT | D3DTA_ALPHAREPLICATE)));
+
+    switch (ta & D3DTA_SELECTMASK) {
+    case D3DTA_CURRENT:
+        return ps->rCur;
+    case D3DTA_TEMP:
+        return ps->rTmp;
+    default:
+        assert(0);
+        return ureg_dst_undef();
+    }
+}
+
+static uint8_t ps_d3dtop_args_mask(D3DTEXTUREOP top)
+{
+    switch (top) {
+    case D3DTOP_DISABLE:
+        return 0x0;
+    case D3DTOP_SELECTARG1:
+    case D3DTOP_PREMODULATE:
+        return 0x2;
+    case D3DTOP_SELECTARG2:
+        return 0x4;
+    case D3DTOP_MULTIPLYADD:
+    case D3DTOP_LERP:
+        return 0x7;
+    default:
+        return 0x6;
+    }
+}
+
+static INLINE boolean
+is_MOV_no_op(struct ureg_dst dst, struct ureg_src src)
+{
+    return !dst.WriteMask ||
+        (dst.File == src.File &&
+         dst.Index == src.Index &&
+         !dst.Indirect &&
+         !dst.Saturate &&
+         !src.Indirect &&
+         !src.Negate &&
+         !src.Absolute &&
+         (!(dst.WriteMask & TGSI_WRITEMASK_X) || (src.SwizzleX == TGSI_SWIZZLE_X)) &&
+         (!(dst.WriteMask & TGSI_WRITEMASK_Y) || (src.SwizzleY == TGSI_SWIZZLE_Y)) &&
+         (!(dst.WriteMask & TGSI_WRITEMASK_Z) || (src.SwizzleZ == TGSI_SWIZZLE_Z)) &&
+         (!(dst.WriteMask & TGSI_WRITEMASK_W) || (src.SwizzleW == TGSI_SWIZZLE_W)));
+
+}
+
+static void
+ps_do_ts_op(struct ps_build_ctx *ps, unsigned top, struct ureg_dst dst, struct ureg_src *arg)
+{
+    struct ureg_program *ureg = ps->ureg;
+    struct ureg_dst tmp = ps->r[ps->stage.num_regs];
+    struct ureg_dst tmp2 = ps->r[ps->stage.num_regs+1];
+    struct ureg_dst tmp_x = ureg_writemask(tmp, TGSI_WRITEMASK_X);
+
+    tmp.WriteMask = dst.WriteMask;
+
+    if (top != D3DTOP_SELECTARG1 && top != D3DTOP_SELECTARG2 &&
+        top != D3DTOP_MODULATE && top != D3DTOP_PREMODULATE &&
+        top != D3DTOP_BLENDDIFFUSEALPHA && top != D3DTOP_BLENDTEXTUREALPHA &&
+        top != D3DTOP_BLENDFACTORALPHA && top != D3DTOP_BLENDCURRENTALPHA &&
+        top != D3DTOP_BUMPENVMAP && top != D3DTOP_BUMPENVMAPLUMINANCE &&
+        top != D3DTOP_LERP)
+        dst = ureg_saturate(dst);
+
+    switch (top) {
+    case D3DTOP_SELECTARG1:
+        if (!is_MOV_no_op(dst, arg[1]))
+            ureg_MOV(ureg, dst, arg[1]);
+        break;
+    case D3DTOP_SELECTARG2:
+        if (!is_MOV_no_op(dst, arg[2]))
+            ureg_MOV(ureg, dst, arg[2]);
+        break;
+    case D3DTOP_MODULATE:
+        ureg_MUL(ureg, dst, arg[1], arg[2]);
+        break;
+    case D3DTOP_MODULATE2X:
+        ureg_MUL(ureg, tmp, arg[1], arg[2]);
+        ureg_ADD(ureg, dst, ureg_src(tmp), ureg_src(tmp));
+        break;
+    case D3DTOP_MODULATE4X:
+        ureg_MUL(ureg, tmp, arg[1], arg[2]);
+        ureg_MUL(ureg, dst, ureg_src(tmp), ureg_imm1f(ureg, 4.0f));
+        break;
+    case D3DTOP_ADD:
+        ureg_ADD(ureg, dst, arg[1], arg[2]);
+        break;
+    case D3DTOP_ADDSIGNED:
+        ureg_ADD(ureg, tmp, arg[1], arg[2]);
+        ureg_SUB(ureg, dst, ureg_src(tmp), ureg_imm1f(ureg, 0.5f));
+        break;
+    case D3DTOP_ADDSIGNED2X:
+        ureg_ADD(ureg, tmp, arg[1], arg[2]);
+        ureg_MAD(ureg, dst, ureg_src(tmp), ureg_imm1f(ureg, 2.0f), ureg_imm1f(ureg, -1.0f));
+        break;
+    case D3DTOP_SUBTRACT:
+        ureg_SUB(ureg, dst, arg[1], arg[2]);
+        break;
+    case D3DTOP_ADDSMOOTH:
+        ureg_SUB(ureg, tmp, ureg_imm1f(ureg, 1.0f), arg[1]);
+        ureg_MAD(ureg, dst, ureg_src(tmp), arg[2], arg[1]);
+        break;
+    case D3DTOP_BLENDDIFFUSEALPHA:
+        ureg_LRP(ureg, dst, _WWWW(ps->vC[0]), arg[1], arg[2]);
+        break;
+    case D3DTOP_BLENDTEXTUREALPHA:
+        /* XXX: alpha taken from previous stage, texture or result ? */
+        ureg_LRP(ureg, dst, _W(ps->rTex), arg[1], arg[2]);
+        break;
+    case D3DTOP_BLENDFACTORALPHA:
+        ureg_LRP(ureg, dst, _WWWW(_CONST(20)), arg[1], arg[2]);
+        break;
+    case D3DTOP_BLENDTEXTUREALPHAPM:
+        ureg_SUB(ureg, tmp_x, ureg_imm1f(ureg, 1.0f), _W(ps->rTex));
+        ureg_MAD(ureg, dst, arg[2], _X(tmp), arg[1]);
+        break;
+    case D3DTOP_BLENDCURRENTALPHA:
+        ureg_LRP(ureg, dst, _WWWW(ps->rCurSrc), arg[1], arg[2]);
+        break;
+    case D3DTOP_PREMODULATE:
+        ureg_MOV(ureg, dst, arg[1]);
+        ps->stage.index_pre_mod = ps->stage.index + 1;
+        break;
+    case D3DTOP_MODULATEALPHA_ADDCOLOR:
+        ureg_MAD(ureg, dst, _WWWW(arg[1]), arg[2], arg[1]);
+        break;
+    case D3DTOP_MODULATECOLOR_ADDALPHA:
+        ureg_MAD(ureg, dst, arg[1], arg[2], _WWWW(arg[1]));
+        break;
+    case D3DTOP_MODULATEINVALPHA_ADDCOLOR:
+        ureg_SUB(ureg, tmp_x, ureg_imm1f(ureg, 1.0f), _WWWW(arg[1]));
+        ureg_MAD(ureg, dst, _X(tmp), arg[2], arg[1]);
+        break;
+    case D3DTOP_MODULATEINVCOLOR_ADDALPHA:
+        ureg_SUB(ureg, tmp, ureg_imm1f(ureg, 1.0f), arg[1]);
+        ureg_MAD(ureg, dst, ureg_src(tmp), arg[2], _WWWW(arg[1]));
+        break;
+    case D3DTOP_BUMPENVMAP:
+        break;
+    case D3DTOP_BUMPENVMAPLUMINANCE:
+        break;
+    case D3DTOP_DOTPRODUCT3:
+        ureg_SUB(ureg, tmp, arg[1], ureg_imm4f(ureg,0.5,0.5,0.5,0.5));
+        ureg_SUB(ureg, tmp2, arg[2] , ureg_imm4f(ureg,0.5,0.5,0.5,0.5));
+        ureg_DP3(ureg, tmp, ureg_src(tmp), ureg_src(tmp2));
+        ureg_MUL(ureg, ureg_saturate(dst), ureg_src(tmp), ureg_imm4f(ureg,4.0,4.0,4.0,4.0));
+        break;
+    case D3DTOP_MULTIPLYADD:
+        ureg_MAD(ureg, dst, arg[2], arg[0], arg[1]);
+        break;
+    case D3DTOP_LERP:
+        ureg_LRP(ureg, dst, arg[1], arg[2], arg[0]);
+        break;
+    case D3DTOP_DISABLE:
+        /* no-op ? */
+        break;
+    default:
+        assert(!"invalid D3DTOP");
+        break;
+    }
+}
+
+static void *
+nine_ff_build_ps(struct NineDevice9 *device, struct nine_ff_ps_key *key)
+{
+    struct ps_build_ctx ps;
+    struct ureg_program *ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT);
+    struct ureg_dst oCol;
+    unsigned i, s;
+    const unsigned texcoord_sn = get_texcoord_sn(device->screen);
+
+    memset(&ps, 0, sizeof(ps));
+    ps.ureg = ureg;
+    ps.stage.index_pre_mod = -1;
+
+    ps.vC[0] = ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_COLOR, 0, TGSI_INTERPOLATE_PERSPECTIVE);
+
+    /* Declare all TEMPs we might need, serious drivers have a register allocator. */
+    for (i = 0; i < Elements(ps.r); ++i)
+        ps.r[i] = ureg_DECL_local_temporary(ureg);
+    ps.rCur = ps.r[0];
+    ps.rTmp = ps.r[1];
+    ps.rTex = ps.r[2];
+    ps.rCurSrc = ureg_src(ps.rCur);
+    ps.rTmpSrc = ureg_src(ps.rTmp);
+    ps.rTexSrc = ureg_src(ps.rTex);
+
+    for (s = 0; s < 8; ++s) {
+        ps.s[s] = ureg_src_undef();
+
+        if (key->ts[s].colorop != D3DTOP_DISABLE) {
+            if (key->ts[s].colorarg0 == D3DTA_SPECULAR ||
+                key->ts[s].colorarg1 == D3DTA_SPECULAR ||
+                key->ts[s].colorarg2 == D3DTA_SPECULAR)
+                ps.vC[1] = ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_COLOR, 1, TGSI_INTERPOLATE_PERSPECTIVE);
+
+            if (key->ts[s].colorarg0 == D3DTA_TEXTURE ||
+                key->ts[s].colorarg1 == D3DTA_TEXTURE ||
+                key->ts[s].colorarg2 == D3DTA_TEXTURE) {
+                ps.s[s] = ureg_DECL_sampler(ureg, s);
+                ps.vT[s] = ureg_DECL_fs_input(ureg, texcoord_sn, s, TGSI_INTERPOLATE_PERSPECTIVE);
+            }
+            if (s && (key->ts[s - 1].colorop == D3DTOP_PREMODULATE ||
+                      key->ts[s - 1].alphaop == D3DTOP_PREMODULATE))
+                ps.s[s] = ureg_DECL_sampler(ureg, s);
+        }
+
+        if (key->ts[s].alphaop != D3DTOP_DISABLE) {
+            if (key->ts[s].alphaarg0 == D3DTA_SPECULAR ||
+                key->ts[s].alphaarg1 == D3DTA_SPECULAR ||
+                key->ts[s].alphaarg2 == D3DTA_SPECULAR)
+                ps.vC[1] = ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_COLOR, 1, TGSI_INTERPOLATE_PERSPECTIVE);
+
+            if (key->ts[s].alphaarg0 == D3DTA_TEXTURE ||
+                key->ts[s].alphaarg1 == D3DTA_TEXTURE ||
+                key->ts[s].alphaarg2 == D3DTA_TEXTURE) {
+                ps.s[s] = ureg_DECL_sampler(ureg, s);
+                ps.vT[s] = ureg_DECL_fs_input(ureg, texcoord_sn, s, TGSI_INTERPOLATE_PERSPECTIVE);
+            }
+        }
+    }
+    if (key->specular)
+        ps.vC[1] = ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_COLOR, 1, TGSI_INTERPOLATE_PERSPECTIVE);
+
+    oCol = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0);
+
+    if (key->ts[0].colorop == D3DTOP_DISABLE &&
+        key->ts[0].alphaop == D3DTOP_DISABLE)
+        ureg_MOV(ureg, ps.rCur, ps.vC[0]);
+    /* Or is it undefined then ? */
+
+    /* Run stages.
+     */
+    for (s = 0; s < 8; ++s) {
+        unsigned colorarg[3];
+        unsigned alphaarg[3];
+        const uint8_t used_c = ps_d3dtop_args_mask(key->ts[s].colorop);
+        const uint8_t used_a = ps_d3dtop_args_mask(key->ts[s].alphaop);
+        struct ureg_dst dst;
+        struct ureg_src arg[3];
+
+        if (key->ts[s].colorop == D3DTOP_DISABLE &&
+            key->ts[s].alphaop == D3DTOP_DISABLE)
+            continue;
+        ps.stage.index = s;
+        ps.stage.num_regs = 3;
+
+        DBG("STAGE[%u]: colorop=%s alphaop=%s\n", s,
+            nine_D3DTOP_to_str(key->ts[s].colorop),
+            nine_D3DTOP_to_str(key->ts[s].alphaop));
+
+        if (!ureg_src_is_undef(ps.s[s])) {
+            unsigned target;
+            switch (key->ts[s].textarget) {
+            case 0: target = TGSI_TEXTURE_1D; break;
+            case 1: target = TGSI_TEXTURE_2D; break;
+            case 2: target = TGSI_TEXTURE_3D; break;
+            case 3: target = TGSI_TEXTURE_CUBE; break;
+            /* this is a 2 bit bitfield, do I really need a default case ? */
+            }
+
+            /* sample the texture */
+            if (key->ts[s].colorop == D3DTOP_BUMPENVMAP ||
+                key->ts[s].colorop == D3DTOP_BUMPENVMAPLUMINANCE) {
+            }
+            if (key->ts[s].projected)
+                ureg_TXP(ureg, ps.rTex, target, ps.vT[s], ps.s[s]);
+            else
+                ureg_TEX(ureg, ps.rTex, target, ps.vT[s], ps.s[s]);
+        }
+
+        if (s == 0 &&
+            (key->ts[0].resultarg != 0 /* not current */ ||
+             key->ts[0].colorop == D3DTOP_DISABLE ||
+             key->ts[0].alphaop == D3DTOP_DISABLE ||
+             key->ts[0].colorarg0 == D3DTA_CURRENT ||
+             key->ts[0].colorarg1 == D3DTA_CURRENT ||
+             key->ts[0].colorarg2 == D3DTA_CURRENT ||
+             key->ts[0].alphaarg0 == D3DTA_CURRENT ||
+             key->ts[0].alphaarg1 == D3DTA_CURRENT ||
+             key->ts[0].alphaarg2 == D3DTA_CURRENT)
+           ) {
+            /* Initialize D3DTA_CURRENT.
+             * (Yes we can do this before the loop but not until
+             *  NVE4 has an instruction scheduling pass.)
+             */
+            ureg_MOV(ureg, ps.rCur, ps.vC[0]);
+        }
+
+        dst = ps_get_ts_dst(&ps, key->ts[s].resultarg ? D3DTA_TEMP : D3DTA_CURRENT);
+
+        if (ps.stage.index_pre_mod == ps.stage.index) {
+            ps.rMod = ps.r[ps.stage.num_regs++];
+            ureg_MUL(ureg, ps.rMod, ps.rCurSrc, ps.rTexSrc);
+        }
+
+        colorarg[0] = (key->ts[s].colorarg0 | ((key->colorarg_b4[0] >> s) << 4) | ((key->colorarg_b5[0] >> s) << 5)) & 0x3f;
+        colorarg[1] = (key->ts[s].colorarg1 | ((key->colorarg_b4[1] >> s) << 4) | ((key->colorarg_b5[1] >> s) << 5)) & 0x3f;
+        colorarg[2] = (key->ts[s].colorarg2 | ((key->colorarg_b4[2] >> s) << 4) | ((key->colorarg_b5[2] >> s) << 5)) & 0x3f;
+        alphaarg[0] = (key->ts[s].alphaarg0 | ((key->alphaarg_b4[0] >> s) << 4)) & 0x1f;
+        alphaarg[1] = (key->ts[s].alphaarg1 | ((key->alphaarg_b4[1] >> s) << 4)) & 0x1f;
+        alphaarg[2] = (key->ts[s].alphaarg2 | ((key->alphaarg_b4[2] >> s) << 4)) & 0x1f;
+
+        if (key->ts[s].colorop != key->ts[s].alphaop ||
+            colorarg[0] != alphaarg[0] ||
+            colorarg[1] != alphaarg[1] ||
+            colorarg[2] != alphaarg[2])
+            dst.WriteMask = TGSI_WRITEMASK_XYZ;
+
+        if (used_c & 0x1) arg[0] = ps_get_ts_arg(&ps, colorarg[0]);
+        if (used_c & 0x2) arg[1] = ps_get_ts_arg(&ps, colorarg[1]);
+        if (used_c & 0x4) arg[2] = ps_get_ts_arg(&ps, colorarg[2]);
+        ps_do_ts_op(&ps, key->ts[s].colorop, dst, arg);
+
+        if (dst.WriteMask != TGSI_WRITEMASK_XYZW) {
+            dst.WriteMask = TGSI_WRITEMASK_W;
+
+            if (used_a & 0x1) arg[0] = ps_get_ts_arg(&ps, alphaarg[0]);
+            if (used_a & 0x2) arg[1] = ps_get_ts_arg(&ps, alphaarg[1]);
+            if (used_a & 0x4) arg[2] = ps_get_ts_arg(&ps, alphaarg[2]);
+            ps_do_ts_op(&ps, key->ts[s].alphaop, dst, arg);
+        }
+    }
+
+    if (key->specular)
+        ureg_ADD(ureg, ps.rCur, ps.rCurSrc, ps.vC[1]);
+
+    /* Fog.
+     */
+    if (key->fog_mode) {
+        struct ureg_src vPos = ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_POSITION, 0, TGSI_INTERPOLATE_LINEAR);
+        struct ureg_dst rFog = ureg_writemask(ps.rTmp, TGSI_WRITEMASK_X);
+        if (key->fog_mode == D3DFOG_EXP) {
+            ureg_MUL(ureg, rFog, _ZZZZ(vPos), _ZZZZ(_CONST(22)));
+            ureg_MUL(ureg, rFog, _X(rFog), ureg_imm1f(ureg, -1.442695f));
+            ureg_EX2(ureg, rFog, _X(rFog));
+        } else
+        if (key->fog_mode == D3DFOG_EXP2) {
+            ureg_MUL(ureg, rFog, _ZZZZ(vPos), _ZZZZ(_CONST(22)));
+            ureg_MUL(ureg, rFog, _X(rFog), _X(rFog));
+            ureg_MUL(ureg, rFog, _X(rFog), ureg_imm1f(ureg, -1.442695f));
+            ureg_EX2(ureg, rFog, _X(rFog));
+        } else
+        if (key->fog_mode == D3DFOG_LINEAR) {
+            ureg_SUB(ureg, rFog, _XXXX(_CONST(22)), _ZZZZ(vPos));
+            ureg_MUL(ureg, ureg_saturate(rFog), _X(rFog), _YYYY(_CONST(22)));
+        }
+        ureg_LRP(ureg, ureg_writemask(oCol, TGSI_WRITEMASK_XYZ), _X(rFog), ps.rCurSrc, _CONST(21));
+        ureg_MOV(ureg, ureg_writemask(oCol, TGSI_WRITEMASK_W), ps.rCurSrc);
+    } else
+    if (key->fog) {
+        struct ureg_src vFog = ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_FOG, 0, TGSI_INTERPOLATE_PERSPECTIVE);
+        ureg_LRP(ureg, ureg_writemask(oCol, TGSI_WRITEMASK_XYZ), _XXXX(vFog), ps.rCurSrc, _CONST(21));
+        ureg_MOV(ureg, ureg_writemask(oCol, TGSI_WRITEMASK_W), ps.rCurSrc);
+    } else {
+        ureg_MOV(ureg, oCol, ps.rCurSrc);
+    }
+
+    ureg_END(ureg);
+    nine_ureg_tgsi_dump(ureg, FALSE);
+    return ureg_create_shader_and_destroy(ureg, device->pipe);
+}
+
+static struct NineVertexShader9 *
+nine_ff_get_vs(struct NineDevice9 *device)
+{
+    const struct nine_state *state = &device->state;
+    struct NineVertexShader9 *vs;
+    enum pipe_error err;
+    struct vs_build_ctx bld;
+    struct nine_ff_vs_key key;
+    unsigned s;
+
+    assert(sizeof(key) <= sizeof(key.value32));
+
+    memset(&key, 0, sizeof(key));
+    memset(&bld, 0, sizeof(bld));
+
+    bld.key = &key;
+
+    /* FIXME: this shouldn't be NULL, but it is on init */
+    if (state->vdecl) {
+        if (state->vdecl->usage_map[NINE_DECLUSAGE_POSITIONT] != 0xff)
+            key.position_t = 1;
+        if (state->vdecl->usage_map[NINE_DECLUSAGE_COLOR(0)] == 0xff)
+            key.color0in_one = 1;
+        if (state->vdecl->usage_map[NINE_DECLUSAGE_COLOR(1)] == 0xff)
+            key.color1in_one = 1;
+        if (state->vdecl->usage_map[NINE_DECLUSAGE_PSIZE] != 0xff)
+            key.vertexpointsize = 1;
+    }
+    if (!key.vertexpointsize)
+        key.pointscale = !!state->rs[D3DRS_POINTSCALEENABLE];
+
+    key.lighting = !!state->rs[D3DRS_LIGHTING] &&  state->ff.num_lights_active;
+    key.darkness = !!state->rs[D3DRS_LIGHTING] && !state->ff.num_lights_active;
+    if (key.position_t) {
+        key.darkness = 0; /* |= key.lighting; */ /* XXX ? */
+        key.lighting = 0;
+    }
+    if ((key.lighting | key.darkness) && state->rs[D3DRS_COLORVERTEX]) {
+        key.mtl_diffuse = state->rs[D3DRS_DIFFUSEMATERIALSOURCE];
+        key.mtl_ambient = state->rs[D3DRS_AMBIENTMATERIALSOURCE];
+        key.mtl_specular = state->rs[D3DRS_SPECULARMATERIALSOURCE];
+        key.mtl_emissive = state->rs[D3DRS_EMISSIVEMATERIALSOURCE];
+    }
+    key.fog_mode = state->rs[D3DRS_FOGENABLE] ? state->rs[D3DRS_FOGVERTEXMODE] : 0;
+    if (key.fog_mode)
+        key.fog_range = !key.position_t && state->rs[D3DRS_RANGEFOGENABLE];
+
+    if (state->rs[D3DRS_VERTEXBLEND] != D3DVBF_DISABLE) {
+        key.vertexblend_indexed = !!state->rs[D3DRS_INDEXEDVERTEXBLENDENABLE];
+
+        switch (state->rs[D3DRS_VERTEXBLEND]) {
+        case D3DVBF_0WEIGHTS: key.vertexblend = key.vertexblend_indexed; break;
+        case D3DVBF_1WEIGHTS: key.vertexblend = 2; break;
+        case D3DVBF_2WEIGHTS: key.vertexblend = 3; break;
+        case D3DVBF_3WEIGHTS: key.vertexblend = 4; break;
+        case D3DVBF_TWEENING: key.vertextween = 1; break;
+        default:
+            assert(!"invalid D3DVBF");
+            break;
+        }
+    }
+
+    for (s = 0; s < 8; ++s) {
+        if (state->ff.tex_stage[s][D3DTSS_COLOROP] == D3DTOP_DISABLE &&
+            state->ff.tex_stage[s][D3DTSS_ALPHAOP] == D3DTOP_DISABLE)
+            break;
+        key.tc_idx |= (state->ff.tex_stage[s][D3DTSS_TEXCOORDINDEX] & 7) << (s * 3);
+        if (!key.position_t) {
+            unsigned gen = (state->ff.tex_stage[s][D3DTSS_TEXCOORDINDEX] >> 16) + 1;
+            unsigned dim = MIN2(state->ff.tex_stage[s][D3DTSS_TEXTURETRANSFORMFLAGS] & 0x7, 4);
+            key.tc_gen |= gen << (s * 3);
+            key.tc_dim |= dim << (s * 3);
+        } else {
+            key.tc_gen |= NINED3DTSS_TCI_PASSTHRU << (s * 3);
+        }
+    }
+
+    vs = util_hash_table_get(device->ff.ht_vs, &key);
+    if (vs)
+        return vs;
+    NineVertexShader9_new(device, &vs, NULL, nine_ff_build_vs(device, &bld));
+
+    nine_ff_prune_vs(device);
+    if (vs) {
+        unsigned n;
+
+        memcpy(&vs->ff_key, &key, sizeof(vs->ff_key));
+
+        err = util_hash_table_set(device->ff.ht_vs, &vs->ff_key, vs);
+        assert(err == PIPE_OK);
+        device->ff.num_vs++;
+        NineUnknown_ConvertRefToBind(NineUnknown(vs));
+
+        vs->num_inputs = bld.num_inputs;
+        for (n = 0; n < bld.num_inputs; ++n)
+            vs->input_map[n].ndecl = bld.input[n];
+
+        vs->position_t = key.position_t;
+        vs->point_size = key.vertexpointsize | key.pointscale;
+    }
+    return vs;
+}
+
+static struct NinePixelShader9 *
+nine_ff_get_ps(struct NineDevice9 *device)
+{
+    struct nine_state *state = &device->state;
+    struct NinePixelShader9 *ps;
+    enum pipe_error err;
+    struct nine_ff_ps_key key;
+    unsigned s;
+
+    assert(sizeof(key) <= sizeof(key.value32));
+
+    memset(&key, 0, sizeof(key));
+    for (s = 0; s < 8; ++s) {
+        key.ts[s].colorop = state->ff.tex_stage[s][D3DTSS_COLOROP];
+        key.ts[s].alphaop = state->ff.tex_stage[s][D3DTSS_ALPHAOP];
+        /* MSDN says D3DTOP_DISABLE disables this and all subsequent stages. */
+        /* ALPHAOP cannot be disabled if COLOROP is enabled. */
+        if (key.ts[s].colorop == D3DTOP_DISABLE) {
+            key.ts[s].alphaop = D3DTOP_DISABLE; /* DISABLE == 1, avoid degenerate keys */
+            break;
+        }
+        if (!state->texture[s] &&
+            state->ff.tex_stage[s][D3DTSS_COLORARG1] == D3DTA_TEXTURE) {
+            /* This should also disable the stage. */
+            key.ts[s].colorop = key.ts[s].alphaop = D3DTOP_DISABLE;
+            break;
+        }
+        if (key.ts[s].colorop != D3DTOP_DISABLE) {
+            uint8_t used_c = ps_d3dtop_args_mask(key.ts[s].colorop);
+            if (used_c & 0x1) key.ts[s].colorarg0 = state->ff.tex_stage[s][D3DTSS_COLORARG0];
+            if (used_c & 0x2) key.ts[s].colorarg1 = state->ff.tex_stage[s][D3DTSS_COLORARG1];
+            if (used_c & 0x4) key.ts[s].colorarg2 = state->ff.tex_stage[s][D3DTSS_COLORARG2];
+            if (used_c & 0x1) key.colorarg_b4[0] |= (state->ff.tex_stage[s][D3DTSS_COLORARG0] >> 4) << s;
+            if (used_c & 0x1) key.colorarg_b5[0] |= (state->ff.tex_stage[s][D3DTSS_COLORARG0] >> 5) << s;
+            if (used_c & 0x2) key.colorarg_b4[1] |= (state->ff.tex_stage[s][D3DTSS_COLORARG1] >> 4) << s;
+            if (used_c & 0x2) key.colorarg_b5[1] |= (state->ff.tex_stage[s][D3DTSS_COLORARG1] >> 5) << s;
+            if (used_c & 0x4) key.colorarg_b4[2] |= (state->ff.tex_stage[s][D3DTSS_COLORARG2] >> 4) << s;
+            if (used_c & 0x4) key.colorarg_b5[2] |= (state->ff.tex_stage[s][D3DTSS_COLORARG2] >> 5) << s;
+        }
+        if (key.ts[s].alphaop != D3DTOP_DISABLE) {
+            uint8_t used_a = ps_d3dtop_args_mask(key.ts[s].alphaop);
+            if (used_a & 0x1) key.ts[s].alphaarg0 = state->ff.tex_stage[s][D3DTSS_ALPHAARG0];
+            if (used_a & 0x2) key.ts[s].alphaarg1 = state->ff.tex_stage[s][D3DTSS_ALPHAARG1];
+            if (used_a & 0x4) key.ts[s].alphaarg2 = state->ff.tex_stage[s][D3DTSS_ALPHAARG2];
+            if (used_a & 0x1) key.alphaarg_b4[0] |= (state->ff.tex_stage[s][D3DTSS_ALPHAARG0] >> 4) << s;
+            if (used_a & 0x2) key.alphaarg_b4[1] |= (state->ff.tex_stage[s][D3DTSS_ALPHAARG1] >> 4) << s;
+            if (used_a & 0x4) key.alphaarg_b4[2] |= (state->ff.tex_stage[s][D3DTSS_ALPHAARG2] >> 4) << s;
+        }
+        key.ts[s].resultarg = state->ff.tex_stage[s][D3DTSS_RESULTARG] == D3DTA_TEMP;
+
+        key.ts[s].projected = !!(state->ff.tex_stage[s][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED);
+
+        if (state->texture[s]) {
+            switch (state->texture[s]->base.type) {
+            case D3DRTYPE_TEXTURE:       key.ts[s].textarget = 1; break;
+            case D3DRTYPE_VOLUMETEXTURE: key.ts[s].textarget = 2; break;
+            case D3DRTYPE_CUBETEXTURE:   key.ts[s].textarget = 3; break;
+            default:
+                assert(!"unexpected texture type");
+                break;
+            }
+        } else {
+            key.ts[s].textarget = 1;
+        }
+    }
+    for (; s < 8; ++s)
+        key.ts[s].colorop = key.ts[s].alphaop = D3DTOP_DISABLE;
+    if (state->rs[D3DRS_FOGENABLE])
+        key.fog_mode = state->rs[D3DRS_FOGTABLEMODE];
+
+    ps = util_hash_table_get(device->ff.ht_ps, &key);
+    if (ps)
+        return ps;
+    NinePixelShader9_new(device, &ps, NULL, nine_ff_build_ps(device, &key));
+
+    nine_ff_prune_ps(device);
+    if (ps) {
+        memcpy(&ps->ff_key, &key, sizeof(ps->ff_key));
+
+        err = util_hash_table_set(device->ff.ht_ps, &ps->ff_key, ps);
+        assert(err == PIPE_OK);
+        device->ff.num_ps++;
+        NineUnknown_ConvertRefToBind(NineUnknown(ps));
+
+        ps->rt_mask = 0x1;
+    }
+    return ps;
+}
+
+#define GET_D3DTS(n) nine_state_access_transform(state, D3DTS_##n, FALSE)
+#define IS_D3DTS_DIRTY(s,n) ((s)->ff.changed.transform[(D3DTS_##n) / 32] & (1 << ((D3DTS_##n) % 32)))
+static void
+nine_ff_load_vs_transforms(struct NineDevice9 *device)
+{
+    struct nine_state *state = &device->state;
+    D3DMATRIX T;
+    D3DMATRIX *M = (D3DMATRIX *)device->ff.vs_const;
+    unsigned i;
+
+    /* TODO: make this nicer, and only upload the ones we need */
+    /* TODO: use ff.vs_const as storage of W, V, P matrices */
+
+    if (IS_D3DTS_DIRTY(state, WORLD) ||
+        IS_D3DTS_DIRTY(state, VIEW) ||
+        IS_D3DTS_DIRTY(state, PROJECTION)) {
+        /* WVP, WV matrices */
+        nine_d3d_matrix_matrix_mul(&M[1], GET_D3DTS(WORLD), GET_D3DTS(VIEW));
+        nine_d3d_matrix_matrix_mul(&M[0], &M[1], GET_D3DTS(PROJECTION));
+
+        /* normal matrix == transpose(inverse(WV)) */
+        nine_d3d_matrix_inverse_3x3(&T, &M[1]);
+        nine_d3d_matrix_transpose(&M[4], &T);
+
+        /* VP matrix */
+        nine_d3d_matrix_matrix_mul(&M[2], GET_D3DTS(VIEW), GET_D3DTS(PROJECTION));
+
+        /* V and W matrix */
+        M[3] = *GET_D3DTS(VIEW);
+        M[56] = *GET_D3DTS(WORLD);
+    }
+
+    if (state->rs[D3DRS_VERTEXBLEND] != D3DVBF_DISABLE) {
+        /* load other world matrices */
+        for (i = 1; i <= 7; ++i)
+            M[56 + i] = *GET_D3DTS(WORLDMATRIX(i));
+    }
+
+    device->ff.vs_const[30 * 4] = asfloat(state->rs[D3DRS_TWEENFACTOR]);
+}
+
+static void
+nine_ff_load_lights(struct NineDevice9 *device)
+{
+    struct nine_state *state = &device->state;
+    struct fvec4 *dst = (struct fvec4 *)device->ff.vs_const;
+    unsigned l;
+
+    if (state->changed.group & NINE_STATE_FF_MATERIAL) {
+        const D3DMATERIAL9 *mtl = &state->ff.material;
+
+        memcpy(&dst[20], &mtl->Diffuse, 4 * sizeof(float));
+        memcpy(&dst[21], &mtl->Ambient, 4 * sizeof(float));
+        memcpy(&dst[22], &mtl->Specular, 4 * sizeof(float));
+        dst[23].x = mtl->Power;
+        memcpy(&dst[24], &mtl->Emissive, 4 * sizeof(float));
+        d3dcolor_to_rgba(&dst[25].x, state->rs[D3DRS_AMBIENT]);
+        dst[19].x = dst[25].x * mtl->Ambient.r + mtl->Emissive.r;
+        dst[19].y = dst[25].y * mtl->Ambient.g + mtl->Emissive.g;
+        dst[19].z = dst[25].z * mtl->Ambient.b + mtl->Emissive.b;
+        dst[19].w = mtl->Ambient.a + mtl->Emissive.a;
+    }
+
+    if (!(state->changed.group & NINE_STATE_FF_LIGHTING))
+        return;
+
+    for (l = 0; l < state->ff.num_lights_active; ++l) {
+        const D3DLIGHT9 *light = &state->ff.light[state->ff.active_light[l]];
+
+        dst[32 + l * 8].x = light->Type;
+        dst[32 + l * 8].y = light->Attenuation0;
+        dst[32 + l * 8].z = light->Attenuation1;
+        dst[32 + l * 8].w = light->Attenuation2;
+        memcpy(&dst[33 + l * 8].x, &light->Diffuse, sizeof(light->Diffuse));
+        memcpy(&dst[34 + l * 8].x, &light->Specular, sizeof(light->Specular));
+        memcpy(&dst[35 + l * 8].x, &light->Ambient, sizeof(light->Ambient));
+        nine_d3d_vector4_matrix_mul((D3DVECTOR *)&dst[36 + l * 8].x, &light->Position, GET_D3DTS(VIEW));
+        nine_d3d_vector3_matrix_mul((D3DVECTOR *)&dst[37 + l * 8].x, &light->Direction, GET_D3DTS(VIEW));
+        dst[36 + l * 8].w = light->Type == D3DLIGHT_DIRECTIONAL ? 1e9f : light->Range;
+        dst[37 + l * 8].w = light->Falloff;
+        dst[38 + l * 8].x = cosf(light->Theta * 0.5f);
+        dst[38 + l * 8].y = cosf(light->Phi * 0.5f);
+        dst[38 + l * 8].z = 1.0f / (dst[38 + l * 8].x - dst[38 + l * 8].y);
+        dst[39 + l * 8].w = (l + 1) == state->ff.num_lights_active;
+    }
+}
+
+static void
+nine_ff_load_point_and_fog_params(struct NineDevice9 *device)
+{
+    const struct nine_state *state = &device->state;
+    struct fvec4 *dst = (struct fvec4 *)device->ff.vs_const;
+
+    if (!(state->changed.group & NINE_STATE_FF_OTHER))
+        return;
+    dst[26].x = asfloat(state->rs[D3DRS_POINTSIZE_MIN]);
+    dst[26].y = asfloat(state->rs[D3DRS_POINTSIZE_MAX]);
+    dst[26].z = asfloat(state->rs[D3DRS_POINTSIZE]);
+    dst[26].w = asfloat(state->rs[D3DRS_POINTSCALE_A]);
+    dst[27].x = asfloat(state->rs[D3DRS_POINTSCALE_B]);
+    dst[27].y = asfloat(state->rs[D3DRS_POINTSCALE_C]);
+    dst[28].x = asfloat(state->rs[D3DRS_FOGEND]);
+    dst[28].y = 1.0f / (asfloat(state->rs[D3DRS_FOGEND]) - asfloat(state->rs[D3DRS_FOGSTART]));
+    if (isinf(dst[28].y))
+        dst[28].y = 0.0f;
+    dst[28].z = asfloat(state->rs[D3DRS_FOGDENSITY]);
+    d3dcolor_to_rgba(&dst[29].x, state->rs[D3DRS_FOGCOLOR]);
+}
+
+static void
+nine_ff_load_tex_matrices(struct NineDevice9 *device)
+{
+    struct nine_state *state = &device->state;
+    D3DMATRIX *M = (D3DMATRIX *)device->ff.vs_const;
+    unsigned s;
+
+    if (!(state->ff.changed.transform[0] & 0xff0000))
+        return;
+    for (s = 0; s < 8; ++s) {
+        if (IS_D3DTS_DIRTY(state, TEXTURE0 + s))
+            M[32 + s] = *nine_state_access_transform(state, D3DTS_TEXTURE0 + s, FALSE);
+    }
+}
+
+static void
+nine_ff_load_ps_params(struct NineDevice9 *device)
+{
+    const struct nine_state *state = &device->state;
+    struct fvec4 *dst = (struct fvec4 *)device->ff.ps_const;
+    unsigned s;
+
+    if (!(state->changed.group & (NINE_STATE_FF_PSSTAGES | NINE_STATE_FF_OTHER)))
+        return;
+
+    for (s = 0; s < 8; ++s)
+        d3dcolor_to_rgba(&dst[s].x, state->ff.tex_stage[s][D3DTSS_CONSTANT]);
+
+    for (s = 0; s < 8; ++s) {
+        dst[8 + s].x = asfloat(state->ff.tex_stage[s][D3DTSS_BUMPENVMAT00]);
+        dst[8 + s].y = asfloat(state->ff.tex_stage[s][D3DTSS_BUMPENVMAT01]);
+        dst[8 + s].z = asfloat(state->ff.tex_stage[s][D3DTSS_BUMPENVMAT10]);
+        dst[8 + s].w = asfloat(state->ff.tex_stage[s][D3DTSS_BUMPENVMAT11]);
+        if (s & 1) {
+            dst[8 + s / 2].z = asfloat(state->ff.tex_stage[s][D3DTSS_BUMPENVLSCALE]);
+            dst[8 + s / 2].w = asfloat(state->ff.tex_stage[s][D3DTSS_BUMPENVLOFFSET]);
+        } else {
+            dst[8 + s / 2].x = asfloat(state->ff.tex_stage[s][D3DTSS_BUMPENVLSCALE]);
+            dst[8 + s / 2].y = asfloat(state->ff.tex_stage[s][D3DTSS_BUMPENVLOFFSET]);
+        }
+    }
+
+    d3dcolor_to_rgba(&dst[20].x, state->rs[D3DRS_TEXTUREFACTOR]);
+    d3dcolor_to_rgba(&dst[21].x, state->rs[D3DRS_FOGCOLOR]);
+    dst[22].x = asfloat(state->rs[D3DRS_FOGEND]);
+    dst[22].y = 1.0f / (asfloat(state->rs[D3DRS_FOGEND]) - asfloat(state->rs[D3DRS_FOGSTART]));
+    dst[22].z = asfloat(state->rs[D3DRS_FOGDENSITY]);
+}
+
+static void
+nine_ff_load_viewport_info(struct NineDevice9 *device)
+{
+    D3DVIEWPORT9 *viewport = &device->state.viewport;
+    struct fvec4 *dst = (struct fvec4 *)device->ff.vs_const;
+    float diffZ = viewport->MaxZ - viewport->MinZ;
+
+    /* Note: the other functions avoids to fill the const again if nothing changed.
+     * But we don't have much to fill, and adding code to allow that may be complex
+     * so just fill it always */
+    dst[100].x = 2.0f / (float)(viewport->Width);
+    dst[100].y = 2.0f / (float)(viewport->Height);
+    dst[100].z = (diffZ == 0.0f) ? 0.0f : (1.0f / diffZ);
+    dst[101].x = (float)(viewport->X);
+    dst[101].y = (float)(viewport->Y);
+    dst[101].z = (float)(viewport->MinZ);
+}
+
+void
+nine_ff_update(struct NineDevice9 *device)
+{
+    struct pipe_context *pipe = device->pipe;
+    struct nine_state *state = &device->state;
+
+    DBG("vs=%p ps=%p\n", device->state.vs, device->state.ps);
+
+    /* NOTE: the only reference belongs to the hash table */
+    if (!device->state.vs)
+        device->ff.vs = nine_ff_get_vs(device);
+    if (!device->state.ps)
+        device->ff.ps = nine_ff_get_ps(device);
+
+    if (!device->state.vs) {
+        if (device->state.ff.clobber.vs_const) {
+            device->state.ff.clobber.vs_const = FALSE;
+            device->state.changed.group |=
+                NINE_STATE_FF_VSTRANSF |
+                NINE_STATE_FF_MATERIAL |
+                NINE_STATE_FF_LIGHTING |
+                NINE_STATE_FF_OTHER;
+            device->state.ff.changed.transform[0] |= 0xff000c;
+            device->state.ff.changed.transform[8] |= 0xff;
+        }
+        nine_ff_load_vs_transforms(device);
+        nine_ff_load_tex_matrices(device);
+        nine_ff_load_lights(device);
+        nine_ff_load_point_and_fog_params(device);
+        nine_ff_load_viewport_info(device);
+
+        memset(state->ff.changed.transform, 0, sizeof(state->ff.changed.transform));
+
+        device->state.changed.group |= NINE_STATE_VS;
+        device->state.changed.group |= NINE_STATE_VS_CONST;
+
+        if (device->prefer_user_constbuf) {
+            struct pipe_context *pipe = device->pipe;
+            struct pipe_constant_buffer cb;
+            cb.buffer_offset = 0;
+            cb.buffer = NULL;
+            cb.user_buffer = device->ff.vs_const;
+            cb.buffer_size = NINE_FF_NUM_VS_CONST * 4 * sizeof(float);
+            pipe->set_constant_buffer(pipe, PIPE_SHADER_VERTEX, 0, &cb);
+        } else {
+            struct pipe_box box;
+            u_box_1d(0, NINE_FF_NUM_VS_CONST * 4 * sizeof(float), &box);
+            pipe->transfer_inline_write(pipe, device->constbuf_vs, 0,
+                                        0, &box,
+                                        device->ff.vs_const, 0, 0);
+            nine_ranges_insert(&device->state.changed.vs_const_f, 0, NINE_FF_NUM_VS_CONST,
+                               &device->range_pool);
+        }
+    }
+
+    if (!device->state.ps) {
+        if (device->state.ff.clobber.ps_const) {
+            device->state.ff.clobber.ps_const = FALSE;
+            device->state.changed.group |=
+                NINE_STATE_FF_PSSTAGES |
+                NINE_STATE_FF_OTHER;
+        }
+        nine_ff_load_ps_params(device);
+
+        device->state.changed.group |= NINE_STATE_PS;
+        device->state.changed.group |= NINE_STATE_PS_CONST;
+
+        if (device->prefer_user_constbuf) {
+            struct pipe_context *pipe = device->pipe;
+            struct pipe_constant_buffer cb;
+            cb.buffer_offset = 0;
+            cb.buffer = NULL;
+            cb.user_buffer = device->ff.ps_const;
+            cb.buffer_size = NINE_FF_NUM_PS_CONST * 4 * sizeof(float);
+            pipe->set_constant_buffer(pipe, PIPE_SHADER_FRAGMENT, 0, &cb);
+        } else {
+            struct pipe_box box;
+            u_box_1d(0, NINE_FF_NUM_PS_CONST * 4 * sizeof(float), &box);
+            pipe->transfer_inline_write(pipe, device->constbuf_ps, 0,
+                                        0, &box,
+                                        device->ff.ps_const, 0, 0);
+            nine_ranges_insert(&device->state.changed.ps_const_f, 0, NINE_FF_NUM_PS_CONST,
+                               &device->range_pool);
+        }
+    }
+
+    device->state.changed.group &= ~NINE_STATE_FF;
+}
+
+
+boolean
+nine_ff_init(struct NineDevice9 *device)
+{
+    device->ff.ht_vs = util_hash_table_create(nine_ff_vs_key_hash,
+                                              nine_ff_vs_key_comp);
+    device->ff.ht_ps = util_hash_table_create(nine_ff_ps_key_hash,
+                                              nine_ff_ps_key_comp);
+
+    device->ff.ht_fvf = util_hash_table_create(nine_ff_fvf_key_hash,
+                                               nine_ff_fvf_key_comp);
+
+    device->ff.vs_const = CALLOC(NINE_FF_NUM_VS_CONST, 4 * sizeof(float));
+    device->ff.ps_const = CALLOC(NINE_FF_NUM_PS_CONST, 4 * sizeof(float));
+
+    return device->ff.ht_vs && device->ff.ht_ps &&
+        device->ff.ht_fvf &&
+        device->ff.vs_const && device->ff.ps_const;
+}
+
+static enum pipe_error nine_ff_ht_delete_cb(void *key, void *value, void *data)
+{
+    NineUnknown_Unbind(NineUnknown(value));
+    return PIPE_OK;
+}
+
+void
+nine_ff_fini(struct NineDevice9 *device)
+{
+    if (device->ff.ht_vs) {
+        util_hash_table_foreach(device->ff.ht_vs, nine_ff_ht_delete_cb, NULL);
+        util_hash_table_destroy(device->ff.ht_vs);
+    }
+    if (device->ff.ht_ps) {
+        util_hash_table_foreach(device->ff.ht_ps, nine_ff_ht_delete_cb, NULL);
+        util_hash_table_destroy(device->ff.ht_ps);
+    }
+    if (device->ff.ht_fvf) {
+        util_hash_table_foreach(device->ff.ht_fvf, nine_ff_ht_delete_cb, NULL);
+        util_hash_table_destroy(device->ff.ht_fvf);
+    }
+    device->ff.vs = NULL; /* destroyed by unbinding from hash table */
+    device->ff.ps = NULL;
+
+    FREE(device->ff.vs_const);
+    FREE(device->ff.ps_const);
+}
+
+static void
+nine_ff_prune_vs(struct NineDevice9 *device)
+{
+    if (device->ff.num_vs > 100) {
+        /* could destroy the bound one here, so unbind */
+        device->pipe->bind_vs_state(device->pipe, NULL);
+        util_hash_table_foreach(device->ff.ht_vs, nine_ff_ht_delete_cb, NULL);
+        util_hash_table_clear(device->ff.ht_vs);
+        device->ff.num_vs = 0;
+        device->state.changed.group |= NINE_STATE_VS;
+    }
+}
+static void
+nine_ff_prune_ps(struct NineDevice9 *device)
+{
+    if (device->ff.num_ps > 100) {
+        /* could destroy the bound one here, so unbind */
+        device->pipe->bind_fs_state(device->pipe, NULL);
+        util_hash_table_foreach(device->ff.ht_ps, nine_ff_ht_delete_cb, NULL);
+        util_hash_table_clear(device->ff.ht_ps);
+        device->ff.num_ps = 0;
+        device->state.changed.group |= NINE_STATE_PS;
+    }
+}
+
+/* ========================================================================== */
+
+/* Matrix multiplication:
+ *
+ * in memory: 0 1 2 3 (row major)
+ *            4 5 6 7
+ *            8 9 a b
+ *            c d e f
+ *
+ *    cA cB cC cD
+ * r0             = (r0 * cA) (r0 * cB) . .
+ * r1             = (r1 * cA) (r1 * cB)
+ * r2             = (r2 * cA) .
+ * r3             = (r3 * cA) .
+ *
+ *               r: (11) (12) (13) (14)
+ *                  (21) (22) (23) (24)
+ *                  (31) (32) (33) (34)
+ *                  (41) (42) (43) (44)
+ * l: (11 12 13 14)
+ *    (21 22 23 24)
+ *    (31 32 33 34)
+ *    (41 42 43 44)
+ *
+ * v: (x  y  z  1 )
+ *
+ * t.xyzw = MUL(v.xxxx, r[0]);
+ * t.xyzw = MAD(v.yyyy, r[1], t.xyzw);
+ * t.xyzw = MAD(v.zzzz, r[2], t.xyzw);
+ * v.xyzw = MAD(v.wwww, r[3], t.xyzw);
+ *
+ * v.x = DP4(v, c[0]);
+ * v.y = DP4(v, c[1]);
+ * v.z = DP4(v, c[2]);
+ * v.w = DP4(v, c[3]) = 1
+ */
+
+/*
+static void
+nine_D3DMATRIX_print(const D3DMATRIX *M)
+{
+    DBG("\n(%f %f %f %f)\n"
+        "(%f %f %f %f)\n"
+        "(%f %f %f %f)\n"
+        "(%f %f %f %f)\n",
+        M->m[0][0], M->m[0][1], M->m[0][2], M->m[0][3],
+        M->m[1][0], M->m[1][1], M->m[1][2], M->m[1][3],
+        M->m[2][0], M->m[2][1], M->m[2][2], M->m[2][3],
+        M->m[3][0], M->m[3][1], M->m[3][2], M->m[3][3]);
+}
+*/
+
+static INLINE float
+nine_DP4_row_col(const D3DMATRIX *A, int r, const D3DMATRIX *B, int c)
+{
+    return A->m[r][0] * B->m[0][c] +
+           A->m[r][1] * B->m[1][c] +
+           A->m[r][2] * B->m[2][c] +
+           A->m[r][3] * B->m[3][c];
+}
+
+static INLINE float
+nine_DP4_vec_col(const D3DVECTOR *v, const D3DMATRIX *M, int c)
+{
+    return v->x * M->m[0][c] +
+           v->y * M->m[1][c] +
+           v->z * M->m[2][c] +
+           1.0f * M->m[3][c];
+}
+
+static INLINE float
+nine_DP3_vec_col(const D3DVECTOR *v, const D3DMATRIX *M, int c)
+{
+    return v->x * M->m[0][c] +
+           v->y * M->m[1][c] +
+           v->z * M->m[2][c];
+}
+
+void
+nine_d3d_matrix_matrix_mul(D3DMATRIX *D, const D3DMATRIX *L, const D3DMATRIX *R)
+{
+    D->_11 = nine_DP4_row_col(L, 0, R, 0);
+    D->_12 = nine_DP4_row_col(L, 0, R, 1);
+    D->_13 = nine_DP4_row_col(L, 0, R, 2);
+    D->_14 = nine_DP4_row_col(L, 0, R, 3);
+
+    D->_21 = nine_DP4_row_col(L, 1, R, 0);
+    D->_22 = nine_DP4_row_col(L, 1, R, 1);
+    D->_23 = nine_DP4_row_col(L, 1, R, 2);
+    D->_24 = nine_DP4_row_col(L, 1, R, 3);
+
+    D->_31 = nine_DP4_row_col(L, 2, R, 0);
+    D->_32 = nine_DP4_row_col(L, 2, R, 1);
+    D->_33 = nine_DP4_row_col(L, 2, R, 2);
+    D->_34 = nine_DP4_row_col(L, 2, R, 3);
+
+    D->_41 = nine_DP4_row_col(L, 3, R, 0);
+    D->_42 = nine_DP4_row_col(L, 3, R, 1);
+    D->_43 = nine_DP4_row_col(L, 3, R, 2);
+    D->_44 = nine_DP4_row_col(L, 3, R, 3);
+}
+
+void
+nine_d3d_vector4_matrix_mul(D3DVECTOR *d, const D3DVECTOR *v, const D3DMATRIX *M)
+{
+    d->x = nine_DP4_vec_col(v, M, 0);
+    d->y = nine_DP4_vec_col(v, M, 1);
+    d->z = nine_DP4_vec_col(v, M, 2);
+}
+
+void
+nine_d3d_vector3_matrix_mul(D3DVECTOR *d, const D3DVECTOR *v, const D3DMATRIX *M)
+{
+    d->x = nine_DP3_vec_col(v, M, 0);
+    d->y = nine_DP3_vec_col(v, M, 1);
+    d->z = nine_DP3_vec_col(v, M, 2);
+}
+
+void
+nine_d3d_matrix_transpose(D3DMATRIX *D, const D3DMATRIX *M)
+{
+    unsigned i, j;
+    for (i = 0; i < 4; ++i)
+    for (j = 0; j < 4; ++j)
+        D->m[i][j] = M->m[j][i];
+}
+
+#define _M_ADD_PROD_1i_2j_3k_4l(i,j,k,l) do {            \
+    float t = M->_1##i * M->_2##j * M->_3##k * M->_4##l; \
+    if (t > 0.0f) pos += t; else neg += t; } while(0)
+
+#define _M_SUB_PROD_1i_2j_3k_4l(i,j,k,l) do {            \
+    float t = M->_1##i * M->_2##j * M->_3##k * M->_4##l; \
+    if (t > 0.0f) neg -= t; else pos -= t; } while(0)
+float
+nine_d3d_matrix_det(const D3DMATRIX *M)
+{
+    float pos = 0.0f;
+    float neg = 0.0f;
+
+    _M_ADD_PROD_1i_2j_3k_4l(1, 2, 3, 4);
+    _M_ADD_PROD_1i_2j_3k_4l(1, 3, 4, 2);
+    _M_ADD_PROD_1i_2j_3k_4l(1, 4, 2, 3);
+
+    _M_ADD_PROD_1i_2j_3k_4l(2, 1, 4, 3);
+    _M_ADD_PROD_1i_2j_3k_4l(2, 3, 1, 4);
+    _M_ADD_PROD_1i_2j_3k_4l(2, 4, 3, 1);
+
+    _M_ADD_PROD_1i_2j_3k_4l(3, 1, 2, 4);
+    _M_ADD_PROD_1i_2j_3k_4l(3, 2, 4, 1);
+    _M_ADD_PROD_1i_2j_3k_4l(3, 4, 1, 2);
+
+    _M_ADD_PROD_1i_2j_3k_4l(4, 1, 3, 2);
+    _M_ADD_PROD_1i_2j_3k_4l(4, 2, 1, 3);
+    _M_ADD_PROD_1i_2j_3k_4l(4, 3, 2, 1);
+
+    _M_SUB_PROD_1i_2j_3k_4l(1, 2, 4, 3);
+    _M_SUB_PROD_1i_2j_3k_4l(1, 3, 2, 4);
+    _M_SUB_PROD_1i_2j_3k_4l(1, 4, 3, 2);
+
+    _M_SUB_PROD_1i_2j_3k_4l(2, 1, 3, 4);
+    _M_SUB_PROD_1i_2j_3k_4l(2, 3, 4, 1);
+    _M_SUB_PROD_1i_2j_3k_4l(2, 4, 1, 3);
+
+    _M_SUB_PROD_1i_2j_3k_4l(3, 1, 4, 2);
+    _M_SUB_PROD_1i_2j_3k_4l(3, 2, 1, 4);
+    _M_SUB_PROD_1i_2j_3k_4l(3, 4, 2, 1);
+
+    _M_SUB_PROD_1i_2j_3k_4l(4, 1, 2, 3);
+    _M_SUB_PROD_1i_2j_3k_4l(4, 2, 3, 1);
+    _M_SUB_PROD_1i_2j_3k_4l(4, 3, 1, 2);
+
+    return pos + neg;
+}
+
+/* XXX: Probably better to just use src/mesa/math/m_matrix.c because
+ * I have no idea where this code came from.
+ */
+void
+nine_d3d_matrix_inverse(D3DMATRIX *D, const D3DMATRIX *M)
+{
+    int i, k;
+    float det;
+
+    D->m[0][0] =
+        M->m[1][1] * M->m[2][2] * M->m[3][3] -
+        M->m[1][1] * M->m[3][2] * M->m[2][3] -
+        M->m[1][2] * M->m[2][1] * M->m[3][3] +
+        M->m[1][2] * M->m[3][1] * M->m[2][3] +
+        M->m[1][3] * M->m[2][1] * M->m[3][2] -
+        M->m[1][3] * M->m[3][1] * M->m[2][2];
+
+    D->m[0][1] =
+       -M->m[0][1] * M->m[2][2] * M->m[3][3] +
+        M->m[0][1] * M->m[3][2] * M->m[2][3] +
+        M->m[0][2] * M->m[2][1] * M->m[3][3] -
+        M->m[0][2] * M->m[3][1] * M->m[2][3] -
+        M->m[0][3] * M->m[2][1] * M->m[3][2] +
+        M->m[0][3] * M->m[3][1] * M->m[2][2];
+
+    D->m[0][2] =
+        M->m[0][1] * M->m[1][2] * M->m[3][3] -
+        M->m[0][1] * M->m[3][2] * M->m[1][3] -
+        M->m[0][2] * M->m[1][1] * M->m[3][3] +
+        M->m[0][2] * M->m[3][1] * M->m[1][3] +
+        M->m[0][3] * M->m[1][1] * M->m[3][2] -
+        M->m[0][3] * M->m[3][1] * M->m[1][2];
+
+    D->m[0][3] =
+       -M->m[0][1] * M->m[1][2] * M->m[2][3] +
+        M->m[0][1] * M->m[2][2] * M->m[1][3] +
+        M->m[0][2] * M->m[1][1] * M->m[2][3] -
+        M->m[0][2] * M->m[2][1] * M->m[1][3] -
+        M->m[0][3] * M->m[1][1] * M->m[2][2] +
+        M->m[0][3] * M->m[2][1] * M->m[1][2];
+
+    D->m[1][0] =
+       -M->m[1][0] * M->m[2][2] * M->m[3][3] +
+        M->m[1][0] * M->m[3][2] * M->m[2][3] +
+        M->m[1][2] * M->m[2][0] * M->m[3][3] -
+        M->m[1][2] * M->m[3][0] * M->m[2][3] -
+        M->m[1][3] * M->m[2][0] * M->m[3][2] +
+        M->m[1][3] * M->m[3][0] * M->m[2][2];
+
+    D->m[1][1] =
+        M->m[0][0] * M->m[2][2] * M->m[3][3] -
+        M->m[0][0] * M->m[3][2] * M->m[2][3] -
+        M->m[0][2] * M->m[2][0] * M->m[3][3] +
+        M->m[0][2] * M->m[3][0] * M->m[2][3] +
+        M->m[0][3] * M->m[2][0] * M->m[3][2] -
+        M->m[0][3] * M->m[3][0] * M->m[2][2];
+
+    D->m[1][2] =
+       -M->m[0][0] * M->m[1][2] * M->m[3][3] +
+        M->m[0][0] * M->m[3][2] * M->m[1][3] +
+        M->m[0][2] * M->m[1][0] * M->m[3][3] -
+        M->m[0][2] * M->m[3][0] * M->m[1][3] -
+        M->m[0][3] * M->m[1][0] * M->m[3][2] +
+        M->m[0][3] * M->m[3][0] * M->m[1][2];
+
+    D->m[1][3] =
+        M->m[0][0] * M->m[1][2] * M->m[2][3] -
+        M->m[0][0] * M->m[2][2] * M->m[1][3] -
+        M->m[0][2] * M->m[1][0] * M->m[2][3] +
+        M->m[0][2] * M->m[2][0] * M->m[1][3] +
+        M->m[0][3] * M->m[1][0] * M->m[2][2] -
+        M->m[0][3] * M->m[2][0] * M->m[1][2];
+
+    D->m[2][0] =
+        M->m[1][0] * M->m[2][1] * M->m[3][3] -
+        M->m[1][0] * M->m[3][1] * M->m[2][3] -
+        M->m[1][1] * M->m[2][0] * M->m[3][3] +
+        M->m[1][1] * M->m[3][0] * M->m[2][3] +
+        M->m[1][3] * M->m[2][0] * M->m[3][1] -
+        M->m[1][3] * M->m[3][0] * M->m[2][1];
+
+    D->m[2][1] =
+       -M->m[0][0] * M->m[2][1] * M->m[3][3] +
+        M->m[0][0] * M->m[3][1] * M->m[2][3] +
+        M->m[0][1] * M->m[2][0] * M->m[3][3] -
+        M->m[0][1] * M->m[3][0] * M->m[2][3] -
+        M->m[0][3] * M->m[2][0] * M->m[3][1] +
+        M->m[0][3] * M->m[3][0] * M->m[2][1];
+
+    D->m[2][2] =
+        M->m[0][0] * M->m[1][1] * M->m[3][3] -
+        M->m[0][0] * M->m[3][1] * M->m[1][3] -
+        M->m[0][1] * M->m[1][0] * M->m[3][3] +
+        M->m[0][1] * M->m[3][0] * M->m[1][3] +
+        M->m[0][3] * M->m[1][0] * M->m[3][1] -
+        M->m[0][3] * M->m[3][0] * M->m[1][1];
+
+    D->m[2][3] =
+       -M->m[0][0] * M->m[1][1] * M->m[2][3] +
+        M->m[0][0] * M->m[2][1] * M->m[1][3] +
+        M->m[0][1] * M->m[1][0] * M->m[2][3] -
+        M->m[0][1] * M->m[2][0] * M->m[1][3] -
+        M->m[0][3] * M->m[1][0] * M->m[2][1] +
+        M->m[0][3] * M->m[2][0] * M->m[1][1];
+
+    D->m[3][0] =
+       -M->m[1][0] * M->m[2][1] * M->m[3][2] +
+        M->m[1][0] * M->m[3][1] * M->m[2][2] +
+        M->m[1][1] * M->m[2][0] * M->m[3][2] -
+        M->m[1][1] * M->m[3][0] * M->m[2][2] -
+        M->m[1][2] * M->m[2][0] * M->m[3][1] +
+        M->m[1][2] * M->m[3][0] * M->m[2][1];
+
+    D->m[3][1] =
+        M->m[0][0] * M->m[2][1] * M->m[3][2] -
+        M->m[0][0] * M->m[3][1] * M->m[2][2] -
+        M->m[0][1] * M->m[2][0] * M->m[3][2] +
+        M->m[0][1] * M->m[3][0] * M->m[2][2] +
+        M->m[0][2] * M->m[2][0] * M->m[3][1] -
+        M->m[0][2] * M->m[3][0] * M->m[2][1];
+
+    D->m[3][2] =
+       -M->m[0][0] * M->m[1][1] * M->m[3][2] +
+        M->m[0][0] * M->m[3][1] * M->m[1][2] +
+        M->m[0][1] * M->m[1][0] * M->m[3][2] -
+        M->m[0][1] * M->m[3][0] * M->m[1][2] -
+        M->m[0][2] * M->m[1][0] * M->m[3][1] +
+        M->m[0][2] * M->m[3][0] * M->m[1][1];
+
+    D->m[3][3] =
+        M->m[0][0] * M->m[1][1] * M->m[2][2] -
+        M->m[0][0] * M->m[2][1] * M->m[1][2] -
+        M->m[0][1] * M->m[1][0] * M->m[2][2] +
+        M->m[0][1] * M->m[2][0] * M->m[1][2] +
+        M->m[0][2] * M->m[1][0] * M->m[2][1] -
+        M->m[0][2] * M->m[2][0] * M->m[1][1];
+
+    det =
+        M->m[0][0] * D->m[0][0] +
+        M->m[1][0] * D->m[0][1] +
+        M->m[2][0] * D->m[0][2] +
+        M->m[3][0] * D->m[0][3];
+
+    det = 1.0 / det;
+
+    for (i = 0; i < 4; i++)
+    for (k = 0; k < 4; k++)
+        D->m[i][k] *= det;
+
+#ifdef DEBUG
+    {
+        D3DMATRIX I;
+
+        nine_d3d_matrix_matrix_mul(&I, D, M);
+
+        for (i = 0; i < 4; ++i)
+        for (k = 0; k < 4; ++k)
+            if (fabsf(I.m[i][k] - (float)(i == k)) > 1e-3)
+                DBG("Matrix inversion check FAILED !\n");
+    }
+#endif
+}
+
+/* TODO: don't use 4x4 inverse, unless this gets all nicely inlined ? */
+void
+nine_d3d_matrix_inverse_3x3(D3DMATRIX *D, const D3DMATRIX *M)
+{
+    D3DMATRIX T;
+    unsigned i, j;
+
+    for (i = 0; i < 3; ++i)
+    for (j = 0; j < 3; ++j)
+        T.m[i][j] = M->m[i][j];
+    for (i = 0; i < 3; ++i) {
+        T.m[i][3] = 0.0f;
+        T.m[3][i] = 0.0f;
+    }
+    T.m[3][3] = 1.0f;
+
+    nine_d3d_matrix_inverse(D, &T);
+}
diff --git a/src/gallium/state_trackers/nine/nine_ff.h b/src/gallium/state_trackers/nine/nine_ff.h
new file mode 100644 (file)
index 0000000..7cefa65
--- /dev/null
@@ -0,0 +1,32 @@
+
+#ifndef _NINE_FF_H_
+#define _NINE_FF_H_
+
+#include "device9.h"
+
+boolean nine_ff_init(struct NineDevice9 *);
+void    nine_ff_fini(struct NineDevice9 *);
+
+void nine_ff_update(struct NineDevice9 *);
+
+void
+nine_d3d_matrix_matrix_mul(D3DMATRIX *, const D3DMATRIX *, const D3DMATRIX *);
+
+void
+nine_d3d_vector4_matrix_mul(D3DVECTOR *, const D3DVECTOR *, const D3DMATRIX *);
+void
+nine_d3d_vector3_matrix_mul(D3DVECTOR *, const D3DVECTOR *, const D3DMATRIX *);
+
+float
+nine_d3d_matrix_det(const D3DMATRIX *);
+
+void
+nine_d3d_matrix_inverse(D3DMATRIX *, const D3DMATRIX *);
+
+void
+nine_d3d_matrix_inverse_3x3(D3DMATRIX *, const D3DMATRIX *);
+
+void
+nine_d3d_matrix_transpose(D3DMATRIX *, const D3DMATRIX *);
+
+#endif /* _NINE_FF_H_ */
diff --git a/src/gallium/state_trackers/nine/nine_helpers.c b/src/gallium/state_trackers/nine/nine_helpers.c
new file mode 100644 (file)
index 0000000..ed179f9
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2013 Christoph Bumiller
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "nine_helpers.h"
+
+static struct nine_range *
+nine_range_pool_more(struct nine_range_pool *pool)
+{
+    struct nine_range *r = MALLOC(64 * sizeof(struct nine_range));
+    int i;
+    assert(!pool->free);
+
+    if (pool->num_slabs == pool->num_slabs_max) {
+        unsigned p = pool->num_slabs_max;
+        unsigned n = pool->num_slabs_max * 2;
+        if (!n)
+            n = 4;
+        pool->slabs = REALLOC(pool->slabs,
+                              p * sizeof(struct nine_range *),
+                              n * sizeof(struct nine_range *));
+        pool->num_slabs_max = n;
+    }
+    pool->free = pool->slabs[pool->num_slabs++] = r;
+
+    for (i = 0; i < 63; ++i, r = r->next)
+        r->next = (struct nine_range *)
+            ((uint8_t *)r + sizeof(struct nine_range));
+    r->next = NULL;
+
+    return pool->free;
+}
+
+static INLINE struct nine_range *
+nine_range_pool_get(struct nine_range_pool *pool, int16_t bgn, int16_t end)
+{
+    struct nine_range *r = pool->free;
+    if (!r)
+        r = nine_range_pool_more(pool);
+    assert(r);
+    pool->free = r->next;
+    r->bgn = bgn;
+    r->end = end;
+    return r;
+}
+
+static INLINE void
+nine_ranges_coalesce(struct nine_range *r, struct nine_range_pool *pool)
+{
+    struct nine_range *n;
+
+    while (r->next && r->end >= r->next->bgn) {
+        n = r->next->next;
+        r->end = (r->end >= r->next->end) ? r->end : r->next->end;
+        nine_range_pool_put(pool, r->next);
+        r->next = n;
+    }
+}
+
+void
+nine_ranges_insert(struct nine_range **head, int16_t bgn, int16_t end,
+                   struct nine_range_pool *pool)
+{
+    struct nine_range *r, **pn = head;
+
+    for (r = *head; r && bgn > r->end; pn = &r->next, r = r->next);
+
+    if (!r || end < r->bgn) {
+        *pn = nine_range_pool_get(pool, bgn, end);
+        (*pn)->next = r;
+    } else
+    if (bgn < r->bgn) {
+        r->bgn = bgn;
+        if (end > r->end)
+            r->end = end;
+        nine_ranges_coalesce(r, pool);
+    } else
+    if (end > r->end) {
+        r->end = end;
+        nine_ranges_coalesce(r, pool);
+    }
+}
diff --git a/src/gallium/state_trackers/nine/nine_helpers.h b/src/gallium/state_trackers/nine/nine_helpers.h
new file mode 100644 (file)
index 0000000..e81db79
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _NINE_HELPERS_H_
+#define _NINE_HELPERS_H_
+
+#include "iunknown.h"
+#include "nine_lock.h"
+
+/*
+ * Note: we use these function rather than the MIN2, MAX2, CLAMP macros to
+ * avoid evaluating arguments (which are often function calls) more than once.
+ */
+
+static inline unsigned _min(unsigned a, unsigned b)
+{
+   return (a < b) ? a : b;
+}
+
+
+/* Sshhh ... */
+#define nine_reference(a, b) _nine_reference((void **)(a), (b))
+
+static inline void _nine_reference(void **ref, void *ptr)
+{
+    if (*ref != ptr) {
+        if (*ref)
+            NineUnknown_Release(*ref);
+        if (ptr)
+            NineUnknown_AddRef(ptr);
+        *ref = ptr;
+    }
+}
+
+#define nine_reference_set(a, b) _nine_reference_set((void **)(a), (b))
+
+static inline void _nine_reference_set(void **ref, void *ptr)
+{
+    *ref = ptr;
+    if (ptr)
+        NineUnknown_AddRef(ptr);
+}
+
+#define nine_bind(a, b) _nine_bind((void **)(a), (b))
+
+static inline void _nine_bind(void **dst, void *obj)
+{
+    if (*dst != obj) {
+        if (*dst)
+            NineUnknown_Unbind(*dst);
+        if (obj)
+            NineUnknown_Bind(obj);
+        *dst = obj;
+    }
+}
+
+#define NINE_DEVICE_CHILD_NEW(nine, out, dev, ...) \
+    { \
+        struct NineUnknownParams __params; \
+        struct Nine##nine *__data; \
+         \
+        __data = CALLOC_STRUCT(Nine##nine); \
+        if (!__data) { return E_OUTOFMEMORY; } \
+         \
+        __params.vtable = ((dev)->params.BehaviorFlags & D3DCREATE_MULTITHREADED) ? &Lock##nine##_vtable : &Nine##nine##_vtable; \
+        __params.guids = Nine##nine##_IIDs; \
+        __params.dtor = (void *)Nine##nine##_dtor; \
+        __params.container = NULL; \
+        __params.device = dev; \
+        { \
+            HRESULT __hr = Nine##nine##_ctor(__data, &__params, ## __VA_ARGS__); \
+            if (FAILED(__hr)) { \
+                Nine##nine##_dtor(__data); \
+                return __hr; \
+            } \
+        } \
+         \
+        *(out) = __data; \
+    } \
+    return D3D_OK
+
+#define NINE_NEW(nine, out, lock, ...) \
+    { \
+        struct NineUnknownParams __params; \
+        struct Nine##nine *__data; \
+         \
+        __data = CALLOC_STRUCT(Nine##nine); \
+        if (!__data) { return E_OUTOFMEMORY; } \
+         \
+        __params.vtable = (lock) ? &Lock##nine##_vtable : &Nine##nine##_vtable; \
+        __params.guids = Nine##nine##_IIDs; \
+        __params.dtor = (void *)Nine##nine##_dtor; \
+        __params.container = NULL; \
+        __params.device = NULL; \
+        { \
+            HRESULT __hr = Nine##nine##_ctor(__data, &__params, ## __VA_ARGS__); \
+            if (FAILED(__hr)) { \
+                Nine##nine##_dtor(__data); \
+                return __hr; \
+            } \
+        } \
+         \
+        *(out) = __data; \
+    } \
+    return D3D_OK
+
+static INLINE float asfloat(DWORD value)
+{
+    union {
+        float f;
+        DWORD w;
+    } u;
+    u.w = value;
+    return u.f;
+}
+
+#define CHECK_PIPE_RESOURCE_TEMPLATE(t) \
+    screen->is_format_supported(screen, (t).format, (t).target, (t).nr_samples, (t).bind)
+
+
+struct nine_range
+{
+    struct nine_range *next;
+    int16_t bgn; /* inclusive */
+    int16_t end; /* exclusive */
+};
+
+/* We won't ever need more than 256 ranges, so just allocate once. */
+struct nine_range_pool
+{
+    struct nine_range *free;
+    struct nine_range **slabs;
+    unsigned num_slabs;
+    unsigned num_slabs_max;
+};
+
+static INLINE void
+nine_range_pool_put(struct nine_range_pool *pool, struct nine_range *r)
+{
+    r->next = pool->free;
+    pool->free = r;
+}
+
+static INLINE void
+nine_range_pool_put_chain(struct nine_range_pool *pool,
+                          struct nine_range *head,
+                          struct nine_range *tail)
+{
+    tail->next = pool->free;
+    pool->free = head;
+}
+
+void
+nine_ranges_insert(struct nine_range **head, int16_t bgn, int16_t end,
+                   struct nine_range_pool *pool);
+
+#endif /* _NINE_HELPERS_H_ */
diff --git a/src/gallium/state_trackers/nine/nine_lock.c b/src/gallium/state_trackers/nine/nine_lock.c
new file mode 100644 (file)
index 0000000..42cbb05
--- /dev/null
@@ -0,0 +1,3319 @@
+/*
+ * Copyright 2013 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "authenticatedchannel9.h"
+#include "basetexture9.h"
+#include "cryptosession9.h"
+#include "cubetexture9.h"
+#include "device9.h"
+#include "device9ex.h"
+#include "device9video.h"
+#include "indexbuffer9.h"
+#include "pixelshader9.h"
+#include "query9.h"
+#include "resource9.h"
+#include "stateblock9.h"
+#include "surface9.h"
+#include "swapchain9.h"
+#include "swapchain9ex.h"
+#include "texture9.h"
+#include "vertexbuffer9.h"
+#include "vertexdeclaration9.h"
+#include "vertexshader9.h"
+#include "volume9.h"
+#include "volumetexture9.h"
+
+#include "d3d9.h"
+
+#include "os/os_thread.h"
+
+/* Global mutex as described by MSDN */
+pipe_static_mutex(d3dlock_global);
+
+static HRESULT WINAPI
+LockAuthenticatedChannel9_GetCertificateSize( struct NineAuthenticatedChannel9 *This,
+                                              UINT *pCertificateSize )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineAuthenticatedChannel9_GetCertificateSize(This, pCertificateSize);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockAuthenticatedChannel9_GetCertificate( struct NineAuthenticatedChannel9 *This,
+                                          UINT CertifacteSize,
+                                          BYTE *ppCertificate )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineAuthenticatedChannel9_GetCertificate(This, CertifacteSize, ppCertificate);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockAuthenticatedChannel9_NegotiateKeyExchange( struct NineAuthenticatedChannel9 *This,
+                                                UINT DataSize,
+                                                void *pData )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineAuthenticatedChannel9_NegotiateKeyExchange(This, DataSize, pData);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockAuthenticatedChannel9_Query( struct NineAuthenticatedChannel9 *This,
+                                 UINT InputSize,
+                                 const void *pInput,
+                                 UINT OutputSize,
+                                 void *pOutput )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineAuthenticatedChannel9_Query(This, InputSize, pInput, OutputSize, pOutput);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockAuthenticatedChannel9_Configure( struct NineAuthenticatedChannel9 *This,
+                                     UINT InputSize,
+                                     const void *pInput,
+                                     D3DAUTHENTICATEDCHANNEL_CONFIGURE_OUTPUT *pOutput )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineAuthenticatedChannel9_Configure(This, InputSize, pInput, pOutput);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+IDirect3DAuthenticatedChannel9Vtbl LockAuthenticatedChannel9_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)LockAuthenticatedChannel9_GetCertificateSize,
+    (void *)LockAuthenticatedChannel9_GetCertificate,
+    (void *)LockAuthenticatedChannel9_NegotiateKeyExchange,
+    (void *)LockAuthenticatedChannel9_Query,
+    (void *)LockAuthenticatedChannel9_Configure
+};
+
+#if 0
+static HRESULT WINAPI
+LockResource9_GetDevice( struct NineResource9 *This,
+                         IDirect3DDevice9 **ppDevice )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineUnknown_GetDevice(NineUnknown(This), ppDevice);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+#endif
+
+static HRESULT WINAPI
+LockResource9_SetPrivateData( struct NineResource9 *This,
+                              REFGUID refguid,
+                              const void *pData,
+                              DWORD SizeOfData,
+                              DWORD Flags )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineResource9_SetPrivateData(This, refguid, pData, SizeOfData, Flags);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockResource9_GetPrivateData( struct NineResource9 *This,
+                              REFGUID refguid,
+                              void *pData,
+                              DWORD *pSizeOfData )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineResource9_GetPrivateData(This, refguid, pData, pSizeOfData);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockResource9_FreePrivateData( struct NineResource9 *This,
+                               REFGUID refguid )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineResource9_FreePrivateData(This, refguid);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static DWORD WINAPI
+LockResource9_SetPriority( struct NineResource9 *This,
+                           DWORD PriorityNew )
+{
+    DWORD r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineResource9_SetPriority(This, PriorityNew);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static DWORD WINAPI
+LockResource9_GetPriority( struct NineResource9 *This )
+{
+    DWORD r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineResource9_GetPriority(This);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+#if 0
+static void WINAPI
+LockResource9_PreLoad( struct NineResource9 *This )
+{
+    pipe_mutex_lock(d3dlock_global);
+    NineResource9_PreLoad(This);
+    pipe_mutex_unlock(d3dlock_global);
+}
+#endif
+
+#if 0
+static D3DRESOURCETYPE WINAPI
+LockResource9_GetType( struct NineResource9 *This )
+{
+    D3DRESOURCETYPE r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineResource9_GetType(This);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+#endif
+
+static DWORD WINAPI
+LockBaseTexture9_SetLOD( struct NineBaseTexture9 *This,
+                         DWORD LODNew )
+{
+    DWORD r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineBaseTexture9_SetLOD(This, LODNew);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static DWORD WINAPI
+LockBaseTexture9_GetLOD( struct NineBaseTexture9 *This )
+{
+    DWORD r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineBaseTexture9_GetLOD(This);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static DWORD WINAPI
+LockBaseTexture9_GetLevelCount( struct NineBaseTexture9 *This )
+{
+    DWORD r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineBaseTexture9_GetLevelCount(This);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockBaseTexture9_SetAutoGenFilterType( struct NineBaseTexture9 *This,
+                                       D3DTEXTUREFILTERTYPE FilterType )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineBaseTexture9_SetAutoGenFilterType(This, FilterType);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static D3DTEXTUREFILTERTYPE WINAPI
+LockBaseTexture9_GetAutoGenFilterType( struct NineBaseTexture9 *This )
+{
+    D3DTEXTUREFILTERTYPE r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineBaseTexture9_GetAutoGenFilterType(This);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static void WINAPI
+LockBaseTexture9_PreLoad( struct NineBaseTexture9 *This )
+{
+    pipe_mutex_lock(d3dlock_global);
+    NineBaseTexture9_PreLoad(This);
+    pipe_mutex_unlock(d3dlock_global);
+}
+
+static void WINAPI
+LockBaseTexture9_GenerateMipSubLevels( struct NineBaseTexture9 *This )
+{
+    pipe_mutex_lock(d3dlock_global);
+    NineBaseTexture9_GenerateMipSubLevels(This);
+    pipe_mutex_unlock(d3dlock_global);
+}
+
+static HRESULT WINAPI
+LockCryptoSession9_GetCertificateSize( struct NineCryptoSession9 *This,
+                                       UINT *pCertificateSize )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineCryptoSession9_GetCertificateSize(This, pCertificateSize);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockCryptoSession9_GetCertificate( struct NineCryptoSession9 *This,
+                                   UINT CertifacteSize,
+                                   BYTE *ppCertificate )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineCryptoSession9_GetCertificate(This, CertifacteSize, ppCertificate);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockCryptoSession9_NegotiateKeyExchange( struct NineCryptoSession9 *This,
+                                         UINT DataSize,
+                                         void *pData )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineCryptoSession9_NegotiateKeyExchange(This, DataSize, pData);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockCryptoSession9_EncryptionBlt( struct NineCryptoSession9 *This,
+                                  IDirect3DSurface9 *pSrcSurface,
+                                  IDirect3DSurface9 *pDstSurface,
+                                  UINT DstSurfaceSize,
+                                  void *pIV )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineCryptoSession9_EncryptionBlt(This, pSrcSurface, pDstSurface, DstSurfaceSize, pIV);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockCryptoSession9_DecryptionBlt( struct NineCryptoSession9 *This,
+                                  IDirect3DSurface9 *pSrcSurface,
+                                  IDirect3DSurface9 *pDstSurface,
+                                  UINT SrcSurfaceSize,
+                                  D3DENCRYPTED_BLOCK_INFO *pEncryptedBlockInfo,
+                                  void *pContentKey,
+                                  void *pIV )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineCryptoSession9_DecryptionBlt(This, pSrcSurface, pDstSurface, SrcSurfaceSize, pEncryptedBlockInfo, pContentKey, pIV);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockCryptoSession9_GetSurfacePitch( struct NineCryptoSession9 *This,
+                                    IDirect3DSurface9 *pSrcSurface,
+                                    UINT *pSurfacePitch )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineCryptoSession9_GetSurfacePitch(This, pSrcSurface, pSurfacePitch);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockCryptoSession9_StartSessionKeyRefresh( struct NineCryptoSession9 *This,
+                                           void *pRandomNumber,
+                                           UINT RandomNumberSize )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineCryptoSession9_StartSessionKeyRefresh(This, pRandomNumber, RandomNumberSize);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockCryptoSession9_FinishSessionKeyRefresh( struct NineCryptoSession9 *This )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineCryptoSession9_FinishSessionKeyRefresh(This);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockCryptoSession9_GetEncryptionBltKey( struct NineCryptoSession9 *This,
+                                        void *pReadbackKey,
+                                        UINT KeySize )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineCryptoSession9_GetEncryptionBltKey(This, pReadbackKey, KeySize);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+IDirect3DCryptoSession9Vtbl LockCryptoSession9_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)LockCryptoSession9_GetCertificateSize,
+    (void *)LockCryptoSession9_GetCertificate,
+    (void *)LockCryptoSession9_NegotiateKeyExchange,
+    (void *)LockCryptoSession9_EncryptionBlt,
+    (void *)LockCryptoSession9_DecryptionBlt,
+    (void *)LockCryptoSession9_GetSurfacePitch,
+    (void *)LockCryptoSession9_StartSessionKeyRefresh,
+    (void *)LockCryptoSession9_FinishSessionKeyRefresh,
+    (void *)LockCryptoSession9_GetEncryptionBltKey
+};
+
+#if 0
+static HRESULT WINAPI
+LockCubeTexture9_GetLevelDesc( struct NineCubeTexture9 *This,
+                               UINT Level,
+                               D3DSURFACE_DESC *pDesc )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineCubeTexture9_GetLevelDesc(This, Level, pDesc);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+#endif
+
+#if 0
+static HRESULT WINAPI
+LockCubeTexture9_GetCubeMapSurface( struct NineCubeTexture9 *This,
+                                    D3DCUBEMAP_FACES FaceType,
+                                    UINT Level,
+                                    IDirect3DSurface9 **ppCubeMapSurface )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineCubeTexture9_GetCubeMapSurface(This, FaceType, Level, ppCubeMapSurface);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+#endif
+
+static HRESULT WINAPI
+LockCubeTexture9_LockRect( struct NineCubeTexture9 *This,
+                           D3DCUBEMAP_FACES FaceType,
+                           UINT Level,
+                           D3DLOCKED_RECT *pLockedRect,
+                           const RECT *pRect,
+                           DWORD Flags )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineCubeTexture9_LockRect(This, FaceType, Level, pLockedRect, pRect, Flags);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockCubeTexture9_UnlockRect( struct NineCubeTexture9 *This,
+                             D3DCUBEMAP_FACES FaceType,
+                             UINT Level )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineCubeTexture9_UnlockRect(This, FaceType, Level);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockCubeTexture9_AddDirtyRect( struct NineCubeTexture9 *This,
+                               D3DCUBEMAP_FACES FaceType,
+                               const RECT *pDirtyRect )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineCubeTexture9_AddDirtyRect(This, FaceType, pDirtyRect);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+IDirect3DCubeTexture9Vtbl LockCubeTexture9_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */
+    (void *)LockResource9_SetPrivateData,
+    (void *)LockResource9_GetPrivateData,
+    (void *)LockResource9_FreePrivateData,
+    (void *)LockResource9_SetPriority,
+    (void *)LockResource9_GetPriority,
+    (void *)LockBaseTexture9_PreLoad,
+    (void *)NineResource9_GetType, /* immutable */
+    (void *)LockBaseTexture9_SetLOD,
+    (void *)LockBaseTexture9_GetLOD,
+    (void *)LockBaseTexture9_GetLevelCount,
+    (void *)LockBaseTexture9_SetAutoGenFilterType,
+    (void *)LockBaseTexture9_GetAutoGenFilterType,
+    (void *)LockBaseTexture9_GenerateMipSubLevels,
+    (void *)NineCubeTexture9_GetLevelDesc, /* immutable */
+    (void *)NineCubeTexture9_GetCubeMapSurface, /* AddRef */
+    (void *)LockCubeTexture9_LockRect,
+    (void *)LockCubeTexture9_UnlockRect,
+    (void *)LockCubeTexture9_AddDirtyRect
+};
+
+static HRESULT WINAPI
+LockDevice9_TestCooperativeLevel( struct NineDevice9 *This )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_TestCooperativeLevel(This);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static UINT WINAPI
+LockDevice9_GetAvailableTextureMem( struct NineDevice9 *This )
+{
+    UINT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetAvailableTextureMem(This);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_EvictManagedResources( struct NineDevice9 *This )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_EvictManagedResources(This);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_GetDirect3D( struct NineDevice9 *This,
+                         IDirect3D9 **ppD3D9 )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetDirect3D(This, ppD3D9);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+#if 0
+static HRESULT WINAPI
+LockDevice9_GetDeviceCaps( struct NineDevice9 *This,
+                           D3DCAPS9 *pCaps )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetDeviceCaps(This, pCaps);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+#endif
+
+static HRESULT WINAPI
+LockDevice9_GetDisplayMode( struct NineDevice9 *This,
+                            UINT iSwapChain,
+                            D3DDISPLAYMODE *pMode )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetDisplayMode(This, iSwapChain, pMode);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+#if 0
+static HRESULT WINAPI
+LockDevice9_GetCreationParameters( struct NineDevice9 *This,
+                                   D3DDEVICE_CREATION_PARAMETERS *pParameters )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetCreationParameters(This, pParameters);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+#endif
+
+static HRESULT WINAPI
+LockDevice9_SetCursorProperties( struct NineDevice9 *This,
+                                 UINT XHotSpot,
+                                 UINT YHotSpot,
+                                 IDirect3DSurface9 *pCursorBitmap )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_SetCursorProperties(This, XHotSpot, YHotSpot, pCursorBitmap);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static void WINAPI
+LockDevice9_SetCursorPosition( struct NineDevice9 *This,
+                               int X,
+                               int Y,
+                               DWORD Flags )
+{
+    pipe_mutex_lock(d3dlock_global);
+    NineDevice9_SetCursorPosition(This, X, Y, Flags);
+    pipe_mutex_unlock(d3dlock_global);
+}
+
+static BOOL WINAPI
+LockDevice9_ShowCursor( struct NineDevice9 *This,
+                        BOOL bShow )
+{
+    BOOL r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_ShowCursor(This, bShow);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_CreateAdditionalSwapChain( struct NineDevice9 *This,
+                                       D3DPRESENT_PARAMETERS *pPresentationParameters,
+                                       IDirect3DSwapChain9 **pSwapChain )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_CreateAdditionalSwapChain(This, pPresentationParameters, pSwapChain);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_GetSwapChain( struct NineDevice9 *This,
+                          UINT iSwapChain,
+                          IDirect3DSwapChain9 **pSwapChain )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetSwapChain(This, iSwapChain, pSwapChain);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static UINT WINAPI
+LockDevice9_GetNumberOfSwapChains( struct NineDevice9 *This )
+{
+    UINT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetNumberOfSwapChains(This);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_Reset( struct NineDevice9 *This,
+                   D3DPRESENT_PARAMETERS *pPresentationParameters )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_Reset(This, pPresentationParameters);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_Present( struct NineDevice9 *This,
+                     const RECT *pSourceRect,
+                     const RECT *pDestRect,
+                     HWND hDestWindowOverride,
+                     const RGNDATA *pDirtyRegion )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_Present(This, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_GetBackBuffer( struct NineDevice9 *This,
+                           UINT iSwapChain,
+                           UINT iBackBuffer,
+                           D3DBACKBUFFER_TYPE Type,
+                           IDirect3DSurface9 **ppBackBuffer )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetBackBuffer(This, iSwapChain, iBackBuffer, Type, ppBackBuffer);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_GetRasterStatus( struct NineDevice9 *This,
+                             UINT iSwapChain,
+                             D3DRASTER_STATUS *pRasterStatus )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetRasterStatus(This, iSwapChain, pRasterStatus);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_SetDialogBoxMode( struct NineDevice9 *This,
+                              BOOL bEnableDialogs )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_SetDialogBoxMode(This, bEnableDialogs);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static void WINAPI
+LockDevice9_SetGammaRamp( struct NineDevice9 *This,
+                          UINT iSwapChain,
+                          DWORD Flags,
+                          const D3DGAMMARAMP *pRamp )
+{
+    pipe_mutex_lock(d3dlock_global);
+    NineDevice9_SetGammaRamp(This, iSwapChain, Flags, pRamp);
+    pipe_mutex_unlock(d3dlock_global);
+}
+
+static void WINAPI
+LockDevice9_GetGammaRamp( struct NineDevice9 *This,
+                          UINT iSwapChain,
+                          D3DGAMMARAMP *pRamp )
+{
+    pipe_mutex_lock(d3dlock_global);
+    NineDevice9_GetGammaRamp(This, iSwapChain, pRamp);
+    pipe_mutex_unlock(d3dlock_global);
+}
+
+static HRESULT WINAPI
+LockDevice9_CreateTexture( struct NineDevice9 *This,
+                           UINT Width,
+                           UINT Height,
+                           UINT Levels,
+                           DWORD Usage,
+                           D3DFORMAT Format,
+                           D3DPOOL Pool,
+                           IDirect3DTexture9 **ppTexture,
+                           HANDLE *pSharedHandle )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_CreateTexture(This, Width, Height, Levels, Usage, Format, Pool, ppTexture, pSharedHandle);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_CreateVolumeTexture( struct NineDevice9 *This,
+                                 UINT Width,
+                                 UINT Height,
+                                 UINT Depth,
+                                 UINT Levels,
+                                 DWORD Usage,
+                                 D3DFORMAT Format,
+                                 D3DPOOL Pool,
+                                 IDirect3DVolumeTexture9 **ppVolumeTexture,
+                                 HANDLE *pSharedHandle )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_CreateVolumeTexture(This, Width, Height, Depth, Levels, Usage, Format, Pool, ppVolumeTexture, pSharedHandle);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_CreateCubeTexture( struct NineDevice9 *This,
+                               UINT EdgeLength,
+                               UINT Levels,
+                               DWORD Usage,
+                               D3DFORMAT Format,
+                               D3DPOOL Pool,
+                               IDirect3DCubeTexture9 **ppCubeTexture,
+                               HANDLE *pSharedHandle )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_CreateCubeTexture(This, EdgeLength, Levels, Usage, Format, Pool, ppCubeTexture, pSharedHandle);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_CreateVertexBuffer( struct NineDevice9 *This,
+                                UINT Length,
+                                DWORD Usage,
+                                DWORD FVF,
+                                D3DPOOL Pool,
+                                IDirect3DVertexBuffer9 **ppVertexBuffer,
+                                HANDLE *pSharedHandle )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_CreateVertexBuffer(This, Length, Usage, FVF, Pool, ppVertexBuffer, pSharedHandle);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_CreateIndexBuffer( struct NineDevice9 *This,
+                               UINT Length,
+                               DWORD Usage,
+                               D3DFORMAT Format,
+                               D3DPOOL Pool,
+                               IDirect3DIndexBuffer9 **ppIndexBuffer,
+                               HANDLE *pSharedHandle )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_CreateIndexBuffer(This, Length, Usage, Format, Pool, ppIndexBuffer, pSharedHandle);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_CreateRenderTarget( struct NineDevice9 *This,
+                                UINT Width,
+                                UINT Height,
+                                D3DFORMAT Format,
+                                D3DMULTISAMPLE_TYPE MultiSample,
+                                DWORD MultisampleQuality,
+                                BOOL Lockable,
+                                IDirect3DSurface9 **ppSurface,
+                                HANDLE *pSharedHandle )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_CreateRenderTarget(This, Width, Height, Format, MultiSample, MultisampleQuality, Lockable, ppSurface, pSharedHandle);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_CreateDepthStencilSurface( struct NineDevice9 *This,
+                                       UINT Width,
+                                       UINT Height,
+                                       D3DFORMAT Format,
+                                       D3DMULTISAMPLE_TYPE MultiSample,
+                                       DWORD MultisampleQuality,
+                                       BOOL Discard,
+                                       IDirect3DSurface9 **ppSurface,
+                                       HANDLE *pSharedHandle )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_CreateDepthStencilSurface(This, Width, Height, Format, MultiSample, MultisampleQuality, Discard, ppSurface, pSharedHandle);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_UpdateSurface( struct NineDevice9 *This,
+                           IDirect3DSurface9 *pSourceSurface,
+                           const RECT *pSourceRect,
+                           IDirect3DSurface9 *pDestinationSurface,
+                           const POINT *pDestPoint )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_UpdateSurface(This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_UpdateTexture( struct NineDevice9 *This,
+                           IDirect3DBaseTexture9 *pSourceTexture,
+                           IDirect3DBaseTexture9 *pDestinationTexture )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_UpdateTexture(This, pSourceTexture, pDestinationTexture);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_GetRenderTargetData( struct NineDevice9 *This,
+                                 IDirect3DSurface9 *pRenderTarget,
+                                 IDirect3DSurface9 *pDestSurface )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetRenderTargetData(This, pRenderTarget, pDestSurface);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_GetFrontBufferData( struct NineDevice9 *This,
+                                UINT iSwapChain,
+                                IDirect3DSurface9 *pDestSurface )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetFrontBufferData(This, iSwapChain, pDestSurface);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_StretchRect( struct NineDevice9 *This,
+                         IDirect3DSurface9 *pSourceSurface,
+                         const RECT *pSourceRect,
+                         IDirect3DSurface9 *pDestSurface,
+                         const RECT *pDestRect,
+                         D3DTEXTUREFILTERTYPE Filter )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_StretchRect(This, pSourceSurface, pSourceRect, pDestSurface, pDestRect, Filter);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_ColorFill( struct NineDevice9 *This,
+                       IDirect3DSurface9 *pSurface,
+                       const RECT *pRect,
+                       D3DCOLOR color )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_ColorFill(This, pSurface, pRect, color);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_CreateOffscreenPlainSurface( struct NineDevice9 *This,
+                                         UINT Width,
+                                         UINT Height,
+                                         D3DFORMAT Format,
+                                         D3DPOOL Pool,
+                                         IDirect3DSurface9 **ppSurface,
+                                         HANDLE *pSharedHandle )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_CreateOffscreenPlainSurface(This, Width, Height, Format, Pool, ppSurface, pSharedHandle);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_SetRenderTarget( struct NineDevice9 *This,
+                             DWORD RenderTargetIndex,
+                             IDirect3DSurface9 *pRenderTarget )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_SetRenderTarget(This, RenderTargetIndex, pRenderTarget);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_GetRenderTarget( struct NineDevice9 *This,
+                             DWORD RenderTargetIndex,
+                             IDirect3DSurface9 **ppRenderTarget )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetRenderTarget(This, RenderTargetIndex, ppRenderTarget);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_SetDepthStencilSurface( struct NineDevice9 *This,
+                                    IDirect3DSurface9 *pNewZStencil )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_SetDepthStencilSurface(This, pNewZStencil);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_GetDepthStencilSurface( struct NineDevice9 *This,
+                                    IDirect3DSurface9 **ppZStencilSurface )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetDepthStencilSurface(This, ppZStencilSurface);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_BeginScene( struct NineDevice9 *This )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_BeginScene(This);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_EndScene( struct NineDevice9 *This )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_EndScene(This);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_Clear( struct NineDevice9 *This,
+                   DWORD Count,
+                   const D3DRECT *pRects,
+                   DWORD Flags,
+                   D3DCOLOR Color,
+                   float Z,
+                   DWORD Stencil )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_Clear(This, Count, pRects, Flags, Color, Z, Stencil);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_SetTransform( struct NineDevice9 *This,
+                          D3DTRANSFORMSTATETYPE State,
+                          const D3DMATRIX *pMatrix )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_SetTransform(This, State, pMatrix);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_GetTransform( struct NineDevice9 *This,
+                          D3DTRANSFORMSTATETYPE State,
+                          D3DMATRIX *pMatrix )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetTransform(This, State, pMatrix);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_MultiplyTransform( struct NineDevice9 *This,
+                               D3DTRANSFORMSTATETYPE State,
+                               const D3DMATRIX *pMatrix )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_MultiplyTransform(This, State, pMatrix);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_SetViewport( struct NineDevice9 *This,
+                         const D3DVIEWPORT9 *pViewport )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_SetViewport(This, pViewport);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_GetViewport( struct NineDevice9 *This,
+                         D3DVIEWPORT9 *pViewport )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetViewport(This, pViewport);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_SetMaterial( struct NineDevice9 *This,
+                         const D3DMATERIAL9 *pMaterial )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_SetMaterial(This, pMaterial);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_GetMaterial( struct NineDevice9 *This,
+                         D3DMATERIAL9 *pMaterial )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetMaterial(This, pMaterial);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_SetLight( struct NineDevice9 *This,
+                      DWORD Index,
+                      const D3DLIGHT9 *pLight )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_SetLight(This, Index, pLight);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_GetLight( struct NineDevice9 *This,
+                      DWORD Index,
+                      D3DLIGHT9 *pLight )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetLight(This, Index, pLight);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_LightEnable( struct NineDevice9 *This,
+                         DWORD Index,
+                         BOOL Enable )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_LightEnable(This, Index, Enable);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_GetLightEnable( struct NineDevice9 *This,
+                            DWORD Index,
+                            BOOL *pEnable )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetLightEnable(This, Index, pEnable);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_SetClipPlane( struct NineDevice9 *This,
+                          DWORD Index,
+                          const float *pPlane )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_SetClipPlane(This, Index, pPlane);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_GetClipPlane( struct NineDevice9 *This,
+                          DWORD Index,
+                          float *pPlane )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetClipPlane(This, Index, pPlane);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_SetRenderState( struct NineDevice9 *This,
+                            D3DRENDERSTATETYPE State,
+                            DWORD Value )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_SetRenderState(This, State, Value);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_GetRenderState( struct NineDevice9 *This,
+                            D3DRENDERSTATETYPE State,
+                            DWORD *pValue )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetRenderState(This, State, pValue);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_CreateStateBlock( struct NineDevice9 *This,
+                              D3DSTATEBLOCKTYPE Type,
+                              IDirect3DStateBlock9 **ppSB )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_CreateStateBlock(This, Type, ppSB);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_BeginStateBlock( struct NineDevice9 *This )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_BeginStateBlock(This);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_EndStateBlock( struct NineDevice9 *This,
+                           IDirect3DStateBlock9 **ppSB )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_EndStateBlock(This, ppSB);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_SetClipStatus( struct NineDevice9 *This,
+                           const D3DCLIPSTATUS9 *pClipStatus )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_SetClipStatus(This, pClipStatus);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_GetClipStatus( struct NineDevice9 *This,
+                           D3DCLIPSTATUS9 *pClipStatus )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetClipStatus(This, pClipStatus);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_GetTexture( struct NineDevice9 *This,
+                        DWORD Stage,
+                        IDirect3DBaseTexture9 **ppTexture )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetTexture(This, Stage, ppTexture);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_SetTexture( struct NineDevice9 *This,
+                        DWORD Stage,
+                        IDirect3DBaseTexture9 *pTexture )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_SetTexture(This, Stage, pTexture);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_GetTextureStageState( struct NineDevice9 *This,
+                                  DWORD Stage,
+                                  D3DTEXTURESTAGESTATETYPE Type,
+                                  DWORD *pValue )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetTextureStageState(This, Stage, Type, pValue);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_SetTextureStageState( struct NineDevice9 *This,
+                                  DWORD Stage,
+                                  D3DTEXTURESTAGESTATETYPE Type,
+                                  DWORD Value )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_SetTextureStageState(This, Stage, Type, Value);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_GetSamplerState( struct NineDevice9 *This,
+                             DWORD Sampler,
+                             D3DSAMPLERSTATETYPE Type,
+                             DWORD *pValue )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetSamplerState(This, Sampler, Type, pValue);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_SetSamplerState( struct NineDevice9 *This,
+                             DWORD Sampler,
+                             D3DSAMPLERSTATETYPE Type,
+                             DWORD Value )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_SetSamplerState(This, Sampler, Type, Value);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_ValidateDevice( struct NineDevice9 *This,
+                            DWORD *pNumPasses )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_ValidateDevice(This, pNumPasses);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_SetPaletteEntries( struct NineDevice9 *This,
+                               UINT PaletteNumber,
+                               const PALETTEENTRY *pEntries )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_SetPaletteEntries(This, PaletteNumber, pEntries);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_GetPaletteEntries( struct NineDevice9 *This,
+                               UINT PaletteNumber,
+                               PALETTEENTRY *pEntries )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetPaletteEntries(This, PaletteNumber, pEntries);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_SetCurrentTexturePalette( struct NineDevice9 *This,
+                                      UINT PaletteNumber )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_SetCurrentTexturePalette(This, PaletteNumber);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_GetCurrentTexturePalette( struct NineDevice9 *This,
+                                      UINT *PaletteNumber )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetCurrentTexturePalette(This, PaletteNumber);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_SetScissorRect( struct NineDevice9 *This,
+                            const RECT *pRect )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_SetScissorRect(This, pRect);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_GetScissorRect( struct NineDevice9 *This,
+                            RECT *pRect )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetScissorRect(This, pRect);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_SetSoftwareVertexProcessing( struct NineDevice9 *This,
+                                         BOOL bSoftware )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_SetSoftwareVertexProcessing(This, bSoftware);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static BOOL WINAPI
+LockDevice9_GetSoftwareVertexProcessing( struct NineDevice9 *This )
+{
+    BOOL r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetSoftwareVertexProcessing(This);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_SetNPatchMode( struct NineDevice9 *This,
+                           float nSegments )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_SetNPatchMode(This, nSegments);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static float WINAPI
+LockDevice9_GetNPatchMode( struct NineDevice9 *This )
+{
+    float r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetNPatchMode(This);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_DrawPrimitive( struct NineDevice9 *This,
+                           D3DPRIMITIVETYPE PrimitiveType,
+                           UINT StartVertex,
+                           UINT PrimitiveCount )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_DrawPrimitive(This, PrimitiveType, StartVertex, PrimitiveCount);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_DrawIndexedPrimitive( struct NineDevice9 *This,
+                                  D3DPRIMITIVETYPE PrimitiveType,
+                                  INT BaseVertexIndex,
+                                  UINT MinVertexIndex,
+                                  UINT NumVertices,
+                                  UINT startIndex,
+                                  UINT primCount )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_DrawIndexedPrimitive(This, PrimitiveType, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_DrawPrimitiveUP( struct NineDevice9 *This,
+                             D3DPRIMITIVETYPE PrimitiveType,
+                             UINT PrimitiveCount,
+                             const void *pVertexStreamZeroData,
+                             UINT VertexStreamZeroStride )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_DrawPrimitiveUP(This, PrimitiveType, PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_DrawIndexedPrimitiveUP( struct NineDevice9 *This,
+                                    D3DPRIMITIVETYPE PrimitiveType,
+                                    UINT MinVertexIndex,
+                                    UINT NumVertices,
+                                    UINT PrimitiveCount,
+                                    const void *pIndexData,
+                                    D3DFORMAT IndexDataFormat,
+                                    const void *pVertexStreamZeroData,
+                                    UINT VertexStreamZeroStride )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_DrawIndexedPrimitiveUP(This, PrimitiveType, MinVertexIndex, NumVertices, PrimitiveCount, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_ProcessVertices( struct NineDevice9 *This,
+                             UINT SrcStartIndex,
+                             UINT DestIndex,
+                             UINT VertexCount,
+                             IDirect3DVertexBuffer9 *pDestBuffer,
+                             IDirect3DVertexDeclaration9 *pVertexDecl,
+                             DWORD Flags )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_ProcessVertices(This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_CreateVertexDeclaration( struct NineDevice9 *This,
+                                     const D3DVERTEXELEMENT9 *pVertexElements,
+                                     IDirect3DVertexDeclaration9 **ppDecl )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_CreateVertexDeclaration(This, pVertexElements, ppDecl);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_SetVertexDeclaration( struct NineDevice9 *This,
+                                  IDirect3DVertexDeclaration9 *pDecl )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_SetVertexDeclaration(This, pDecl);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_GetVertexDeclaration( struct NineDevice9 *This,
+                                  IDirect3DVertexDeclaration9 **ppDecl )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetVertexDeclaration(This, ppDecl);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_SetFVF( struct NineDevice9 *This,
+                    DWORD FVF )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_SetFVF(This, FVF);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_GetFVF( struct NineDevice9 *This,
+                    DWORD *pFVF )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetFVF(This, pFVF);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_CreateVertexShader( struct NineDevice9 *This,
+                                const DWORD *pFunction,
+                                IDirect3DVertexShader9 **ppShader )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_CreateVertexShader(This, pFunction, ppShader);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_SetVertexShader( struct NineDevice9 *This,
+                             IDirect3DVertexShader9 *pShader )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_SetVertexShader(This, pShader);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_GetVertexShader( struct NineDevice9 *This,
+                             IDirect3DVertexShader9 **ppShader )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetVertexShader(This, ppShader);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_SetVertexShaderConstantF( struct NineDevice9 *This,
+                                      UINT StartRegister,
+                                      const float *pConstantData,
+                                      UINT Vector4fCount )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_SetVertexShaderConstantF(This, StartRegister, pConstantData, Vector4fCount);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_GetVertexShaderConstantF( struct NineDevice9 *This,
+                                      UINT StartRegister,
+                                      float *pConstantData,
+                                      UINT Vector4fCount )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetVertexShaderConstantF(This, StartRegister, pConstantData, Vector4fCount);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_SetVertexShaderConstantI( struct NineDevice9 *This,
+                                      UINT StartRegister,
+                                      const int *pConstantData,
+                                      UINT Vector4iCount )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_SetVertexShaderConstantI(This, StartRegister, pConstantData, Vector4iCount);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_GetVertexShaderConstantI( struct NineDevice9 *This,
+                                      UINT StartRegister,
+                                      int *pConstantData,
+                                      UINT Vector4iCount )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetVertexShaderConstantI(This, StartRegister, pConstantData, Vector4iCount);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_SetVertexShaderConstantB( struct NineDevice9 *This,
+                                      UINT StartRegister,
+                                      const BOOL *pConstantData,
+                                      UINT BoolCount )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_SetVertexShaderConstantB(This, StartRegister, pConstantData, BoolCount);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_GetVertexShaderConstantB( struct NineDevice9 *This,
+                                      UINT StartRegister,
+                                      BOOL *pConstantData,
+                                      UINT BoolCount )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetVertexShaderConstantB(This, StartRegister, pConstantData, BoolCount);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_SetStreamSource( struct NineDevice9 *This,
+                             UINT StreamNumber,
+                             IDirect3DVertexBuffer9 *pStreamData,
+                             UINT OffsetInBytes,
+                             UINT Stride )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_SetStreamSource(This, StreamNumber, pStreamData, OffsetInBytes, Stride);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_GetStreamSource( struct NineDevice9 *This,
+                             UINT StreamNumber,
+                             IDirect3DVertexBuffer9 **ppStreamData,
+                             UINT *pOffsetInBytes,
+                             UINT *pStride )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetStreamSource(This, StreamNumber, ppStreamData, pOffsetInBytes, pStride);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_SetStreamSourceFreq( struct NineDevice9 *This,
+                                 UINT StreamNumber,
+                                 UINT Setting )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_SetStreamSourceFreq(This, StreamNumber, Setting);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_GetStreamSourceFreq( struct NineDevice9 *This,
+                                 UINT StreamNumber,
+                                 UINT *pSetting )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetStreamSourceFreq(This, StreamNumber, pSetting);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_SetIndices( struct NineDevice9 *This,
+                        IDirect3DIndexBuffer9 *pIndexData )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_SetIndices(This, pIndexData);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_GetIndices( struct NineDevice9 *This,
+                        IDirect3DIndexBuffer9 **ppIndexData )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetIndices(This, ppIndexData);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_CreatePixelShader( struct NineDevice9 *This,
+                               const DWORD *pFunction,
+                               IDirect3DPixelShader9 **ppShader )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_CreatePixelShader(This, pFunction, ppShader);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_SetPixelShader( struct NineDevice9 *This,
+                            IDirect3DPixelShader9 *pShader )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_SetPixelShader(This, pShader);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_GetPixelShader( struct NineDevice9 *This,
+                            IDirect3DPixelShader9 **ppShader )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetPixelShader(This, ppShader);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_SetPixelShaderConstantF( struct NineDevice9 *This,
+                                     UINT StartRegister,
+                                     const float *pConstantData,
+                                     UINT Vector4fCount )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_SetPixelShaderConstantF(This, StartRegister, pConstantData, Vector4fCount);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_GetPixelShaderConstantF( struct NineDevice9 *This,
+                                     UINT StartRegister,
+                                     float *pConstantData,
+                                     UINT Vector4fCount )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetPixelShaderConstantF(This, StartRegister, pConstantData, Vector4fCount);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_SetPixelShaderConstantI( struct NineDevice9 *This,
+                                     UINT StartRegister,
+                                     const int *pConstantData,
+                                     UINT Vector4iCount )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_SetPixelShaderConstantI(This, StartRegister, pConstantData, Vector4iCount);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_GetPixelShaderConstantI( struct NineDevice9 *This,
+                                     UINT StartRegister,
+                                     int *pConstantData,
+                                     UINT Vector4iCount )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetPixelShaderConstantI(This, StartRegister, pConstantData, Vector4iCount);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_SetPixelShaderConstantB( struct NineDevice9 *This,
+                                     UINT StartRegister,
+                                     const BOOL *pConstantData,
+                                     UINT BoolCount )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_SetPixelShaderConstantB(This, StartRegister, pConstantData, BoolCount);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_GetPixelShaderConstantB( struct NineDevice9 *This,
+                                     UINT StartRegister,
+                                     BOOL *pConstantData,
+                                     UINT BoolCount )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_GetPixelShaderConstantB(This, StartRegister, pConstantData, BoolCount);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_DrawRectPatch( struct NineDevice9 *This,
+                           UINT Handle,
+                           const float *pNumSegs,
+                           const D3DRECTPATCH_INFO *pRectPatchInfo )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_DrawRectPatch(This, Handle, pNumSegs, pRectPatchInfo);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_DrawTriPatch( struct NineDevice9 *This,
+                          UINT Handle,
+                          const float *pNumSegs,
+                          const D3DTRIPATCH_INFO *pTriPatchInfo )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_DrawTriPatch(This, Handle, pNumSegs, pTriPatchInfo);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_DeletePatch( struct NineDevice9 *This,
+                         UINT Handle )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_DeletePatch(This, Handle);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9_CreateQuery( struct NineDevice9 *This,
+                         D3DQUERYTYPE Type,
+                         IDirect3DQuery9 **ppQuery )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9_CreateQuery(This, Type, ppQuery);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+IDirect3DDevice9Vtbl LockDevice9_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)LockDevice9_TestCooperativeLevel,
+    (void *)LockDevice9_GetAvailableTextureMem,
+    (void *)LockDevice9_EvictManagedResources,
+    (void *)LockDevice9_GetDirect3D,
+    (void *)NineDevice9_GetDeviceCaps, /* immutable */
+    (void *)LockDevice9_GetDisplayMode,
+    (void *)NineDevice9_GetCreationParameters, /* immutable */
+    (void *)LockDevice9_SetCursorProperties,
+    (void *)LockDevice9_SetCursorPosition,
+    (void *)LockDevice9_ShowCursor,
+    (void *)LockDevice9_CreateAdditionalSwapChain,
+    (void *)LockDevice9_GetSwapChain,
+    (void *)LockDevice9_GetNumberOfSwapChains,
+    (void *)LockDevice9_Reset,
+    (void *)LockDevice9_Present,
+    (void *)LockDevice9_GetBackBuffer,
+    (void *)LockDevice9_GetRasterStatus,
+    (void *)LockDevice9_SetDialogBoxMode,
+    (void *)LockDevice9_SetGammaRamp,
+    (void *)LockDevice9_GetGammaRamp,
+    (void *)LockDevice9_CreateTexture,
+    (void *)LockDevice9_CreateVolumeTexture,
+    (void *)LockDevice9_CreateCubeTexture,
+    (void *)LockDevice9_CreateVertexBuffer,
+    (void *)LockDevice9_CreateIndexBuffer,
+    (void *)LockDevice9_CreateRenderTarget,
+    (void *)LockDevice9_CreateDepthStencilSurface,
+    (void *)LockDevice9_UpdateSurface,
+    (void *)LockDevice9_UpdateTexture,
+    (void *)LockDevice9_GetRenderTargetData,
+    (void *)LockDevice9_GetFrontBufferData,
+    (void *)LockDevice9_StretchRect,
+    (void *)LockDevice9_ColorFill,
+    (void *)LockDevice9_CreateOffscreenPlainSurface,
+    (void *)LockDevice9_SetRenderTarget,
+    (void *)LockDevice9_GetRenderTarget,
+    (void *)LockDevice9_SetDepthStencilSurface,
+    (void *)LockDevice9_GetDepthStencilSurface,
+    (void *)LockDevice9_BeginScene,
+    (void *)LockDevice9_EndScene,
+    (void *)LockDevice9_Clear,
+    (void *)LockDevice9_SetTransform,
+    (void *)LockDevice9_GetTransform,
+    (void *)LockDevice9_MultiplyTransform,
+    (void *)LockDevice9_SetViewport,
+    (void *)LockDevice9_GetViewport,
+    (void *)LockDevice9_SetMaterial,
+    (void *)LockDevice9_GetMaterial,
+    (void *)LockDevice9_SetLight,
+    (void *)LockDevice9_GetLight,
+    (void *)LockDevice9_LightEnable,
+    (void *)LockDevice9_GetLightEnable,
+    (void *)LockDevice9_SetClipPlane,
+    (void *)LockDevice9_GetClipPlane,
+    (void *)LockDevice9_SetRenderState,
+    (void *)LockDevice9_GetRenderState,
+    (void *)LockDevice9_CreateStateBlock,
+    (void *)LockDevice9_BeginStateBlock,
+    (void *)LockDevice9_EndStateBlock,
+    (void *)LockDevice9_SetClipStatus,
+    (void *)LockDevice9_GetClipStatus,
+    (void *)LockDevice9_GetTexture,
+    (void *)LockDevice9_SetTexture,
+    (void *)LockDevice9_GetTextureStageState,
+    (void *)LockDevice9_SetTextureStageState,
+    (void *)LockDevice9_GetSamplerState,
+    (void *)LockDevice9_SetSamplerState,
+    (void *)LockDevice9_ValidateDevice,
+    (void *)LockDevice9_SetPaletteEntries,
+    (void *)LockDevice9_GetPaletteEntries,
+    (void *)LockDevice9_SetCurrentTexturePalette,
+    (void *)LockDevice9_GetCurrentTexturePalette,
+    (void *)LockDevice9_SetScissorRect,
+    (void *)LockDevice9_GetScissorRect,
+    (void *)LockDevice9_SetSoftwareVertexProcessing,
+    (void *)LockDevice9_GetSoftwareVertexProcessing,
+    (void *)LockDevice9_SetNPatchMode,
+    (void *)LockDevice9_GetNPatchMode,
+    (void *)LockDevice9_DrawPrimitive,
+    (void *)LockDevice9_DrawIndexedPrimitive,
+    (void *)LockDevice9_DrawPrimitiveUP,
+    (void *)LockDevice9_DrawIndexedPrimitiveUP,
+    (void *)LockDevice9_ProcessVertices,
+    (void *)LockDevice9_CreateVertexDeclaration,
+    (void *)LockDevice9_SetVertexDeclaration,
+    (void *)LockDevice9_GetVertexDeclaration,
+    (void *)LockDevice9_SetFVF,
+    (void *)LockDevice9_GetFVF,
+    (void *)LockDevice9_CreateVertexShader,
+    (void *)LockDevice9_SetVertexShader,
+    (void *)LockDevice9_GetVertexShader,
+    (void *)LockDevice9_SetVertexShaderConstantF,
+    (void *)LockDevice9_GetVertexShaderConstantF,
+    (void *)LockDevice9_SetVertexShaderConstantI,
+    (void *)LockDevice9_GetVertexShaderConstantI,
+    (void *)LockDevice9_SetVertexShaderConstantB,
+    (void *)LockDevice9_GetVertexShaderConstantB,
+    (void *)LockDevice9_SetStreamSource,
+    (void *)LockDevice9_GetStreamSource,
+    (void *)LockDevice9_SetStreamSourceFreq,
+    (void *)LockDevice9_GetStreamSourceFreq,
+    (void *)LockDevice9_SetIndices,
+    (void *)LockDevice9_GetIndices,
+    (void *)LockDevice9_CreatePixelShader,
+    (void *)LockDevice9_SetPixelShader,
+    (void *)LockDevice9_GetPixelShader,
+    (void *)LockDevice9_SetPixelShaderConstantF,
+    (void *)LockDevice9_GetPixelShaderConstantF,
+    (void *)LockDevice9_SetPixelShaderConstantI,
+    (void *)LockDevice9_GetPixelShaderConstantI,
+    (void *)LockDevice9_SetPixelShaderConstantB,
+    (void *)LockDevice9_GetPixelShaderConstantB,
+    (void *)LockDevice9_DrawRectPatch,
+    (void *)LockDevice9_DrawTriPatch,
+    (void *)LockDevice9_DeletePatch,
+    (void *)LockDevice9_CreateQuery
+};
+
+static HRESULT WINAPI
+LockDevice9Ex_SetConvolutionMonoKernel( struct NineDevice9Ex *This,
+                                        UINT width,
+                                        UINT height,
+                                        float *rows,
+                                        float *columns )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9Ex_SetConvolutionMonoKernel(This, width, height, rows, columns);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9Ex_ComposeRects( struct NineDevice9Ex *This,
+                            IDirect3DSurface9 *pSrc,
+                            IDirect3DSurface9 *pDst,
+                            IDirect3DVertexBuffer9 *pSrcRectDescs,
+                            UINT NumRects,
+                            IDirect3DVertexBuffer9 *pDstRectDescs,
+                            D3DCOMPOSERECTSOP Operation,
+                            int Xoffset,
+                            int Yoffset )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9Ex_ComposeRects(This, pSrc, pDst, pSrcRectDescs, NumRects, pDstRectDescs, Operation, Xoffset, Yoffset);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9Ex_PresentEx( struct NineDevice9Ex *This,
+                         const RECT *pSourceRect,
+                         const RECT *pDestRect,
+                         HWND hDestWindowOverride,
+                         const RGNDATA *pDirtyRegion,
+                         DWORD dwFlags )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9Ex_PresentEx(This, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, dwFlags);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9Ex_GetGPUThreadPriority( struct NineDevice9Ex *This,
+                                    INT *pPriority )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9Ex_GetGPUThreadPriority(This, pPriority);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9Ex_SetGPUThreadPriority( struct NineDevice9Ex *This,
+                                    INT Priority )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9Ex_SetGPUThreadPriority(This, Priority);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9Ex_WaitForVBlank( struct NineDevice9Ex *This,
+                             UINT iSwapChain )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9Ex_WaitForVBlank(This, iSwapChain);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9Ex_CheckResourceResidency( struct NineDevice9Ex *This,
+                                      IDirect3DResource9 **pResourceArray,
+                                      UINT32 NumResources )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9Ex_CheckResourceResidency(This, pResourceArray, NumResources);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9Ex_SetMaximumFrameLatency( struct NineDevice9Ex *This,
+                                      UINT MaxLatency )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9Ex_SetMaximumFrameLatency(This, MaxLatency);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9Ex_GetMaximumFrameLatency( struct NineDevice9Ex *This,
+                                      UINT *pMaxLatency )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9Ex_GetMaximumFrameLatency(This, pMaxLatency);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9Ex_CheckDeviceState( struct NineDevice9Ex *This,
+                                HWND hDestinationWindow )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9Ex_CheckDeviceState(This, hDestinationWindow);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9Ex_CreateRenderTargetEx( struct NineDevice9Ex *This,
+                                    UINT Width,
+                                    UINT Height,
+                                    D3DFORMAT Format,
+                                    D3DMULTISAMPLE_TYPE MultiSample,
+                                    DWORD MultisampleQuality,
+                                    BOOL Lockable,
+                                    IDirect3DSurface9 **ppSurface,
+                                    HANDLE *pSharedHandle,
+                                    DWORD Usage )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9Ex_CreateRenderTargetEx(This, Width, Height, Format, MultiSample, MultisampleQuality, Lockable, ppSurface, pSharedHandle, Usage);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9Ex_CreateOffscreenPlainSurfaceEx( struct NineDevice9Ex *This,
+                                             UINT Width,
+                                             UINT Height,
+                                             D3DFORMAT Format,
+                                             D3DPOOL Pool,
+                                             IDirect3DSurface9 **ppSurface,
+                                             HANDLE *pSharedHandle,
+                                             DWORD Usage )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9Ex_CreateOffscreenPlainSurfaceEx(This, Width, Height, Format, Pool, ppSurface, pSharedHandle, Usage);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9Ex_CreateDepthStencilSurfaceEx( struct NineDevice9Ex *This,
+                                           UINT Width,
+                                           UINT Height,
+                                           D3DFORMAT Format,
+                                           D3DMULTISAMPLE_TYPE MultiSample,
+                                           DWORD MultisampleQuality,
+                                           BOOL Discard,
+                                           IDirect3DSurface9 **ppSurface,
+                                           HANDLE *pSharedHandle,
+                                           DWORD Usage )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9Ex_CreateDepthStencilSurfaceEx(This, Width, Height, Format, MultiSample, MultisampleQuality, Discard, ppSurface, pSharedHandle, Usage);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9Ex_ResetEx( struct NineDevice9Ex *This,
+                       D3DPRESENT_PARAMETERS *pPresentationParameters,
+                       D3DDISPLAYMODEEX *pFullscreenDisplayMode )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9Ex_ResetEx(This, pPresentationParameters, pFullscreenDisplayMode);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9Ex_GetDisplayModeEx( struct NineDevice9Ex *This,
+                                UINT iSwapChain,
+                                D3DDISPLAYMODEEX *pMode,
+                                D3DDISPLAYROTATION *pRotation )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9Ex_GetDisplayModeEx(This, iSwapChain, pMode, pRotation);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+IDirect3DDevice9ExVtbl LockDevice9Ex_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)LockDevice9_TestCooperativeLevel,
+    (void *)LockDevice9_GetAvailableTextureMem,
+    (void *)LockDevice9_EvictManagedResources,
+    (void *)LockDevice9_GetDirect3D,
+    (void *)NineDevice9_GetDeviceCaps,
+    (void *)LockDevice9_GetDisplayMode,
+    (void *)NineDevice9_GetCreationParameters,
+    (void *)LockDevice9_SetCursorProperties,
+    (void *)LockDevice9_SetCursorPosition,
+    (void *)LockDevice9_ShowCursor,
+    (void *)LockDevice9_CreateAdditionalSwapChain,
+    (void *)LockDevice9_GetSwapChain,
+    (void *)LockDevice9_GetNumberOfSwapChains,
+    (void *)LockDevice9_Reset,
+    (void *)LockDevice9_Present,
+    (void *)LockDevice9_GetBackBuffer,
+    (void *)LockDevice9_GetRasterStatus,
+    (void *)LockDevice9_SetDialogBoxMode,
+    (void *)LockDevice9_SetGammaRamp,
+    (void *)LockDevice9_GetGammaRamp,
+    (void *)LockDevice9_CreateTexture,
+    (void *)LockDevice9_CreateVolumeTexture,
+    (void *)LockDevice9_CreateCubeTexture,
+    (void *)LockDevice9_CreateVertexBuffer,
+    (void *)LockDevice9_CreateIndexBuffer,
+    (void *)LockDevice9_CreateRenderTarget,
+    (void *)LockDevice9_CreateDepthStencilSurface,
+    (void *)LockDevice9_UpdateSurface,
+    (void *)LockDevice9_UpdateTexture,
+    (void *)LockDevice9_GetRenderTargetData,
+    (void *)LockDevice9_GetFrontBufferData,
+    (void *)LockDevice9_StretchRect,
+    (void *)LockDevice9_ColorFill,
+    (void *)LockDevice9_CreateOffscreenPlainSurface,
+    (void *)LockDevice9_SetRenderTarget,
+    (void *)LockDevice9_GetRenderTarget,
+    (void *)LockDevice9_SetDepthStencilSurface,
+    (void *)LockDevice9_GetDepthStencilSurface,
+    (void *)LockDevice9_BeginScene,
+    (void *)LockDevice9_EndScene,
+    (void *)LockDevice9_Clear,
+    (void *)LockDevice9_SetTransform,
+    (void *)LockDevice9_GetTransform,
+    (void *)LockDevice9_MultiplyTransform,
+    (void *)LockDevice9_SetViewport,
+    (void *)LockDevice9_GetViewport,
+    (void *)LockDevice9_SetMaterial,
+    (void *)LockDevice9_GetMaterial,
+    (void *)LockDevice9_SetLight,
+    (void *)LockDevice9_GetLight,
+    (void *)LockDevice9_LightEnable,
+    (void *)LockDevice9_GetLightEnable,
+    (void *)LockDevice9_SetClipPlane,
+    (void *)LockDevice9_GetClipPlane,
+    (void *)LockDevice9_SetRenderState,
+    (void *)LockDevice9_GetRenderState,
+    (void *)LockDevice9_CreateStateBlock,
+    (void *)LockDevice9_BeginStateBlock,
+    (void *)LockDevice9_EndStateBlock,
+    (void *)LockDevice9_SetClipStatus,
+    (void *)LockDevice9_GetClipStatus,
+    (void *)LockDevice9_GetTexture,
+    (void *)LockDevice9_SetTexture,
+    (void *)LockDevice9_GetTextureStageState,
+    (void *)LockDevice9_SetTextureStageState,
+    (void *)LockDevice9_GetSamplerState,
+    (void *)LockDevice9_SetSamplerState,
+    (void *)LockDevice9_ValidateDevice,
+    (void *)LockDevice9_SetPaletteEntries,
+    (void *)LockDevice9_GetPaletteEntries,
+    (void *)LockDevice9_SetCurrentTexturePalette,
+    (void *)LockDevice9_GetCurrentTexturePalette,
+    (void *)LockDevice9_SetScissorRect,
+    (void *)LockDevice9_GetScissorRect,
+    (void *)LockDevice9_SetSoftwareVertexProcessing,
+    (void *)LockDevice9_GetSoftwareVertexProcessing,
+    (void *)LockDevice9_SetNPatchMode,
+    (void *)LockDevice9_GetNPatchMode,
+    (void *)LockDevice9_DrawPrimitive,
+    (void *)LockDevice9_DrawIndexedPrimitive,
+    (void *)LockDevice9_DrawPrimitiveUP,
+    (void *)LockDevice9_DrawIndexedPrimitiveUP,
+    (void *)LockDevice9_ProcessVertices,
+    (void *)LockDevice9_CreateVertexDeclaration,
+    (void *)LockDevice9_SetVertexDeclaration,
+    (void *)LockDevice9_GetVertexDeclaration,
+    (void *)LockDevice9_SetFVF,
+    (void *)LockDevice9_GetFVF,
+    (void *)LockDevice9_CreateVertexShader,
+    (void *)LockDevice9_SetVertexShader,
+    (void *)LockDevice9_GetVertexShader,
+    (void *)LockDevice9_SetVertexShaderConstantF,
+    (void *)LockDevice9_GetVertexShaderConstantF,
+    (void *)LockDevice9_SetVertexShaderConstantI,
+    (void *)LockDevice9_GetVertexShaderConstantI,
+    (void *)LockDevice9_SetVertexShaderConstantB,
+    (void *)LockDevice9_GetVertexShaderConstantB,
+    (void *)LockDevice9_SetStreamSource,
+    (void *)LockDevice9_GetStreamSource,
+    (void *)LockDevice9_SetStreamSourceFreq,
+    (void *)LockDevice9_GetStreamSourceFreq,
+    (void *)LockDevice9_SetIndices,
+    (void *)LockDevice9_GetIndices,
+    (void *)LockDevice9_CreatePixelShader,
+    (void *)LockDevice9_SetPixelShader,
+    (void *)LockDevice9_GetPixelShader,
+    (void *)LockDevice9_SetPixelShaderConstantF,
+    (void *)LockDevice9_GetPixelShaderConstantF,
+    (void *)LockDevice9_SetPixelShaderConstantI,
+    (void *)LockDevice9_GetPixelShaderConstantI,
+    (void *)LockDevice9_SetPixelShaderConstantB,
+    (void *)LockDevice9_GetPixelShaderConstantB,
+    (void *)LockDevice9_DrawRectPatch,
+    (void *)LockDevice9_DrawTriPatch,
+    (void *)LockDevice9_DeletePatch,
+    (void *)LockDevice9_CreateQuery,
+    (void *)LockDevice9Ex_SetConvolutionMonoKernel,
+    (void *)LockDevice9Ex_ComposeRects,
+    (void *)LockDevice9Ex_PresentEx,
+    (void *)LockDevice9Ex_GetGPUThreadPriority,
+    (void *)LockDevice9Ex_SetGPUThreadPriority,
+    (void *)LockDevice9Ex_WaitForVBlank,
+    (void *)LockDevice9Ex_CheckResourceResidency,
+    (void *)LockDevice9Ex_SetMaximumFrameLatency,
+    (void *)LockDevice9Ex_GetMaximumFrameLatency,
+    (void *)LockDevice9Ex_CheckDeviceState,
+    (void *)LockDevice9Ex_CreateRenderTargetEx,
+    (void *)LockDevice9Ex_CreateOffscreenPlainSurfaceEx,
+    (void *)LockDevice9Ex_CreateDepthStencilSurfaceEx,
+    (void *)LockDevice9Ex_ResetEx,
+    (void *)LockDevice9Ex_GetDisplayModeEx
+};
+
+static HRESULT WINAPI
+LockDevice9Video_GetContentProtectionCaps( struct NineDevice9Video *This,
+                                           const GUID *pCryptoType,
+                                           const GUID *pDecodeProfile,
+                                           D3DCONTENTPROTECTIONCAPS *pCaps )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9Video_GetContentProtectionCaps(This, pCryptoType, pDecodeProfile, pCaps);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9Video_CreateAuthenticatedChannel( struct NineDevice9Video *This,
+                                             D3DAUTHENTICATEDCHANNELTYPE ChannelType,
+                                             IDirect3DAuthenticatedChannel9 **ppAuthenticatedChannel,
+                                             HANDLE *pChannelHandle )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9Video_CreateAuthenticatedChannel(This, ChannelType, ppAuthenticatedChannel, pChannelHandle);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockDevice9Video_CreateCryptoSession( struct NineDevice9Video *This,
+                                      const GUID *pCryptoType,
+                                      const GUID *pDecodeProfile,
+                                      IDirect3DCryptoSession9 **ppCryptoSession,
+                                      HANDLE *pCryptoHandle )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineDevice9Video_CreateCryptoSession(This, pCryptoType, pDecodeProfile, ppCryptoSession, pCryptoHandle);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+IDirect3DDevice9VideoVtbl LockDevice9Video_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)LockDevice9Video_GetContentProtectionCaps,
+    (void *)LockDevice9Video_CreateAuthenticatedChannel,
+    (void *)LockDevice9Video_CreateCryptoSession
+};
+
+static HRESULT WINAPI
+LockIndexBuffer9_Lock( struct NineIndexBuffer9 *This,
+                       UINT OffsetToLock,
+                       UINT SizeToLock,
+                       void **ppbData,
+                       DWORD Flags )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineIndexBuffer9_Lock(This, OffsetToLock, SizeToLock, ppbData, Flags);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockIndexBuffer9_Unlock( struct NineIndexBuffer9 *This )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineIndexBuffer9_Unlock(This);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+#if 0
+static HRESULT WINAPI
+LockIndexBuffer9_GetDesc( struct NineIndexBuffer9 *This,
+                          D3DINDEXBUFFER_DESC *pDesc )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineIndexBuffer9_GetDesc(This, pDesc);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+#endif
+
+IDirect3DIndexBuffer9Vtbl LockIndexBuffer9_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */
+    (void *)LockResource9_SetPrivateData,
+    (void *)LockResource9_GetPrivateData,
+    (void *)LockResource9_FreePrivateData,
+    (void *)LockResource9_SetPriority,
+    (void *)LockResource9_GetPriority,
+    (void *)NineResource9_PreLoad, /* nop */
+    (void *)NineResource9_GetType, /* immutable */
+    (void *)LockIndexBuffer9_Lock,
+    (void *)LockIndexBuffer9_Unlock,
+    (void *)NineIndexBuffer9_GetDesc /* immutable */
+};
+
+#if 0
+static HRESULT WINAPI
+LockPixelShader9_GetDevice( struct NinePixelShader9 *This,
+                            IDirect3DDevice9 **ppDevice )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineUnknown_GetDevice(NineUnknown(This), ppDevice);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+#endif
+
+static HRESULT WINAPI
+LockPixelShader9_GetFunction( struct NinePixelShader9 *This,
+                              void *pData,
+                              UINT *pSizeOfData )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NinePixelShader9_GetFunction(This, pData, pSizeOfData);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+IDirect3DPixelShader9Vtbl LockPixelShader9_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)NineUnknown_GetDevice,
+    (void *)LockPixelShader9_GetFunction
+};
+
+#if 0
+static HRESULT WINAPI
+LockQuery9_GetDevice( struct NineQuery9 *This,
+                      IDirect3DDevice9 **ppDevice )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineUnknown_GetDevice(NineUnknown(This), ppDevice);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+#endif
+
+#if 0
+static D3DQUERYTYPE WINAPI
+LockQuery9_GetType( struct NineQuery9 *This )
+{
+    D3DQUERYTYPE r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineQuery9_GetType(This);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+#endif
+
+#if 0
+static DWORD WINAPI
+LockQuery9_GetDataSize( struct NineQuery9 *This )
+{
+    DWORD r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineQuery9_GetDataSize(This);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+#endif
+
+static HRESULT WINAPI
+LockQuery9_Issue( struct NineQuery9 *This,
+                  DWORD dwIssueFlags )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineQuery9_Issue(This, dwIssueFlags);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockQuery9_GetData( struct NineQuery9 *This,
+                    void *pData,
+                    DWORD dwSize,
+                    DWORD dwGetDataFlags )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineQuery9_GetData(This, pData, dwSize, dwGetDataFlags);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+IDirect3DQuery9Vtbl LockQuery9_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)NineUnknown_GetDevice, /* actually part of Query9 iface */
+    (void *)NineQuery9_GetType, /* immutable */
+    (void *)NineQuery9_GetDataSize, /* immutable */
+    (void *)LockQuery9_Issue,
+    (void *)LockQuery9_GetData
+};
+
+#if 0
+static HRESULT WINAPI
+LockStateBlock9_GetDevice( struct NineStateBlock9 *This,
+                           IDirect3DDevice9 **ppDevice )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineUnknown_GetDevice(NineUnknown(This), ppDevice);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+#endif
+
+static HRESULT WINAPI
+LockStateBlock9_Capture( struct NineStateBlock9 *This )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineStateBlock9_Capture(This);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockStateBlock9_Apply( struct NineStateBlock9 *This )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineStateBlock9_Apply(This);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+IDirect3DStateBlock9Vtbl LockStateBlock9_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)NineUnknown_GetDevice, /* actually part of StateBlock9 iface */
+    (void *)LockStateBlock9_Capture,
+    (void *)LockStateBlock9_Apply
+};
+
+static HRESULT WINAPI
+LockSurface9_GetContainer( struct NineSurface9 *This,
+                           REFIID riid,
+                           void **ppContainer )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineSurface9_GetContainer(This, riid, ppContainer);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+#if 0
+static HRESULT WINAPI
+LockSurface9_GetDesc( struct NineSurface9 *This,
+                      D3DSURFACE_DESC *pDesc )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineSurface9_GetDesc(This, pDesc);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+#endif
+
+static HRESULT WINAPI
+LockSurface9_LockRect( struct NineSurface9 *This,
+                       D3DLOCKED_RECT *pLockedRect,
+                       const RECT *pRect,
+                       DWORD Flags )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineSurface9_LockRect(This, pLockedRect, pRect, Flags);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockSurface9_UnlockRect( struct NineSurface9 *This )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineSurface9_UnlockRect(This);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockSurface9_GetDC( struct NineSurface9 *This,
+                    HDC *phdc )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineSurface9_GetDC(This, phdc);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockSurface9_ReleaseDC( struct NineSurface9 *This,
+                        HDC hdc )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineSurface9_ReleaseDC(This, hdc);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+IDirect3DSurface9Vtbl LockSurface9_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */
+    (void *)LockResource9_SetPrivateData,
+    (void *)LockResource9_GetPrivateData,
+    (void *)LockResource9_FreePrivateData,
+    (void *)LockResource9_SetPriority,
+    (void *)LockResource9_GetPriority,
+    (void *)NineResource9_PreLoad, /* nop */
+    (void *)NineResource9_GetType, /* immutable */
+    (void *)LockSurface9_GetContainer,
+    (void *)NineSurface9_GetDesc, /* immutable */
+    (void *)LockSurface9_LockRect,
+    (void *)LockSurface9_UnlockRect,
+    (void *)LockSurface9_GetDC,
+    (void *)LockSurface9_ReleaseDC
+};
+
+static HRESULT WINAPI
+LockSwapChain9_Present( struct NineSwapChain9 *This,
+                        const RECT *pSourceRect,
+                        const RECT *pDestRect,
+                        HWND hDestWindowOverride,
+                        const RGNDATA *pDirtyRegion,
+                        DWORD dwFlags )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineSwapChain9_Present(This, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, dwFlags);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockSwapChain9_GetFrontBufferData( struct NineSwapChain9 *This,
+                                   IDirect3DSurface9 *pDestSurface )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineSwapChain9_GetFrontBufferData(This, pDestSurface);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockSwapChain9_GetBackBuffer( struct NineSwapChain9 *This,
+                              UINT iBackBuffer,
+                              D3DBACKBUFFER_TYPE Type,
+                              IDirect3DSurface9 **ppBackBuffer )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineSwapChain9_GetBackBuffer(This, iBackBuffer, Type, ppBackBuffer);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockSwapChain9_GetRasterStatus( struct NineSwapChain9 *This,
+                                D3DRASTER_STATUS *pRasterStatus )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineSwapChain9_GetRasterStatus(This, pRasterStatus);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockSwapChain9_GetDisplayMode( struct NineSwapChain9 *This,
+                               D3DDISPLAYMODE *pMode )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineSwapChain9_GetDisplayMode(This, pMode);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+#if 0
+static HRESULT WINAPI
+LockSwapChain9_GetDevice( struct NineSwapChain9 *This,
+                          IDirect3DDevice9 **ppDevice )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineUnknown_GetDevice(NineUnknown(This), ppDevice);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+#endif
+
+static HRESULT WINAPI
+LockSwapChain9_GetPresentParameters( struct NineSwapChain9 *This,
+                                     D3DPRESENT_PARAMETERS *pPresentationParameters )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineSwapChain9_GetPresentParameters(This, pPresentationParameters);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+IDirect3DSwapChain9Vtbl LockSwapChain9_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)LockSwapChain9_Present,
+    (void *)LockSwapChain9_GetFrontBufferData,
+    (void *)LockSwapChain9_GetBackBuffer,
+    (void *)LockSwapChain9_GetRasterStatus,
+    (void *)LockSwapChain9_GetDisplayMode,
+    (void *)NineUnknown_GetDevice, /* actually part of SwapChain9 iface */
+    (void *)LockSwapChain9_GetPresentParameters
+};
+
+static HRESULT WINAPI
+LockSwapChain9Ex_GetLastPresentCount( struct NineSwapChain9Ex *This,
+                                      UINT *pLastPresentCount )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineSwapChain9Ex_GetLastPresentCount(This, pLastPresentCount);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockSwapChain9Ex_GetPresentStats( struct NineSwapChain9Ex *This,
+                                  D3DPRESENTSTATS *pPresentationStatistics )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineSwapChain9Ex_GetPresentStats(This, pPresentationStatistics);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockSwapChain9Ex_GetDisplayModeEx( struct NineSwapChain9Ex *This,
+                                   D3DDISPLAYMODEEX *pMode,
+                                   D3DDISPLAYROTATION *pRotation )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineSwapChain9Ex_GetDisplayModeEx(This, pMode, pRotation);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+IDirect3DSwapChain9ExVtbl LockSwapChain9Ex_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)LockSwapChain9_Present,
+    (void *)LockSwapChain9_GetFrontBufferData,
+    (void *)LockSwapChain9_GetBackBuffer,
+    (void *)LockSwapChain9_GetRasterStatus,
+    (void *)LockSwapChain9_GetDisplayMode,
+    (void *)NineUnknown_GetDevice, /* actually part of NineSwapChain9 iface */
+    (void *)LockSwapChain9_GetPresentParameters,
+    (void *)LockSwapChain9Ex_GetLastPresentCount,
+    (void *)LockSwapChain9Ex_GetPresentStats,
+    (void *)LockSwapChain9Ex_GetDisplayModeEx
+};
+
+#if 0
+static HRESULT WINAPI
+LockTexture9_GetLevelDesc( struct NineTexture9 *This,
+                           UINT Level,
+                           D3DSURFACE_DESC *pDesc )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineTexture9_GetLevelDesc(This, Level, pDesc);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+#endif
+
+#if 0
+static HRESULT WINAPI
+LockTexture9_GetSurfaceLevel( struct NineTexture9 *This,
+                              UINT Level,
+                              IDirect3DSurface9 **ppSurfaceLevel )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineTexture9_GetSurfaceLevel(This, Level, ppSurfaceLevel);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+#endif
+
+static HRESULT WINAPI
+LockTexture9_LockRect( struct NineTexture9 *This,
+                       UINT Level,
+                       D3DLOCKED_RECT *pLockedRect,
+                       const RECT *pRect,
+                       DWORD Flags )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineTexture9_LockRect(This, Level, pLockedRect, pRect, Flags);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockTexture9_UnlockRect( struct NineTexture9 *This,
+                         UINT Level )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineTexture9_UnlockRect(This, Level);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockTexture9_AddDirtyRect( struct NineTexture9 *This,
+                           const RECT *pDirtyRect )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineTexture9_AddDirtyRect(This, pDirtyRect);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+IDirect3DTexture9Vtbl LockTexture9_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */
+    (void *)LockResource9_SetPrivateData,
+    (void *)LockResource9_GetPrivateData,
+    (void *)LockResource9_FreePrivateData,
+    (void *)LockResource9_SetPriority,
+    (void *)LockResource9_GetPriority,
+    (void *)LockBaseTexture9_PreLoad,
+    (void *)NineResource9_GetType, /* immutable */
+    (void *)LockBaseTexture9_SetLOD,
+    (void *)LockBaseTexture9_GetLOD,
+    (void *)LockBaseTexture9_GetLevelCount,
+    (void *)LockBaseTexture9_SetAutoGenFilterType,
+    (void *)LockBaseTexture9_GetAutoGenFilterType,
+    (void *)LockBaseTexture9_GenerateMipSubLevels,
+    (void *)NineTexture9_GetLevelDesc, /* immutable */
+    (void *)NineTexture9_GetSurfaceLevel, /* AddRef */
+    (void *)LockTexture9_LockRect,
+    (void *)LockTexture9_UnlockRect,
+    (void *)LockTexture9_AddDirtyRect
+};
+
+static HRESULT WINAPI
+LockVertexBuffer9_Lock( struct NineVertexBuffer9 *This,
+                        UINT OffsetToLock,
+                        UINT SizeToLock,
+                        void **ppbData,
+                        DWORD Flags )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineVertexBuffer9_Lock(This, OffsetToLock, SizeToLock, ppbData, Flags);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockVertexBuffer9_Unlock( struct NineVertexBuffer9 *This )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineVertexBuffer9_Unlock(This);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+#if 0
+static HRESULT WINAPI
+LockVertexBuffer9_GetDesc( struct NineVertexBuffer9 *This,
+                           D3DVERTEXBUFFER_DESC *pDesc )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineVertexBuffer9_GetDesc(This, pDesc);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+#endif
+
+IDirect3DVertexBuffer9Vtbl LockVertexBuffer9_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */
+    (void *)LockResource9_SetPrivateData,
+    (void *)LockResource9_GetPrivateData,
+    (void *)LockResource9_FreePrivateData,
+    (void *)LockResource9_SetPriority,
+    (void *)LockResource9_GetPriority,
+    (void *)NineResource9_PreLoad, /* nop */
+    (void *)NineResource9_GetType, /* immutable */
+    (void *)LockVertexBuffer9_Lock,
+    (void *)LockVertexBuffer9_Unlock,
+    (void *)NineVertexBuffer9_GetDesc /* immutable */
+};
+
+#if 0
+static HRESULT WINAPI
+LockVertexDeclaration9_GetDevice( struct NineVertexDeclaration9 *This,
+                                  IDirect3DDevice9 **ppDevice )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineUnknown_GetDevice(NineUnknown(This), ppDevice);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+#endif
+
+static HRESULT WINAPI
+LockVertexDeclaration9_GetDeclaration( struct NineVertexDeclaration9 *This,
+                                       D3DVERTEXELEMENT9 *pElement,
+                                       UINT *pNumElements )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineVertexDeclaration9_GetDeclaration(This, pElement, pNumElements);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+IDirect3DVertexDeclaration9Vtbl LockVertexDeclaration9_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)NineUnknown_GetDevice, /* actually part of VertexDecl9 iface */
+    (void *)LockVertexDeclaration9_GetDeclaration
+};
+
+#if 0
+static HRESULT WINAPI
+LockVertexShader9_GetDevice( struct NineVertexShader9 *This,
+                             IDirect3DDevice9 **ppDevice )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineUnknown_GetDevice(NineUnknown(This), ppDevice);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+#endif
+
+static HRESULT WINAPI
+LockVertexShader9_GetFunction( struct NineVertexShader9 *This,
+                               void *pData,
+                               UINT *pSizeOfData )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineVertexShader9_GetFunction(This, pData, pSizeOfData);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+IDirect3DVertexShader9Vtbl LockVertexShader9_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)NineUnknown_GetDevice,
+    (void *)LockVertexShader9_GetFunction
+};
+
+#if 0
+static HRESULT WINAPI
+LockVolume9_GetDevice( struct NineVolume9 *This,
+                       IDirect3DDevice9 **ppDevice )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineUnknown_GetDevice(NineUnknown(This), ppDevice);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+#endif
+
+static HRESULT WINAPI
+LockVolume9_SetPrivateData( struct NineVolume9 *This,
+                            REFGUID refguid,
+                            const void *pData,
+                            DWORD SizeOfData,
+                            DWORD Flags )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineVolume9_SetPrivateData(This, refguid, pData, SizeOfData, Flags);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockVolume9_GetPrivateData( struct NineVolume9 *This,
+                            REFGUID refguid,
+                            void *pData,
+                            DWORD *pSizeOfData )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineVolume9_GetPrivateData(This, refguid, pData, pSizeOfData);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockVolume9_FreePrivateData( struct NineVolume9 *This,
+                             REFGUID refguid )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineVolume9_FreePrivateData(This, refguid);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockVolume9_GetContainer( struct NineVolume9 *This,
+                          REFIID riid,
+                          void **ppContainer )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineVolume9_GetContainer(This, riid, ppContainer);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+#if 0
+static HRESULT WINAPI
+LockVolume9_GetDesc( struct NineVolume9 *This,
+                     D3DVOLUME_DESC *pDesc )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineVolume9_GetDesc(This, pDesc);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+#endif
+
+static HRESULT WINAPI
+LockVolume9_LockBox( struct NineVolume9 *This,
+                     D3DLOCKED_BOX *pLockedVolume,
+                     const D3DBOX *pBox,
+                     DWORD Flags )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineVolume9_LockBox(This, pLockedVolume, pBox, Flags);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockVolume9_UnlockBox( struct NineVolume9 *This )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineVolume9_UnlockBox(This);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+IDirect3DVolume9Vtbl LockVolume9_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)NineUnknown_GetDevice, /* actually part of Volume9 iface */
+    (void *)LockVolume9_SetPrivateData,
+    (void *)LockVolume9_GetPrivateData,
+    (void *)LockVolume9_FreePrivateData,
+    (void *)LockVolume9_GetContainer,
+    (void *)NineVolume9_GetDesc, /* immutable */
+    (void *)LockVolume9_LockBox,
+    (void *)LockVolume9_UnlockBox
+};
+
+#if 0
+static HRESULT WINAPI
+LockVolumeTexture9_GetLevelDesc( struct NineVolumeTexture9 *This,
+                                 UINT Level,
+                                 D3DVOLUME_DESC *pDesc )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineVolumeTexture9_GetLevelDesc(This, Level, pDesc);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+#endif
+
+#if 0
+static HRESULT WINAPI
+LockVolumeTexture9_GetVolumeLevel( struct NineVolumeTexture9 *This,
+                                   UINT Level,
+                                   IDirect3DVolume9 **ppVolumeLevel )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineVolumeTexture9_GetVolumeLevel(This, Level, ppVolumeLevel);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+#endif
+
+static HRESULT WINAPI
+LockVolumeTexture9_LockBox( struct NineVolumeTexture9 *This,
+                            UINT Level,
+                            D3DLOCKED_BOX *pLockedVolume,
+                            const D3DBOX *pBox,
+                            DWORD Flags )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineVolumeTexture9_LockBox(This, Level, pLockedVolume, pBox, Flags);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockVolumeTexture9_UnlockBox( struct NineVolumeTexture9 *This,
+                              UINT Level )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineVolumeTexture9_UnlockBox(This, Level);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+static HRESULT WINAPI
+LockVolumeTexture9_AddDirtyBox( struct NineVolumeTexture9 *This,
+                                const D3DBOX *pDirtyBox )
+{
+    HRESULT r;
+    pipe_mutex_lock(d3dlock_global);
+    r = NineVolumeTexture9_AddDirtyBox(This, pDirtyBox);
+    pipe_mutex_unlock(d3dlock_global);
+    return r;
+}
+
+IDirect3DVolumeTexture9Vtbl LockVolumeTexture9_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */
+    (void *)LockResource9_SetPrivateData,
+    (void *)LockResource9_GetPrivateData,
+    (void *)LockResource9_FreePrivateData,
+    (void *)LockResource9_SetPriority,
+    (void *)LockResource9_GetPriority,
+    (void *)LockBaseTexture9_PreLoad,
+    (void *)NineResource9_GetType, /* immutable */
+    (void *)LockBaseTexture9_SetLOD,
+    (void *)LockBaseTexture9_GetLOD,
+    (void *)LockBaseTexture9_GetLevelCount,
+    (void *)LockBaseTexture9_SetAutoGenFilterType,
+    (void *)LockBaseTexture9_GetAutoGenFilterType,
+    (void *)LockBaseTexture9_GenerateMipSubLevels,
+    (void *)NineVolumeTexture9_GetLevelDesc, /* immutable */
+    (void *)NineVolumeTexture9_GetVolumeLevel, /* AddRef */
+    (void *)LockVolumeTexture9_LockBox,
+    (void *)LockVolumeTexture9_UnlockBox,
+    (void *)LockVolumeTexture9_AddDirtyBox
+};
+
+ID3DAdapter9Vtbl LockAdapter9_vtable = { /* not used */
+    (void *)NULL,
+    (void *)NULL,
+    (void *)NULL,
+    (void *)NULL,
+    (void *)NULL,
+    (void *)NULL,
+    (void *)NULL,
+    (void *)NULL,
+    (void *)NULL,
+    (void *)NULL,
+    (void *)NULL,
+    (void *)NULL
+};
diff --git a/src/gallium/state_trackers/nine/nine_lock.h b/src/gallium/state_trackers/nine/nine_lock.h
new file mode 100644 (file)
index 0000000..9738a20
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2013 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _NINE_LOCK_H_
+#define _NINE_LOCK_H_
+
+#include "d3d9.h"
+#include "d3dadapter/d3dadapter9.h"
+
+extern IDirect3DAuthenticatedChannel9Vtbl LockAuthenticatedChannel9_vtable;
+extern IDirect3DCryptoSession9Vtbl LockCryptoSession9_vtable;
+extern IDirect3DCubeTexture9Vtbl LockCubeTexture9_vtable;
+extern IDirect3DDevice9Vtbl LockDevice9_vtable;
+extern IDirect3DDevice9ExVtbl LockDevice9Ex_vtable;
+extern IDirect3DDevice9VideoVtbl LockDevice9Video_vtable;
+extern IDirect3DIndexBuffer9Vtbl LockIndexBuffer9_vtable;
+extern IDirect3DPixelShader9Vtbl LockPixelShader9_vtable;
+extern IDirect3DQuery9Vtbl LockQuery9_vtable;
+extern IDirect3DStateBlock9Vtbl LockStateBlock9_vtable;
+extern IDirect3DSurface9Vtbl LockSurface9_vtable;
+extern IDirect3DSwapChain9Vtbl LockSwapChain9_vtable;
+extern IDirect3DSwapChain9ExVtbl LockSwapChain9Ex_vtable;
+extern IDirect3DTexture9Vtbl LockTexture9_vtable;
+extern IDirect3DVertexBuffer9Vtbl LockVertexBuffer9_vtable;
+extern IDirect3DVertexDeclaration9Vtbl LockVertexDeclaration9_vtable;
+extern IDirect3DVertexShader9Vtbl LockVertexShader9_vtable;
+extern IDirect3DVolume9Vtbl LockVolume9_vtable;
+extern IDirect3DVolumeTexture9Vtbl LockVolumeTexture9_vtable;
+extern IDirect3DVolumeTexture9Vtbl LockVolumeTexture9_vtable;
+extern ID3DAdapter9Vtbl LockAdapter9_vtable;
+
+#endif /* _NINE_LOCK_H_ */
diff --git a/src/gallium/state_trackers/nine/nine_pdata.h b/src/gallium/state_trackers/nine/nine_pdata.h
new file mode 100644 (file)
index 0000000..7bdd702
--- /dev/null
@@ -0,0 +1,45 @@
+
+#ifndef _NINE_PDATA_H_
+#define _NINE_PDATA_H_
+
+struct pheader
+{
+    boolean unknown;
+    DWORD size;
+    char data[1];
+};
+
+static int
+ht_guid_compare( void *a,
+                 void *b )
+{
+    return GUID_equal(a, b) ? 0 : 1;
+}
+
+static unsigned
+ht_guid_hash( void *key )
+{
+    unsigned i, hash = 0;
+    const unsigned char *str = key;
+
+    for (i = 0; i < sizeof(GUID); i++) {
+        hash = (unsigned)(str[i]) + (hash << 6) + (hash << 16) - hash;
+    }
+
+    return hash;
+}
+
+static enum pipe_error
+ht_guid_delete( void *key,
+                void *value,
+                void *data )
+{
+    struct pheader *header = value;
+
+    if (header->unknown) { IUnknown_Release(*(IUnknown **)header->data); }
+    FREE(header);
+
+    return PIPE_OK;
+}
+
+#endif /* _NINE_PDATA_H_ */
diff --git a/src/gallium/state_trackers/nine/nine_pipe.c b/src/gallium/state_trackers/nine/nine_pipe.c
new file mode 100644 (file)
index 0000000..3a7bb90
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ * Copyright 2013 Christoph Bumiller
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "device9.h"
+#include "nine_pipe.h"
+
+#include "cso_cache/cso_context.h"
+
+void
+nine_convert_dsa_state(struct cso_context *ctx, const DWORD *rs)
+{
+    struct pipe_depth_stencil_alpha_state dsa;
+
+    memset(&dsa, 0, sizeof(dsa)); /* memcmp safety */
+
+    if (rs[D3DRS_ZENABLE]) {
+        dsa.depth.enabled = 1;
+        dsa.depth.writemask = !!rs[D3DRS_ZWRITEENABLE];
+        dsa.depth.func = d3dcmpfunc_to_pipe_func(rs[D3DRS_ZFUNC]);
+    }
+
+    if (rs[D3DRS_STENCILENABLE]) {
+        dsa.stencil[0].enabled = 1;
+        dsa.stencil[0].func = d3dcmpfunc_to_pipe_func(rs[D3DRS_STENCILFUNC]);
+        dsa.stencil[0].fail_op = d3dstencilop_to_pipe_stencil_op(rs[D3DRS_STENCILFAIL]);
+        dsa.stencil[0].zpass_op = d3dstencilop_to_pipe_stencil_op(rs[D3DRS_STENCILPASS]);
+        dsa.stencil[0].zfail_op = d3dstencilop_to_pipe_stencil_op(rs[D3DRS_STENCILZFAIL]);
+        dsa.stencil[0].valuemask = rs[D3DRS_STENCILMASK];
+        dsa.stencil[0].writemask = rs[D3DRS_STENCILWRITEMASK];
+
+        if (rs[D3DRS_TWOSIDEDSTENCILMODE]) {
+            dsa.stencil[1].enabled = 1;
+            dsa.stencil[1].func = d3dcmpfunc_to_pipe_func(rs[D3DRS_CCW_STENCILFUNC]);
+            dsa.stencil[1].fail_op = d3dstencilop_to_pipe_stencil_op(rs[D3DRS_CCW_STENCILFAIL]);
+            dsa.stencil[1].zpass_op = d3dstencilop_to_pipe_stencil_op(rs[D3DRS_CCW_STENCILPASS]);
+            dsa.stencil[1].zfail_op = d3dstencilop_to_pipe_stencil_op(rs[D3DRS_CCW_STENCILZFAIL]);
+            dsa.stencil[1].valuemask = dsa.stencil[0].valuemask;
+            dsa.stencil[1].writemask = dsa.stencil[0].writemask;
+        }
+    }
+
+    if (rs[D3DRS_ALPHATESTENABLE]) {
+        dsa.alpha.enabled = 1;
+        dsa.alpha.func = d3dcmpfunc_to_pipe_func(rs[D3DRS_ALPHAFUNC]);
+        dsa.alpha.ref_value = (float)rs[D3DRS_ALPHAREF] / 255.0f;
+    }
+
+    cso_set_depth_stencil_alpha(ctx, &dsa);
+}
+
+/* TODO: Keep a static copy in device so we don't have to memset every time ? */
+void
+nine_convert_rasterizer_state(struct cso_context *ctx, const DWORD *rs)
+{
+    struct pipe_rasterizer_state rast;
+
+    memset(&rast, 0, sizeof(rast)); /* memcmp safety */
+
+    rast.flatshade = rs[D3DRS_SHADEMODE] == D3DSHADE_FLAT;
+ /* rast.light_twoside = 0; */
+ /* rast.clamp_fragment_color = 0; */
+ /* rast.clamp_vertex_color = 0; */
+ /* rast.front_ccw = 0; */
+    rast.cull_face = d3dcull_to_pipe_face(rs[D3DRS_CULLMODE]);
+    rast.fill_front = d3dfillmode_to_pipe_polygon_mode(rs[D3DRS_FILLMODE]);
+    rast.fill_back = rast.fill_front;
+    rast.offset_tri = !!(rs[D3DRS_DEPTHBIAS] | rs[D3DRS_SLOPESCALEDEPTHBIAS]);
+    rast.offset_line = rast.offset_tri; /* triangles in wireframe mode */
+    rast.offset_point = 0; /* XXX ? */
+    rast.scissor = !!rs[D3DRS_SCISSORTESTENABLE];
+ /* rast.poly_smooth = 0; */
+ /* rast.poly_stipple_enable = 0; */
+ /* rast.point_smooth = 0; */
+    rast.sprite_coord_mode = PIPE_SPRITE_COORD_UPPER_LEFT;
+    rast.point_quad_rasterization = !!rs[D3DRS_POINTSPRITEENABLE];
+    rast.point_size_per_vertex = rs[NINED3DRS_VSPOINTSIZE];
+    rast.multisample = !!rs[D3DRS_MULTISAMPLEANTIALIAS];
+    rast.line_smooth = !!rs[D3DRS_ANTIALIASEDLINEENABLE];
+ /* rast.line_stipple_enable = 0; */
+    rast.line_last_pixel = !!rs[D3DRS_LASTPIXEL];
+    rast.flatshade_first = 1;
+ /* rast.half_pixel_center = 0; */
+ /* rast.lower_left_origin = 0; */
+ /* rast.bottom_edge_rule = 0; */
+ /* rast.rasterizer_discard = 0; */
+    rast.depth_clip = 1;
+    rast.clip_halfz = 1;
+    rast.clip_plane_enable = rs[D3DRS_CLIPPLANEENABLE];
+ /* rast.line_stipple_factor = 0; */
+ /* rast.line_stipple_pattern = 0; */
+    rast.sprite_coord_enable = rs[D3DRS_POINTSPRITEENABLE] ? 0xff : 0x00;
+    rast.line_width = 1.0f;
+    rast.point_size = rs[NINED3DRS_VSPOINTSIZE] ? 1.0f : asfloat(rs[D3DRS_POINTSIZE]); /* XXX: D3DRS_POINTSIZE_MIN/MAX */
+    rast.offset_units = asfloat(rs[D3DRS_DEPTHBIAS]) * asfloat(rs[NINED3DRS_ZBIASSCALE]);
+    rast.offset_scale = asfloat(rs[D3DRS_SLOPESCALEDEPTHBIAS]);
+ /* rast.offset_clamp = 0.0f; */
+
+    cso_set_rasterizer(ctx, &rast);
+}
+
+static INLINE void
+nine_convert_blend_state_fixup(struct pipe_blend_state *blend, const DWORD *rs)
+{
+    if (unlikely(rs[D3DRS_SRCBLEND] == D3DBLEND_BOTHSRCALPHA ||
+                 rs[D3DRS_SRCBLEND] == D3DBLEND_BOTHINVSRCALPHA)) {
+        blend->rt[0].rgb_dst_factor = (rs[D3DRS_SRCBLEND] == D3DBLEND_BOTHSRCALPHA) ?
+            PIPE_BLENDFACTOR_INV_SRC_ALPHA : PIPE_BLENDFACTOR_SRC_ALPHA;
+        if (!rs[D3DRS_SEPARATEALPHABLENDENABLE])
+            blend->rt[0].alpha_dst_factor = blend->rt[0].rgb_dst_factor;
+    } else
+    if (unlikely(rs[D3DRS_SEPARATEALPHABLENDENABLE] &&
+                 (rs[D3DRS_SRCBLENDALPHA] == D3DBLEND_BOTHSRCALPHA ||
+                  rs[D3DRS_SRCBLENDALPHA] == D3DBLEND_BOTHINVSRCALPHA))) {
+        blend->rt[0].alpha_dst_factor = (rs[D3DRS_SRCBLENDALPHA] == D3DBLEND_BOTHSRCALPHA) ?
+            PIPE_BLENDFACTOR_INV_SRC_ALPHA : PIPE_BLENDFACTOR_SRC_ALPHA;
+    }
+}
+
+void
+nine_convert_blend_state(struct cso_context *ctx, const DWORD *rs)
+{
+    struct pipe_blend_state blend;
+
+    memset(&blend, 0, sizeof(blend)); /* memcmp safety */
+
+    blend.dither = !!rs[D3DRS_DITHERENABLE];
+
+ /* blend.alpha_to_one = 0; */
+ /* blend.alpha_to_coverage = 0; */ /* XXX */
+
+    blend.rt[0].blend_enable = !!rs[D3DRS_ALPHABLENDENABLE];
+    if (blend.rt[0].blend_enable) {
+        blend.rt[0].rgb_func = d3dblendop_to_pipe_blend(rs[D3DRS_BLENDOP]);
+        blend.rt[0].rgb_src_factor = d3dblend_color_to_pipe_blendfactor(rs[D3DRS_SRCBLEND]);
+        blend.rt[0].rgb_dst_factor = d3dblend_color_to_pipe_blendfactor(rs[D3DRS_DESTBLEND]);
+        if (rs[D3DRS_SEPARATEALPHABLENDENABLE]) {
+            blend.rt[0].alpha_func = d3dblendop_to_pipe_blend(rs[D3DRS_BLENDOPALPHA]);
+            blend.rt[0].alpha_src_factor = d3dblend_alpha_to_pipe_blendfactor(rs[D3DRS_SRCBLENDALPHA]);
+            blend.rt[0].alpha_dst_factor = d3dblend_alpha_to_pipe_blendfactor(rs[D3DRS_DESTBLENDALPHA]);
+        } else {
+            /* TODO: Just copy the rgb values ? SRC1_x may differ ... */
+            blend.rt[0].alpha_func = blend.rt[0].rgb_func;
+            blend.rt[0].alpha_src_factor = d3dblend_alpha_to_pipe_blendfactor(rs[D3DRS_SRCBLEND]);
+            blend.rt[0].alpha_dst_factor = d3dblend_alpha_to_pipe_blendfactor(rs[D3DRS_DESTBLEND]);
+        }
+        nine_convert_blend_state_fixup(&blend, rs); /* for BOTH[INV]SRCALPHA */
+    }
+    blend.rt[0].colormask = rs[D3DRS_COLORWRITEENABLE];
+
+    if (rs[D3DRS_COLORWRITEENABLE1] != rs[D3DRS_COLORWRITEENABLE] ||
+        rs[D3DRS_COLORWRITEENABLE2] != rs[D3DRS_COLORWRITEENABLE] ||
+        rs[D3DRS_COLORWRITEENABLE3] != rs[D3DRS_COLORWRITEENABLE]) {
+        unsigned i;
+        blend.independent_blend_enable = TRUE;
+        for (i = 1; i < 4; ++i)
+            blend.rt[i] = blend.rt[0];
+        blend.rt[1].colormask = rs[D3DRS_COLORWRITEENABLE1];
+        blend.rt[2].colormask = rs[D3DRS_COLORWRITEENABLE2];
+        blend.rt[3].colormask = rs[D3DRS_COLORWRITEENABLE3];
+    }
+
+    /* blend.force_srgb = !!rs[D3DRS_SRGBWRITEENABLE]; */
+
+    cso_set_blend(ctx, &blend);
+}
+
+void
+nine_convert_sampler_state(struct cso_context *ctx, int idx, const DWORD *ss)
+{
+    struct pipe_sampler_state samp;
+
+    assert(idx >= 0 &&
+           (idx < NINE_MAX_SAMPLERS_PS || idx >= NINE_SAMPLER_VS(0)) &&
+           (idx < NINE_MAX_SAMPLERS));
+
+    memset(&samp, 0, sizeof(samp)); /* memcmp safety */
+
+    if (ss[D3DSAMP_MIPFILTER] != D3DTEXF_NONE) {
+        samp.lod_bias = asfloat(ss[D3DSAMP_MIPMAPLODBIAS]);
+        samp.min_lod = ss[NINED3DSAMP_MINLOD];
+        samp.min_mip_filter = (ss[D3DSAMP_MIPFILTER] == D3DTEXF_POINT) ? PIPE_TEX_FILTER_NEAREST : PIPE_TEX_FILTER_LINEAR;
+    } else {
+        samp.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
+    }
+    samp.max_lod = 15.0f;
+    samp.wrap_s = d3dtextureaddress_to_pipe_tex_wrap(ss[D3DSAMP_ADDRESSU]);
+    samp.wrap_t = d3dtextureaddress_to_pipe_tex_wrap(ss[D3DSAMP_ADDRESSV]);
+    samp.wrap_r = d3dtextureaddress_to_pipe_tex_wrap(ss[D3DSAMP_ADDRESSW]);
+    samp.min_img_filter = ss[D3DSAMP_MINFILTER] == D3DTEXF_POINT ? PIPE_TEX_FILTER_NEAREST : PIPE_TEX_FILTER_LINEAR;
+    samp.mag_img_filter = ss[D3DSAMP_MAGFILTER] == D3DTEXF_POINT ? PIPE_TEX_FILTER_NEAREST : PIPE_TEX_FILTER_LINEAR;
+    if (ss[D3DSAMP_MINFILTER] == D3DTEXF_ANISOTROPIC ||
+        ss[D3DSAMP_MAGFILTER] == D3DTEXF_ANISOTROPIC)
+        samp.max_anisotropy = ss[D3DSAMP_MAXANISOTROPY];
+    samp.compare_mode = ss[NINED3DSAMP_SHADOW] ? PIPE_TEX_COMPARE_R_TO_TEXTURE : PIPE_TEX_COMPARE_NONE;
+    samp.compare_func = PIPE_FUNC_LEQUAL;
+    samp.normalized_coords = 1;
+    samp.seamless_cube_map = 1;
+    d3dcolor_to_pipe_color_union(&samp.border_color, ss[D3DSAMP_BORDERCOLOR]);
+
+    /* see nine_state.h */
+    if (idx < NINE_MAX_SAMPLERS_PS)
+        cso_single_sampler(ctx, PIPE_SHADER_FRAGMENT, idx - NINE_SAMPLER_PS(0), &samp);
+    else
+        cso_single_sampler(ctx, PIPE_SHADER_VERTEX, idx - NINE_SAMPLER_VS(0), &samp);
+}
+
+void
+nine_pipe_context_clear(struct NineDevice9 *This)
+{
+    struct pipe_context *pipe = This->pipe;
+    struct cso_context *cso = This->cso;
+    pipe->bind_vs_state(pipe, NULL);
+    pipe->bind_fs_state(pipe, NULL);
+
+    /* Don't unbind constant buffers, they're device-private and
+     * do not change on Reset.
+     */
+
+    cso_set_samplers(cso, PIPE_SHADER_VERTEX, 0, NULL);
+    cso_set_samplers(cso, PIPE_SHADER_FRAGMENT, 0, NULL);
+
+    pipe->set_sampler_views(pipe, PIPE_SHADER_FRAGMENT, 0, 0, NULL);
+    pipe->set_sampler_views(pipe, PIPE_SHADER_VERTEX, 0, 0, NULL);
+
+    pipe->set_vertex_buffers(pipe, 0, This->caps.MaxStreams, NULL);
+    pipe->set_index_buffer(pipe, NULL);
+}
+
+const enum pipe_format nine_d3d9_to_pipe_format_map[120] =
+{
+   [D3DFMT_UNKNOWN] = PIPE_FORMAT_NONE,
+
+   [D3DFMT_A8R8G8B8]     = PIPE_FORMAT_B8G8R8A8_UNORM,
+   [D3DFMT_X8R8G8B8]     = PIPE_FORMAT_B8G8R8X8_UNORM,
+   [D3DFMT_R5G6B5]       = PIPE_FORMAT_B5G6R5_UNORM,
+   [D3DFMT_X1R5G5B5]     = PIPE_FORMAT_B5G5R5X1_UNORM,
+   [D3DFMT_A1R5G5B5]     = PIPE_FORMAT_B5G5R5A1_UNORM,
+   [D3DFMT_A4R4G4B4]     = PIPE_FORMAT_B4G4R4A4_UNORM,
+   [D3DFMT_A8]           = PIPE_FORMAT_A8_UNORM,
+   [D3DFMT_X4R4G4B4]     = PIPE_FORMAT_B4G4R4X4_UNORM,
+   [D3DFMT_R3G3B2]       = PIPE_FORMAT_B2G3R3_UNORM,
+   [D3DFMT_A2B10G10R10]  = PIPE_FORMAT_R10G10B10A2_UNORM,
+   [D3DFMT_A8B8G8R8]     = PIPE_FORMAT_R8G8B8A8_UNORM,
+   [D3DFMT_X8B8G8R8]     = PIPE_FORMAT_R8G8B8X8_UNORM,
+   [D3DFMT_G16R16]       = PIPE_FORMAT_R16G16_UNORM,
+   [D3DFMT_A2R10G10B10]  = PIPE_FORMAT_B10G10R10A2_UNORM,
+   [D3DFMT_A16B16G16R16] = PIPE_FORMAT_R16G16B16A16_UNORM,
+
+    /* palette texture formats not supported by gallium/hardware, TODO ? */
+   [D3DFMT_P8]   = PIPE_FORMAT_NONE,
+   [D3DFMT_A8P8] = PIPE_FORMAT_NONE,
+
+   [D3DFMT_L8]   = PIPE_FORMAT_L8_UNORM,
+   [D3DFMT_A8L8] = PIPE_FORMAT_L8A8_UNORM,
+   [D3DFMT_A4L4] = PIPE_FORMAT_L4A4_UNORM,
+
+   [D3DFMT_V8U8]        = PIPE_FORMAT_R8G8_SNORM,
+   [D3DFMT_Q8W8V8U8]    = PIPE_FORMAT_R8G8B8A8_SNORM,
+   [D3DFMT_V16U16]      = PIPE_FORMAT_R16G16_SNORM,
+   [D3DFMT_A2W10V10U10] = PIPE_FORMAT_R10SG10SB10SA2U_NORM,
+
+   /* [D3DFMT_UYVY] = PIPE_FORMAT_YUYV, fourcc */
+   /* [D3DFMT_YUY2] = PIPE_FORMAT_NONE, fourcc */
+
+   /* XXX: DXT2, DXT4 */
+   /* fourcc
+   [D3DFMT_DXT1] = PIPE_FORMAT_DXT1_RGBA,
+   [D3DFMT_DXT2] = PIPE_FORMAT_DXT3_RGBA,
+   [D3DFMT_DXT3] = PIPE_FORMAT_DXT3_RGBA,
+   [D3DFMT_DXT4] = PIPE_FORMAT_DXT5_RGBA,
+   [D3DFMT_DXT5] = PIPE_FORMAT_DXT5_RGBA,
+   */
+
+   /* XXX: order ? */
+   /* fourcc
+   [D3DFMT_G8R8_G8B8] = PIPE_FORMAT_G8R8_G8B8_UNORM,
+   [D3DFMT_R8G8_B8G8] = PIPE_FORMAT_R8G8_B8G8_UNORM,
+   */
+
+   [D3DFMT_D16_LOCKABLE]  = PIPE_FORMAT_Z16_UNORM,
+   [D3DFMT_D32]           = PIPE_FORMAT_Z32_UNORM,
+   [D3DFMT_D24S8]         = PIPE_FORMAT_S8_UINT_Z24_UNORM,
+   [D3DFMT_D24X8]         = PIPE_FORMAT_X8Z24_UNORM,
+   [D3DFMT_D16]           = PIPE_FORMAT_Z16_UNORM,
+   [D3DFMT_L16]           = PIPE_FORMAT_L16_UNORM,
+   [D3DFMT_D32F_LOCKABLE] = PIPE_FORMAT_Z32_FLOAT,
+
+   [D3DFMT_INDEX16]      = PIPE_FORMAT_R16_UINT,
+   [D3DFMT_INDEX32]      = PIPE_FORMAT_R32_UINT,
+   [D3DFMT_Q16W16V16U16] = PIPE_FORMAT_R16G16B16A16_SNORM,
+
+   [D3DFMT_R16F]          = PIPE_FORMAT_R16_FLOAT,
+   [D3DFMT_R32F]          = PIPE_FORMAT_R32_FLOAT,
+   [D3DFMT_G16R16F]       = PIPE_FORMAT_R16G16_FLOAT,
+   [D3DFMT_G32R32F]       = PIPE_FORMAT_R32G32_FLOAT,
+   [D3DFMT_A16B16G16R16F] = PIPE_FORMAT_R16G16B16A16_FLOAT,
+   [D3DFMT_A32B32G32R32F] = PIPE_FORMAT_R32G32B32A32_FLOAT,
+
+   /* non-1:1 formats (don't support because we'd have to convert) */
+   [D3DFMT_R8G8B8]   = PIPE_FORMAT_NONE, /* XXX order */
+   [D3DFMT_A8R3G3B2] = PIPE_FORMAT_NONE, /* XXX alpha */
+   /* This is ok because they're not lockable: */
+   [D3DFMT_D15S1]    = PIPE_FORMAT_Z24_UNORM_S8_UINT,
+   [D3DFMT_D24X4S4]  = PIPE_FORMAT_Z24_UNORM_S8_UINT,
+   [D3DFMT_D24FS8]   = PIPE_FORMAT_Z32_FLOAT_S8X24_UINT,
+
+   /* not really formats */
+   [D3DFMT_VERTEXDATA]   = PIPE_FORMAT_NONE,
+   /* [D3DFMT_BINARYBUFFER] = PIPE_FORMAT_NONE, too large */
+
+   /* unsupported formats */
+   [D3DFMT_L6V5U5]      = PIPE_FORMAT_NONE,
+   [D3DFMT_X8L8V8U8]    = PIPE_FORMAT_NONE,
+
+   /* [D3DFMT_MULTI2_ARGB8] = PIPE_FORMAT_NONE, fourcc, MET */
+
+   [D3DFMT_CxV8U8]              = PIPE_FORMAT_NONE,
+   [D3DFMT_A1]                  = PIPE_FORMAT_NONE, /* XXX: add this ? */
+   [D3DFMT_A2B10G10R10_XR_BIAS] = PIPE_FORMAT_NONE, /* XXX ? */
+};
+
+const D3DFORMAT nine_pipe_to_d3d9_format_map[PIPE_FORMAT_COUNT] =
+{
+   [PIPE_FORMAT_NONE]               = D3DFMT_UNKNOWN,
+
+/* [PIPE_FORMAT_B8G8R8_UNORM]       = D3DFMT_R8G8B8, */
+   [PIPE_FORMAT_B8G8R8A8_UNORM]     = D3DFMT_A8R8G8B8,
+   [PIPE_FORMAT_B8G8R8X8_UNORM]     = D3DFMT_X8R8G8B8,
+   [PIPE_FORMAT_B5G6R5_UNORM]       = D3DFMT_R5G6B5,
+   [PIPE_FORMAT_B5G5R5X1_UNORM]     = D3DFMT_X1R5G5B5,
+   [PIPE_FORMAT_B5G5R5A1_UNORM]     = D3DFMT_A1R5G5B5,
+   [PIPE_FORMAT_B4G4R4A4_UNORM]     = D3DFMT_A4R4G4B4,
+   [PIPE_FORMAT_B2G3R3_UNORM]       = D3DFMT_R3G3B2,
+   [PIPE_FORMAT_A8_UNORM]           = D3DFMT_A8,
+/* [PIPE_FORMAT_B2G3R3A8_UNORM]     = D3DFMT_A8R3G3B2, */
+   [PIPE_FORMAT_B4G4R4X4_UNORM]     = D3DFMT_X4R4G4B4,
+   [PIPE_FORMAT_R10G10B10A2_UNORM]  = D3DFMT_A2B10G10R10,
+   [PIPE_FORMAT_R8G8B8A8_UNORM]     = D3DFMT_A8B8G8R8,
+   [PIPE_FORMAT_R8G8B8X8_UNORM]     = D3DFMT_X8B8G8R8,
+   [PIPE_FORMAT_R16G16_UNORM]       = D3DFMT_G16R16,
+   [PIPE_FORMAT_B10G10R10A2_UNORM]  = D3DFMT_A2R10G10B10,
+   [PIPE_FORMAT_R16G16B16A16_UNORM] = D3DFMT_A16B16G16R16,
+
+   [PIPE_FORMAT_R8_UINT]            = D3DFMT_P8,
+   [PIPE_FORMAT_R8A8_UINT]          = D3DFMT_A8P8,
+
+   [PIPE_FORMAT_L8_UNORM]           = D3DFMT_L8,
+   [PIPE_FORMAT_L8A8_UNORM]         = D3DFMT_A8L8,
+   [PIPE_FORMAT_L4A4_UNORM]         = D3DFMT_A4L4,
+
+   [PIPE_FORMAT_R8G8_SNORM]           = D3DFMT_V8U8,
+/* [PIPE_FORMAT_?]                    = D3DFMT_L6V5U5, */
+/* [PIPE_FORMAT_?]                    = D3DFMT_X8L8V8U8, */
+   [PIPE_FORMAT_R8G8B8A8_SNORM]       = D3DFMT_Q8W8V8U8,
+   [PIPE_FORMAT_R16G16_SNORM]         = D3DFMT_V16U16,
+   [PIPE_FORMAT_R10SG10SB10SA2U_NORM] = D3DFMT_A2W10V10U10,
+
+   [PIPE_FORMAT_YUYV]               = D3DFMT_UYVY,
+/* [PIPE_FORMAT_YUY2]               = D3DFMT_YUY2, */
+   [PIPE_FORMAT_DXT1_RGBA]          = D3DFMT_DXT1,
+/* [PIPE_FORMAT_DXT2_RGBA]          = D3DFMT_DXT2, */
+   [PIPE_FORMAT_DXT3_RGBA]          = D3DFMT_DXT3,
+/* [PIPE_FORMAT_DXT4_RGBA]          = D3DFMT_DXT4, */
+   [PIPE_FORMAT_DXT5_RGBA]          = D3DFMT_DXT5,
+/* [PIPE_FORMAT_?]                  = D3DFMT_MULTI2_ARGB8, (MET) */
+   [PIPE_FORMAT_R8G8_B8G8_UNORM]    = D3DFMT_R8G8_B8G8, /* XXX: order */
+   [PIPE_FORMAT_G8R8_G8B8_UNORM]    = D3DFMT_G8R8_G8B8,
+
+   [PIPE_FORMAT_Z16_UNORM]          = D3DFMT_D16_LOCKABLE,
+   [PIPE_FORMAT_Z32_UNORM]          = D3DFMT_D32,
+/* [PIPE_FORMAT_Z15_UNORM_S1_UINT]  = D3DFMT_D15S1, */
+   [PIPE_FORMAT_S8_UINT_Z24_UNORM]  = D3DFMT_D24S8,
+   [PIPE_FORMAT_X8Z24_UNORM]        = D3DFMT_D24X8,
+   [PIPE_FORMAT_L16_UNORM]          = D3DFMT_L16,
+   [PIPE_FORMAT_Z32_FLOAT]          = D3DFMT_D32F_LOCKABLE,
+/* [PIPE_FORMAT_Z24_FLOAT_S8_UINT]  = D3DFMT_D24FS8, */
+
+   [PIPE_FORMAT_R16_UINT]           = D3DFMT_INDEX16,
+   [PIPE_FORMAT_R32_UINT]           = D3DFMT_INDEX32,
+   [PIPE_FORMAT_R16G16B16A16_SNORM] = D3DFMT_Q16W16V16U16,
+
+   [PIPE_FORMAT_R16_FLOAT]          = D3DFMT_R16F,
+   [PIPE_FORMAT_R32_FLOAT]          = D3DFMT_R32F,
+   [PIPE_FORMAT_R16G16_FLOAT]       = D3DFMT_G16R16F,
+   [PIPE_FORMAT_R32G32_FLOAT]       = D3DFMT_G32R32F,
+   [PIPE_FORMAT_R16G16B16A16_FLOAT] = D3DFMT_A16B16G16R16F,
+   [PIPE_FORMAT_R32G32B32A32_FLOAT] = D3DFMT_A32B32G32R32F,
+
+/* [PIPE_FORMAT_?]                  = D3DFMT_CxV8U8, */
+};
diff --git a/src/gallium/state_trackers/nine/nine_pipe.h b/src/gallium/state_trackers/nine/nine_pipe.h
new file mode 100644 (file)
index 0000000..1fd1694
--- /dev/null
@@ -0,0 +1,568 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _NINE_PIPE_H_
+#define _NINE_PIPE_H_
+
+#include "d3d9.h"
+#include "pipe/p_format.h"
+#include "pipe/p_state.h" /* pipe_box */
+#include "util/u_rect.h"
+#include "nine_helpers.h"
+
+struct cso_context;
+
+extern const enum pipe_format nine_d3d9_to_pipe_format_map[120];
+extern const D3DFORMAT nine_pipe_to_d3d9_format_map[PIPE_FORMAT_COUNT];
+
+void nine_convert_dsa_state(struct cso_context *, const DWORD *);
+void nine_convert_rasterizer_state(struct cso_context *, const DWORD *);
+void nine_convert_blend_state(struct cso_context *, const DWORD *);
+void nine_convert_sampler_state(struct cso_context *, int idx, const DWORD *);
+
+void nine_pipe_context_clear(struct NineDevice9 *);
+
+static INLINE unsigned d3dlock_buffer_to_pipe_transfer_usage(DWORD Flags)
+{
+    unsigned usage;
+
+    if (Flags & D3DLOCK_DISCARD)
+        usage = PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE;
+    else
+    if (Flags & D3DLOCK_READONLY)
+        usage = PIPE_TRANSFER_READ;
+    else
+        usage = PIPE_TRANSFER_READ_WRITE;
+
+    if (Flags & D3DLOCK_NOOVERWRITE)
+        usage = (PIPE_TRANSFER_UNSYNCHRONIZED |
+                 PIPE_TRANSFER_DISCARD_RANGE | usage) & ~PIPE_TRANSFER_READ;
+    else
+    if (Flags & D3DLOCK_DONOTWAIT)
+        usage |= PIPE_TRANSFER_DONTBLOCK;
+
+    /*
+    if (Flags & D3DLOCK_NO_DIRTY_UPDATE)
+        usage |= PIPE_TRANSFER_FLUSH_EXPLICIT;
+    */
+
+    return usage;
+}
+
+static INLINE void
+rect_to_pipe_box(struct pipe_box *dst, const RECT *src)
+{
+    dst->x = src->left;
+    dst->y = src->top;
+    dst->z = 0;
+    dst->width = src->right - src->left;
+    dst->height = src->bottom - src->top;
+    dst->depth = 1;
+}
+
+static INLINE boolean
+rect_to_pipe_box_clamp(struct pipe_box *dst, const RECT *src)
+{
+    rect_to_pipe_box(dst, src);
+
+    if (dst->width <= 0 || dst->height <= 0) {
+        DBG_FLAG(DBG_UNKNOWN, "Warning: NULL box");
+        dst->width = MAX2(dst->width, 0);
+        dst->height = MAX2(dst->height, 0);
+        return TRUE;
+    }
+    return FALSE;
+}
+
+static INLINE boolean
+rect_to_pipe_box_flip(struct pipe_box *dst, const RECT *src)
+{
+    rect_to_pipe_box(dst, src);
+
+    if (dst->width >= 0 && dst->height >= 0)
+        return FALSE;
+    if (dst->width < 0) dst->width = -dst->width;
+    if (dst->height < 0) dst->height = -dst->height;
+    return TRUE;
+}
+
+static INLINE void
+nine_u_rect_to_pipe_box(struct pipe_box *dst, const struct u_rect *rect, int z)
+{
+    dst->x = rect->x0;
+    dst->y = rect->y0;
+    dst->z = z;
+    dst->width = rect->x1 - rect->x0;
+    dst->height = rect->y1 - rect->y0;
+    dst->depth = 1;
+}
+
+static INLINE void
+rect_to_pipe_box_xy_only(struct pipe_box *dst, const RECT *src)
+{
+    user_warn(src->left > src->right || src->top > src->bottom);
+
+    dst->x = src->left;
+    dst->y = src->top;
+    dst->width = src->right - src->left;
+    dst->height = src->bottom - src->top;
+}
+
+static INLINE boolean
+rect_to_pipe_box_xy_only_clamp(struct pipe_box *dst, const RECT *src)
+{
+    rect_to_pipe_box_xy_only(dst, src);
+
+    if (dst->width <= 0 || dst->height <= 0) {
+        DBG_FLAG(DBG_UNKNOWN, "Warning: NULL box");
+        dst->width = MAX2(dst->width, 0);
+        dst->height = MAX2(dst->height, 0);
+        return TRUE;
+    }
+    return FALSE;
+}
+
+static INLINE void
+rect_to_g3d_u_rect(struct u_rect *dst, const RECT *src)
+{
+    user_warn(src->left > src->right || src->top > src->bottom);
+
+    dst->x0 = src->left;
+    dst->x1 = src->right;
+    dst->y0 = src->top;
+    dst->y1 = src->bottom;
+}
+
+static INLINE void
+d3dbox_to_pipe_box(struct pipe_box *dst, const D3DBOX *src)
+{
+    user_warn(src->Left > src->Right);
+    user_warn(src->Top > src->Bottom);
+    user_warn(src->Front > src->Back);
+
+    dst->x = src->Left;
+    dst->y = src->Top;
+    dst->z = src->Front;
+    dst->width = src->Right - src->Left;
+    dst->height = src->Bottom - src->Top;
+    dst->depth = src->Back - src->Front;
+}
+
+static INLINE D3DFORMAT
+pipe_to_d3d9_format(enum pipe_format format)
+{
+    return nine_pipe_to_d3d9_format_map[format];
+}
+
+static INLINE enum pipe_format
+d3d9_to_pipe_format(D3DFORMAT format)
+{
+    if (format <= D3DFMT_A2B10G10R10_XR_BIAS)
+        return nine_d3d9_to_pipe_format_map[format];
+    switch (format) {
+    case D3DFMT_INTZ: return PIPE_FORMAT_Z24_UNORM_S8_UINT;
+    case D3DFMT_DXT1: return PIPE_FORMAT_DXT1_RGBA;
+    case D3DFMT_DXT2: return PIPE_FORMAT_DXT3_RGBA; /* XXX */
+    case D3DFMT_DXT3: return PIPE_FORMAT_DXT3_RGBA;
+    case D3DFMT_DXT4: return PIPE_FORMAT_DXT5_RGBA; /* XXX */
+    case D3DFMT_DXT5: return PIPE_FORMAT_DXT5_RGBA;
+    case D3DFMT_UYVY: return PIPE_FORMAT_UYVY;
+    case D3DFMT_YUY2: return PIPE_FORMAT_YUYV; /* XXX check */
+    case D3DFMT_NV12: return PIPE_FORMAT_NV12;
+    case D3DFMT_G8R8_G8B8: return PIPE_FORMAT_G8R8_G8B8_UNORM; /* XXX order ? */
+    case D3DFMT_R8G8_B8G8: return PIPE_FORMAT_R8G8_B8G8_UNORM; /* XXX order ? */
+    case D3DFMT_BINARYBUFFER: return PIPE_FORMAT_NONE; /* not a format */
+    case D3DFMT_MULTI2_ARGB8: return PIPE_FORMAT_NONE; /* not supported */
+    case D3DFMT_Y210: /* XXX */
+    case D3DFMT_Y216:
+    case D3DFMT_NV11:
+    case D3DFMT_DF16: /* useless, not supported by wine either */
+    case D3DFMT_DF24: /* useless, not supported by wine either */
+    case D3DFMT_NULL: /* special cased, only for surfaces */
+        return PIPE_FORMAT_NONE;
+    default:
+        DBG_FLAG(DBG_UNKNOWN, "unknown D3DFORMAT: 0x%x/%c%c%c%c\n",
+                 format, (char)format, (char)(format >> 8),
+                 (char)(format >> 16), (char)(format >> 24));
+        return PIPE_FORMAT_NONE;
+    }
+}
+
+static INLINE const char *
+d3dformat_to_string(D3DFORMAT fmt)
+{
+    switch (fmt) {
+    case D3DFMT_UNKNOWN: return "D3DFMT_UNKNOWN";
+    case D3DFMT_R8G8B8: return "D3DFMT_R8G8B8";
+    case D3DFMT_A8R8G8B8: return "D3DFMT_A8R8G8B8";
+    case D3DFMT_X8R8G8B8: return "D3DFMT_X8R8G8B8";
+    case D3DFMT_R5G6B5: return "D3DFMT_R5G6B5";
+    case D3DFMT_X1R5G5B5: return "D3DFMT_X1R5G5B5";
+    case D3DFMT_A1R5G5B5: return "D3DFMT_A1R5G5B5";
+    case D3DFMT_A4R4G4B4: return "D3DFMT_A4R4G4B4";
+    case D3DFMT_R3G3B2: return "D3DFMT_R3G3B2";
+    case D3DFMT_A8: return "D3DFMT_A8";
+    case D3DFMT_A8R3G3B2: return "D3DFMT_A8R3G3B2";
+    case D3DFMT_X4R4G4B4: return "D3DFMT_X4R4G4B4";
+    case D3DFMT_A2B10G10R10: return "D3DFMT_A2B10G10R10";
+    case D3DFMT_A8B8G8R8: return "D3DFMT_A8B8G8R8";
+    case D3DFMT_X8B8G8R8: return "D3DFMT_X8B8G8R8";
+    case D3DFMT_G16R16: return "D3DFMT_G16R16";
+    case D3DFMT_A2R10G10B10: return "D3DFMT_A2R10G10B10";
+    case D3DFMT_A16B16G16R16: return "D3DFMT_A16B16G16R16";
+    case D3DFMT_A8P8: return "D3DFMT_A8P8";
+    case D3DFMT_P8: return "D3DFMT_P8";
+    case D3DFMT_L8: return "D3DFMT_L8";
+    case D3DFMT_A8L8: return "D3DFMT_A8L8";
+    case D3DFMT_A4L4: return "D3DFMT_A4L4";
+    case D3DFMT_V8U8: return "D3DFMT_V8U8";
+    case D3DFMT_L6V5U5: return "D3DFMT_L6V5U5";
+    case D3DFMT_X8L8V8U8: return "D3DFMT_X8L8V8U8";
+    case D3DFMT_Q8W8V8U8: return "D3DFMT_Q8W8V8U8";
+    case D3DFMT_V16U16: return "D3DFMT_V16U16";
+    case D3DFMT_A2W10V10U10: return "D3DFMT_A2W10V10U10";
+    case D3DFMT_UYVY: return "D3DFMT_UYVY";
+    case D3DFMT_R8G8_B8G8: return "D3DFMT_R8G8_B8G8";
+    case D3DFMT_YUY2: return "D3DFMT_YUY2";
+    case D3DFMT_G8R8_G8B8: return "D3DFMT_G8R8_G8B8";
+    case D3DFMT_DXT1: return "D3DFMT_DXT1";
+    case D3DFMT_DXT2: return "D3DFMT_DXT2";
+    case D3DFMT_DXT3: return "D3DFMT_DXT3";
+    case D3DFMT_DXT4: return "D3DFMT_DXT4";
+    case D3DFMT_DXT5: return "D3DFMT_DXT5";
+    case D3DFMT_D16_LOCKABLE: return "D3DFMT_D16_LOCKABLE";
+    case D3DFMT_D32: return "D3DFMT_D32";
+    case D3DFMT_D15S1: return "D3DFMT_D15S1";
+    case D3DFMT_D24S8: return "D3DFMT_D24S8";
+    case D3DFMT_D24X8: return "D3DFMT_D24X8";
+    case D3DFMT_D24X4S4: return "D3DFMT_D24X4S4";
+    case D3DFMT_D16: return "D3DFMT_D16";
+    case D3DFMT_D32F_LOCKABLE: return "D3DFMT_D32F_LOCKABLE";
+    case D3DFMT_D24FS8: return "D3DFMT_D24FS8";
+    case D3DFMT_D32_LOCKABLE: return "D3DFMT_D32_LOCKABLE";
+    case D3DFMT_S8_LOCKABLE: return "D3DFMT_S8_LOCKABLE";
+    case D3DFMT_L16: return "D3DFMT_L16";
+    case D3DFMT_VERTEXDATA: return "D3DFMT_VERTEXDATA";
+    case D3DFMT_INDEX16: return "D3DFMT_INDEX16";
+    case D3DFMT_INDEX32: return "D3DFMT_INDEX32";
+    case D3DFMT_Q16W16V16U16: return "D3DFMT_Q16W16V16U16";
+    case D3DFMT_MULTI2_ARGB8: return "D3DFMT_MULTI2_ARGB8";
+    case D3DFMT_R16F: return "D3DFMT_R16F";
+    case D3DFMT_G16R16F: return "D3DFMT_G16R16F";
+    case D3DFMT_A16B16G16R16F: return "D3DFMT_A16B16G16R16F";
+    case D3DFMT_R32F: return "D3DFMT_R32F";
+    case D3DFMT_G32R32F: return "D3DFMT_G32R32F";
+    case D3DFMT_A32B32G32R32F: return "D3DFMT_A32B32G32R32F";
+    case D3DFMT_CxV8U8: return "D3DFMT_CxV8U8";
+    case D3DFMT_A1: return "D3DFMT_A1";
+    case D3DFMT_A2B10G10R10_XR_BIAS: return "D3DFMT_A2B10G10R10_XR_BIAS";
+    case D3DFMT_BINARYBUFFER: return "D3DFMT_BINARYBUFFER";
+    case D3DFMT_DF16: return "D3DFMT_DF16";
+    case D3DFMT_DF24: return "D3DFMT_DF24";
+    case D3DFMT_INTZ: return "D3DFMT_INTZ";
+    case D3DFMT_NULL: return "D3DFMT_NULL";
+    default:
+        break;
+    }
+    return "Unknown";
+}
+
+static INLINE unsigned
+nine_fvf_stride( DWORD fvf )
+{
+    unsigned texcount, i, size = 0;
+
+    switch (fvf & D3DFVF_POSITION_MASK) {
+    case D3DFVF_XYZ:    size += 3*4; break;
+    case D3DFVF_XYZRHW: size += 4*4; break;
+    case D3DFVF_XYZB1:  size += 4*4; break;
+    case D3DFVF_XYZB2:  size += 5*4; break;
+    case D3DFVF_XYZB3:  size += 6*4; break;
+    case D3DFVF_XYZB4:  size += 7*4; break;
+    case D3DFVF_XYZB5:  size += 8*4; break;
+    case D3DFVF_XYZW:   size += 4*4; break;
+    default:
+        user_warn("Position doesn't match any known combination.");
+        break;
+    }
+
+    if (fvf & D3DFVF_NORMAL)   { size += 3*4; }
+    if (fvf & D3DFVF_PSIZE)    { size += 1*4; }
+    if (fvf & D3DFVF_DIFFUSE)  { size += 1*4; }
+    if (fvf & D3DFVF_SPECULAR) { size += 1*4; }
+
+    texcount = (fvf >> D3DFVF_TEXCOUNT_SHIFT) & D3DFVF_TEXCOUNT_MASK;
+    if (user_error(texcount <= 8))
+        texcount = 8;
+
+    for (i = 0; i < texcount; ++i) {
+        unsigned texformat = (fvf>>(16+i*2))&0x3;
+        /* texformats are defined having been shifted around so 1=3,2=0,3=1,4=2
+         * meaning we can just do this instead of the switch below */
+        size += (((texformat+1)&0x3)+1)*4;
+
+        /*
+        switch (texformat) {
+        case D3DFVF_TEXTUREFORMAT1: size += 1*4;
+        case D3DFVF_TEXTUREFORMAT2: size += 2*4;
+        case D3DFVF_TEXTUREFORMAT3: size += 3*4;
+        case D3DFVF_TEXTUREFORMAT4: size += 4*4;
+        }
+        */
+    }
+
+    return size;
+}
+
+static INLINE void
+d3dcolor_to_rgba(float *rgba, D3DCOLOR color)
+{
+    rgba[0] = (float)((color >> 16) & 0xFF) / 0xFF;
+    rgba[1] = (float)((color >>  8) & 0xFF) / 0xFF;
+    rgba[2] = (float)((color >>  0) & 0xFF) / 0xFF;
+    rgba[3] = (float)((color >> 24) & 0xFF) / 0xFF;
+}
+
+static INLINE void
+d3dcolor_to_pipe_color_union(union pipe_color_union *rgba, D3DCOLOR color)
+{
+    d3dcolor_to_rgba(&rgba->f[0], color);
+}
+
+static INLINE unsigned
+d3dprimitivetype_to_pipe_prim(D3DPRIMITIVETYPE prim)
+{
+    switch (prim) {
+    case D3DPT_POINTLIST:     return PIPE_PRIM_POINTS;
+    case D3DPT_LINELIST:      return PIPE_PRIM_LINES;
+    case D3DPT_LINESTRIP:     return PIPE_PRIM_LINE_STRIP;
+    case D3DPT_TRIANGLELIST:  return PIPE_PRIM_TRIANGLES;
+    case D3DPT_TRIANGLESTRIP: return PIPE_PRIM_TRIANGLE_STRIP;
+    case D3DPT_TRIANGLEFAN:   return PIPE_PRIM_TRIANGLE_FAN;
+    default:
+        assert(0);
+        return PIPE_PRIM_POINTS;
+    }
+}
+
+static INLINE unsigned
+prim_count_to_vertex_count(D3DPRIMITIVETYPE prim, UINT count)
+{
+    switch (prim) {
+    case D3DPT_POINTLIST:     return count;
+    case D3DPT_LINELIST:      return count * 2;
+    case D3DPT_LINESTRIP:     return count + 1;
+    case D3DPT_TRIANGLELIST:  return count * 3;
+    case D3DPT_TRIANGLESTRIP: return count + 2;
+    case D3DPT_TRIANGLEFAN:   return count + 2;
+    default:
+        assert(0);
+        return 0;
+    }
+}
+
+static INLINE unsigned
+d3dcmpfunc_to_pipe_func(D3DCMPFUNC func)
+{
+    switch (func) {
+    case D3DCMP_NEVER:        return PIPE_FUNC_NEVER;
+    case D3DCMP_LESS:         return PIPE_FUNC_LESS;
+    case D3DCMP_EQUAL:        return PIPE_FUNC_EQUAL;
+    case D3DCMP_LESSEQUAL:    return PIPE_FUNC_LEQUAL;
+    case D3DCMP_GREATER:      return PIPE_FUNC_GREATER;
+    case D3DCMP_NOTEQUAL:     return PIPE_FUNC_NOTEQUAL;
+    case D3DCMP_GREATEREQUAL: return PIPE_FUNC_GEQUAL;
+    case D3DCMP_ALWAYS:       return PIPE_FUNC_ALWAYS;
+    default:
+        assert(0);
+        return PIPE_FUNC_NEVER;
+    }
+}
+
+static INLINE unsigned
+d3dstencilop_to_pipe_stencil_op(D3DSTENCILOP op)
+{
+    switch (op) {
+    case D3DSTENCILOP_KEEP:    return PIPE_STENCIL_OP_KEEP;
+    case D3DSTENCILOP_ZERO:    return PIPE_STENCIL_OP_ZERO;
+    case D3DSTENCILOP_REPLACE: return PIPE_STENCIL_OP_REPLACE;
+    case D3DSTENCILOP_INCRSAT: return PIPE_STENCIL_OP_INCR;
+    case D3DSTENCILOP_DECRSAT: return PIPE_STENCIL_OP_DECR;
+    case D3DSTENCILOP_INVERT:  return PIPE_STENCIL_OP_INVERT;
+    case D3DSTENCILOP_INCR:    return PIPE_STENCIL_OP_INCR_WRAP;
+    case D3DSTENCILOP_DECR:    return PIPE_STENCIL_OP_DECR_WRAP;
+    default:
+        return PIPE_STENCIL_OP_ZERO;
+    }
+}
+
+static INLINE unsigned
+d3dcull_to_pipe_face(D3DCULL cull)
+{
+    switch (cull) {
+    case D3DCULL_NONE: return PIPE_FACE_NONE;
+    case D3DCULL_CW:   return PIPE_FACE_FRONT;
+    case D3DCULL_CCW:  return PIPE_FACE_BACK;
+    default:
+        assert(0);
+        return PIPE_FACE_NONE;
+    }
+}
+
+static INLINE unsigned
+d3dfillmode_to_pipe_polygon_mode(D3DFILLMODE mode)
+{
+    switch (mode) {
+    case D3DFILL_POINT:     return PIPE_POLYGON_MODE_POINT;
+    case D3DFILL_WIREFRAME: return PIPE_POLYGON_MODE_LINE;
+    case D3DFILL_SOLID:     return PIPE_POLYGON_MODE_FILL;
+    default:
+        assert(0);
+        return PIPE_POLYGON_MODE_FILL;
+    }
+}
+
+static INLINE unsigned
+d3dblendop_to_pipe_blend(D3DBLENDOP op)
+{
+    switch (op) {
+    case D3DBLENDOP_ADD:         return PIPE_BLEND_ADD;
+    case D3DBLENDOP_SUBTRACT:    return PIPE_BLEND_SUBTRACT;
+    case D3DBLENDOP_REVSUBTRACT: return PIPE_BLEND_REVERSE_SUBTRACT;
+    case D3DBLENDOP_MIN:         return PIPE_BLEND_MIN;
+    case D3DBLENDOP_MAX:         return PIPE_BLEND_MAX;
+    default:
+        assert(0);
+        return PIPE_BLEND_ADD;
+    }
+}
+
+/* NOTE: The COLOR factors for are equal to the ALPHA ones for alpha.
+ * Drivers may check RGB and ALPHA factors for equality so we should not
+ * simply substitute the ALPHA variants.
+ */
+static INLINE unsigned
+d3dblend_alpha_to_pipe_blendfactor(D3DBLEND b)
+{
+    switch (b) {
+    case D3DBLEND_ZERO:            return PIPE_BLENDFACTOR_ZERO;
+    case D3DBLEND_ONE:             return PIPE_BLENDFACTOR_ONE;
+    case D3DBLEND_SRCCOLOR:        return PIPE_BLENDFACTOR_SRC_COLOR/*ALPHA*/;
+    case D3DBLEND_INVSRCCOLOR:     return PIPE_BLENDFACTOR_INV_SRC_COLOR/*ALPHA*/;
+    case D3DBLEND_SRCALPHA:        return PIPE_BLENDFACTOR_SRC_ALPHA;
+    case D3DBLEND_INVSRCALPHA:     return PIPE_BLENDFACTOR_INV_SRC_ALPHA;
+    case D3DBLEND_DESTALPHA:       return PIPE_BLENDFACTOR_DST_ALPHA;
+    case D3DBLEND_INVDESTALPHA:    return PIPE_BLENDFACTOR_INV_DST_ALPHA;
+    case D3DBLEND_DESTCOLOR:       return PIPE_BLENDFACTOR_DST_COLOR/*ALPHA*/;
+    case D3DBLEND_INVDESTCOLOR:    return PIPE_BLENDFACTOR_INV_DST_COLOR/*ALPHA*/;
+    case D3DBLEND_SRCALPHASAT:     return PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE;
+    case D3DBLEND_BOTHSRCALPHA:    return PIPE_BLENDFACTOR_SRC_ALPHA;
+    case D3DBLEND_BOTHINVSRCALPHA: return PIPE_BLENDFACTOR_INV_SRC_ALPHA;
+    case D3DBLEND_BLENDFACTOR:     return PIPE_BLENDFACTOR_CONST_COLOR/*ALPHA*/;
+    case D3DBLEND_INVBLENDFACTOR:  return PIPE_BLENDFACTOR_INV_CONST_COLOR/*ALPHA*/;
+    case D3DBLEND_SRCCOLOR2:       return PIPE_BLENDFACTOR_ONE; /* XXX */
+    case D3DBLEND_INVSRCCOLOR2:    return PIPE_BLENDFACTOR_ZERO; /* XXX */
+    default:
+       DBG_FLAG(DBG_UNKNOWN, "Unhandled blend factor %d\n", b);
+       return PIPE_BLENDFACTOR_ZERO;
+    }
+}
+
+static INLINE unsigned
+d3dblend_color_to_pipe_blendfactor(D3DBLEND b)
+{
+    switch (b) {
+    case D3DBLEND_ZERO:            return PIPE_BLENDFACTOR_ZERO;
+    case D3DBLEND_ONE:             return PIPE_BLENDFACTOR_ONE;
+    case D3DBLEND_SRCCOLOR:        return PIPE_BLENDFACTOR_SRC_COLOR;
+    case D3DBLEND_INVSRCCOLOR:     return PIPE_BLENDFACTOR_INV_SRC_COLOR;
+    case D3DBLEND_SRCALPHA:        return PIPE_BLENDFACTOR_SRC_ALPHA;
+    case D3DBLEND_INVSRCALPHA:     return PIPE_BLENDFACTOR_INV_SRC_ALPHA;
+    case D3DBLEND_DESTALPHA:       return PIPE_BLENDFACTOR_DST_ALPHA;
+    case D3DBLEND_INVDESTALPHA:    return PIPE_BLENDFACTOR_INV_DST_ALPHA;
+    case D3DBLEND_DESTCOLOR:       return PIPE_BLENDFACTOR_DST_COLOR;
+    case D3DBLEND_INVDESTCOLOR:    return PIPE_BLENDFACTOR_INV_DST_COLOR;
+    case D3DBLEND_SRCALPHASAT:     return PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE;
+    case D3DBLEND_BOTHSRCALPHA:    return PIPE_BLENDFACTOR_SRC_ALPHA;
+    case D3DBLEND_BOTHINVSRCALPHA: return PIPE_BLENDFACTOR_INV_SRC_ALPHA;
+    case D3DBLEND_BLENDFACTOR:     return PIPE_BLENDFACTOR_CONST_COLOR;
+    case D3DBLEND_INVBLENDFACTOR:  return PIPE_BLENDFACTOR_INV_CONST_COLOR;
+    case D3DBLEND_SRCCOLOR2:       return PIPE_BLENDFACTOR_SRC1_COLOR;
+    case D3DBLEND_INVSRCCOLOR2:    return PIPE_BLENDFACTOR_INV_SRC1_COLOR;
+    default:
+       DBG_FLAG(DBG_UNKNOWN, "Unhandled blend factor %d\n", b);
+       return PIPE_BLENDFACTOR_ZERO;
+    }
+}
+
+static INLINE unsigned
+d3dtextureaddress_to_pipe_tex_wrap(D3DTEXTUREADDRESS addr)
+{
+    switch (addr) {
+    case D3DTADDRESS_WRAP:       return PIPE_TEX_WRAP_REPEAT;
+    case D3DTADDRESS_MIRROR:     return PIPE_TEX_WRAP_MIRROR_REPEAT;
+    case D3DTADDRESS_CLAMP:      return PIPE_TEX_WRAP_CLAMP_TO_EDGE;
+    case D3DTADDRESS_BORDER:     return PIPE_TEX_WRAP_CLAMP_TO_BORDER;
+    case D3DTADDRESS_MIRRORONCE: return PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE;
+    default:
+        assert(0);
+        return PIPE_TEX_WRAP_CLAMP_TO_EDGE;
+    }
+}
+
+static INLINE unsigned
+d3dtexturefiltertype_to_pipe_tex_filter(D3DTEXTUREFILTERTYPE filter)
+{
+    switch (filter) {
+    case D3DTEXF_POINT:       return PIPE_TEX_FILTER_NEAREST;
+    case D3DTEXF_LINEAR:      return PIPE_TEX_FILTER_LINEAR;
+    case D3DTEXF_ANISOTROPIC: return PIPE_TEX_FILTER_LINEAR;
+
+    case D3DTEXF_NONE:
+    case D3DTEXF_PYRAMIDALQUAD:
+    case D3DTEXF_GAUSSIANQUAD:
+    case D3DTEXF_CONVOLUTIONMONO:
+    default:
+        assert(0);
+        return PIPE_TEX_FILTER_NEAREST;
+    }
+}
+
+static INLINE unsigned
+d3dtexturefiltertype_to_pipe_tex_mipfilter(D3DTEXTUREFILTERTYPE filter)
+{
+    switch (filter) {
+    case D3DTEXF_NONE:        return PIPE_TEX_MIPFILTER_NONE;
+    case D3DTEXF_POINT:       return PIPE_TEX_FILTER_NEAREST;
+    case D3DTEXF_LINEAR:      return PIPE_TEX_FILTER_LINEAR;
+    case D3DTEXF_ANISOTROPIC: return PIPE_TEX_FILTER_LINEAR;
+
+    case D3DTEXF_PYRAMIDALQUAD:
+    case D3DTEXF_GAUSSIANQUAD:
+    case D3DTEXF_CONVOLUTIONMONO:
+    default:
+        assert(0);
+        return PIPE_TEX_MIPFILTER_NONE;
+    }
+}
+
+#endif /* _NINE_PIPE_H_ */
diff --git a/src/gallium/state_trackers/nine/nine_quirk.c b/src/gallium/state_trackers/nine/nine_quirk.c
new file mode 100644 (file)
index 0000000..267436b
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "nine_quirk.h"
+
+#include "util/u_debug.h"
+
+static const struct debug_named_value nine_quirk_table[] = {
+    { "fakecaps", QUIRK_FAKE_CAPS,
+      "Fake caps to emulate D3D specs regardless of hardware caps." },
+    { "lenientshader", QUIRK_LENIENT_SHADER,
+      "Be lenient when translating shaders." },
+    { "all", ~0U,
+      "Enable all quirks." },
+    DEBUG_NAMED_VALUE_END
+};
+
+boolean
+_nine_get_quirk( unsigned quirk )
+{
+    static boolean first = TRUE;
+    static unsigned long flags = 0;
+
+    if (first) {
+        first = FALSE;
+        flags = debug_get_flags_option("NINE_QUIRKS", nine_quirk_table, 0);
+    }
+
+    return !!(flags & quirk);
+}
diff --git a/src/gallium/state_trackers/nine/nine_quirk.h b/src/gallium/state_trackers/nine/nine_quirk.h
new file mode 100644 (file)
index 0000000..9c082dd
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _NINE_QUIRK_H_
+#define _NINE_QUIRK_H_
+
+#include "pipe/p_compiler.h"
+
+boolean
+_nine_get_quirk( unsigned quirk );
+
+#define QUIRK(q) (_nine_get_quirk(QUIRK_##q))
+
+#define QUIRK_FAKE_CAPS         0x00000001
+#define QUIRK_LENIENT_SHADER    0x00000002
+
+#endif /* _NINE_QUIRK_H_ */
diff --git a/src/gallium/state_trackers/nine/nine_shader.c b/src/gallium/state_trackers/nine/nine_shader.c
new file mode 100644 (file)
index 0000000..cc027b4
--- /dev/null
@@ -0,0 +1,2959 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ * Copyright 2013 Christoph Bumiller
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "nine_shader.h"
+
+#include "device9.h"
+#include "nine_debug.h"
+#include "nine_state.h"
+
+#include "util/u_memory.h"
+#include "util/u_inlines.h"
+#include "pipe/p_shader_tokens.h"
+#include "tgsi/tgsi_ureg.h"
+#include "tgsi/tgsi_dump.h"
+
+#define DBG_CHANNEL DBG_SHADER
+
+#if 1
+#define NINE_TGSI_LAZY_DEVS /* don't use TGSI_OPCODE_BREAKC */
+#endif
+#define NINE_TGSI_LAZY_R600 /* don't use TGSI_OPCODE_DP2A */
+
+#define DUMP(args...) _nine_debug_printf(DBG_CHANNEL, NULL, args)
+
+
+struct shader_translator;
+
+typedef HRESULT (*translate_instruction_func)(struct shader_translator *);
+
+static INLINE const char *d3dsio_to_string(unsigned opcode);
+
+
+#define NINED3D_SM1_VS 0xfffe
+#define NINED3D_SM1_PS 0xffff
+
+#define NINE_MAX_COND_DEPTH 64
+#define NINE_MAX_LOOP_DEPTH 64
+
+#define NINED3DSP_END 0x0000ffff
+
+#define NINED3DSPTYPE_FLOAT4  0
+#define NINED3DSPTYPE_INT4    1
+#define NINED3DSPTYPE_BOOL    2
+
+#define NINED3DSPR_IMMEDIATE (D3DSPR_PREDICATE + 1)
+
+#define NINED3DSP_WRITEMASK_MASK  D3DSP_WRITEMASK_ALL
+#define NINED3DSP_WRITEMASK_SHIFT 16
+
+#define NINED3DSHADER_INST_PREDICATED (1 << 28)
+
+#define NINED3DSHADER_REL_OP_GT 1
+#define NINED3DSHADER_REL_OP_EQ 2
+#define NINED3DSHADER_REL_OP_GE 3
+#define NINED3DSHADER_REL_OP_LT 4
+#define NINED3DSHADER_REL_OP_NE 5
+#define NINED3DSHADER_REL_OP_LE 6
+
+#define NINED3DSIO_OPCODE_FLAGS_SHIFT 16
+#define NINED3DSIO_OPCODE_FLAGS_MASK  (0xff << NINED3DSIO_OPCODE_FLAGS_SHIFT)
+
+#define NINED3DSI_TEXLD_PROJECT 0x1
+#define NINED3DSI_TEXLD_BIAS    0x2
+
+#define NINED3DSP_WRITEMASK_0   0x1
+#define NINED3DSP_WRITEMASK_1   0x2
+#define NINED3DSP_WRITEMASK_2   0x4
+#define NINED3DSP_WRITEMASK_3   0x8
+#define NINED3DSP_WRITEMASK_ALL 0xf
+
+#define NINED3DSP_NOSWIZZLE ((0 << 0) | (1 << 2) | (2 << 4) | (3 << 6))
+
+#define NINE_SWIZZLE4(x,y,z,w) \
+   TGSI_SWIZZLE_##x, TGSI_SWIZZLE_##y, TGSI_SWIZZLE_##z, TGSI_SWIZZLE_##w
+
+#define NINED3DSPDM_SATURATE (D3DSPDM_SATURATE >> D3DSP_DSTMOD_SHIFT)
+#define NINED3DSPDM_PARTIALP (D3DSPDM_PARTIALPRECISION >> D3DSP_DSTMOD_SHIFT)
+#define NINED3DSPDM_CENTROID (D3DSPDM_MSAMPCENTROID >> D3DSP_DSTMOD_SHIFT)
+
+/*
+ * NEG     all, not ps: m3x2, m3x3, m3x4, m4x3, m4x4
+ * BIAS    <= PS 1.4 (x-0.5)
+ * BIASNEG <= PS 1.4 (-(x-0.5))
+ * SIGN    <= PS 1.4 (2(x-0.5))
+ * SIGNNEG <= PS 1.4 (-2(x-0.5))
+ * COMP    <= PS 1.4 (1-x)
+ * X2       = PS 1.4 (2x)
+ * X2NEG    = PS 1.4 (-2x)
+ * DZ      <= PS 1.4, tex{ld,crd} (.xy/.z), z=0 => .11
+ * DW      <= PS 1.4, tex{ld,crd} (.xy/.w), w=0 => .11
+ * ABS     >= SM 3.0 (abs(x))
+ * ABSNEG  >= SM 3.0 (-abs(x))
+ * NOT     >= SM 2.0 pedication only
+ */
+#define NINED3DSPSM_NONE    (D3DSPSM_NONE    >> D3DSP_SRCMOD_SHIFT)
+#define NINED3DSPSM_NEG     (D3DSPSM_NEG     >> D3DSP_SRCMOD_SHIFT)
+#define NINED3DSPSM_BIAS    (D3DSPSM_BIAS    >> D3DSP_SRCMOD_SHIFT)
+#define NINED3DSPSM_BIASNEG (D3DSPSM_BIASNEG >> D3DSP_SRCMOD_SHIFT)
+#define NINED3DSPSM_SIGN    (D3DSPSM_SIGN    >> D3DSP_SRCMOD_SHIFT)
+#define NINED3DSPSM_SIGNNEG (D3DSPSM_SIGNNEG >> D3DSP_SRCMOD_SHIFT)
+#define NINED3DSPSM_COMP    (D3DSPSM_COMP    >> D3DSP_SRCMOD_SHIFT)
+#define NINED3DSPSM_X2      (D3DSPSM_X2      >> D3DSP_SRCMOD_SHIFT)
+#define NINED3DSPSM_X2NEG   (D3DSPSM_X2NEG   >> D3DSP_SRCMOD_SHIFT)
+#define NINED3DSPSM_DZ      (D3DSPSM_DZ      >> D3DSP_SRCMOD_SHIFT)
+#define NINED3DSPSM_DW      (D3DSPSM_DW      >> D3DSP_SRCMOD_SHIFT)
+#define NINED3DSPSM_ABS     (D3DSPSM_ABS     >> D3DSP_SRCMOD_SHIFT)
+#define NINED3DSPSM_ABSNEG  (D3DSPSM_ABSNEG  >> D3DSP_SRCMOD_SHIFT)
+#define NINED3DSPSM_NOT     (D3DSPSM_NOT     >> D3DSP_SRCMOD_SHIFT)
+
+static const char *sm1_mod_str[] =
+{
+    [NINED3DSPSM_NONE] = "",
+    [NINED3DSPSM_NEG] = "-",
+    [NINED3DSPSM_BIAS] = "bias",
+    [NINED3DSPSM_BIASNEG] = "biasneg",
+    [NINED3DSPSM_SIGN] = "sign",
+    [NINED3DSPSM_SIGNNEG] = "signneg",
+    [NINED3DSPSM_COMP] = "comp",
+    [NINED3DSPSM_X2] = "x2",
+    [NINED3DSPSM_X2NEG] = "x2neg",
+    [NINED3DSPSM_DZ] = "dz",
+    [NINED3DSPSM_DW] = "dw",
+    [NINED3DSPSM_ABS] = "abs",
+    [NINED3DSPSM_ABSNEG] = "-abs",
+    [NINED3DSPSM_NOT] = "not"
+};
+
+static void
+sm1_dump_writemask(BYTE mask)
+{
+    if (mask & 1) DUMP("x"); else DUMP("_");
+    if (mask & 2) DUMP("y"); else DUMP("_");
+    if (mask & 4) DUMP("z"); else DUMP("_");
+    if (mask & 8) DUMP("w"); else DUMP("_");
+}
+
+static void
+sm1_dump_swizzle(BYTE s)
+{
+    char c[4] = { 'x', 'y', 'z', 'w' };
+    DUMP("%c%c%c%c",
+         c[(s >> 0) & 3], c[(s >> 2) & 3], c[(s >> 4) & 3], c[(s >> 6) & 3]);
+}
+
+static const char sm1_file_char[] =
+{
+    [D3DSPR_TEMP] = 'r',
+    [D3DSPR_INPUT] = 'v',
+    [D3DSPR_CONST] = 'c',
+    [D3DSPR_ADDR] = 'A',
+    [D3DSPR_RASTOUT] = 'R',
+    [D3DSPR_ATTROUT] = 'D',
+    [D3DSPR_OUTPUT] = 'o',
+    [D3DSPR_CONSTINT] = 'I',
+    [D3DSPR_COLOROUT] = 'C',
+    [D3DSPR_DEPTHOUT] = 'D',
+    [D3DSPR_SAMPLER] = 's',
+    [D3DSPR_CONST2] = 'c',
+    [D3DSPR_CONST3] = 'c',
+    [D3DSPR_CONST4] = 'c',
+    [D3DSPR_CONSTBOOL] = 'B',
+    [D3DSPR_LOOP] = 'L',
+    [D3DSPR_TEMPFLOAT16] = 'h',
+    [D3DSPR_MISCTYPE] = 'M',
+    [D3DSPR_LABEL] = 'X',
+    [D3DSPR_PREDICATE] = 'p'
+};
+
+static void
+sm1_dump_reg(BYTE file, INT index)
+{
+    switch (file) {
+    case D3DSPR_LOOP:
+        DUMP("aL");
+        break;
+    case D3DSPR_COLOROUT:
+        DUMP("oC%i", index);
+        break;
+    case D3DSPR_DEPTHOUT:
+        DUMP("oDepth");
+        break;
+    case D3DSPR_RASTOUT:
+        DUMP("oRast%i", index);
+        break;
+    case D3DSPR_CONSTINT:
+        DUMP("iconst[%i]", index);
+        break;
+    case D3DSPR_CONSTBOOL:
+        DUMP("bconst[%i]", index);
+        break;
+    default:
+        DUMP("%c%i", sm1_file_char[file], index);
+        break;
+    }
+}
+
+struct sm1_src_param
+{
+    INT idx;
+    struct sm1_src_param *rel;
+    BYTE file;
+    BYTE swizzle;
+    BYTE mod;
+    BYTE type;
+    union {
+        DWORD d[4];
+        float f[4];
+        int i[4];
+        BOOL b;
+    } imm;
+};
+static void
+sm1_parse_immediate(struct shader_translator *, struct sm1_src_param *);
+
+struct sm1_dst_param
+{
+    INT idx;
+    struct sm1_src_param *rel;
+    BYTE file;
+    BYTE mask;
+    BYTE mod;
+    BYTE shift; /* sint4 */
+    BYTE type;
+};
+
+static INLINE void
+assert_replicate_swizzle(const struct ureg_src *reg)
+{
+    assert(reg->SwizzleY == reg->SwizzleX &&
+           reg->SwizzleZ == reg->SwizzleX &&
+           reg->SwizzleW == reg->SwizzleX);
+}
+
+static void
+sm1_dump_immediate(const struct sm1_src_param *param)
+{
+    switch (param->type) {
+    case NINED3DSPTYPE_FLOAT4:
+        DUMP("{ %f %f %f %f }",
+             param->imm.f[0], param->imm.f[1],
+             param->imm.f[2], param->imm.f[3]);
+        break;
+    case NINED3DSPTYPE_INT4:
+        DUMP("{ %i %i %i %i }",
+             param->imm.i[0], param->imm.i[1],
+             param->imm.i[2], param->imm.i[3]);
+        break;
+    case NINED3DSPTYPE_BOOL:
+        DUMP("%s", param->imm.b ? "TRUE" : "FALSE");
+        break;
+    default:
+        assert(0);
+        break;
+    }
+}
+
+static void
+sm1_dump_src_param(const struct sm1_src_param *param)
+{
+    if (param->file == NINED3DSPR_IMMEDIATE) {
+        assert(!param->mod &&
+               !param->rel &&
+               param->swizzle == NINED3DSP_NOSWIZZLE);
+        sm1_dump_immediate(param);
+        return;
+    }
+
+    if (param->mod)
+        DUMP("%s(", sm1_mod_str[param->mod]);
+    if (param->rel) {
+        DUMP("%c[", sm1_file_char[param->file]);
+        sm1_dump_src_param(param->rel);
+        DUMP("+%i]", param->idx);
+    } else {
+        sm1_dump_reg(param->file, param->idx);
+    }
+    if (param->mod)
+       DUMP(")");
+    if (param->swizzle != NINED3DSP_NOSWIZZLE) {
+       DUMP(".");
+       sm1_dump_swizzle(param->swizzle);
+    }
+}
+
+static void
+sm1_dump_dst_param(const struct sm1_dst_param *param)
+{
+   if (param->mod & NINED3DSPDM_SATURATE)
+      DUMP("sat ");
+   if (param->mod & NINED3DSPDM_PARTIALP)
+      DUMP("pp ");
+   if (param->mod & NINED3DSPDM_CENTROID)
+      DUMP("centroid ");
+   if (param->shift < 0)
+      DUMP("/%u ", 1 << -param->shift);
+   if (param->shift > 0)
+      DUMP("*%u ", 1 << param->shift);
+
+   if (param->rel) {
+      DUMP("%c[", sm1_file_char[param->file]);
+      sm1_dump_src_param(param->rel);
+      DUMP("+%i]", param->idx);
+   } else {
+      sm1_dump_reg(param->file, param->idx);
+   }
+   if (param->mask != NINED3DSP_WRITEMASK_ALL) {
+      DUMP(".");
+      sm1_dump_writemask(param->mask);
+   }
+}
+
+struct sm1_semantic
+{
+   struct sm1_dst_param reg;
+   BYTE sampler_type;
+   D3DDECLUSAGE usage;
+   BYTE usage_idx;
+};
+
+struct sm1_op_info
+{
+    /* NOTE: 0 is a valid TGSI opcode, but if handler is set, this parameter
+     * should be ignored completely */
+    unsigned sio;
+    unsigned opcode; /* TGSI_OPCODE_x */
+
+    /* versions are still set even handler is set */
+    struct {
+        unsigned min;
+        unsigned max;
+    } vert_version, frag_version;
+
+    /* number of regs parsed outside of special handler */
+    unsigned ndst;
+    unsigned nsrc;
+
+    /* some instructions don't map perfectly, so use a special handler */
+    translate_instruction_func handler;
+};
+
+struct sm1_instruction
+{
+    D3DSHADER_INSTRUCTION_OPCODE_TYPE opcode;
+    BYTE flags;
+    BOOL coissue;
+    BOOL predicated;
+    BYTE ndst;
+    BYTE nsrc;
+    struct sm1_src_param src[4];
+    struct sm1_src_param src_rel[4];
+    struct sm1_src_param pred;
+    struct sm1_src_param dst_rel[1];
+    struct sm1_dst_param dst[1];
+
+    struct sm1_op_info *info;
+};
+
+static void
+sm1_dump_instruction(struct sm1_instruction *insn, unsigned indent)
+{
+    unsigned i;
+
+    /* no info stored for these: */
+    if (insn->opcode == D3DSIO_DCL)
+        return;
+    for (i = 0; i < indent; ++i)
+        DUMP("  ");
+
+    if (insn->predicated) {
+        DUMP("@");
+        sm1_dump_src_param(&insn->pred);
+        DUMP(" ");
+    }
+    DUMP("%s", d3dsio_to_string(insn->opcode));
+    if (insn->flags) {
+        switch (insn->opcode) {
+        case D3DSIO_TEX:
+            DUMP(insn->flags == NINED3DSI_TEXLD_PROJECT ? "p" : "b");
+            break;
+        default:
+            DUMP("_%x", insn->flags);
+            break;
+        }
+    }
+    if (insn->coissue)
+        DUMP("_co");
+    DUMP(" ");
+
+    for (i = 0; i < insn->ndst && i < Elements(insn->dst); ++i) {
+        sm1_dump_dst_param(&insn->dst[i]);
+        DUMP(" ");
+    }
+
+    for (i = 0; i < insn->nsrc && i < Elements(insn->src); ++i) {
+        sm1_dump_src_param(&insn->src[i]);
+        DUMP(" ");
+    }
+    if (insn->opcode == D3DSIO_DEF ||
+        insn->opcode == D3DSIO_DEFI ||
+        insn->opcode == D3DSIO_DEFB)
+        sm1_dump_immediate(&insn->src[0]);
+
+    DUMP("\n");
+}
+
+struct sm1_local_const
+{
+    INT idx;
+    struct ureg_src reg;
+    union {
+        boolean b;
+        float f[4];
+        int32_t i[4];
+    } imm;
+};
+
+struct shader_translator
+{
+    const DWORD *byte_code;
+    const DWORD *parse;
+    const DWORD *parse_next;
+
+    struct ureg_program *ureg;
+
+    /* shader version */
+    struct {
+        BYTE major;
+        BYTE minor;
+    } version;
+    unsigned processor; /* TGSI_PROCESSOR_VERTEX/FRAMGENT */
+
+    boolean native_integers;
+    boolean inline_subroutines;
+    boolean lower_preds;
+    boolean want_texcoord;
+    boolean shift_wpos;
+    unsigned texcoord_sn;
+
+    struct sm1_instruction insn; /* current instruction */
+
+    struct {
+        struct ureg_dst *r;
+        struct ureg_dst oPos;
+        struct ureg_dst oFog;
+        struct ureg_dst oPts;
+        struct ureg_dst oCol[4];
+        struct ureg_dst o[PIPE_MAX_SHADER_OUTPUTS];
+        struct ureg_dst oDepth;
+        struct ureg_src v[PIPE_MAX_SHADER_INPUTS];
+        struct ureg_src vPos;
+        struct ureg_src vFace;
+        struct ureg_src s;
+        struct ureg_dst p;
+        struct ureg_dst a;
+        struct ureg_dst tS[8]; /* texture stage registers */
+        struct ureg_dst tdst; /* scratch dst if we need extra modifiers */
+        struct ureg_dst t[5]; /* scratch TEMPs */
+        struct ureg_src vC[2]; /* PS color in */
+        struct ureg_src vT[8]; /* PS texcoord in */
+        struct ureg_dst rL[NINE_MAX_LOOP_DEPTH]; /* loop ctr */
+        struct ureg_dst aL[NINE_MAX_LOOP_DEPTH]; /* loop ctr ADDR register */
+    } regs;
+    unsigned num_temp; /* Elements(regs.r) */
+    unsigned num_scratch;
+    unsigned loop_depth;
+    unsigned loop_depth_max;
+    unsigned cond_depth;
+    unsigned loop_labels[NINE_MAX_LOOP_DEPTH];
+    unsigned cond_labels[NINE_MAX_COND_DEPTH];
+
+    unsigned *inst_labels; /* LABEL op */
+    unsigned num_inst_labels;
+
+    unsigned sampler_targets[NINE_MAX_SAMPLERS]; /* TGSI_TEXTURE_x */
+
+    struct sm1_local_const *lconstf;
+    unsigned num_lconstf;
+    struct sm1_local_const lconsti[NINE_MAX_CONST_I];
+    struct sm1_local_const lconstb[NINE_MAX_CONST_B];
+
+    boolean indirect_const_access;
+
+    struct nine_shader_info *info;
+
+    int16_t op_info_map[D3DSIO_BREAKP + 1];
+};
+
+#define IS_VS (tx->processor == TGSI_PROCESSOR_VERTEX)
+#define IS_PS (tx->processor == TGSI_PROCESSOR_FRAGMENT)
+
+static void
+sm1_read_semantic(struct shader_translator *, struct sm1_semantic *);
+
+static void
+sm1_instruction_check(const struct sm1_instruction *insn)
+{
+    if (insn->opcode == D3DSIO_CRS)
+    {
+        if (insn->dst[0].mask & NINED3DSP_WRITEMASK_3)
+        {
+            DBG("CRS.mask.w\n");
+        }
+    }
+}
+
+static boolean
+tx_lconstf(struct shader_translator *tx, struct ureg_src *src, INT index)
+{
+   INT i;
+   assert(index >= 0 && index < (NINE_MAX_CONST_F * 2));
+   for (i = 0; i < tx->num_lconstf; ++i) {
+      if (tx->lconstf[i].idx == index) {
+         *src = tx->lconstf[i].reg;
+         return TRUE;
+      }
+   }
+   return FALSE;
+}
+static boolean
+tx_lconsti(struct shader_translator *tx, struct ureg_src *src, INT index)
+{
+   assert(index >= 0 && index < NINE_MAX_CONST_I);
+   if (tx->lconsti[index].idx == index)
+      *src = tx->lconsti[index].reg;
+   return tx->lconsti[index].idx == index;
+}
+static boolean
+tx_lconstb(struct shader_translator *tx, struct ureg_src *src, INT index)
+{
+   assert(index >= 0 && index < NINE_MAX_CONST_B);
+   if (tx->lconstb[index].idx == index)
+      *src = tx->lconstb[index].reg;
+   return tx->lconstb[index].idx == index;
+}
+
+static void
+tx_set_lconstf(struct shader_translator *tx, INT index, float f[4])
+{
+    unsigned n;
+
+    /* Anno1404 sets out of range constants. */
+    assert(index >= 0 && index < (NINE_MAX_CONST_F * 2));
+    if (index >= NINE_MAX_CONST_F)
+        WARN("lconstf index %i too high, indirect access won't work\n", index);
+
+    for (n = 0; n < tx->num_lconstf; ++n)
+        if (tx->lconstf[n].idx == index)
+            break;
+    if (n == tx->num_lconstf) {
+       if ((n % 8) == 0) {
+          tx->lconstf = REALLOC(tx->lconstf,
+                                (n + 0) * sizeof(tx->lconstf[0]),
+                                (n + 8) * sizeof(tx->lconstf[0]));
+          assert(tx->lconstf);
+       }
+       tx->num_lconstf++;
+    }
+    tx->lconstf[n].idx = index;
+    tx->lconstf[n].reg = ureg_imm4f(tx->ureg, f[0], f[1], f[2], f[3]);
+
+    memcpy(tx->lconstf[n].imm.f, f, sizeof(tx->lconstf[n].imm.f));
+}
+static void
+tx_set_lconsti(struct shader_translator *tx, INT index, int i[4])
+{
+    assert(index >= 0 && index < NINE_MAX_CONST_I);
+    tx->lconsti[index].idx = index;
+    tx->lconsti[index].reg = tx->native_integers ?
+       ureg_imm4i(tx->ureg, i[0], i[1], i[2], i[3]) :
+       ureg_imm4f(tx->ureg, i[0], i[1], i[2], i[3]);
+}
+static void
+tx_set_lconstb(struct shader_translator *tx, INT index, BOOL b)
+{
+    assert(index >= 0 && index < NINE_MAX_CONST_B);
+    tx->lconstb[index].idx = index;
+    tx->lconstb[index].reg = tx->native_integers ?
+       ureg_imm1u(tx->ureg, b ? 0xffffffff : 0) :
+       ureg_imm1f(tx->ureg, b ? 1.0f : 0.0f);
+}
+
+static INLINE struct ureg_dst
+tx_scratch(struct shader_translator *tx)
+{
+    assert(tx->num_scratch < Elements(tx->regs.t));
+    if (ureg_dst_is_undef(tx->regs.t[tx->num_scratch]))
+        tx->regs.t[tx->num_scratch] = ureg_DECL_local_temporary(tx->ureg);
+    return tx->regs.t[tx->num_scratch++];
+}
+
+static INLINE struct ureg_dst
+tx_scratch_scalar(struct shader_translator *tx)
+{
+    return ureg_writemask(tx_scratch(tx), TGSI_WRITEMASK_X);
+}
+
+static INLINE struct ureg_src
+tx_src_scalar(struct ureg_dst dst)
+{
+    struct ureg_src src = ureg_src(dst);
+    int c = ffs(dst.WriteMask) - 1;
+    if (dst.WriteMask == (1 << c))
+        src = ureg_scalar(src, c);
+    return src;
+}
+
+/* Need to declare all constants if indirect addressing is used,
+ * otherwise we could scan the shader to determine the maximum.
+ * TODO: It doesn't really matter for nv50 so I won't do the scan,
+ * but radeon drivers might care, if they don't infer it from TGSI.
+ */
+static void
+tx_decl_constants(struct shader_translator *tx)
+{
+    unsigned i, n = 0;
+
+    for (i = 0; i < NINE_MAX_CONST_F; ++i)
+        ureg_DECL_constant(tx->ureg, n++);
+    for (i = 0; i < NINE_MAX_CONST_I; ++i)
+        ureg_DECL_constant(tx->ureg, n++);
+    for (i = 0; i < (NINE_MAX_CONST_B / 4); ++i)
+        ureg_DECL_constant(tx->ureg, n++);
+}
+
+static INLINE void
+tx_temp_alloc(struct shader_translator *tx, INT idx)
+{
+    assert(idx >= 0);
+    if (idx >= tx->num_temp) {
+       unsigned k = tx->num_temp;
+       unsigned n = idx + 1;
+       tx->regs.r = REALLOC(tx->regs.r,
+                            k * sizeof(tx->regs.r[0]),
+                            n * sizeof(tx->regs.r[0]));
+       for (; k < n; ++k)
+          tx->regs.r[k] = ureg_dst_undef();
+       tx->num_temp = n;
+    }
+    if (ureg_dst_is_undef(tx->regs.r[idx]))
+        tx->regs.r[idx] = ureg_DECL_temporary(tx->ureg);
+}
+
+static INLINE void
+tx_addr_alloc(struct shader_translator *tx, INT idx)
+{
+    assert(idx == 0);
+    if (ureg_dst_is_undef(tx->regs.a))
+        tx->regs.a = ureg_DECL_address(tx->ureg);
+}
+
+static INLINE void
+tx_pred_alloc(struct shader_translator *tx, INT idx)
+{
+    assert(idx == 0);
+    if (ureg_dst_is_undef(tx->regs.p))
+        tx->regs.p = ureg_DECL_predicate(tx->ureg);
+}
+
+static INLINE void
+tx_texcoord_alloc(struct shader_translator *tx, INT idx)
+{
+    assert(IS_PS);
+    assert(idx >= 0 && idx < Elements(tx->regs.vT));
+    if (ureg_src_is_undef(tx->regs.vT[idx]))
+       tx->regs.vT[idx] = ureg_DECL_fs_input(tx->ureg, tx->texcoord_sn, idx,
+                                             TGSI_INTERPOLATE_PERSPECTIVE);
+}
+
+static INLINE unsigned *
+tx_bgnloop(struct shader_translator *tx)
+{
+    tx->loop_depth++;
+    if (tx->loop_depth_max < tx->loop_depth)
+        tx->loop_depth_max = tx->loop_depth;
+    assert(tx->loop_depth < NINE_MAX_LOOP_DEPTH);
+    return &tx->loop_labels[tx->loop_depth - 1];
+}
+
+static INLINE unsigned *
+tx_endloop(struct shader_translator *tx)
+{
+    assert(tx->loop_depth);
+    tx->loop_depth--;
+    ureg_fixup_label(tx->ureg, tx->loop_labels[tx->loop_depth],
+                     ureg_get_instruction_number(tx->ureg));
+    return &tx->loop_labels[tx->loop_depth];
+}
+
+static struct ureg_dst
+tx_get_loopctr(struct shader_translator *tx)
+{
+    const unsigned l = tx->loop_depth - 1;
+
+    if (!tx->loop_depth)
+    {
+        DBG("loop counter requested outside of loop\n");
+        return ureg_dst_undef();
+    }
+
+    if (ureg_dst_is_undef(tx->regs.aL[l]))
+    {
+        struct ureg_dst rreg = ureg_DECL_local_temporary(tx->ureg);
+        struct ureg_dst areg = ureg_DECL_address(tx->ureg);
+        unsigned c;
+
+        assert(l % 4 == 0);
+        for (c = l; c < (l + 4) && c < Elements(tx->regs.aL); ++c) {
+            tx->regs.rL[c] = ureg_writemask(rreg, 1 << (c & 3));
+            tx->regs.aL[c] = ureg_writemask(areg, 1 << (c & 3));
+        }
+    }
+    return tx->regs.rL[l];
+}
+static struct ureg_dst
+tx_get_aL(struct shader_translator *tx)
+{
+    if (!ureg_dst_is_undef(tx_get_loopctr(tx)))
+        return tx->regs.aL[tx->loop_depth - 1];
+    return ureg_dst_undef();
+}
+
+static INLINE unsigned *
+tx_cond(struct shader_translator *tx)
+{
+   assert(tx->cond_depth <= NINE_MAX_COND_DEPTH);
+   tx->cond_depth++;
+   return &tx->cond_labels[tx->cond_depth - 1];
+}
+
+static INLINE unsigned *
+tx_elsecond(struct shader_translator *tx)
+{
+   assert(tx->cond_depth);
+   return &tx->cond_labels[tx->cond_depth - 1];
+}
+
+static INLINE void
+tx_endcond(struct shader_translator *tx)
+{
+   assert(tx->cond_depth);
+   tx->cond_depth--;
+   ureg_fixup_label(tx->ureg, tx->cond_labels[tx->cond_depth],
+                    ureg_get_instruction_number(tx->ureg));
+}
+
+static INLINE struct ureg_dst
+nine_ureg_dst_register(unsigned file, int index)
+{
+    return ureg_dst(ureg_src_register(file, index));
+}
+
+static struct ureg_src
+tx_src_param(struct shader_translator *tx, const struct sm1_src_param *param)
+{
+    struct ureg_program *ureg = tx->ureg;
+    struct ureg_src src;
+    struct ureg_dst tmp;
+
+    switch (param->file)
+    {
+    case D3DSPR_TEMP:
+        assert(!param->rel);
+        tx_temp_alloc(tx, param->idx);
+        src = ureg_src(tx->regs.r[param->idx]);
+        break;
+ /* case D3DSPR_TEXTURE: == D3DSPR_ADDR */
+    case D3DSPR_ADDR:
+        assert(!param->rel);
+        if (IS_VS) {
+            tx_addr_alloc(tx, param->idx);
+            src = ureg_src(tx->regs.a);
+        } else {
+            if (tx->version.major < 2 && tx->version.minor < 4) {
+                /* no subroutines, so should be defined */
+                src = ureg_src(tx->regs.tS[param->idx]);
+            } else {
+                tx_texcoord_alloc(tx, param->idx);
+                src = tx->regs.vT[param->idx];
+            }
+        }
+        break;
+    case D3DSPR_INPUT:
+        if (IS_VS) {
+            src = ureg_src_register(TGSI_FILE_INPUT, param->idx);
+        } else {
+            if (tx->version.major < 3) {
+                assert(!param->rel);
+                src = ureg_DECL_fs_input(tx->ureg, TGSI_SEMANTIC_COLOR,
+                                         param->idx,
+                                         TGSI_INTERPOLATE_PERSPECTIVE);
+            } else {
+                assert(!param->rel); /* TODO */
+                assert(param->idx < Elements(tx->regs.v));
+                src = tx->regs.v[param->idx];
+            }
+        }
+        break;
+    case D3DSPR_PREDICATE:
+        assert(!param->rel);
+        tx_pred_alloc(tx, param->idx);
+        src = ureg_src(tx->regs.p);
+        break;
+    case D3DSPR_SAMPLER:
+        assert(param->mod == NINED3DSPSM_NONE);
+        assert(param->swizzle == NINED3DSP_NOSWIZZLE);
+        assert(!param->rel);
+        src = ureg_src_register(TGSI_FILE_SAMPLER, param->idx);
+        break;
+    case D3DSPR_CONST:
+        if (param->rel)
+            tx->indirect_const_access = TRUE;
+        if (param->rel || !tx_lconstf(tx, &src, param->idx)) {
+            if (!param->rel)
+                nine_info_mark_const_f_used(tx->info, param->idx);
+            src = ureg_src_register(TGSI_FILE_CONSTANT, param->idx);
+        }
+        break;
+    case D3DSPR_CONST2:
+    case D3DSPR_CONST3:
+    case D3DSPR_CONST4:
+        DBG("CONST2/3/4 should have been collapsed into D3DSPR_CONST !\n");
+        assert(!"CONST2/3/4");
+        src = ureg_imm1f(ureg, 0.0f);
+        break;
+    case D3DSPR_CONSTINT:
+        if (param->rel || !tx_lconsti(tx, &src, param->idx)) {
+            if (!param->rel)
+                nine_info_mark_const_i_used(tx->info, param->idx);
+            src = ureg_src_register(TGSI_FILE_CONSTANT,
+                                    tx->info->const_i_base + param->idx);
+        }
+        break;
+    case D3DSPR_CONSTBOOL:
+        if (param->rel || !tx_lconstb(tx, &src, param->idx)) {
+           char r = param->idx / 4;
+           char s = param->idx & 3;
+           if (!param->rel)
+               nine_info_mark_const_b_used(tx->info, param->idx);
+           src = ureg_src_register(TGSI_FILE_CONSTANT,
+                                   tx->info->const_b_base + r);
+           src = ureg_swizzle(src, s, s, s, s);
+        }
+        break;
+    case D3DSPR_LOOP:
+        src = tx_src_scalar(tx_get_aL(tx));
+        break;
+    case D3DSPR_MISCTYPE:
+        switch (param->idx) {
+        case D3DSMO_POSITION:
+           if (ureg_src_is_undef(tx->regs.vPos))
+               tx->regs.vPos = ureg_DECL_fs_input(ureg,
+                                                  TGSI_SEMANTIC_POSITION, 0,
+                                                  TGSI_INTERPOLATE_LINEAR);
+           if (tx->shift_wpos) {
+               /* TODO: do this only once */
+               struct ureg_dst wpos = tx_scratch(tx);
+               ureg_SUB(ureg, wpos, tx->regs.vPos,
+                        ureg_imm4f(ureg, 0.5f, 0.5f, 0.0f, 0.0f));
+               src = ureg_src(wpos);
+           } else {
+               src = tx->regs.vPos;
+           }
+           break;
+        case D3DSMO_FACE:
+           if (ureg_src_is_undef(tx->regs.vFace)) {
+               tx->regs.vFace = ureg_DECL_fs_input(ureg,
+                                                   TGSI_SEMANTIC_FACE, 0,
+                                                   TGSI_INTERPOLATE_CONSTANT);
+               tx->regs.vFace = ureg_scalar(tx->regs.vFace, TGSI_SWIZZLE_X);
+           }
+           src = tx->regs.vFace;
+           break;
+        default:
+            assert(!"invalid src D3DSMO");
+            break;
+        }
+        assert(!param->rel);
+        break;
+    case D3DSPR_TEMPFLOAT16:
+        break;
+    default:
+        assert(!"invalid src D3DSPR");
+    }
+    if (param->rel)
+        src = ureg_src_indirect(src, tx_src_param(tx, param->rel));
+
+    if (param->swizzle != NINED3DSP_NOSWIZZLE)
+        src = ureg_swizzle(src,
+                           (param->swizzle >> 0) & 0x3,
+                           (param->swizzle >> 2) & 0x3,
+                           (param->swizzle >> 4) & 0x3,
+                           (param->swizzle >> 6) & 0x3);
+
+    switch (param->mod) {
+    case NINED3DSPSM_ABS:
+        src = ureg_abs(src);
+        break;
+    case NINED3DSPSM_ABSNEG:
+        src = ureg_negate(ureg_abs(src));
+        break;
+    case NINED3DSPSM_NEG:
+        src = ureg_negate(src);
+        break;
+    case NINED3DSPSM_BIAS:
+        tmp = tx_scratch(tx);
+        ureg_SUB(ureg, tmp, src, ureg_imm1f(ureg, 0.5f));
+        src = ureg_src(tmp);
+        break;
+    case NINED3DSPSM_BIASNEG:
+        tmp = tx_scratch(tx);
+        ureg_SUB(ureg, tmp, ureg_imm1f(ureg, 0.5f), src);
+        src = ureg_src(tmp);
+        break;
+    case NINED3DSPSM_NOT:
+        if (tx->native_integers) {
+            tmp = tx_scratch(tx);
+            ureg_NOT(ureg, tmp, src);
+            src = ureg_src(tmp);
+            break;
+        }
+        /* fall through */
+    case NINED3DSPSM_COMP:
+        tmp = tx_scratch(tx);
+        ureg_SUB(ureg, tmp, ureg_imm1f(ureg, 1.0f), src);
+        src = ureg_src(tmp);
+        break;
+    case NINED3DSPSM_DZ:
+    case NINED3DSPSM_DW:
+        /* handled in instruction */
+        break;
+    case NINED3DSPSM_SIGN:
+        tmp = tx_scratch(tx);
+        ureg_MAD(ureg, tmp, src, ureg_imm1f(ureg, 2.0f), ureg_imm1f(ureg, -1.0f));
+        src = ureg_src(tmp);
+        break;
+    case NINED3DSPSM_SIGNNEG:
+        tmp = tx_scratch(tx);
+        ureg_MAD(ureg, tmp, src, ureg_imm1f(ureg, -2.0f), ureg_imm1f(ureg, 1.0f));
+        src = ureg_src(tmp);
+        break;
+    case NINED3DSPSM_X2:
+        tmp = tx_scratch(tx);
+        ureg_ADD(ureg, tmp, src, src);
+        src = ureg_src(tmp);
+        break;
+    case NINED3DSPSM_X2NEG:
+        tmp = tx_scratch(tx);
+        ureg_ADD(ureg, tmp, src, src);
+        src = ureg_negate(ureg_src(tmp));
+        break;
+    default:
+        assert(param->mod == NINED3DSPSM_NONE);
+        break;
+    }
+
+    return src;
+}
+
+static struct ureg_dst
+_tx_dst_param(struct shader_translator *tx, const struct sm1_dst_param *param)
+{
+    struct ureg_dst dst;
+
+    switch (param->file)
+    {
+    case D3DSPR_TEMP:
+        assert(!param->rel);
+        tx_temp_alloc(tx, param->idx);
+        dst = tx->regs.r[param->idx];
+        break;
+ /* case D3DSPR_TEXTURE: == D3DSPR_ADDR */
+    case D3DSPR_ADDR:
+        assert(!param->rel);
+        if (tx->version.major < 2 && !IS_VS) {
+            if (ureg_dst_is_undef(tx->regs.tS[param->idx]))
+                tx->regs.tS[param->idx] = ureg_DECL_temporary(tx->ureg);
+            dst = tx->regs.tS[param->idx];
+        } else
+        if (!IS_VS && tx->insn.opcode == D3DSIO_TEXKILL) { /* maybe others, too */
+            tx_texcoord_alloc(tx, param->idx);
+            dst = ureg_dst(tx->regs.vT[param->idx]);
+        } else {
+            tx_addr_alloc(tx, param->idx);
+            dst = tx->regs.a;
+        }
+        break;
+    case D3DSPR_RASTOUT:
+        assert(!param->rel);
+        switch (param->idx) {
+        case 0:
+            if (ureg_dst_is_undef(tx->regs.oPos))
+                tx->regs.oPos =
+                    ureg_DECL_output(tx->ureg, TGSI_SEMANTIC_POSITION, 0);
+            dst = tx->regs.oPos;
+            break;
+        case 1:
+            if (ureg_dst_is_undef(tx->regs.oFog))
+                tx->regs.oFog =
+                    ureg_DECL_output(tx->ureg, TGSI_SEMANTIC_FOG, 0);
+            dst = tx->regs.oFog;
+            break;
+        case 2:
+            if (ureg_dst_is_undef(tx->regs.oPts))
+                tx->regs.oPts =
+                    ureg_DECL_output(tx->ureg, TGSI_SEMANTIC_PSIZE, 0);
+            dst = tx->regs.oPts;
+            break;
+        default:
+            assert(0);
+            break;
+        }
+        break;
+ /* case D3DSPR_TEXCRDOUT: == D3DSPR_OUTPUT */
+    case D3DSPR_OUTPUT:
+        if (tx->version.major < 3) {
+            assert(!param->rel);
+            dst = ureg_DECL_output(tx->ureg, tx->texcoord_sn, param->idx);
+        } else {
+            assert(!param->rel); /* TODO */
+            assert(param->idx < Elements(tx->regs.o));
+            dst = tx->regs.o[param->idx];
+        }
+        break;
+    case D3DSPR_ATTROUT: /* VS */
+    case D3DSPR_COLOROUT: /* PS */
+        assert(param->idx >= 0 && param->idx < 4);
+        assert(!param->rel);
+        tx->info->rt_mask |= 1 << param->idx;
+        if (ureg_dst_is_undef(tx->regs.oCol[param->idx]))
+            tx->regs.oCol[param->idx] =
+               ureg_DECL_output(tx->ureg, TGSI_SEMANTIC_COLOR, param->idx);
+        dst = tx->regs.oCol[param->idx];
+        if (IS_VS && tx->version.major < 3)
+            dst = ureg_saturate(dst);
+        break;
+    case D3DSPR_DEPTHOUT:
+        assert(!param->rel);
+        if (ureg_dst_is_undef(tx->regs.oDepth))
+           tx->regs.oDepth =
+              ureg_DECL_output_masked(tx->ureg, TGSI_SEMANTIC_POSITION, 0,
+                                      TGSI_WRITEMASK_Z);
+        dst = tx->regs.oDepth; /* XXX: must write .z component */
+        break;
+    case D3DSPR_PREDICATE:
+        assert(!param->rel);
+        tx_pred_alloc(tx, param->idx);
+        dst = tx->regs.p;
+        break;
+    case D3DSPR_TEMPFLOAT16:
+        DBG("unhandled D3DSPR: %u\n", param->file);
+        break;
+    default:
+        assert(!"invalid dst D3DSPR");
+        break;
+    }
+    if (param->rel)
+        dst = ureg_dst_indirect(dst, tx_src_param(tx, param->rel));
+
+    if (param->mask != NINED3DSP_WRITEMASK_ALL)
+        dst = ureg_writemask(dst, param->mask);
+    if (param->mod & NINED3DSPDM_SATURATE)
+        dst = ureg_saturate(dst);
+
+    return dst;
+}
+
+static struct ureg_dst
+tx_dst_param(struct shader_translator *tx, const struct sm1_dst_param *param)
+{
+    if (param->shift) {
+        tx->regs.tdst = ureg_writemask(tx_scratch(tx), param->mask);
+        return tx->regs.tdst;
+    }
+    return _tx_dst_param(tx, param);
+}
+
+static void
+tx_apply_dst0_modifiers(struct shader_translator *tx)
+{
+    struct ureg_dst rdst;
+    float f;
+
+    if (!tx->insn.ndst || !tx->insn.dst[0].shift || tx->insn.opcode == D3DSIO_TEXKILL)
+        return;
+    rdst = _tx_dst_param(tx, &tx->insn.dst[0]);
+
+    assert(rdst.File != TGSI_FILE_ADDRESS); /* this probably isn't possible */
+
+    if (tx->insn.dst[0].shift < 0)
+        f = 1.0f / (1 << -tx->insn.dst[0].shift);
+    else
+        f = 1 << tx->insn.dst[0].shift;
+
+    ureg_MUL(tx->ureg, rdst, ureg_src(tx->regs.tdst), ureg_imm1f(tx->ureg, f));
+}
+
+static struct ureg_src
+tx_dst_param_as_src(struct shader_translator *tx, const struct sm1_dst_param *param)
+{
+    struct ureg_src src;
+
+    assert(!param->shift);
+    assert(!(param->mod & NINED3DSPDM_SATURATE));
+
+    switch (param->file) {
+    case D3DSPR_INPUT:
+        if (IS_VS) {
+            src = ureg_src_register(TGSI_FILE_INPUT, param->idx);
+        } else {
+            assert(!param->rel);
+            assert(param->idx < Elements(tx->regs.v));
+            src = tx->regs.v[param->idx];
+        }
+        break;
+    default:
+        src = ureg_src(tx_dst_param(tx, param));
+        break;
+    }
+    if (param->rel)
+        src = ureg_src_indirect(src, tx_src_param(tx, param->rel));
+
+    if (!param->mask)
+        WARN("mask is 0, using identity swizzle\n");
+
+    if (param->mask && param->mask != NINED3DSP_WRITEMASK_ALL) {
+        char s[4];
+        int n;
+        int c;
+        for (n = 0, c = 0; c < 4; ++c)
+            if (param->mask & (1 << c))
+                s[n++] = c;
+        assert(n);
+        for (c = n; c < 4; ++c)
+            s[c] = s[n - 1];
+        src = ureg_swizzle(src, s[0], s[1], s[2], s[3]);
+    }
+    return src;
+}
+
+static HRESULT
+NineTranslateInstruction_Mkxn(struct shader_translator *tx, const unsigned k, const unsigned n)
+{
+    struct ureg_program *ureg = tx->ureg;
+    struct ureg_dst dst;
+    struct ureg_src src[2];
+    unsigned i;
+
+    dst = tx_dst_param(tx, &tx->insn.dst[0]);
+    src[0] = tx_src_param(tx, &tx->insn.src[0]);
+    src[1] = tx_src_param(tx, &tx->insn.src[1]);
+
+    for (i = 0; i < n; i++, src[1].Index++)
+    {
+        const unsigned m = (1 << i);
+
+        if (!(dst.WriteMask & m))
+            continue;
+
+        /* XXX: src == dst case ? */
+
+        switch (k) {
+        case 3:
+            ureg_DP3(ureg, ureg_writemask(dst, m), src[0], src[1]);
+            break;
+        case 4:
+            ureg_DP4(ureg, ureg_writemask(dst, m), src[0], src[1]);
+            break;
+        default:
+            DBG("invalid operation: M%ux%u\n", m, n);
+            break;
+        }
+    }
+
+    return D3D_OK;
+}
+
+#define VNOTSUPPORTED   0, 0
+#define V(maj, min)     (((maj) << 8) | (min))
+
+static INLINE const char *
+d3dsio_to_string( unsigned opcode )
+{
+    static const char *names[] = {
+        "NOP",
+        "MOV",
+        "ADD",
+        "SUB",
+        "MAD",
+        "MUL",
+        "RCP",
+        "RSQ",
+        "DP3",
+        "DP4",
+        "MIN",
+        "MAX",
+        "SLT",
+        "SGE",
+        "EXP",
+        "LOG",
+        "LIT",
+        "DST",
+        "LRP",
+        "FRC",
+        "M4x4",
+        "M4x3",
+        "M3x4",
+        "M3x3",
+        "M3x2",
+        "CALL",
+        "CALLNZ",
+        "LOOP",
+        "RET",
+        "ENDLOOP",
+        "LABEL",
+        "DCL",
+        "POW",
+        "CRS",
+        "SGN",
+        "ABS",
+        "NRM",
+        "SINCOS",
+        "REP",
+        "ENDREP",
+        "IF",
+        "IFC",
+        "ELSE",
+        "ENDIF",
+        "BREAK",
+        "BREAKC",
+        "MOVA",
+        "DEFB",
+        "DEFI",
+        NULL,
+        NULL,
+        NULL,
+        NULL,
+        NULL,
+        NULL,
+        NULL,
+        NULL,
+        NULL,
+        NULL,
+        NULL,
+        NULL,
+        NULL,
+        NULL,
+        NULL,
+        "TEXCOORD",
+        "TEXKILL",
+        "TEX",
+        "TEXBEM",
+        "TEXBEML",
+        "TEXREG2AR",
+        "TEXREG2GB",
+        "TEXM3x2PAD",
+        "TEXM3x2TEX",
+        "TEXM3x3PAD",
+        "TEXM3x3TEX",
+        NULL,
+        "TEXM3x3SPEC",
+        "TEXM3x3VSPEC",
+        "EXPP",
+        "LOGP",
+        "CND",
+        "DEF",
+        "TEXREG2RGB",
+        "TEXDP3TEX",
+        "TEXM3x2DEPTH",
+        "TEXDP3",
+        "TEXM3x3",
+        "TEXDEPTH",
+        "CMP",
+        "BEM",
+        "DP2ADD",
+        "DSX",
+        "DSY",
+        "TEXLDD",
+        "SETP",
+        "TEXLDL",
+        "BREAKP"
+    };
+
+    if (opcode < Elements(names)) return names[opcode];
+
+    switch (opcode) {
+    case D3DSIO_PHASE: return "PHASE";
+    case D3DSIO_COMMENT: return "COMMENT";
+    case D3DSIO_END: return "END";
+    default:
+        return NULL;
+    }
+}
+
+#define NULL_INSTRUCTION            { 0, { 0, 0 }, { 0, 0 }, 0, 0, NULL }
+#define IS_VALID_INSTRUCTION(inst)  ((inst).vert_version.min | \
+                                     (inst).vert_version.max | \
+                                     (inst).frag_version.min | \
+                                     (inst).frag_version.max)
+
+#define SPECIAL(name) \
+    NineTranslateInstruction_##name
+
+#define DECL_SPECIAL(name) \
+    static HRESULT \
+    NineTranslateInstruction_##name( struct shader_translator *tx )
+
+static HRESULT
+NineTranslateInstruction_Generic(struct shader_translator *);
+
+DECL_SPECIAL(M4x4)
+{
+    return NineTranslateInstruction_Mkxn(tx, 4, 3);
+}
+
+DECL_SPECIAL(M4x3)
+{
+    return NineTranslateInstruction_Mkxn(tx, 4, 3);
+}
+
+DECL_SPECIAL(M3x4)
+{
+    return NineTranslateInstruction_Mkxn(tx, 3, 4);
+}
+
+DECL_SPECIAL(M3x3)
+{
+    return NineTranslateInstruction_Mkxn(tx, 3, 3);
+}
+
+DECL_SPECIAL(M3x2)
+{
+    return NineTranslateInstruction_Mkxn(tx, 3, 2);
+}
+
+DECL_SPECIAL(CMP)
+{
+    ureg_CMP(tx->ureg, tx_dst_param(tx, &tx->insn.dst[0]),
+             tx_src_param(tx, &tx->insn.src[0]),
+             tx_src_param(tx, &tx->insn.src[2]),
+             tx_src_param(tx, &tx->insn.src[1]));
+    return D3D_OK;
+}
+
+DECL_SPECIAL(CND)
+{
+    struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]);
+    struct ureg_dst cgt;
+    struct ureg_src cnd;
+
+    if (tx->insn.coissue && tx->version.major == 1 && tx->version.minor < 4) {
+        ureg_MOV(tx->ureg,
+                 dst, tx_src_param(tx, &tx->insn.src[1]));
+        return D3D_OK;
+    }
+
+    cnd = tx_src_param(tx, &tx->insn.src[0]);
+#ifdef NINE_TGSI_LAZY_R600
+    cgt = tx_scratch(tx);
+
+    if (tx->version.major == 1 && tx->version.minor < 4) {
+        cgt.WriteMask = TGSI_WRITEMASK_W;
+        ureg_SGT(tx->ureg, cgt, cnd, ureg_imm1f(tx->ureg, 0.5f));
+        cnd = ureg_scalar(cnd, TGSI_SWIZZLE_W);
+    } else {
+        ureg_SGT(tx->ureg, cgt, cnd, ureg_imm1f(tx->ureg, 0.5f));
+    }
+    ureg_CMP(tx->ureg, dst,
+             tx_src_param(tx, &tx->insn.src[1]),
+             tx_src_param(tx, &tx->insn.src[2]), ureg_negate(cnd));
+#else
+    if (tx->version.major == 1 && tx->version.minor < 4)
+        cnd = ureg_scalar(cnd, TGSI_SWIZZLE_W);
+    ureg_CND(tx->ureg, dst,
+             tx_src_param(tx, &tx->insn.src[1]),
+             tx_src_param(tx, &tx->insn.src[2]), cnd);
+#endif
+    return D3D_OK;
+}
+
+DECL_SPECIAL(CALL)
+{
+    assert(tx->insn.src[0].idx < tx->num_inst_labels);
+    ureg_CAL(tx->ureg, &tx->inst_labels[tx->insn.src[0].idx]);
+    return D3D_OK;
+}
+
+DECL_SPECIAL(CALLNZ)
+{
+    struct ureg_program *ureg = tx->ureg;
+    struct ureg_dst tmp = tx_scratch_scalar(tx);
+    struct ureg_src src = tx_src_param(tx, &tx->insn.src[1]);
+
+    /* NOTE: source should be const bool, so we can use NOT/SUB instead of [U]SNE 0 */
+    if (!tx->insn.flags) {
+        if (tx->native_integers)
+            ureg_NOT(ureg, tmp, src);
+        else
+            ureg_SUB(ureg, tmp, ureg_imm1f(ureg, 1.0f), src);
+    }
+    ureg_IF(ureg, tx->insn.flags ? src : tx_src_scalar(tmp), tx_cond(tx));
+    ureg_CAL(ureg, &tx->inst_labels[tx->insn.src[0].idx]);
+    tx_endcond(tx);
+    ureg_ENDIF(ureg);
+    return D3D_OK;
+}
+
+DECL_SPECIAL(MOV_vs1x)
+{
+    if (tx->insn.dst[0].file == D3DSPR_ADDR) {
+        ureg_ARL(tx->ureg,
+                 tx_dst_param(tx, &tx->insn.dst[0]),
+                 tx_src_param(tx, &tx->insn.src[0]));
+        return D3D_OK;
+    }
+    return NineTranslateInstruction_Generic(tx);
+}
+
+DECL_SPECIAL(LOOP)
+{
+    struct ureg_program *ureg = tx->ureg;
+    unsigned *label;
+    struct ureg_src src = tx_src_param(tx, &tx->insn.src[1]);
+    struct ureg_src iter = ureg_scalar(src, TGSI_SWIZZLE_X);
+    struct ureg_src init = ureg_scalar(src, TGSI_SWIZZLE_Y);
+    struct ureg_src step = ureg_scalar(src, TGSI_SWIZZLE_Z);
+    struct ureg_dst ctr;
+    struct ureg_dst tmp = tx_scratch_scalar(tx);
+
+    label = tx_bgnloop(tx);
+    ctr = tx_get_loopctr(tx);
+
+    ureg_MOV(tx->ureg, ctr, init);
+    ureg_BGNLOOP(tx->ureg, label);
+    if (tx->native_integers) {
+        /* we'll let the backend pull up that MAD ... */
+        ureg_UMAD(ureg, tmp, iter, step, init);
+        ureg_USEQ(ureg, tmp, ureg_src(ctr), tx_src_scalar(tmp));
+#ifdef NINE_TGSI_LAZY_DEVS
+        ureg_UIF(ureg, tx_src_scalar(tmp), tx_cond(tx));
+#endif
+    } else {
+        /* can't simply use SGE for precision because step might be negative */
+        ureg_MAD(ureg, tmp, iter, step, init);
+        ureg_SEQ(ureg, tmp, ureg_src(ctr), tx_src_scalar(tmp));
+#ifdef NINE_TGSI_LAZY_DEVS
+        ureg_IF(ureg, tx_src_scalar(tmp), tx_cond(tx));
+#endif
+    }
+#ifdef NINE_TGSI_LAZY_DEVS
+    ureg_BRK(ureg);
+    tx_endcond(tx);
+    ureg_ENDIF(ureg);
+#else
+    ureg_BREAKC(ureg, tx_src_scalar(tmp));
+#endif
+    if (tx->native_integers) {
+        ureg_UARL(ureg, tx_get_aL(tx), tx_src_scalar(ctr));
+        ureg_UADD(ureg, ctr, tx_src_scalar(ctr), step);
+    } else {
+        ureg_ARL(ureg, tx_get_aL(tx), tx_src_scalar(ctr));
+        ureg_ADD(ureg, ctr, tx_src_scalar(ctr), step);
+    }
+    return D3D_OK;
+}
+
+DECL_SPECIAL(RET)
+{
+    ureg_RET(tx->ureg);
+    return D3D_OK;
+}
+
+DECL_SPECIAL(ENDLOOP)
+{
+    ureg_ENDLOOP(tx->ureg, tx_endloop(tx));
+    return D3D_OK;
+}
+
+DECL_SPECIAL(LABEL)
+{
+    unsigned k = tx->num_inst_labels;
+    unsigned n = tx->insn.src[0].idx;
+    assert(n < 2048);
+    if (n >= k)
+       tx->inst_labels = REALLOC(tx->inst_labels,
+                                 k * sizeof(tx->inst_labels[0]),
+                                 n * sizeof(tx->inst_labels[0]));
+
+    tx->inst_labels[n] = ureg_get_instruction_number(tx->ureg);
+    return D3D_OK;
+}
+
+DECL_SPECIAL(SINCOS)
+{
+    struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]);
+    struct ureg_src src = tx_src_param(tx, &tx->insn.src[0]);
+
+    assert(!(dst.WriteMask & 0xc));
+
+    dst.WriteMask &= TGSI_WRITEMASK_XY; /* z undefined, w untouched */
+    ureg_SCS(tx->ureg, dst, src);
+    return D3D_OK;
+}
+
+DECL_SPECIAL(SGN)
+{
+    ureg_SSG(tx->ureg,
+             tx_dst_param(tx, &tx->insn.dst[0]),
+             tx_src_param(tx, &tx->insn.src[0]));
+    return D3D_OK;
+}
+
+DECL_SPECIAL(REP)
+{
+    struct ureg_program *ureg = tx->ureg;
+    unsigned *label;
+    struct ureg_src rep = tx_src_param(tx, &tx->insn.src[0]);
+    struct ureg_dst ctr;
+    struct ureg_dst tmp = tx_scratch_scalar(tx);
+    struct ureg_src imm =
+        tx->native_integers ? ureg_imm1u(ureg, 0) : ureg_imm1f(ureg, 0.0f);
+
+    label = tx_bgnloop(tx);
+    ctr = tx_get_loopctr(tx);
+
+    /* NOTE: rep must be constant, so we don't have to save the count */
+    assert(rep.File == TGSI_FILE_CONSTANT || rep.File == TGSI_FILE_IMMEDIATE);
+
+    ureg_MOV(ureg, ctr, imm);
+    ureg_BGNLOOP(ureg, label);
+    if (tx->native_integers)
+    {
+        ureg_USGE(ureg, tmp, tx_src_scalar(ctr), rep);
+#ifdef NINE_TGSI_LAZY_DEVS
+        ureg_UIF(ureg, tx_src_scalar(tmp), tx_cond(tx));
+#endif
+    }
+    else
+    {
+        ureg_SGE(ureg, tmp, tx_src_scalar(ctr), rep);
+#ifdef NINE_TGSI_LAZY_DEVS
+        ureg_IF(ureg, tx_src_scalar(tmp), tx_cond(tx));
+#endif
+    }
+#ifdef NINE_TGSI_LAZY_DEVS
+    ureg_BRK(ureg);
+    tx_endcond(tx);
+    ureg_ENDIF(ureg);
+#else
+    ureg_BREAKC(ureg, tx_src_scalar(tmp));
+#endif
+
+    if (tx->native_integers) {
+        ureg_UADD(ureg, ctr, tx_src_scalar(ctr), ureg_imm1u(ureg, 1));
+    } else {
+        ureg_ADD(ureg, ctr, tx_src_scalar(ctr), ureg_imm1f(ureg, 1.0f));
+    }
+
+    return D3D_OK;
+}
+
+DECL_SPECIAL(ENDREP)
+{
+    ureg_ENDLOOP(tx->ureg, tx_endloop(tx));
+    return D3D_OK;
+}
+
+DECL_SPECIAL(ENDIF)
+{
+    tx_endcond(tx);
+    ureg_ENDIF(tx->ureg);
+    return D3D_OK;
+}
+
+DECL_SPECIAL(IF)
+{
+    struct ureg_src src = tx_src_param(tx, &tx->insn.src[0]);
+
+    if (tx->native_integers && tx->insn.src[0].file == D3DSPR_CONSTBOOL)
+        ureg_UIF(tx->ureg, src, tx_cond(tx));
+    else
+        ureg_IF(tx->ureg, src, tx_cond(tx));
+
+    return D3D_OK;
+}
+
+static INLINE unsigned
+sm1_insn_flags_to_tgsi_setop(BYTE flags)
+{
+    switch (flags) {
+    case NINED3DSHADER_REL_OP_GT: return TGSI_OPCODE_SGT;
+    case NINED3DSHADER_REL_OP_EQ: return TGSI_OPCODE_SEQ;
+    case NINED3DSHADER_REL_OP_GE: return TGSI_OPCODE_SGE;
+    case NINED3DSHADER_REL_OP_LT: return TGSI_OPCODE_SLT;
+    case NINED3DSHADER_REL_OP_NE: return TGSI_OPCODE_SNE;
+    case NINED3DSHADER_REL_OP_LE: return TGSI_OPCODE_SLE;
+    default:
+        assert(!"invalid comparison flags");
+        return TGSI_OPCODE_SFL;
+    }
+}
+
+DECL_SPECIAL(IFC)
+{
+    const unsigned cmp_op = sm1_insn_flags_to_tgsi_setop(tx->insn.flags);
+    struct ureg_src src[2];
+    struct ureg_dst tmp = ureg_writemask(tx_scratch(tx), TGSI_WRITEMASK_X);
+    src[0] = tx_src_param(tx, &tx->insn.src[0]);
+    src[1] = tx_src_param(tx, &tx->insn.src[1]);
+    ureg_insn(tx->ureg, cmp_op, &tmp, 1, src, 2);
+    ureg_IF(tx->ureg, ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X), tx_cond(tx));
+    return D3D_OK;
+}
+
+DECL_SPECIAL(ELSE)
+{
+    ureg_ELSE(tx->ureg, tx_elsecond(tx));
+    return D3D_OK;
+}
+
+DECL_SPECIAL(BREAKC)
+{
+    const unsigned cmp_op = sm1_insn_flags_to_tgsi_setop(tx->insn.flags);
+    struct ureg_src src[2];
+    struct ureg_dst tmp = ureg_writemask(tx_scratch(tx), TGSI_WRITEMASK_X);
+    src[0] = tx_src_param(tx, &tx->insn.src[0]);
+    src[1] = tx_src_param(tx, &tx->insn.src[1]);
+    ureg_insn(tx->ureg, cmp_op, &tmp, 1, src, 2);
+#ifdef NINE_TGSI_LAZY_DEVS
+    ureg_IF(tx->ureg, ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X), tx_cond(tx));
+    ureg_BRK(tx->ureg);
+    tx_endcond(tx);
+    ureg_ENDIF(tx->ureg);
+#else
+    ureg_BREAKC(tx->ureg, ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X));
+#endif
+    return D3D_OK;
+}
+
+static const char *sm1_declusage_names[] =
+{
+    [D3DDECLUSAGE_POSITION] = "POSITION",
+    [D3DDECLUSAGE_BLENDWEIGHT] = "BLENDWEIGHT",
+    [D3DDECLUSAGE_BLENDINDICES] = "BLENDINDICES",
+    [D3DDECLUSAGE_NORMAL] = "NORMAL",
+    [D3DDECLUSAGE_PSIZE] = "PSIZE",
+    [D3DDECLUSAGE_TEXCOORD] = "TEXCOORD",
+    [D3DDECLUSAGE_TANGENT] = "TANGENT",
+    [D3DDECLUSAGE_BINORMAL] = "BINORMAL",
+    [D3DDECLUSAGE_TESSFACTOR] = "TESSFACTOR",
+    [D3DDECLUSAGE_POSITIONT] = "POSITIONT",
+    [D3DDECLUSAGE_COLOR] = "COLOR",
+    [D3DDECLUSAGE_FOG] = "FOG",
+    [D3DDECLUSAGE_DEPTH] = "DEPTH",
+    [D3DDECLUSAGE_SAMPLE] = "SAMPLE"
+};
+
+static INLINE unsigned
+sm1_to_nine_declusage(struct sm1_semantic *dcl)
+{
+    return nine_d3d9_to_nine_declusage(dcl->usage, dcl->usage_idx);
+}
+
+static void
+sm1_declusage_to_tgsi(struct tgsi_declaration_semantic *sem,
+                      boolean tc,
+                      struct sm1_semantic *dcl)
+{
+    const unsigned generic_base = tc ? 0 : 8; /* TEXCOORD[0..7] */
+
+    sem->Name = TGSI_SEMANTIC_GENERIC;
+    sem->Index = 0;
+
+    /* TGSI_SEMANTIC_GENERIC assignments (+8 if !PIPE_CAP_TGSI_TEXCOORD):
+     * Try to put frequently used semantics at low GENERIC indices.
+     *
+     * POSITION[1..4]: 17, 27, 28, 29
+     * COLOR[2..4]: 14, 15, 26
+     * TEXCOORD[8..15]: 10, 11, 18, 19, 20, 21, 22, 23
+     * BLENDWEIGHT[0..3]: 0, 4, 8, 12
+     * BLENDINDICES[0..3]: 1, 5, 9, 13
+     * NORMAL[0..1]: 2, 6
+     * TANGENT[0]: 3, 24
+     * BINORMAL[0]: 7, 25
+     * TESSFACTOR[0]: 16
+     */
+
+    switch (dcl->usage) {
+    case D3DDECLUSAGE_POSITION:
+    case D3DDECLUSAGE_POSITIONT:
+    case D3DDECLUSAGE_DEPTH:
+        sem->Name = TGSI_SEMANTIC_POSITION;
+        assert(dcl->usage_idx <= 4);
+        if (dcl->usage_idx == 1) {
+            sem->Name = TGSI_SEMANTIC_GENERIC;
+            sem->Index = generic_base + 17;
+        } else
+        if (dcl->usage_idx >= 2) {
+            sem->Name = TGSI_SEMANTIC_GENERIC;
+            sem->Index = generic_base + 27 + (dcl->usage_idx - 2);
+        }
+        break;
+    case D3DDECLUSAGE_COLOR:
+        assert(dcl->usage_idx <= 4);
+        if (dcl->usage_idx < 2) {
+            sem->Name = TGSI_SEMANTIC_COLOR;
+            sem->Index = dcl->usage_idx;
+        } else
+        if (dcl->usage_idx < 4) {
+            sem->Index = generic_base + 14 + (dcl->usage_idx - 2);
+        } else {
+            sem->Index = generic_base + 26;
+        }
+        break;
+    case D3DDECLUSAGE_FOG:
+        sem->Name = TGSI_SEMANTIC_FOG;
+        assert(dcl->usage_idx == 0);
+        break;
+    case D3DDECLUSAGE_PSIZE:
+        sem->Name = TGSI_SEMANTIC_PSIZE;
+        assert(dcl->usage_idx == 0);
+        break;
+    case D3DDECLUSAGE_TEXCOORD:
+        assert(dcl->usage_idx < 16);
+        if (dcl->usage_idx < 8) {
+            if (tc)
+                sem->Name = TGSI_SEMANTIC_TEXCOORD;
+            sem->Index = dcl->usage_idx;
+        } else
+        if (dcl->usage_idx < 10) {
+            sem->Index = generic_base + 10 + (dcl->usage_idx - 8);
+        } else {
+            sem->Index = generic_base + 18 + (dcl->usage_idx - 10);
+        }
+        break;
+    case D3DDECLUSAGE_BLENDWEIGHT: /* 0, 4, 8, 12 */
+        assert(dcl->usage_idx < 4);
+        sem->Index = generic_base + dcl->usage_idx * 4;
+        break;
+    case D3DDECLUSAGE_BLENDINDICES: /* 1, 5, 9, 13 */
+        assert(dcl->usage_idx < 4);
+        sem->Index = generic_base + dcl->usage_idx * 4 + 1;
+        break;
+    case D3DDECLUSAGE_NORMAL: /* 2, 3 */
+        assert(dcl->usage_idx < 2);
+        sem->Index = generic_base + 2 + dcl->usage_idx * 4;
+        break;
+    case D3DDECLUSAGE_TANGENT:
+        /* Yes these are weird, but we try to fit the more frequently used
+         * into lower slots. */
+        assert(dcl->usage_idx <= 1);
+        sem->Index = generic_base + (dcl->usage_idx ? 24 : 3);
+        break;
+    case D3DDECLUSAGE_BINORMAL:
+        assert(dcl->usage_idx <= 1);
+        sem->Index = generic_base + (dcl->usage_idx ? 25 : 7);
+        break;
+    case D3DDECLUSAGE_TESSFACTOR:
+        assert(dcl->usage_idx == 0);
+        sem->Index = generic_base + 16;
+        break;
+    case D3DDECLUSAGE_SAMPLE:
+        sem->Name = TGSI_SEMANTIC_COUNT;
+        break;
+    default:
+        assert(!"Invalid DECLUSAGE.");
+        break;
+    }
+}
+
+#define NINED3DSTT_1D     (D3DSTT_1D >> D3DSP_TEXTURETYPE_SHIFT)
+#define NINED3DSTT_2D     (D3DSTT_2D >> D3DSP_TEXTURETYPE_SHIFT)
+#define NINED3DSTT_VOLUME (D3DSTT_VOLUME >> D3DSP_TEXTURETYPE_SHIFT)
+#define NINED3DSTT_CUBE   (D3DSTT_CUBE >> D3DSP_TEXTURETYPE_SHIFT)
+static INLINE unsigned
+d3dstt_to_tgsi_tex(BYTE sampler_type)
+{
+    switch (sampler_type) {
+    case NINED3DSTT_1D:     return TGSI_TEXTURE_1D;
+    case NINED3DSTT_2D:     return TGSI_TEXTURE_2D;
+    case NINED3DSTT_VOLUME: return TGSI_TEXTURE_3D;
+    case NINED3DSTT_CUBE:   return TGSI_TEXTURE_CUBE;
+    default:
+        assert(0);
+        return TGSI_TEXTURE_UNKNOWN;
+    }
+}
+static INLINE unsigned
+d3dstt_to_tgsi_tex_shadow(BYTE sampler_type)
+{
+    switch (sampler_type) {
+    case NINED3DSTT_1D: return TGSI_TEXTURE_SHADOW1D;
+    case NINED3DSTT_2D: return TGSI_TEXTURE_SHADOW2D;
+    case NINED3DSTT_VOLUME:
+    case NINED3DSTT_CUBE:
+    default:
+        assert(0);
+        return TGSI_TEXTURE_UNKNOWN;
+    }
+}
+static INLINE unsigned
+ps1x_sampler_type(const struct nine_shader_info *info, unsigned stage)
+{
+    switch ((info->sampler_ps1xtypes >> (stage * 2)) & 0x3) {
+    case 1: return TGSI_TEXTURE_1D;
+    case 0: return TGSI_TEXTURE_2D;
+    case 3: return TGSI_TEXTURE_3D;
+    default:
+        return TGSI_TEXTURE_CUBE;
+    }
+}
+
+static const char *
+sm1_sampler_type_name(BYTE sampler_type)
+{
+    switch (sampler_type) {
+    case NINED3DSTT_1D:     return "1D";
+    case NINED3DSTT_2D:     return "2D";
+    case NINED3DSTT_VOLUME: return "VOLUME";
+    case NINED3DSTT_CUBE:   return "CUBE";
+    default:
+        return "(D3DSTT_?)";
+    }
+}
+
+static INLINE unsigned
+nine_tgsi_to_interp_mode(struct tgsi_declaration_semantic *sem)
+{
+    switch (sem->Name) {
+    case TGSI_SEMANTIC_POSITION:
+    case TGSI_SEMANTIC_NORMAL:
+        return TGSI_INTERPOLATE_LINEAR;
+    case TGSI_SEMANTIC_BCOLOR:
+    case TGSI_SEMANTIC_COLOR:
+    case TGSI_SEMANTIC_FOG:
+    case TGSI_SEMANTIC_GENERIC:
+    case TGSI_SEMANTIC_TEXCOORD:
+    case TGSI_SEMANTIC_CLIPDIST:
+    case TGSI_SEMANTIC_CLIPVERTEX:
+        return TGSI_INTERPOLATE_PERSPECTIVE;
+    case TGSI_SEMANTIC_EDGEFLAG:
+    case TGSI_SEMANTIC_FACE:
+    case TGSI_SEMANTIC_INSTANCEID:
+    case TGSI_SEMANTIC_PCOORD:
+    case TGSI_SEMANTIC_PRIMID:
+    case TGSI_SEMANTIC_PSIZE:
+    case TGSI_SEMANTIC_VERTEXID:
+        return TGSI_INTERPOLATE_CONSTANT;
+    default:
+        assert(0);
+        return TGSI_INTERPOLATE_CONSTANT;
+    }
+}
+
+DECL_SPECIAL(DCL)
+{
+    struct ureg_program *ureg = tx->ureg;
+    boolean is_input;
+    boolean is_sampler;
+    struct tgsi_declaration_semantic tgsi;
+    struct sm1_semantic sem;
+    sm1_read_semantic(tx, &sem);
+
+    is_input = sem.reg.file == D3DSPR_INPUT;
+    is_sampler =
+        sem.usage == D3DDECLUSAGE_SAMPLE || sem.reg.file == D3DSPR_SAMPLER;
+
+    DUMP("DCL ");
+    sm1_dump_dst_param(&sem.reg);
+    if (is_sampler)
+        DUMP(" %s\n", sm1_sampler_type_name(sem.sampler_type));
+    else
+    if (tx->version.major >= 3)
+        DUMP(" %s%i\n", sm1_declusage_names[sem.usage], sem.usage_idx);
+    else
+    if (sem.usage | sem.usage_idx)
+        DUMP(" %u[%u]\n", sem.usage, sem.usage_idx);
+    else
+        DUMP("\n");
+
+    if (is_sampler) {
+        const unsigned m = 1 << sem.reg.idx;
+        ureg_DECL_sampler(ureg, sem.reg.idx);
+        tx->info->sampler_mask |= m;
+        tx->sampler_targets[sem.reg.idx] = (tx->info->sampler_mask_shadow & m) ?
+            d3dstt_to_tgsi_tex_shadow(sem.sampler_type) :
+            d3dstt_to_tgsi_tex(sem.sampler_type);
+        return D3D_OK;
+    }
+
+    sm1_declusage_to_tgsi(&tgsi, tx->want_texcoord, &sem);
+    if (IS_VS) {
+        if (is_input) {
+            /* linkage outside of shader with vertex declaration */
+            ureg_DECL_vs_input(ureg, sem.reg.idx);
+            assert(sem.reg.idx < Elements(tx->info->input_map));
+            tx->info->input_map[sem.reg.idx] = sm1_to_nine_declusage(&sem);
+            tx->info->num_inputs = sem.reg.idx + 1;
+            /* NOTE: preserving order in case of indirect access */
+        } else
+        if (tx->version.major >= 3) {
+            /* SM2 output semantic determined by file */
+            assert(sem.reg.mask != 0);
+            if (sem.usage == D3DDECLUSAGE_POSITIONT)
+                tx->info->position_t = TRUE;
+            assert(sem.reg.idx < Elements(tx->regs.o));
+            tx->regs.o[sem.reg.idx] = ureg_DECL_output_masked(
+                ureg, tgsi.Name, tgsi.Index, sem.reg.mask);
+
+            if (tgsi.Name == TGSI_SEMANTIC_PSIZE)
+                tx->regs.oPts = tx->regs.o[sem.reg.idx];
+        }
+    } else {
+        if (is_input && tx->version.major >= 3) {
+            /* SM3 only, SM2 input semantic determined by file */
+            assert(sem.reg.idx < Elements(tx->regs.v));
+            tx->regs.v[sem.reg.idx] = ureg_DECL_fs_input_cyl_centroid(
+                ureg, tgsi.Name, tgsi.Index,
+                nine_tgsi_to_interp_mode(&tgsi),
+                0, /* cylwrap */
+                sem.reg.mod & NINED3DSPDM_CENTROID);
+        } else
+        if (!is_input && 0) { /* declare in COLOROUT/DEPTHOUT case */
+            /* FragColor or FragDepth */
+            assert(sem.reg.mask != 0);
+            ureg_DECL_output_masked(ureg, tgsi.Name, tgsi.Index, sem.reg.mask);
+        }
+    }
+    return D3D_OK;
+}
+
+DECL_SPECIAL(DEF)
+{
+    tx_set_lconstf(tx, tx->insn.dst[0].idx, tx->insn.src[0].imm.f);
+    return D3D_OK;
+}
+
+DECL_SPECIAL(DEFB)
+{
+    tx_set_lconstb(tx, tx->insn.dst[0].idx, tx->insn.src[0].imm.b);
+    return D3D_OK;
+}
+
+DECL_SPECIAL(DEFI)
+{
+    tx_set_lconsti(tx, tx->insn.dst[0].idx, tx->insn.src[0].imm.i);
+    return D3D_OK;
+}
+
+DECL_SPECIAL(NRM)
+{
+    struct ureg_program *ureg = tx->ureg;
+    struct ureg_dst tmp = tx_scratch_scalar(tx);
+    struct ureg_src nrm = tx_src_scalar(tmp);
+    struct ureg_src src = tx_src_param(tx, &tx->insn.src[0]);
+    ureg_DP3(ureg, tmp, src, src);
+    ureg_RSQ(ureg, tmp, nrm);
+    ureg_MUL(ureg, tx_dst_param(tx, &tx->insn.dst[0]), src, nrm);
+    return D3D_OK;
+}
+
+DECL_SPECIAL(DP2ADD)
+{
+#ifdef NINE_TGSI_LAZY_R600
+    struct ureg_dst tmp = tx_scratch_scalar(tx);
+    struct ureg_src dp2 = tx_src_scalar(tmp);
+    struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]);
+    struct ureg_src src[3];
+    int i;
+    for (i = 0; i < 3; ++i)
+        src[i] = tx_src_param(tx, &tx->insn.src[i]);
+    assert_replicate_swizzle(&src[2]);
+
+    ureg_DP2(tx->ureg, tmp, src[0], src[1]);
+    ureg_ADD(tx->ureg, dst, src[2], dp2);
+
+    return D3D_OK;
+#else
+    return NineTranslateInstruction_Generic(tx);
+#endif
+}
+
+DECL_SPECIAL(TEXCOORD)
+{
+    struct ureg_program *ureg = tx->ureg;
+    const unsigned s = tx->insn.dst[0].idx;
+    struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]);
+
+    if (ureg_src_is_undef(tx->regs.vT[s]))
+        tx->regs.vT[s] = ureg_DECL_fs_input(ureg, tx->texcoord_sn, s, TGSI_INTERPOLATE_PERSPECTIVE);
+    ureg_MOV(ureg, dst, tx->regs.vT[s]); /* XXX is this sufficient ? */
+
+    return D3D_OK;
+}
+
+DECL_SPECIAL(TEXCOORD_ps14)
+{
+    struct ureg_program *ureg = tx->ureg;
+    const unsigned s = tx->insn.src[0].idx;
+    struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]);
+
+    if (ureg_src_is_undef(tx->regs.vT[s]))
+        tx->regs.vT[s] = ureg_DECL_fs_input(ureg, tx->texcoord_sn, s, TGSI_INTERPOLATE_PERSPECTIVE);
+    ureg_MOV(ureg, dst, tx->regs.vT[s]); /* XXX is this sufficient ? */
+
+    return D3D_OK;
+}
+
+DECL_SPECIAL(TEXKILL)
+{
+    struct ureg_src reg;
+
+    if (tx->version.major > 1 || tx->version.minor > 3) {
+        reg = tx_dst_param_as_src(tx, &tx->insn.dst[0]);
+    } else {
+        tx_texcoord_alloc(tx, tx->insn.dst[0].idx);
+        reg = tx->regs.vT[tx->insn.dst[0].idx];
+    }
+    if (tx->version.major < 2)
+        reg = ureg_swizzle(reg, NINE_SWIZZLE4(X,Y,Z,Z));
+    ureg_KILL_IF(tx->ureg, reg);
+
+    return D3D_OK;
+}
+
+DECL_SPECIAL(TEXBEM)
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+DECL_SPECIAL(TEXBEML)
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+DECL_SPECIAL(TEXREG2AR)
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+DECL_SPECIAL(TEXREG2GB)
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+DECL_SPECIAL(TEXM3x2PAD)
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+DECL_SPECIAL(TEXM3x2TEX)
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+DECL_SPECIAL(TEXM3x3PAD)
+{
+    return D3D_OK; /* this is just padding */
+}
+
+DECL_SPECIAL(TEXM3x3SPEC)
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+DECL_SPECIAL(TEXM3x3VSPEC)
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+DECL_SPECIAL(TEXREG2RGB)
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+DECL_SPECIAL(TEXDP3TEX)
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+DECL_SPECIAL(TEXM3x2DEPTH)
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+DECL_SPECIAL(TEXDP3)
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+DECL_SPECIAL(TEXM3x3)
+{
+    struct ureg_program *ureg = tx->ureg;
+    struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]);
+    struct ureg_src src[4];
+    int s;
+    const int m = tx->insn.dst[0].idx - 2;
+    const int n = tx->insn.src[0].idx;
+    assert(m >= 0 && m > n);
+
+    for (s = m; s <= (m + 2); ++s) {
+        if (ureg_src_is_undef(tx->regs.vT[s]))
+            tx->regs.vT[s] = ureg_DECL_fs_input(ureg, tx->texcoord_sn, s, TGSI_INTERPOLATE_PERSPECTIVE);
+        src[s] = tx->regs.vT[s];
+    }
+    ureg_DP3(ureg, ureg_writemask(dst, TGSI_WRITEMASK_X), src[0], ureg_src(tx->regs.tS[n]));
+    ureg_DP3(ureg, ureg_writemask(dst, TGSI_WRITEMASK_Y), src[1], ureg_src(tx->regs.tS[n]));
+    ureg_DP3(ureg, ureg_writemask(dst, TGSI_WRITEMASK_Z), src[2], ureg_src(tx->regs.tS[n]));
+
+    switch (tx->insn.opcode) {
+    case D3DSIO_TEXM3x3:
+        ureg_MOV(ureg, ureg_writemask(dst, TGSI_WRITEMASK_W), ureg_imm1f(ureg, 1.0f));
+        break;
+    case D3DSIO_TEXM3x3TEX:
+        src[3] = ureg_DECL_sampler(ureg, m + 2);
+        tx->info->sampler_mask |= 1 << (m + 2);
+        ureg_TEX(ureg, dst, ps1x_sampler_type(tx->info, m + 2), ureg_src(dst), src[3]);
+        break;
+    default:
+        return D3DERR_INVALIDCALL;
+    }
+    return D3D_OK;
+}
+
+DECL_SPECIAL(TEXDEPTH)
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+DECL_SPECIAL(BEM)
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+DECL_SPECIAL(TEXLD)
+{
+    struct ureg_program *ureg = tx->ureg;
+    unsigned target;
+    struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]);
+    struct ureg_src src[2] = {
+        tx_src_param(tx, &tx->insn.src[0]),
+        tx_src_param(tx, &tx->insn.src[1])
+    };
+    assert(tx->insn.src[1].idx >= 0 &&
+           tx->insn.src[1].idx < Elements(tx->sampler_targets));
+    target = tx->sampler_targets[tx->insn.src[1].idx];
+
+    switch (tx->insn.flags) {
+    case 0:
+        ureg_TEX(ureg, dst, target, src[0], src[1]);
+        break;
+    case NINED3DSI_TEXLD_PROJECT:
+        ureg_TXP(ureg, dst, target, src[0], src[1]);
+        break;
+    case NINED3DSI_TEXLD_BIAS:
+        ureg_TXB(ureg, dst, target, src[0], src[1]);
+        break;
+    default:
+        assert(0);
+        return D3DERR_INVALIDCALL;
+    }
+    return D3D_OK;
+}
+
+DECL_SPECIAL(TEXLD_14)
+{
+    struct ureg_program *ureg = tx->ureg;
+    struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]);
+    struct ureg_src src = tx_src_param(tx, &tx->insn.src[0]);
+    const unsigned s = tx->insn.dst[0].idx;
+    const unsigned t = ps1x_sampler_type(tx->info, s);
+
+    tx->info->sampler_mask |= 1 << s;
+    ureg_TEX(ureg, dst, t, src, ureg_DECL_sampler(ureg, s));
+
+    return D3D_OK;
+}
+
+DECL_SPECIAL(TEX)
+{
+    struct ureg_program *ureg = tx->ureg;
+    const unsigned s = tx->insn.dst[0].idx;
+    const unsigned t = ps1x_sampler_type(tx->info, s);
+    struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]);
+    struct ureg_src src[2];
+
+    if (ureg_src_is_undef(tx->regs.vT[s]))
+        tx->regs.vT[s] = ureg_DECL_fs_input(ureg, tx->texcoord_sn, s, TGSI_INTERPOLATE_PERSPECTIVE);
+
+    src[0] = tx->regs.vT[s];
+    src[1] = ureg_DECL_sampler(ureg, s);
+    tx->info->sampler_mask |= 1 << s;
+
+    ureg_TEX(ureg, dst, t, src[0], src[1]);
+
+    return D3D_OK;
+}
+
+DECL_SPECIAL(TEXLDD)
+{
+    unsigned target;
+    struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]);
+    struct ureg_src src[4] = {
+        tx_src_param(tx, &tx->insn.src[0]),
+        tx_src_param(tx, &tx->insn.src[1]),
+        tx_src_param(tx, &tx->insn.src[2]),
+        tx_src_param(tx, &tx->insn.src[3])
+    };
+    assert(tx->insn.src[3].idx >= 0 &&
+           tx->insn.src[3].idx < Elements(tx->sampler_targets));
+    target = tx->sampler_targets[tx->insn.src[1].idx];
+
+    ureg_TXD(tx->ureg, dst, target, src[0], src[2], src[3], src[1]);
+    return D3D_OK;
+}
+
+DECL_SPECIAL(TEXLDL)
+{
+    unsigned target;
+    struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]);
+    struct ureg_src src[2] = {
+       tx_src_param(tx, &tx->insn.src[0]),
+       tx_src_param(tx, &tx->insn.src[1])
+    };
+    assert(tx->insn.src[3].idx >= 0 &&
+           tx->insn.src[3].idx < Elements(tx->sampler_targets));
+    target = tx->sampler_targets[tx->insn.src[1].idx];
+
+    ureg_TXL(tx->ureg, dst, target, src[0], src[1]);
+    return D3D_OK;
+}
+
+DECL_SPECIAL(SETP)
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+DECL_SPECIAL(BREAKP)
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+DECL_SPECIAL(PHASE)
+{
+    return D3D_OK; /* we don't care about phase */
+}
+
+DECL_SPECIAL(COMMENT)
+{
+    return D3D_OK; /* nothing to do */
+}
+
+
+#define _OPI(o,t,vv1,vv2,pv1,pv2,d,s,h) \
+    { D3DSIO_##o, TGSI_OPCODE_##t, { vv1, vv2 }, { pv1, pv2, }, d, s, h }
+
+struct sm1_op_info inst_table[] =
+{
+    _OPI(NOP, NOP, V(0,0), V(3,0), V(0,0), V(3,0), 0, 0, NULL), /* 0 */
+    _OPI(MOV, MOV, V(0,0), V(1,1), V(0,0), V(0,0), 1, 1, SPECIAL(MOV_vs1x)),
+    _OPI(MOV, MOV, V(2,0), V(3,0), V(0,0), V(3,0), 1, 1, NULL),
+    _OPI(ADD, ADD, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, NULL), /* 2 */
+    _OPI(SUB, SUB, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, NULL), /* 3 */
+    _OPI(MAD, MAD, V(0,0), V(3,0), V(0,0), V(3,0), 1, 3, NULL), /* 4 */
+    _OPI(MUL, MUL, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, NULL), /* 5 */
+    _OPI(RCP, RCP, V(0,0), V(3,0), V(0,0), V(3,0), 1, 1, NULL), /* 6 */
+    _OPI(RSQ, RSQ, V(0,0), V(3,0), V(0,0), V(3,0), 1, 1, NULL), /* 7 */
+    _OPI(DP3, DP3, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, NULL), /* 8 */
+    _OPI(DP4, DP4, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, NULL), /* 9 */
+    _OPI(MIN, MIN, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, NULL), /* 10 */
+    _OPI(MAX, MAX, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, NULL), /* 11 */
+    _OPI(SLT, SLT, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, NULL), /* 12 */
+    _OPI(SGE, SGE, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, NULL), /* 13 */
+    _OPI(EXP, EX2, V(0,0), V(3,0), V(0,0), V(3,0), 1, 1, NULL), /* 14 */
+    _OPI(LOG, LG2, V(0,0), V(3,0), V(0,0), V(3,0), 1, 1, NULL), /* 15 */
+    _OPI(LIT, LIT, V(0,0), V(3,0), V(0,0), V(0,0), 1, 1, NULL), /* 16 */
+    _OPI(DST, DST, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, NULL), /* 17 */
+    _OPI(LRP, LRP, V(0,0), V(3,0), V(0,0), V(3,0), 1, 3, NULL), /* 18 */
+    _OPI(FRC, FRC, V(0,0), V(3,0), V(0,0), V(3,0), 1, 1, NULL), /* 19 */
+
+    _OPI(M4x4, NOP, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, SPECIAL(M4x4)),
+    _OPI(M4x3, NOP, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, SPECIAL(M4x3)),
+    _OPI(M3x4, NOP, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, SPECIAL(M3x4)),
+    _OPI(M3x3, NOP, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, SPECIAL(M3x3)),
+    _OPI(M3x2, NOP, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, SPECIAL(M3x2)),
+
+    _OPI(CALL,    CAL,     V(2,0), V(3,0), V(2,1), V(3,0), 0, 0, SPECIAL(CALL)),
+    _OPI(CALLNZ,  CAL,     V(2,0), V(3,0), V(2,1), V(3,0), 0, 0, SPECIAL(CALLNZ)),
+    _OPI(LOOP,    BGNLOOP, V(2,0), V(3,0), V(3,0), V(3,0), 0, 2, SPECIAL(LOOP)),
+    _OPI(RET,     RET,     V(2,0), V(3,0), V(2,1), V(3,0), 0, 0, SPECIAL(RET)),
+    _OPI(ENDLOOP, ENDLOOP, V(2,0), V(3,0), V(3,0), V(3,0), 0, 0, SPECIAL(ENDLOOP)),
+    _OPI(LABEL,   NOP,     V(2,0), V(3,0), V(2,1), V(3,0), 0, 0, SPECIAL(LABEL)),
+
+    _OPI(DCL, NOP, V(0,0), V(3,0), V(0,0), V(3,0), 0, 0, SPECIAL(DCL)),
+
+    _OPI(POW, POW, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, NULL),
+    _OPI(CRS, XPD, V(0,0), V(3,0), V(0,0), V(3,0), 1, 2, NULL), /* XXX: .w */
+    _OPI(SGN, SSG, V(2,0), V(3,0), V(0,0), V(0,0), 1, 3, SPECIAL(SGN)), /* ignore src1,2 */
+    _OPI(ABS, ABS, V(0,0), V(3,0), V(0,0), V(3,0), 1, 1, NULL),
+    _OPI(NRM, NRM, V(0,0), V(3,0), V(0,0), V(3,0), 1, 1, SPECIAL(NRM)), /* NRM doesn't fit */
+
+    _OPI(SINCOS, SCS, V(2,0), V(2,1), V(2,0), V(2,1), 1, 3, SPECIAL(SINCOS)),
+    _OPI(SINCOS, SCS, V(3,0), V(3,0), V(3,0), V(3,0), 1, 1, SPECIAL(SINCOS)),
+
+    /* More flow control */
+    _OPI(REP,    NOP,    V(2,0), V(3,0), V(2,1), V(3,0), 0, 1, SPECIAL(REP)),
+    _OPI(ENDREP, NOP,    V(2,0), V(3,0), V(2,1), V(3,0), 0, 0, SPECIAL(ENDREP)),
+    _OPI(IF,     IF,     V(2,0), V(3,0), V(2,1), V(3,0), 0, 1, SPECIAL(IF)),
+    _OPI(IFC,    IF,     V(2,1), V(3,0), V(2,1), V(3,0), 0, 2, SPECIAL(IFC)),
+    _OPI(ELSE,   ELSE,   V(2,0), V(3,0), V(2,1), V(3,0), 0, 0, SPECIAL(ELSE)),
+    _OPI(ENDIF,  ENDIF,  V(2,0), V(3,0), V(2,1), V(3,0), 0, 0, SPECIAL(ENDIF)),
+    _OPI(BREAK,  BRK,    V(2,1), V(3,0), V(2,1), V(3,0), 0, 0, NULL),
+    _OPI(BREAKC, BREAKC, V(2,1), V(3,0), V(2,1), V(3,0), 0, 2, SPECIAL(BREAKC)),
+
+    _OPI(MOVA, ARR, V(2,0), V(3,0), V(0,0), V(0,0), 1, 1, NULL),
+
+    _OPI(DEFB, NOP, V(0,0), V(3,0) , V(0,0), V(3,0) , 1, 0, SPECIAL(DEFB)),
+    _OPI(DEFI, NOP, V(0,0), V(3,0) , V(0,0), V(3,0) , 1, 0, SPECIAL(DEFI)),
+
+    _OPI(TEXCOORD,     NOP, V(0,0), V(0,0), V(0,0), V(1,3), 1, 0, SPECIAL(TEXCOORD)),
+    _OPI(TEXCOORD,     MOV, V(0,0), V(0,0), V(1,4), V(1,4), 1, 1, SPECIAL(TEXCOORD_ps14)),
+    _OPI(TEXKILL,      KILL_IF, V(0,0), V(0,0), V(0,0), V(3,0), 1, 0, SPECIAL(TEXKILL)),
+    _OPI(TEX,          TEX, V(0,0), V(0,0), V(0,0), V(1,3), 1, 0, SPECIAL(TEX)),
+    _OPI(TEX,          TEX, V(0,0), V(0,0), V(1,4), V(1,4), 1, 1, SPECIAL(TEXLD_14)),
+    _OPI(TEX,          TEX, V(0,0), V(0,0), V(2,0), V(3,0), 1, 2, SPECIAL(TEXLD)),
+    _OPI(TEXBEM,       TEX, V(0,0), V(0,0), V(0,0), V(1,3), 0, 0, SPECIAL(TEXBEM)),
+    _OPI(TEXBEML,      TEX, V(0,0), V(0,0), V(0,0), V(1,3), 0, 0, SPECIAL(TEXBEML)),
+    _OPI(TEXREG2AR,    TEX, V(0,0), V(0,0), V(0,0), V(1,3), 0, 0, SPECIAL(TEXREG2AR)),
+    _OPI(TEXREG2GB,    TEX, V(0,0), V(0,0), V(0,0), V(1,3), 0, 0, SPECIAL(TEXREG2GB)),
+    _OPI(TEXM3x2PAD,   TEX, V(0,0), V(0,0), V(0,0), V(1,3), 0, 0, SPECIAL(TEXM3x2PAD)),
+    _OPI(TEXM3x2TEX,   TEX, V(0,0), V(0,0), V(0,0), V(1,3), 0, 0, SPECIAL(TEXM3x2TEX)),
+    _OPI(TEXM3x3PAD,   TEX, V(0,0), V(0,0), V(0,0), V(1,3), 0, 0, SPECIAL(TEXM3x3PAD)),
+    _OPI(TEXM3x3TEX,   TEX, V(0,0), V(0,0), V(0,0), V(1,3), 0, 0, SPECIAL(TEXM3x3)),
+    _OPI(TEXM3x3SPEC,  TEX, V(0,0), V(0,0), V(0,0), V(1,3), 0, 0, SPECIAL(TEXM3x3SPEC)),
+    _OPI(TEXM3x3VSPEC, TEX, V(0,0), V(0,0), V(0,0), V(1,3), 0, 0, SPECIAL(TEXM3x3VSPEC)),
+
+    _OPI(EXPP, EXP, V(0,0), V(1,1), V(0,0), V(0,0), 1, 1, NULL),
+    _OPI(EXPP, EX2, V(2,0), V(3,0), V(0,0), V(0,0), 1, 1, NULL),
+    _OPI(LOGP, LG2, V(0,0), V(3,0), V(0,0), V(0,0), 1, 1, NULL),
+    _OPI(CND,  CND, V(0,0), V(0,0), V(0,0), V(1,4), 1, 3, SPECIAL(CND)),
+
+    _OPI(DEF, NOP, V(0,0), V(3,0), V(0,0), V(3,0), 1, 0, SPECIAL(DEF)),
+
+    /* More tex stuff */
+    _OPI(TEXREG2RGB,   TEX, V(0,0), V(0,0), V(1,2), V(1,3), 0, 0, SPECIAL(TEXREG2RGB)),
+    _OPI(TEXDP3TEX,    TEX, V(0,0), V(0,0), V(1,2), V(1,3), 0, 0, SPECIAL(TEXDP3TEX)),
+    _OPI(TEXM3x2DEPTH, TEX, V(0,0), V(0,0), V(1,3), V(1,3), 0, 0, SPECIAL(TEXM3x2DEPTH)),
+    _OPI(TEXDP3,       TEX, V(0,0), V(0,0), V(1,2), V(1,3), 0, 0, SPECIAL(TEXDP3)),
+    _OPI(TEXM3x3,      TEX, V(0,0), V(0,0), V(1,2), V(1,3), 0, 0, SPECIAL(TEXM3x3)),
+    _OPI(TEXDEPTH,     TEX, V(0,0), V(0,0), V(1,4), V(1,4), 0, 0, SPECIAL(TEXDEPTH)),
+
+    /* Misc */
+    _OPI(CMP,    CMP,  V(0,0), V(0,0), V(1,2), V(3,0), 1, 3, SPECIAL(CMP)), /* reversed */
+    _OPI(BEM,    NOP,  V(0,0), V(0,0), V(1,4), V(1,4), 0, 0, SPECIAL(BEM)),
+    _OPI(DP2ADD, DP2A, V(0,0), V(0,0), V(2,0), V(3,0), 1, 3, SPECIAL(DP2ADD)), /* for radeons */
+    _OPI(DSX,    DDX,  V(0,0), V(0,0), V(2,1), V(3,0), 1, 1, NULL),
+    _OPI(DSY,    DDY,  V(0,0), V(0,0), V(2,1), V(3,0), 1, 1, NULL),
+    _OPI(TEXLDD, TXD,  V(0,0), V(0,0), V(2,1), V(3,0), 1, 4, SPECIAL(TEXLDD)),
+    _OPI(SETP,   NOP,  V(0,0), V(3,0), V(2,1), V(3,0), 0, 0, SPECIAL(SETP)),
+    _OPI(TEXLDL, TXL,  V(3,0), V(3,0), V(3,0), V(3,0), 1, 2, SPECIAL(TEXLDL)),
+    _OPI(BREAKP, BRK,  V(0,0), V(3,0), V(2,1), V(3,0), 0, 0, SPECIAL(BREAKP))
+};
+
+struct sm1_op_info inst_phase =
+    _OPI(PHASE, NOP, V(0,0), V(0,0), V(1,4), V(1,4), 0, 0, SPECIAL(PHASE));
+
+struct sm1_op_info inst_comment =
+    _OPI(COMMENT, NOP, V(0,0), V(3,0), V(0,0), V(3,0), 0, 0, SPECIAL(COMMENT));
+
+static void
+create_op_info_map(struct shader_translator *tx)
+{
+    const unsigned version = (tx->version.major << 8) | tx->version.minor;
+    unsigned i;
+
+    for (i = 0; i < Elements(tx->op_info_map); ++i)
+        tx->op_info_map[i] = -1;
+
+    if (tx->processor == TGSI_PROCESSOR_VERTEX) {
+        for (i = 0; i < Elements(inst_table); ++i) {
+            assert(inst_table[i].sio < Elements(tx->op_info_map));
+            if (inst_table[i].vert_version.min <= version &&
+                inst_table[i].vert_version.max >= version)
+                tx->op_info_map[inst_table[i].sio] = i;
+        }
+    } else {
+        for (i = 0; i < Elements(inst_table); ++i) {
+            assert(inst_table[i].sio < Elements(tx->op_info_map));
+            if (inst_table[i].frag_version.min <= version &&
+                inst_table[i].frag_version.max >= version)
+                tx->op_info_map[inst_table[i].sio] = i;
+        }
+    }
+}
+
+static INLINE HRESULT
+NineTranslateInstruction_Generic(struct shader_translator *tx)
+{
+    struct ureg_dst dst[1];
+    struct ureg_src src[4];
+    unsigned i;
+
+    for (i = 0; i < tx->insn.ndst && i < Elements(dst); ++i)
+        dst[i] = tx_dst_param(tx, &tx->insn.dst[i]);
+    for (i = 0; i < tx->insn.nsrc && i < Elements(src); ++i)
+        src[i] = tx_src_param(tx, &tx->insn.src[i]);
+
+    ureg_insn(tx->ureg, tx->insn.info->opcode,
+              dst, tx->insn.ndst,
+              src, tx->insn.nsrc);
+    return D3D_OK;
+}
+
+static INLINE DWORD
+TOKEN_PEEK(struct shader_translator *tx)
+{
+    return *(tx->parse);
+}
+
+static INLINE DWORD
+TOKEN_NEXT(struct shader_translator *tx)
+{
+    return *(tx->parse)++;
+}
+
+static INLINE void
+TOKEN_JUMP(struct shader_translator *tx)
+{
+    if (tx->parse_next && tx->parse != tx->parse_next) {
+        WARN("parse(%p) != parse_next(%p) !\n", tx->parse, tx->parse_next);
+        tx->parse = tx->parse_next;
+    }
+}
+
+static INLINE boolean
+sm1_parse_eof(struct shader_translator *tx)
+{
+    return TOKEN_PEEK(tx) == NINED3DSP_END;
+}
+
+static void
+sm1_read_version(struct shader_translator *tx)
+{
+    const DWORD tok = TOKEN_NEXT(tx);
+
+    tx->version.major = D3DSHADER_VERSION_MAJOR(tok);
+    tx->version.minor = D3DSHADER_VERSION_MINOR(tok);
+
+    switch (tok >> 16) {
+    case NINED3D_SM1_VS: tx->processor = TGSI_PROCESSOR_VERTEX; break;
+    case NINED3D_SM1_PS: tx->processor = TGSI_PROCESSOR_FRAGMENT; break;
+    default:
+       DBG("Invalid shader type: %x\n", tok);
+       tx->processor = ~0;
+       break;
+    }
+}
+
+/* This is just to check if we parsed the instruction properly. */
+static void
+sm1_parse_get_skip(struct shader_translator *tx)
+{
+    const DWORD tok = TOKEN_PEEK(tx);
+
+    if (tx->version.major >= 2) {
+        tx->parse_next = tx->parse + 1 /* this */ +
+            ((tok & D3DSI_INSTLENGTH_MASK) >> D3DSI_INSTLENGTH_SHIFT);
+    } else {
+        tx->parse_next = NULL; /* TODO: determine from param count */
+    }
+}
+
+static void
+sm1_print_comment(const char *comment, UINT size)
+{
+    if (!size)
+        return;
+    /* TODO */
+}
+
+static void
+sm1_parse_comments(struct shader_translator *tx, BOOL print)
+{
+    DWORD tok = TOKEN_PEEK(tx);
+
+    while ((tok & D3DSI_OPCODE_MASK) == D3DSIO_COMMENT)
+    {
+        const char *comment = "";
+        UINT size = (tok & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT;
+        tx->parse += size + 1;
+
+        if (print)
+            sm1_print_comment(comment, size);
+
+        tok = TOKEN_PEEK(tx);
+    }
+}
+
+static void
+sm1_parse_get_param(struct shader_translator *tx, DWORD *reg, DWORD *rel)
+{
+    *reg = TOKEN_NEXT(tx);
+
+    if (*reg & D3DSHADER_ADDRMODE_RELATIVE)
+    {
+        if (tx->version.major < 2)
+            *rel = (1 << 31) |
+                ((D3DSPR_ADDR << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2) |
+                ((D3DSPR_ADDR << D3DSP_REGTYPE_SHIFT)  & D3DSP_REGTYPE_MASK) |
+                (D3DSP_NOSWIZZLE << D3DSP_SWIZZLE_SHIFT);
+        else
+            *rel = TOKEN_NEXT(tx);
+    }
+}
+
+static void
+sm1_parse_dst_param(struct sm1_dst_param *dst, DWORD tok)
+{
+    dst->file =
+        (tok & D3DSP_REGTYPE_MASK)  >> D3DSP_REGTYPE_SHIFT |
+        (tok & D3DSP_REGTYPE_MASK2) >> D3DSP_REGTYPE_SHIFT2;
+    dst->type = TGSI_RETURN_TYPE_FLOAT;
+    dst->idx = tok & D3DSP_REGNUM_MASK;
+    dst->rel = NULL;
+    dst->mask = (tok & NINED3DSP_WRITEMASK_MASK) >> NINED3DSP_WRITEMASK_SHIFT;
+    dst->mod = (tok & D3DSP_DSTMOD_MASK) >> D3DSP_DSTMOD_SHIFT;
+    dst->shift = (tok & D3DSP_DSTSHIFT_MASK) >> D3DSP_DSTSHIFT_SHIFT;
+}
+
+static void
+sm1_parse_src_param(struct sm1_src_param *src, DWORD tok)
+{
+    src->file =
+        ((tok & D3DSP_REGTYPE_MASK)  >> D3DSP_REGTYPE_SHIFT) |
+        ((tok & D3DSP_REGTYPE_MASK2) >> D3DSP_REGTYPE_SHIFT2);
+    src->type = TGSI_RETURN_TYPE_FLOAT;
+    src->idx = tok & D3DSP_REGNUM_MASK;
+    src->rel = NULL;
+    src->swizzle = (tok & D3DSP_SWIZZLE_MASK) >> D3DSP_SWIZZLE_SHIFT;
+    src->mod = (tok & D3DSP_SRCMOD_MASK) >> D3DSP_SRCMOD_SHIFT;
+
+    switch (src->file) {
+    case D3DSPR_CONST2: src->file = D3DSPR_CONST; src->idx += 2048; break;
+    case D3DSPR_CONST3: src->file = D3DSPR_CONST; src->idx += 4096; break;
+    case D3DSPR_CONST4: src->file = D3DSPR_CONST; src->idx += 6144; break;
+    default:
+        break;
+    }
+}
+
+static void
+sm1_parse_immediate(struct shader_translator *tx,
+                    struct sm1_src_param *imm)
+{
+    imm->file = NINED3DSPR_IMMEDIATE;
+    imm->idx = INT_MIN;
+    imm->rel = NULL;
+    imm->swizzle = NINED3DSP_NOSWIZZLE;
+    imm->mod = 0;
+    switch (tx->insn.opcode) {
+    case D3DSIO_DEF:
+        imm->type = NINED3DSPTYPE_FLOAT4;
+        memcpy(&imm->imm.d[0], tx->parse, 4 * sizeof(DWORD));
+        tx->parse += 4;
+        break;
+    case D3DSIO_DEFI:
+        imm->type = NINED3DSPTYPE_INT4;
+        memcpy(&imm->imm.d[0], tx->parse, 4 * sizeof(DWORD));
+        tx->parse += 4;
+        break;
+    case D3DSIO_DEFB:
+        imm->type = NINED3DSPTYPE_BOOL;
+        memcpy(&imm->imm.d[0], tx->parse, 1 * sizeof(DWORD));
+        tx->parse += 1;
+        break;
+    default:
+       assert(0);
+       break;
+    }
+}
+
+static void
+sm1_read_dst_param(struct shader_translator *tx,
+                   struct sm1_dst_param *dst,
+                   struct sm1_src_param *rel)
+{
+    DWORD tok_dst, tok_rel = 0;
+
+    sm1_parse_get_param(tx, &tok_dst, &tok_rel);
+    sm1_parse_dst_param(dst, tok_dst);
+    if (tok_dst & D3DSHADER_ADDRMODE_RELATIVE) {
+        sm1_parse_src_param(rel, tok_rel);
+        dst->rel = rel;
+    }
+}
+
+static void
+sm1_read_src_param(struct shader_translator *tx,
+                   struct sm1_src_param *src,
+                   struct sm1_src_param *rel)
+{
+    DWORD tok_src, tok_rel = 0;
+
+    sm1_parse_get_param(tx, &tok_src, &tok_rel);
+    sm1_parse_src_param(src, tok_src);
+    if (tok_src & D3DSHADER_ADDRMODE_RELATIVE) {
+        assert(rel);
+        sm1_parse_src_param(rel, tok_rel);
+        src->rel = rel;
+    }
+}
+
+static void
+sm1_read_semantic(struct shader_translator *tx,
+                  struct sm1_semantic *sem)
+{
+    const DWORD tok_usg = TOKEN_NEXT(tx);
+    const DWORD tok_dst = TOKEN_NEXT(tx);
+
+    sem->sampler_type = (tok_usg & D3DSP_TEXTURETYPE_MASK) >> D3DSP_TEXTURETYPE_SHIFT;
+    sem->usage = (tok_usg & D3DSP_DCL_USAGE_MASK) >> D3DSP_DCL_USAGE_SHIFT;
+    sem->usage_idx = (tok_usg & D3DSP_DCL_USAGEINDEX_MASK) >> D3DSP_DCL_USAGEINDEX_SHIFT;
+
+    sm1_parse_dst_param(&sem->reg, tok_dst);
+}
+
+static void
+sm1_parse_instruction(struct shader_translator *tx)
+{
+    struct sm1_instruction *insn = &tx->insn;
+    DWORD tok;
+    struct sm1_op_info *info = NULL;
+    unsigned i;
+
+    sm1_parse_comments(tx, TRUE);
+    sm1_parse_get_skip(tx);
+
+    tok = TOKEN_NEXT(tx);
+
+    insn->opcode = tok & D3DSI_OPCODE_MASK;
+    insn->flags = (tok & NINED3DSIO_OPCODE_FLAGS_MASK) >> NINED3DSIO_OPCODE_FLAGS_SHIFT;
+    insn->coissue = !!(tok & D3DSI_COISSUE);
+    insn->predicated = !!(tok & NINED3DSHADER_INST_PREDICATED);
+
+    if (insn->opcode < Elements(tx->op_info_map)) {
+        int k = tx->op_info_map[insn->opcode];
+        if (k >= 0) {
+            assert(k < Elements(inst_table));
+            info = &inst_table[k];
+        }
+    } else {
+       if (insn->opcode == D3DSIO_PHASE)   info = &inst_phase;
+       if (insn->opcode == D3DSIO_COMMENT) info = &inst_comment;
+    }
+    if (!info) {
+       DBG("illegal or unhandled opcode: %08x\n", insn->opcode);
+       TOKEN_JUMP(tx);
+       return;
+    }
+    insn->info = info;
+    insn->ndst = info->ndst;
+    insn->nsrc = info->nsrc;
+
+    assert(!insn->predicated && "TODO: predicated instructions");
+
+    /* check version */
+    {
+        unsigned min = IS_VS ? info->vert_version.min : info->frag_version.min;
+        unsigned max = IS_VS ? info->vert_version.max : info->frag_version.max;
+        unsigned ver = (tx->version.major << 8) | tx->version.minor;
+        if (ver < min || ver > max) {
+            DBG("opcode not supported in this shader version: %x <= %x <= %x\n",
+                min, ver, max);
+            return;
+        }
+    }
+
+    for (i = 0; i < insn->ndst; ++i)
+        sm1_read_dst_param(tx, &insn->dst[i], &insn->dst_rel[i]);
+    if (insn->predicated)
+        sm1_read_src_param(tx, &insn->pred, NULL);
+    for (i = 0; i < insn->nsrc; ++i)
+        sm1_read_src_param(tx, &insn->src[i], &insn->src_rel[i]);
+
+    /* parse here so we can dump them before processing */
+    if (insn->opcode == D3DSIO_DEF ||
+        insn->opcode == D3DSIO_DEFI ||
+        insn->opcode == D3DSIO_DEFB)
+        sm1_parse_immediate(tx, &tx->insn.src[0]);
+
+    sm1_dump_instruction(insn, tx->cond_depth + tx->loop_depth);
+    sm1_instruction_check(insn);
+
+    if (info->handler)
+        info->handler(tx);
+    else
+       NineTranslateInstruction_Generic(tx);
+    tx_apply_dst0_modifiers(tx);
+
+    tx->num_scratch = 0; /* reset */
+
+    TOKEN_JUMP(tx);
+}
+
+static void
+tx_ctor(struct shader_translator *tx, struct nine_shader_info *info)
+{
+    unsigned i;
+
+    tx->info = info;
+
+    tx->byte_code = info->byte_code;
+    tx->parse = info->byte_code;
+
+    for (i = 0; i < Elements(info->input_map); ++i)
+        info->input_map[i] = NINE_DECLUSAGE_NONE;
+    info->num_inputs = 0;
+
+    info->position_t = FALSE;
+    info->point_size = FALSE;
+
+    tx->info->const_used_size = 0;
+
+    info->sampler_mask = 0x0;
+    info->rt_mask = 0x0;
+
+    info->lconstf.data = NULL;
+    info->lconstf.ranges = NULL;
+
+    for (i = 0; i < Elements(tx->regs.aL); ++i) {
+        tx->regs.aL[i] = ureg_dst_undef();
+        tx->regs.rL[i] = ureg_dst_undef();
+    }
+    tx->regs.a = ureg_dst_undef();
+    tx->regs.p = ureg_dst_undef();
+    tx->regs.oDepth = ureg_dst_undef();
+    tx->regs.vPos = ureg_src_undef();
+    tx->regs.vFace = ureg_src_undef();
+    for (i = 0; i < Elements(tx->regs.o); ++i)
+        tx->regs.o[i] = ureg_dst_undef();
+    for (i = 0; i < Elements(tx->regs.oCol); ++i)
+        tx->regs.oCol[i] = ureg_dst_undef();
+    for (i = 0; i < Elements(tx->regs.vC); ++i)
+        tx->regs.vC[i] = ureg_src_undef();
+    for (i = 0; i < Elements(tx->regs.vT); ++i)
+        tx->regs.vT[i] = ureg_src_undef();
+
+    for (i = 0; i < Elements(tx->lconsti); ++i)
+        tx->lconsti[i].idx = -1;
+    for (i = 0; i < Elements(tx->lconstb); ++i)
+        tx->lconstb[i].idx = -1;
+
+    sm1_read_version(tx);
+
+    info->version = (tx->version.major << 4) | tx->version.minor;
+
+    create_op_info_map(tx);
+}
+
+static void
+tx_dtor(struct shader_translator *tx)
+{
+    if (tx->num_inst_labels)
+        FREE(tx->inst_labels);
+    if (tx->lconstf)
+        FREE(tx->lconstf);
+    if (tx->regs.r)
+        FREE(tx->regs.r);
+    FREE(tx);
+}
+
+static INLINE unsigned
+tgsi_processor_from_type(unsigned shader_type)
+{
+    switch (shader_type) {
+    case PIPE_SHADER_VERTEX: return TGSI_PROCESSOR_VERTEX;
+    case PIPE_SHADER_FRAGMENT: return TGSI_PROCESSOR_FRAGMENT;
+    default:
+        return ~0;
+    }
+}
+
+#define GET_CAP(n) device->screen->get_param( \
+      device->screen, PIPE_CAP_##n)
+#define GET_SHADER_CAP(n) device->screen->get_shader_param( \
+      device->screen, info->type, PIPE_SHADER_CAP_##n)
+
+HRESULT
+nine_translate_shader(struct NineDevice9 *device, struct nine_shader_info *info)
+{
+    struct shader_translator *tx;
+    HRESULT hr = D3D_OK;
+    const unsigned processor = tgsi_processor_from_type(info->type);
+
+    user_assert(processor != ~0, D3DERR_INVALIDCALL);
+
+    tx = CALLOC_STRUCT(shader_translator);
+    if (!tx)
+        return E_OUTOFMEMORY;
+    tx_ctor(tx, info);
+
+    if (((tx->version.major << 16) | tx->version.minor) > 0x00030000) {
+        hr = D3DERR_INVALIDCALL;
+        DBG("Unsupported shader version: %u.%u !\n",
+            tx->version.major, tx->version.minor);
+        goto out;
+    }
+    if (tx->processor != processor) {
+        hr = D3DERR_INVALIDCALL;
+        DBG("Shader type mismatch: %u / %u !\n", tx->processor, processor);
+        goto out;
+    }
+    DUMP("%s%u.%u\n", processor == TGSI_PROCESSOR_VERTEX ? "VS" : "PS",
+         tx->version.major, tx->version.minor);
+
+    tx->ureg = ureg_create(processor);
+    if (!tx->ureg) {
+        hr = E_OUTOFMEMORY;
+        goto out;
+    }
+    tx_decl_constants(tx);
+
+    tx->native_integers = GET_SHADER_CAP(INTEGERS);
+    tx->inline_subroutines = !GET_SHADER_CAP(SUBROUTINES);
+    tx->lower_preds = !GET_SHADER_CAP(MAX_PREDS);
+    tx->want_texcoord = GET_CAP(TGSI_TEXCOORD);
+    tx->shift_wpos = !GET_CAP(TGSI_FS_COORD_PIXEL_CENTER_INTEGER);
+    tx->texcoord_sn = tx->want_texcoord ?
+        TGSI_SEMANTIC_TEXCOORD : TGSI_SEMANTIC_GENERIC;
+
+    /* VS must always write position. Declare it here to make it the 1st output.
+     * (Some drivers like nv50 are buggy and rely on that.)
+     */
+    if (IS_VS) {
+        tx->regs.oPos = ureg_DECL_output(tx->ureg, TGSI_SEMANTIC_POSITION, 0);
+    } else {
+        ureg_property(tx->ureg, TGSI_PROPERTY_FS_COORD_ORIGIN, TGSI_FS_COORD_ORIGIN_UPPER_LEFT);
+        if (!tx->shift_wpos)
+            ureg_property(tx->ureg, TGSI_PROPERTY_FS_COORD_PIXEL_CENTER, TGSI_FS_COORD_PIXEL_CENTER_INTEGER);
+    }
+
+    if (!ureg_dst_is_undef(tx->regs.oPts))
+        info->point_size = TRUE;
+
+    while (!sm1_parse_eof(tx))
+        sm1_parse_instruction(tx);
+    tx->parse++; /* for byte_size */
+
+    if (IS_PS && (tx->version.major < 2) && tx->num_temp) {
+        ureg_MOV(tx->ureg, ureg_DECL_output(tx->ureg, TGSI_SEMANTIC_COLOR, 0),
+                 ureg_src(tx->regs.r[0]));
+        info->rt_mask |= 0x1;
+    }
+
+    if (info->position_t)
+        ureg_property(tx->ureg, TGSI_PROPERTY_VS_WINDOW_SPACE_POSITION, TRUE);
+
+    ureg_END(tx->ureg);
+
+    if (debug_get_bool_option("NINE_TGSI_DUMP", FALSE)) {
+        unsigned count;
+        const struct tgsi_token *toks = ureg_get_tokens(tx->ureg, &count);
+        tgsi_dump(toks, 0);
+        ureg_free_tokens(toks);
+    }
+
+    /* record local constants */
+    if (tx->num_lconstf && tx->indirect_const_access) {
+        struct nine_range *ranges;
+        float *data;
+        int *indices;
+        unsigned i, k, n;
+
+        hr = E_OUTOFMEMORY;
+
+        data = MALLOC(tx->num_lconstf * 4 * sizeof(float));
+        if (!data)
+            goto out;
+        info->lconstf.data = data;
+
+        indices = MALLOC(tx->num_lconstf * sizeof(indices[0]));
+        if (!indices)
+            goto out;
+
+        /* lazy sort, num_lconstf should be small */
+        for (n = 0; n < tx->num_lconstf; ++n) {
+            for (k = 0, i = 0; i < tx->num_lconstf; ++i) {
+                if (tx->lconstf[i].idx < tx->lconstf[k].idx)
+                    k = i;
+            }
+            indices[n] = tx->lconstf[k].idx;
+            memcpy(&data[n * 4], &tx->lconstf[k].imm.f[0], 4 * sizeof(float));
+            tx->lconstf[k].idx = INT_MAX;
+        }
+
+        /* count ranges */
+        for (n = 1, i = 1; i < tx->num_lconstf; ++i)
+            if (indices[i] != indices[i - 1] + 1)
+                ++n;
+        ranges = MALLOC(n * sizeof(ranges[0]));
+        if (!ranges) {
+            FREE(indices);
+            goto out;
+        }
+        info->lconstf.ranges = ranges;
+
+        k = 0;
+        ranges[k].bgn = indices[0];
+        for (i = 1; i < tx->num_lconstf; ++i) {
+            if (indices[i] != indices[i - 1] + 1) {
+                ranges[k].next = &ranges[k + 1];
+                ranges[k].end = indices[i - 1] + 1;
+                ++k;
+                ranges[k].bgn = indices[i];
+            }
+        }
+        ranges[k].end = indices[i - 1] + 1;
+        ranges[k].next = NULL;
+        assert(n == (k + 1));
+
+        FREE(indices);
+        hr = D3D_OK;
+    }
+
+    if (tx->indirect_const_access)
+        info->const_used_size = ~0;
+
+    info->cso = ureg_create_shader_and_destroy(tx->ureg, device->pipe);
+    if (!info->cso) {
+        hr = D3DERR_DRIVERINTERNALERROR;
+        FREE(info->lconstf.data);
+        FREE(info->lconstf.ranges);
+        goto out;
+    }
+
+    info->byte_size = (tx->parse - tx->byte_code) * sizeof(DWORD);
+out:
+    tx_dtor(tx);
+    return hr;
+}
diff --git a/src/gallium/state_trackers/nine/nine_shader.h b/src/gallium/state_trackers/nine/nine_shader.h
new file mode 100644 (file)
index 0000000..2182408
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _NINE_SHADER_H_
+#define _NINE_SHADER_H_
+
+#include "d3d9types.h"
+#include "d3d9caps.h"
+#include "nine_defines.h"
+#include "pipe/p_state.h" /* PIPE_MAX_ATTRIBS */
+#include "util/u_memory.h"
+
+struct NineDevice9;
+
+struct nine_lconstf /* NOTE: both pointers should be FREE'd by the user */
+{
+    struct nine_range *ranges; /* single MALLOC, but next-pointers valid */
+    float *data;
+};
+
+struct nine_shader_info
+{
+    unsigned type; /* in, PIPE_SHADER_x */
+
+    uint8_t version; /* (major << 4) | minor */
+
+    const DWORD *byte_code; /* in, pointer to shader tokens */
+    DWORD        byte_size; /* out, size of data at byte_code */
+
+    void *cso; /* out, pipe cso for bind_vs,fs_state */
+
+    uint8_t input_map[PIPE_MAX_ATTRIBS]; /* VS input -> NINE_DECLUSAGE_x */
+    uint8_t num_inputs; /* there may be unused inputs (NINE_DECLUSAGE_NONE) */
+
+    boolean position_t; /* out, true if VP writes pre-transformed position */
+    boolean point_size; /* out, true if VP writes point size */
+
+    uint32_t sampler_ps1xtypes; /* 2 bits per sampler */
+    uint16_t sampler_mask; /* out, which samplers are being used */
+    uint16_t sampler_mask_shadow; /* in, which samplers use depth compare */
+    uint8_t rt_mask; /* out, which render targets are being written */
+
+    unsigned const_i_base; /* in vec4 (16 byte) units */
+    unsigned const_b_base; /* in vec4 (16 byte) units */
+    unsigned const_used_size;
+
+    struct nine_lconstf lconstf; /* out, NOTE: members to be free'd by user */
+};
+
+static INLINE void
+nine_info_mark_const_f_used(struct nine_shader_info *info, int idx)
+{
+    unsigned size = (idx + 1) * 16;
+
+    if (info->const_used_size < size)
+        info->const_used_size = size;
+}
+static INLINE void
+nine_info_mark_const_i_used(struct nine_shader_info *info, int idx)
+{
+    unsigned size = (info->const_i_base + (idx + 1)) * 16;
+
+    if (info->const_used_size < size)
+        info->const_used_size = size;
+}
+static INLINE void
+nine_info_mark_const_b_used(struct nine_shader_info *info, int idx)
+{
+    unsigned size = (info->const_b_base + ((idx + 4) / 4)) * 16;
+
+    if (info->const_used_size < size)
+        info->const_used_size = size;
+}
+
+HRESULT
+nine_translate_shader(struct NineDevice9 *device, struct nine_shader_info *);
+
+
+struct nine_shader_variant
+{
+    struct nine_shader_variant *next;
+    void *cso;
+    uint32_t key;
+};
+
+static INLINE void *
+nine_shader_variant_get(struct nine_shader_variant *list, uint32_t key)
+{
+    while (list->key != key && list->next)
+        list = list->next;
+    if (list->key == key)
+        return list->cso;
+    return NULL;
+}
+
+static INLINE boolean
+nine_shader_variant_add(struct nine_shader_variant *list,
+                        uint32_t key, void *cso)
+{
+    while (list->next) {
+        assert(list->key != key);
+        list = list->next;
+    }
+    list->next = MALLOC_STRUCT(nine_shader_variant);
+    if (!list->next)
+        return FALSE;
+    list->next->next = NULL;
+    list->next->key = key;
+    list->next->cso = cso;
+    return TRUE;
+}
+
+static INLINE void
+nine_shader_variants_free(struct nine_shader_variant *list)
+{
+    while (list->next) {
+        struct nine_shader_variant *ptr = list->next;
+        list->next = ptr->next;
+        FREE(ptr);
+    }
+}
+
+#endif /* _NINE_SHADER_H_ */
diff --git a/src/gallium/state_trackers/nine/nine_state.c b/src/gallium/state_trackers/nine/nine_state.c
new file mode 100644 (file)
index 0000000..0215d08
--- /dev/null
@@ -0,0 +1,1489 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ * Copyright 2013 Christoph Bumiller
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "device9.h"
+#include "basetexture9.h"
+#include "indexbuffer9.h"
+#include "surface9.h"
+#include "vertexdeclaration9.h"
+#include "vertexshader9.h"
+#include "pixelshader9.h"
+#include "nine_pipe.h"
+#include "nine_ff.h"
+#include "pipe/p_context.h"
+#include "pipe/p_state.h"
+#include "cso_cache/cso_context.h"
+#include "util/u_math.h"
+
+#define DBG_CHANNEL DBG_DEVICE
+
+static uint32_t
+update_framebuffer(struct NineDevice9 *device)
+{
+    struct pipe_context *pipe = device->pipe;
+    struct nine_state *state = &device->state;
+    struct pipe_framebuffer_state *fb = &device->state.fb;
+    unsigned i;
+    unsigned w = 0, h = 0; /* no surface can have width or height 0 */
+
+    const int sRGB = state->rs[D3DRS_SRGBWRITEENABLE] ? 1 : 0;
+
+    DBG("\n");
+
+    state->rt_mask = 0x0;
+    fb->nr_cbufs = 0;
+
+    for (i = 0; i < device->caps.NumSimultaneousRTs; ++i) {
+        if (state->rt[i] && state->rt[i]->desc.Format != D3DFMT_NULL) {
+            struct NineSurface9 *rt = state->rt[i];
+            fb->cbufs[i] = NineSurface9_GetSurface(rt, sRGB);
+            state->rt_mask |= 1 << i;
+            fb->nr_cbufs = i + 1;
+            if (w) {
+                w = MIN2(w, rt->desc.Width);
+                h = MIN2(h, rt->desc.Height);
+            } else {
+                w = rt->desc.Width;
+                h = rt->desc.Height;
+            }
+            if (unlikely(rt->desc.Usage & D3DUSAGE_AUTOGENMIPMAP)) {
+                assert(rt->texture == D3DRTYPE_TEXTURE ||
+                       rt->texture == D3DRTYPE_CUBETEXTURE);
+                NineBaseTexture9(rt->base.base.container)->dirty_mip = TRUE;
+            }
+        } else {
+            /* Color outputs must match RT slot,
+             * drivers will have to handle NULL entries for GL, too.
+             */
+            fb->cbufs[i] = NULL;
+        }
+    }
+
+    if (state->ds) {
+        fb->zsbuf = NineSurface9_GetSurface(state->ds, 0);
+        if (w) {
+            w = MIN2(w, state->ds->desc.Width);
+            h = MIN2(h, state->ds->desc.Height);
+        } else {
+            w = state->ds->desc.Width;
+            h = state->ds->desc.Height;
+        }
+    } else {
+        fb->zsbuf = NULL;
+    }
+
+    fb->width = w;
+    fb->height = h;
+
+    pipe->set_framebuffer_state(pipe, fb); /* XXX: cso ? */
+
+    if (fb->zsbuf) {
+        DWORD scale;
+        switch (fb->zsbuf->format) {
+        case PIPE_FORMAT_Z32_FLOAT:
+        case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
+            scale = fui(1.0f);
+            break;
+        case PIPE_FORMAT_Z16_UNORM:
+            scale = fui((float)(1 << 16));
+            break;
+        default:
+            scale = fui((float)(1 << 24));
+            break;
+        }
+        if (state->rs[NINED3DRS_ZBIASSCALE] != scale) {
+            state->rs[NINED3DRS_ZBIASSCALE] = scale;
+            state->changed.group |= NINE_STATE_RASTERIZER;
+        }
+    }
+
+#ifdef DEBUG
+    if (state->rt_mask & (state->ps ? ~state->ps->rt_mask : 0))
+        WARN_ONCE("FIXME: writing undefined values to cbufs 0x%x\n",
+                  state->rt_mask & ~state->ps->rt_mask);
+#endif
+
+    return state->changed.group;
+}
+
+static void
+update_viewport(struct NineDevice9 *device)
+{
+    struct pipe_context *pipe = device->pipe;
+    const D3DVIEWPORT9 *vport = &device->state.viewport;
+    struct pipe_viewport_state pvport;
+
+    /* XXX:
+     * I hope D3D clip coordinates are still
+     * -1 .. +1 for X,Y and
+     *  0 .. +1 for Z (use pipe_rasterizer_state.clip_halfz)
+     */
+    pvport.scale[0] = (float)vport->Width * 0.5f;
+    pvport.scale[1] = (float)vport->Height * -0.5f;
+    pvport.scale[2] = vport->MaxZ - vport->MinZ;
+    pvport.scale[3] = 1.0f;
+    pvport.translate[0] = (float)vport->Width * 0.5f + (float)vport->X;
+    pvport.translate[1] = (float)vport->Height * 0.5f + (float)vport->Y;
+    pvport.translate[2] = vport->MinZ;
+    pvport.translate[3] = 0.0f;
+
+    pipe->set_viewport_states(pipe, 0, 1, &pvport);
+}
+
+static INLINE void
+update_scissor(struct NineDevice9 *device)
+{
+    struct pipe_context *pipe = device->pipe;
+
+    pipe->set_scissor_states(pipe, 0, 1, &device->state.scissor);
+}
+
+static INLINE void
+update_blend(struct NineDevice9 *device)
+{
+    nine_convert_blend_state(device->cso, device->state.rs);
+}
+
+static INLINE void
+update_dsa(struct NineDevice9 *device)
+{
+    nine_convert_dsa_state(device->cso, device->state.rs);
+}
+
+static INLINE void
+update_rasterizer(struct NineDevice9 *device)
+{
+    nine_convert_rasterizer_state(device->cso, device->state.rs);
+}
+
+/* Loop through VS inputs and pick the vertex elements with the declared
+ * usage from the vertex declaration, then insert the instance divisor from
+ * the stream source frequency setting.
+ */
+static void
+update_vertex_elements(struct NineDevice9 *device)
+{
+    struct nine_state *state = &device->state;
+    const struct NineVertexDeclaration9 *vdecl = device->state.vdecl;
+    const struct NineVertexShader9 *vs;
+    unsigned n, l, b;
+    struct pipe_vertex_element ve[PIPE_MAX_ATTRIBS];
+
+    state->stream_usage_mask = 0;
+
+    vs = device->state.vs ? device->state.vs : device->ff.vs;
+
+    if (!vdecl) /* no inputs */
+        return;
+    for (n = 0; n < vs->num_inputs; ++n) {
+        DBG("looking up input %u (usage %u) from vdecl(%p)\n",
+            n, vs->input_map[n].ndecl, vdecl);
+
+        assert(vs->input_map[n].ndecl < Elements(vdecl->usage_map));
+        l = vdecl->usage_map[vs->input_map[n].ndecl];
+
+        if (likely(l < vdecl->nelems)) {
+            ve[n] = vdecl->elems[l];
+            b = ve[n].vertex_buffer_index;
+            state->stream_usage_mask |= 1 << b;
+            /* XXX wine just uses 1 here: */
+            if (state->stream_freq[b] & D3DSTREAMSOURCE_INSTANCEDATA)
+                ve[n].instance_divisor = state->stream_freq[b] & 0x7FFFFF;
+        } else {
+            /* TODO:
+             * If drivers don't want to handle this, insert a dummy buffer.
+             * But on which stream ?
+             */
+            /* no data, disable */
+            ve[n].src_format = PIPE_FORMAT_NONE;
+            ve[n].src_offset = 0;
+            ve[n].instance_divisor = 0;
+            ve[n].vertex_buffer_index = 0;
+        }
+    }
+    cso_set_vertex_elements(device->cso, vs->num_inputs, ve);
+
+    state->changed.stream_freq = 0;
+}
+
+static INLINE uint32_t
+update_shader_variant_keys(struct NineDevice9 *device)
+{
+    struct nine_state *state = &device->state;
+    uint32_t mask = 0;
+    uint32_t vs_key = state->samplers_shadow;
+    uint32_t ps_key = state->samplers_shadow;
+
+    vs_key = (vs_key & NINE_VS_SAMPLERS_MASK) >> NINE_SAMPLER_VS(0);
+    ps_key = (ps_key & NINE_PS_SAMPLERS_MASK) >> NINE_SAMPLER_PS(0);
+
+    if (state->vs) vs_key &= state->vs->sampler_mask;
+    if (state->ps) {
+        if (unlikely(state->ps->byte_code.version < 0x20)) {
+            /* no depth textures, but variable targets */
+            uint32_t m = state->ps->sampler_mask;
+            ps_key = 0;
+            while (m) {
+                int s = ffs(m) - 1;
+                m &= ~(1 << s);
+                ps_key |= (state->texture[s] ? state->texture[s]->pstype : 1) << (s * 2);
+            }
+        } else {
+            ps_key &= state->ps->sampler_mask;
+        }
+    }
+
+    if (state->vs && state->vs_key != vs_key) {
+        state->vs_key = vs_key;
+        mask |= NINE_STATE_VS;
+    }
+    if (state->ps && state->ps_key != ps_key) {
+        state->ps_key = ps_key;
+        mask |= NINE_STATE_PS;
+    }
+    return mask;
+}
+
+static INLINE uint32_t
+update_vs(struct NineDevice9 *device)
+{
+    struct nine_state *state = &device->state;
+    struct NineVertexShader9 *vs = state->vs;
+
+    /* likely because we dislike FF */
+    if (likely(vs)) {
+        state->cso.vs = NineVertexShader9_GetVariant(vs, state->vs_key);
+    } else {
+        vs = device->ff.vs;
+        state->cso.vs = vs->variant.cso;
+    }
+    device->pipe->bind_vs_state(device->pipe, state->cso.vs);
+
+    if (state->rs[NINED3DRS_VSPOINTSIZE] != vs->point_size) {
+        state->rs[NINED3DRS_VSPOINTSIZE] = vs->point_size;
+        return NINE_STATE_RASTERIZER;
+    }
+#ifdef DEBUG
+    {
+        unsigned s, mask = vs->sampler_mask;
+        for (s = 0; mask; ++s, mask >>= 1)
+            if ((mask & 1) && !(device->state.texture[NINE_SAMPLER_VS(s)]))
+                WARN_ONCE("FIXME: unbound sampler should return alpha=1\n");
+    }
+#endif
+    return 0;
+}
+
+static INLINE uint32_t
+update_ps(struct NineDevice9 *device)
+{
+    struct nine_state *state = &device->state;
+    struct NinePixelShader9 *ps = state->ps;
+
+    if (likely(ps)) {
+        state->cso.ps = NinePixelShader9_GetVariant(ps, state->ps_key);
+    } else {
+        ps = device->ff.ps;
+        state->cso.ps = ps->variant.cso;
+    }
+    device->pipe->bind_fs_state(device->pipe, state->cso.ps);
+
+#ifdef DEBUG
+    {
+        unsigned s, mask = ps->sampler_mask;
+        for (s = 0; mask; ++s, mask >>= 1)
+            if ((mask & 1) && !(device->state.texture[NINE_SAMPLER_PS(s)]))
+                WARN_ONCE("FIXME: unbound sampler should return alpha=1\n");
+        if (device->state.rt_mask & ~ps->rt_mask)
+            WARN_ONCE("FIXME: writing undefined values to cbufs 0x%x\n",
+                device->state.rt_mask & ~ps->rt_mask);
+    }
+#endif
+    return 0;
+}
+
+#define DO_UPLOAD_CONST_F(buf,p,c,d) \
+    do { \
+        DBG("upload ConstantF [%u .. %u]\n", x, (x) + (c) - 1); \
+        box.x = (p) * 4 * sizeof(float); \
+        box.width = (c) * 4 * sizeof(float); \
+        pipe->transfer_inline_write(pipe, buf, 0, usage, &box, &((d)[p * 4]), \
+                                    0, 0); \
+    } while(0)
+
+/* OK, this is a bit ugly ... */
+static void
+update_constants(struct NineDevice9 *device, unsigned shader_type)
+{
+    struct pipe_context *pipe = device->pipe;
+    struct pipe_resource *buf;
+    struct pipe_box box;
+    const void *data;
+    const float *const_f;
+    const int *const_i;
+    const BOOL *const_b;
+    uint32_t data_b[NINE_MAX_CONST_B];
+    uint32_t b_true;
+    uint16_t dirty_i;
+    uint16_t dirty_b;
+    const unsigned usage = PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_RANGE;
+    unsigned x = 0; /* silence warning */
+    unsigned i, c, n;
+    const struct nine_lconstf *lconstf;
+    struct nine_range *r, *p;
+
+    box.y = 0;
+    box.z = 0;
+    box.height = 1;
+    box.depth = 1;
+
+    if (shader_type == PIPE_SHADER_VERTEX) {
+        DBG("VS\n");
+        buf = device->constbuf_vs;
+
+        const_f = device->state.vs_const_f;
+        for (p = r = device->state.changed.vs_const_f; r; p = r, r = r->next)
+            DO_UPLOAD_CONST_F(buf, r->bgn, r->end - r->bgn, const_f);
+        if (p) {
+            nine_range_pool_put_chain(&device->range_pool,
+                                      device->state.changed.vs_const_f, p);
+            device->state.changed.vs_const_f = NULL;
+        }
+
+        dirty_i = device->state.changed.vs_const_i;
+        device->state.changed.vs_const_i = 0;
+        const_i = &device->state.vs_const_i[0][0];
+
+        dirty_b = device->state.changed.vs_const_b;
+        device->state.changed.vs_const_b = 0;
+        const_b = device->state.vs_const_b;
+        b_true = device->vs_bool_true;
+
+        lconstf = &device->state.vs->lconstf;
+        device->state.ff.clobber.vs_const = TRUE;
+        device->state.changed.group &= ~NINE_STATE_VS_CONST;
+    } else {
+        DBG("PS\n");
+        buf = device->constbuf_ps;
+
+        const_f = device->state.ps_const_f;
+        for (p = r = device->state.changed.ps_const_f; r; p = r, r = r->next)
+            DO_UPLOAD_CONST_F(buf, r->bgn, r->end - r->bgn, const_f);
+        if (p) {
+            nine_range_pool_put_chain(&device->range_pool,
+                                      device->state.changed.ps_const_f, p);
+            device->state.changed.ps_const_f = NULL;
+        }
+
+        dirty_i = device->state.changed.ps_const_i;
+        device->state.changed.ps_const_i = 0;
+        const_i = &device->state.ps_const_i[0][0];
+
+        dirty_b = device->state.changed.ps_const_b;
+        device->state.changed.vs_const_b = 0;
+        const_b = device->state.ps_const_b;
+        b_true = device->ps_bool_true;
+
+        lconstf = &device->state.ps->lconstf;
+        device->state.ff.clobber.ps_const = TRUE;
+        device->state.changed.group &= ~NINE_STATE_PS_CONST;
+    }
+
+    /* write range from min to max changed, it's not much data */
+    /* bool1 */
+    if (dirty_b) {
+       c = util_last_bit(dirty_b);
+       i = ffs(dirty_b) - 1;
+       x = buf->width0 - (NINE_MAX_CONST_B - i) * 4;
+       c -= i;
+       for (n = 0; n < c; ++n, ++i)
+          data_b[n] = const_b[i] ? b_true : 0;
+       box.x = x;
+       box.width = n * 4;
+       DBG("upload ConstantB [%u .. %u]\n", x, x + n - 1);
+       pipe->transfer_inline_write(pipe, buf, 0, usage, &box, data_b, 0, 0);
+    }
+
+    /* int4 */
+    for (c = 0, i = 0; dirty_i; i++, dirty_i >>= 1) {
+        if (dirty_i & 1) {
+            if (!c)
+                x = i;
+            ++c;
+        } else
+        if (c) {
+            DBG("upload ConstantI [%u .. %u]\n", x, x + c - 1);
+            data = &const_i[x * 4];
+            box.x  = buf->width0 - (NINE_MAX_CONST_I * 4 + NINE_MAX_CONST_B) * 4;
+            box.x += x * 4 * sizeof(int);
+            box.width = c * 4 * sizeof(int);
+            c = 0;
+            pipe->transfer_inline_write(pipe, buf, 0, usage, &box, data, 0, 0);
+        }
+    }
+    if (c) {
+        DBG("upload ConstantI [%u .. %u]\n", x, x + c - 1);
+        data = &const_i[x * 4];
+        box.x  = buf->width0 - (NINE_MAX_CONST_I * 4 + NINE_MAX_CONST_B) * 4;
+        box.x += x * 4 * sizeof(int);
+        box.width = c * 4 * sizeof(int);
+        pipe->transfer_inline_write(pipe, buf, 0, usage, &box, data, 0, 0);
+    }
+
+    /* TODO: only upload these when shader itself changes */
+    if (lconstf->ranges) {
+        unsigned n = 0;
+        struct nine_range *r = lconstf->ranges;
+        while (r) {
+            box.x = r->bgn * 4 * sizeof(float);
+            n += r->end - r->bgn;
+            box.width = (r->end - r->bgn) * 4 * sizeof(float);
+            data = &lconstf->data[4 * n];
+            pipe->transfer_inline_write(pipe, buf, 0, usage, &box, data, 0, 0);
+            r = r->next;
+        }
+    }
+}
+
+static void
+update_vs_constants_userbuf(struct NineDevice9 *device)
+{
+    struct nine_state *state = &device->state;
+    struct pipe_context *pipe = device->pipe;
+    struct pipe_constant_buffer cb;
+    cb.buffer = NULL;
+    cb.buffer_offset = 0;
+    cb.buffer_size = device->state.vs->const_used_size;
+    cb.user_buffer = device->state.vs_const_f;
+
+    if (!cb.buffer_size)
+        return;
+
+    if (state->changed.vs_const_i) {
+        int *idst = (int *)&state->vs_const_f[4 * device->max_vs_const_f];
+        memcpy(idst, state->vs_const_i, sizeof(state->vs_const_i));
+        state->changed.vs_const_i = 0;
+    }
+    if (state->changed.vs_const_b) {
+        int *idst = (int *)&state->vs_const_f[4 * device->max_vs_const_f];
+        uint32_t *bdst = (uint32_t *)&idst[4 * NINE_MAX_CONST_I];
+        int i;
+        for (i = 0; i < NINE_MAX_CONST_B; ++i)
+            bdst[i] = state->vs_const_b[i] ? device->vs_bool_true : 0;
+        state->changed.vs_const_b = 0;
+    }
+
+#ifdef DEBUG
+    if (device->state.vs->lconstf.ranges) {
+        /* TODO: Can we make it so that we don't have to copy everything ? */
+        const struct nine_lconstf *lconstf =  &device->state.vs->lconstf;
+        const struct nine_range *r = lconstf->ranges;
+        unsigned n = 0;
+        float *dst = (float *)MALLOC(cb.buffer_size);
+        float *src = (float *)cb.user_buffer;
+        memcpy(dst, src, cb.buffer_size);
+        while (r) {
+            unsigned p = r->bgn;
+            unsigned c = r->end - r->bgn;
+            memcpy(&dst[p * 4], &lconstf->data[n * 4], c * 4 * sizeof(float));
+            n += c;
+            r = r->next;
+        }
+        cb.user_buffer = dst;
+    }
+#endif
+
+    pipe->set_constant_buffer(pipe, PIPE_SHADER_VERTEX, 0, &cb);
+
+#ifdef DEBUG
+    if (device->state.vs->lconstf.ranges)
+        FREE((void *)cb.user_buffer);
+#endif
+
+    if (device->state.changed.vs_const_f) {
+        struct nine_range *r = device->state.changed.vs_const_f;
+        struct nine_range *p = r;
+        while (p->next)
+            p = p->next;
+        nine_range_pool_put_chain(&device->range_pool, r, p);
+        device->state.changed.vs_const_f = NULL;
+    }
+    state->changed.group &= ~NINE_STATE_VS_CONST;
+}
+
+static void
+update_ps_constants_userbuf(struct NineDevice9 *device)
+{
+    struct nine_state *state = &device->state;
+    struct pipe_context *pipe = device->pipe;
+    struct pipe_constant_buffer cb;
+    cb.buffer = NULL;
+    cb.buffer_offset = 0;
+    cb.buffer_size = device->state.ps->const_used_size;
+    cb.user_buffer = device->state.ps_const_f;
+
+    if (!cb.buffer_size)
+        return;
+
+    if (state->changed.ps_const_i) {
+        int *idst = (int *)&state->ps_const_f[4 * device->max_ps_const_f];
+        memcpy(idst, state->ps_const_i, sizeof(state->ps_const_i));
+        state->changed.ps_const_i = 0;
+    }
+    if (state->changed.ps_const_b) {
+        int *idst = (int *)&state->ps_const_f[4 * device->max_ps_const_f];
+        uint32_t *bdst = (uint32_t *)&idst[4 * NINE_MAX_CONST_I];
+        int i;
+        for (i = 0; i < NINE_MAX_CONST_B; ++i)
+            bdst[i] = state->ps_const_b[i] ? device->ps_bool_true : 0;
+        state->changed.ps_const_b = 0;
+    }
+
+#ifdef DEBUG
+    if (device->state.ps->lconstf.ranges) {
+        /* TODO: Can we make it so that we don't have to copy everything ? */
+        const struct nine_lconstf *lconstf =  &device->state.ps->lconstf;
+        const struct nine_range *r = lconstf->ranges;
+        unsigned n = 0;
+        float *dst = (float *)MALLOC(cb.buffer_size);
+        float *src = (float *)cb.user_buffer;
+        memcpy(dst, src, cb.buffer_size);
+        while (r) {
+            unsigned p = r->bgn;
+            unsigned c = r->end - r->bgn;
+            memcpy(&dst[p * 4], &lconstf->data[n * 4], c * 4 * sizeof(float));
+            n += c;
+            r = r->next;
+        }
+        cb.user_buffer = dst;
+    }
+#endif
+
+    pipe->set_constant_buffer(pipe, PIPE_SHADER_FRAGMENT, 0, &cb);
+
+#ifdef DEBUG
+    if (device->state.ps->lconstf.ranges)
+        FREE((void *)cb.user_buffer);
+#endif
+
+    if (device->state.changed.ps_const_f) {
+        struct nine_range *r = device->state.changed.ps_const_f;
+        struct nine_range *p = r;
+        while (p->next)
+            p = p->next;
+        nine_range_pool_put_chain(&device->range_pool, r, p);
+        device->state.changed.ps_const_f = NULL;
+    }
+    state->changed.group &= ~NINE_STATE_PS_CONST;
+}
+
+static void
+update_vertex_buffers(struct NineDevice9 *device)
+{
+    struct pipe_context *pipe = device->pipe;
+    struct nine_state *state = &device->state;
+    uint32_t mask = state->changed.vtxbuf;
+    unsigned i;
+    unsigned start;
+    unsigned count = 0;
+
+    DBG("mask=%x\n", mask);
+
+    for (i = 0; mask; mask >>= 1, ++i) {
+        if (mask & 1) {
+            if (!count)
+                start = i;
+            ++count;
+        } else {
+            if (count)
+                pipe->set_vertex_buffers(pipe,
+                                         start, count, &state->vtxbuf[start]);
+            count = 0;
+        }
+    }
+    if (count)
+        pipe->set_vertex_buffers(pipe, start, count, &state->vtxbuf[start]);
+
+    state->changed.vtxbuf = 0;
+}
+
+static INLINE void
+update_index_buffer(struct NineDevice9 *device)
+{
+    struct pipe_context *pipe = device->pipe;
+    if (device->state.idxbuf)
+        pipe->set_index_buffer(pipe, &device->state.idxbuf->buffer);
+    else
+        pipe->set_index_buffer(pipe, NULL);
+}
+
+/* TODO: only go through dirty textures */
+static void
+validate_textures(struct NineDevice9 *device)
+{
+    struct NineBaseTexture9 *tex, *ptr;
+    LIST_FOR_EACH_ENTRY_SAFE(tex, ptr, &device->update_textures, list) {
+        list_delinit(&tex->list);
+        NineBaseTexture9_Validate(tex);
+    }
+}
+
+static INLINE boolean
+update_sampler_derived(struct nine_state *state, unsigned s)
+{
+    boolean changed = FALSE;
+
+    if (state->samp[s][NINED3DSAMP_SHADOW] != state->texture[s]->shadow) {
+        changed = TRUE;
+        state->samp[s][NINED3DSAMP_SHADOW] = state->texture[s]->shadow;
+    }
+
+    if (state->samp[s][D3DSAMP_MIPFILTER] != D3DTEXF_NONE) {
+        int lod = state->samp[s][D3DSAMP_MAXMIPLEVEL] - state->texture[s]->lod;
+        if (lod < 0)
+            lod = 0;
+        if (state->samp[s][NINED3DSAMP_MINLOD] != lod) {
+            changed = TRUE;
+            state->samp[s][NINED3DSAMP_MINLOD] = lod;
+        }
+    } else {
+        state->changed.sampler[s] &= ~0x300; /* lod changes irrelevant */
+    }
+
+    return changed;
+}
+
+/* TODO: add sRGB override to pipe_sampler_state ? */
+static void
+update_textures_and_samplers(struct NineDevice9 *device)
+{
+    struct pipe_context *pipe = device->pipe;
+    struct nine_state *state = &device->state;
+    struct pipe_sampler_view *view[NINE_MAX_SAMPLERS];
+    unsigned num_textures;
+    unsigned i;
+    boolean commit_samplers;
+
+    /* TODO: Can we reduce iterations here ? */
+
+    commit_samplers = FALSE;
+    for (num_textures = 0, i = 0; i < NINE_MAX_SAMPLERS_PS; ++i) {
+        const unsigned s = NINE_SAMPLER_PS(i);
+        int sRGB;
+        if (!state->texture[s]) {
+            view[i] = NULL;
+#ifdef DEBUG
+            if (state->ps && state->ps->sampler_mask & (1 << i))
+                WARN_ONCE("FIXME: unbound sampler should return alpha=1\n");
+#endif
+            continue;
+        }
+        sRGB = state->samp[s][D3DSAMP_SRGBTEXTURE] ? 1 : 0;
+
+        view[i] = NineBaseTexture9_GetSamplerView(state->texture[s], sRGB);
+        num_textures = i + 1;
+
+        if (update_sampler_derived(state, s) || (state->changed.sampler[s] & 0x05fe)) {
+            state->changed.sampler[s] = 0;
+            commit_samplers = TRUE;
+            nine_convert_sampler_state(device->cso, s, state->samp[s]);
+        }
+    }
+    if (state->changed.texture & NINE_PS_SAMPLERS_MASK)
+        pipe->set_sampler_views(pipe, PIPE_SHADER_FRAGMENT, 0,
+                                num_textures, view);
+
+    if (commit_samplers)
+        cso_single_sampler_done(device->cso, PIPE_SHADER_FRAGMENT);
+
+    commit_samplers = FALSE;
+    for (num_textures = 0, i = 0; i < NINE_MAX_SAMPLERS_VS; ++i) {
+        const unsigned s = NINE_SAMPLER_VS(i);
+        int sRGB;
+        if (!state->texture[s]) {
+            view[i] = NULL;
+#ifdef DEBUG
+            if (state->vs && state->vs->sampler_mask & (1 << i))
+                WARN_ONCE("FIXME: unbound sampler should return alpha=1\n");
+#endif
+            continue;
+        }
+        sRGB = state->samp[s][D3DSAMP_SRGBTEXTURE] ? 1 : 0;
+
+        view[i] = NineBaseTexture9_GetSamplerView(state->texture[s], sRGB);
+        num_textures = i + 1;
+
+        if (update_sampler_derived(state, s) || (state->changed.sampler[s] & 0x05fe)) {
+            state->changed.sampler[s] = 0;
+            commit_samplers = TRUE;
+            nine_convert_sampler_state(device->cso, s, state->samp[s]);
+        }
+    }
+    if (state->changed.texture & NINE_VS_SAMPLERS_MASK)
+        pipe->set_sampler_views(pipe, PIPE_SHADER_VERTEX, 0,
+                                num_textures, view);
+
+    if (commit_samplers)
+        cso_single_sampler_done(device->cso, PIPE_SHADER_VERTEX);
+
+    state->changed.texture = 0;
+}
+
+
+#define NINE_STATE_FREQ_GROUP_0 \
+   (NINE_STATE_FB |             \
+    NINE_STATE_VIEWPORT |       \
+    NINE_STATE_SCISSOR |        \
+    NINE_STATE_BLEND |          \
+    NINE_STATE_DSA |            \
+    NINE_STATE_RASTERIZER |     \
+    NINE_STATE_VS |             \
+    NINE_STATE_PS |             \
+    NINE_STATE_BLEND_COLOR |    \
+    NINE_STATE_STENCIL_REF |    \
+    NINE_STATE_SAMPLE_MASK)
+
+#define NINE_STATE_FREQ_GROUP_1 ~NINE_STATE_FREQ_GROUP_0
+
+#define NINE_STATE_SHADER_VARIANT_GROUP \
+    (NINE_STATE_TEXTURE | \
+     NINE_STATE_VS | \
+     NINE_STATE_PS)
+
+boolean
+nine_update_state(struct NineDevice9 *device, uint32_t mask)
+{
+    struct pipe_context *pipe = device->pipe;
+    struct nine_state *state = &device->state;
+    uint32_t group;
+
+    DBG("changed state groups: %x | %x\n",
+        state->changed.group & NINE_STATE_FREQ_GROUP_0,
+        state->changed.group & NINE_STATE_FREQ_GROUP_1);
+
+    /* NOTE: We may want to use the cso cache for everything, or let
+     * NineDevice9.RestoreNonCSOState actually set the states, then we wouldn't
+     * have to care about state being clobbered here and could merge this back
+     * into update_textures. Except, we also need to re-validate textures that
+     * may be dirty anyway, even if no texture bindings changed.
+     */
+    validate_textures(device); /* may clobber state */
+
+    /* ff_update may change VS/PS dirty bits */
+    if ((mask & NINE_STATE_FF) && unlikely(!state->vs || !state->ps))
+        nine_ff_update(device);
+    group = state->changed.group & mask;
+
+    if (group & NINE_STATE_SHADER_VARIANT_GROUP)
+        group |= update_shader_variant_keys(device);
+
+    if (group & NINE_STATE_FREQ_GROUP_0) {
+        if (group & NINE_STATE_FB)
+            group = update_framebuffer(device) & mask;
+        if (group & NINE_STATE_VIEWPORT)
+            update_viewport(device);
+        if (group & NINE_STATE_SCISSOR)
+            update_scissor(device);
+
+        if (group & NINE_STATE_DSA)
+            update_dsa(device);
+        if (group & NINE_STATE_BLEND)
+            update_blend(device);
+
+        if (group & NINE_STATE_VS)
+            group |= update_vs(device);
+
+        if (group & NINE_STATE_RASTERIZER)
+            update_rasterizer(device);
+
+        if (group & NINE_STATE_PS)
+            group |= update_ps(device);
+
+        if (group & NINE_STATE_BLEND_COLOR) {
+            struct pipe_blend_color color;
+            d3dcolor_to_rgba(&color.color[0], state->rs[D3DRS_BLENDFACTOR]);
+            pipe->set_blend_color(pipe, &color);
+        }
+        if (group & NINE_STATE_SAMPLE_MASK) {
+            pipe->set_sample_mask(pipe, state->rs[D3DRS_MULTISAMPLEMASK]);
+        }
+        if (group & NINE_STATE_STENCIL_REF) {
+            struct pipe_stencil_ref ref;
+            ref.ref_value[0] = state->rs[D3DRS_STENCILREF];
+            ref.ref_value[1] = ref.ref_value[0];
+            pipe->set_stencil_ref(pipe, &ref);
+        }
+    }
+
+    if (state->changed.ucp)
+        pipe->set_clip_state(pipe, &state->clip);
+
+    if (group & (NINE_STATE_FREQ_GROUP_1 | NINE_STATE_VS)) {
+        if (group & (NINE_STATE_TEXTURE | NINE_STATE_SAMPLER))
+            update_textures_and_samplers(device);
+
+        if (group & NINE_STATE_IDXBUF)
+            update_index_buffer(device);
+
+        if ((group & (NINE_STATE_VDECL | NINE_STATE_VS)) ||
+            state->changed.stream_freq & ~1)
+            update_vertex_elements(device);
+
+        if (device->prefer_user_constbuf) {
+            if ((group & (NINE_STATE_VS_CONST | NINE_STATE_VS)) && state->vs)
+                update_vs_constants_userbuf(device);
+            if ((group & (NINE_STATE_PS_CONST | NINE_STATE_PS)) && state->ps)
+                update_ps_constants_userbuf(device);
+        } else {
+            if ((group & NINE_STATE_VS_CONST) && state->vs)
+                update_constants(device, PIPE_SHADER_VERTEX);
+            if ((group & NINE_STATE_PS_CONST) && state->ps)
+                update_constants(device, PIPE_SHADER_FRAGMENT);
+        }
+    }
+    if (state->changed.vtxbuf)
+        update_vertex_buffers(device);
+
+    device->state.changed.group &= ~mask |
+        (NINE_STATE_FF | NINE_STATE_VS_CONST | NINE_STATE_PS_CONST);
+
+    DBG("finished\n");
+
+    return TRUE;
+}
+
+
+static const DWORD nine_render_state_defaults[NINED3DRS_LAST + 1] =
+{
+ /* [D3DRS_ZENABLE] = D3DZB_TRUE; wine: auto_depth_stencil */
+    [D3DRS_ZENABLE] = D3DZB_FALSE,
+    [D3DRS_FILLMODE] = D3DFILL_SOLID,
+    [D3DRS_SHADEMODE] = D3DSHADE_GOURAUD,
+/*  [D3DRS_LINEPATTERN] = 0x00000000, */
+    [D3DRS_ZWRITEENABLE] = TRUE,
+    [D3DRS_ALPHATESTENABLE] = FALSE,
+    [D3DRS_LASTPIXEL] = TRUE,
+    [D3DRS_SRCBLEND] = D3DBLEND_ONE,
+    [D3DRS_DESTBLEND] = D3DBLEND_ZERO,
+    [D3DRS_CULLMODE] = D3DCULL_CCW,
+    [D3DRS_ZFUNC] = D3DCMP_LESSEQUAL,
+    [D3DRS_ALPHAFUNC] = D3DCMP_ALWAYS,
+    [D3DRS_ALPHAREF] = 0,
+    [D3DRS_DITHERENABLE] = FALSE,
+    [D3DRS_ALPHABLENDENABLE] = FALSE,
+    [D3DRS_FOGENABLE] = FALSE,
+    [D3DRS_SPECULARENABLE] = FALSE,
+/*  [D3DRS_ZVISIBLE] = 0, */
+    [D3DRS_FOGCOLOR] = 0,
+    [D3DRS_FOGTABLEMODE] = D3DFOG_NONE,
+    [D3DRS_FOGSTART] = 0x00000000,
+    [D3DRS_FOGEND] = 0x3F800000,
+    [D3DRS_FOGDENSITY] = 0x3F800000,
+/*  [D3DRS_EDGEANTIALIAS] = FALSE, */
+    [D3DRS_RANGEFOGENABLE] = FALSE,
+    [D3DRS_STENCILENABLE] = FALSE,
+    [D3DRS_STENCILFAIL] = D3DSTENCILOP_KEEP,
+    [D3DRS_STENCILZFAIL] = D3DSTENCILOP_KEEP,
+    [D3DRS_STENCILPASS] = D3DSTENCILOP_KEEP,
+    [D3DRS_STENCILREF] = 0,
+    [D3DRS_STENCILMASK] = 0xFFFFFFFF,
+    [D3DRS_STENCILFUNC] = D3DCMP_ALWAYS,
+    [D3DRS_STENCILWRITEMASK] = 0xFFFFFFFF,
+    [D3DRS_TEXTUREFACTOR] = 0xFFFFFFFF,
+    [D3DRS_WRAP0] = 0,
+    [D3DRS_WRAP1] = 0,
+    [D3DRS_WRAP2] = 0,
+    [D3DRS_WRAP3] = 0,
+    [D3DRS_WRAP4] = 0,
+    [D3DRS_WRAP5] = 0,
+    [D3DRS_WRAP6] = 0,
+    [D3DRS_WRAP7] = 0,
+    [D3DRS_CLIPPING] = TRUE,
+    [D3DRS_LIGHTING] = TRUE,
+    [D3DRS_AMBIENT] = 0,
+    [D3DRS_FOGVERTEXMODE] = D3DFOG_NONE,
+    [D3DRS_COLORVERTEX] = TRUE,
+    [D3DRS_LOCALVIEWER] = TRUE,
+    [D3DRS_NORMALIZENORMALS] = FALSE,
+    [D3DRS_DIFFUSEMATERIALSOURCE] = D3DMCS_COLOR1,
+    [D3DRS_SPECULARMATERIALSOURCE] = D3DMCS_COLOR2,
+    [D3DRS_AMBIENTMATERIALSOURCE] = D3DMCS_MATERIAL,
+    [D3DRS_EMISSIVEMATERIALSOURCE] = D3DMCS_MATERIAL,
+    [D3DRS_VERTEXBLEND] = D3DVBF_DISABLE,
+    [D3DRS_CLIPPLANEENABLE] = 0,
+/*  [D3DRS_SOFTWAREVERTEXPROCESSING] = FALSE, */
+    [D3DRS_POINTSIZE] = 0x3F800000,
+    [D3DRS_POINTSIZE_MIN] = 0x3F800000,
+    [D3DRS_POINTSPRITEENABLE] = FALSE,
+    [D3DRS_POINTSCALEENABLE] = FALSE,
+    [D3DRS_POINTSCALE_A] = 0x3F800000,
+    [D3DRS_POINTSCALE_B] = 0x00000000,
+    [D3DRS_POINTSCALE_C] = 0x00000000,
+    [D3DRS_MULTISAMPLEANTIALIAS] = TRUE,
+    [D3DRS_MULTISAMPLEMASK] = 0xFFFFFFFF,
+    [D3DRS_PATCHEDGESTYLE] = D3DPATCHEDGE_DISCRETE,
+/*  [D3DRS_PATCHSEGMENTS] = 0x3F800000, */
+    [D3DRS_DEBUGMONITORTOKEN] = 0xDEADCAFE,
+    [D3DRS_POINTSIZE_MAX] = 0x3F800000, /* depends on cap */
+    [D3DRS_INDEXEDVERTEXBLENDENABLE] = FALSE,
+    [D3DRS_COLORWRITEENABLE] = 0x0000000f,
+    [D3DRS_TWEENFACTOR] = 0x00000000,
+    [D3DRS_BLENDOP] = D3DBLENDOP_ADD,
+    [D3DRS_POSITIONDEGREE] = D3DDEGREE_CUBIC,
+    [D3DRS_NORMALDEGREE] = D3DDEGREE_LINEAR,
+    [D3DRS_SCISSORTESTENABLE] = FALSE,
+    [D3DRS_SLOPESCALEDEPTHBIAS] = 0,
+    [D3DRS_MINTESSELLATIONLEVEL] = 0x3F800000,
+    [D3DRS_MAXTESSELLATIONLEVEL] = 0x3F800000,
+    [D3DRS_ANTIALIASEDLINEENABLE] = FALSE,
+    [D3DRS_ADAPTIVETESS_X] = 0x00000000,
+    [D3DRS_ADAPTIVETESS_Y] = 0x00000000,
+    [D3DRS_ADAPTIVETESS_Z] = 0x3F800000,
+    [D3DRS_ADAPTIVETESS_W] = 0x00000000,
+    [D3DRS_ENABLEADAPTIVETESSELLATION] = FALSE,
+    [D3DRS_TWOSIDEDSTENCILMODE] = FALSE,
+    [D3DRS_CCW_STENCILFAIL] = D3DSTENCILOP_KEEP,
+    [D3DRS_CCW_STENCILZFAIL] = D3DSTENCILOP_KEEP,
+    [D3DRS_CCW_STENCILPASS] = D3DSTENCILOP_KEEP,
+    [D3DRS_CCW_STENCILFUNC] = D3DCMP_ALWAYS,
+    [D3DRS_COLORWRITEENABLE1] = 0x0000000F,
+    [D3DRS_COLORWRITEENABLE2] = 0x0000000F,
+    [D3DRS_COLORWRITEENABLE3] = 0x0000000F,
+    [D3DRS_BLENDFACTOR] = 0xFFFFFFFF,
+    [D3DRS_SRGBWRITEENABLE] = 0,
+    [D3DRS_DEPTHBIAS] = 0,
+    [D3DRS_WRAP8] = 0,
+    [D3DRS_WRAP9] = 0,
+    [D3DRS_WRAP10] = 0,
+    [D3DRS_WRAP11] = 0,
+    [D3DRS_WRAP12] = 0,
+    [D3DRS_WRAP13] = 0,
+    [D3DRS_WRAP14] = 0,
+    [D3DRS_WRAP15] = 0,
+    [D3DRS_SEPARATEALPHABLENDENABLE] = FALSE,
+    [D3DRS_SRCBLENDALPHA] = D3DBLEND_ONE,
+    [D3DRS_DESTBLENDALPHA] = D3DBLEND_ZERO,
+    [D3DRS_BLENDOPALPHA] = D3DBLENDOP_ADD,
+    [NINED3DRS_VSPOINTSIZE] = FALSE,
+    [NINED3DRS_RTMASK] = 0xf
+};
+static const DWORD nine_tex_stage_state_defaults[NINED3DTSS_LAST + 1] =
+{
+    [D3DTSS_COLOROP] = D3DTOP_DISABLE,
+    [D3DTSS_ALPHAOP] = D3DTOP_DISABLE,
+    [D3DTSS_COLORARG1] = D3DTA_TEXTURE,
+    [D3DTSS_COLORARG2] = D3DTA_CURRENT,
+    [D3DTSS_COLORARG0] = D3DTA_CURRENT,
+    [D3DTSS_ALPHAARG1] = D3DTA_TEXTURE,
+    [D3DTSS_ALPHAARG2] = D3DTA_CURRENT,
+    [D3DTSS_ALPHAARG0] = D3DTA_CURRENT,
+    [D3DTSS_RESULTARG] = D3DTA_CURRENT,
+    [D3DTSS_BUMPENVMAT00] = 0,
+    [D3DTSS_BUMPENVMAT01] = 0,
+    [D3DTSS_BUMPENVMAT10] = 0,
+    [D3DTSS_BUMPENVMAT11] = 0,
+    [D3DTSS_BUMPENVLSCALE] = 0,
+    [D3DTSS_BUMPENVLOFFSET] = 0,
+    [D3DTSS_TEXCOORDINDEX] = 0,
+    [D3DTSS_TEXTURETRANSFORMFLAGS] = D3DTTFF_DISABLE,
+};
+static const DWORD nine_samp_state_defaults[NINED3DSAMP_LAST + 1] =
+{
+    [D3DSAMP_ADDRESSU] = D3DTADDRESS_WRAP,
+    [D3DSAMP_ADDRESSV] = D3DTADDRESS_WRAP,
+    [D3DSAMP_ADDRESSW] = D3DTADDRESS_WRAP,
+    [D3DSAMP_BORDERCOLOR] = 0,
+    [D3DSAMP_MAGFILTER] = D3DTEXF_POINT,
+    [D3DSAMP_MINFILTER] = D3DTEXF_POINT,
+    [D3DSAMP_MIPFILTER] = D3DTEXF_NONE,
+    [D3DSAMP_MIPMAPLODBIAS] = 0,
+    [D3DSAMP_MAXMIPLEVEL] = 0,
+    [D3DSAMP_MAXANISOTROPY] = 1,
+    [D3DSAMP_SRGBTEXTURE] = 0,
+    [D3DSAMP_ELEMENTINDEX] = 0,
+    [D3DSAMP_DMAPOFFSET] = 0,
+    [NINED3DSAMP_MINLOD] = 0,
+    [NINED3DSAMP_SHADOW] = 0
+};
+void
+nine_state_set_defaults(struct nine_state *state, const D3DCAPS9 *caps,
+                        boolean is_reset)
+{
+    unsigned s;
+
+    /* Initialize defaults.
+     */
+    memcpy(state->rs, nine_render_state_defaults, sizeof(state->rs));
+
+    for (s = 0; s < Elements(state->ff.tex_stage); ++s) {
+        memcpy(&state->ff.tex_stage[s], nine_tex_stage_state_defaults,
+               sizeof(state->ff.tex_stage[s]));
+        state->ff.tex_stage[s][D3DTSS_TEXCOORDINDEX] = s;
+    }
+    state->ff.tex_stage[0][D3DTSS_COLOROP] = D3DTOP_MODULATE;
+    state->ff.tex_stage[0][D3DTSS_ALPHAOP] = D3DTOP_SELECTARG1;
+
+    for (s = 0; s < Elements(state->samp); ++s) {
+        memcpy(&state->samp[s], nine_samp_state_defaults,
+               sizeof(state->samp[s]));
+    }
+
+    if (state->vs_const_f)
+        memset(state->vs_const_f, 0, NINE_MAX_CONST_F * 4 * sizeof(float));
+    if (state->ps_const_f)
+        memset(state->ps_const_f, 0, NINE_MAX_CONST_F * 4 * sizeof(float));
+
+    /* Cap dependent initial state:
+     */
+    state->rs[D3DRS_POINTSIZE_MAX] = fui(caps->MaxPointSize);
+
+    /* Set changed flags to initialize driver.
+     */
+    state->changed.group = NINE_STATE_ALL;
+
+    state->ff.changed.transform[0] = ~0;
+    state->ff.changed.transform[D3DTS_WORLD / 32] |= 1 << (D3DTS_WORLD % 32);
+
+    if (!is_reset) {
+        state->viewport.MinZ = 0.0f;
+        state->viewport.MaxZ = 1.0f;
+    }
+
+    for (s = 0; s < Elements(state->changed.sampler); ++s)
+        state->changed.sampler[s] = ~0;
+}
+
+void
+nine_state_clear(struct nine_state *state, const boolean device)
+{
+    unsigned i;
+
+    for (i = 0; i < Elements(state->rt); ++i)
+       nine_bind(&state->rt[i], NULL);
+    nine_bind(&state->ds, NULL);
+    nine_bind(&state->vs, NULL);
+    nine_bind(&state->ps, NULL);
+    nine_bind(&state->vdecl, NULL);
+    for (i = 0; i < PIPE_MAX_ATTRIBS; ++i)
+        nine_bind(&state->stream[i], NULL);
+    nine_bind(&state->idxbuf, NULL);
+    for (i = 0; i < NINE_MAX_SAMPLERS; ++i) {
+        if (device &&
+            state->texture[i] &&
+          --state->texture[i]->bind_count == 0)
+            list_delinit(&state->texture[i]->list);
+        nine_bind(&state->texture[i], NULL);
+    }
+}
+
+/*
+static const DWORD nine_render_states_pixel[] =
+{
+    D3DRS_ALPHABLENDENABLE,
+    D3DRS_ALPHAFUNC,
+    D3DRS_ALPHAREF,
+    D3DRS_ALPHATESTENABLE,
+    D3DRS_ANTIALIASEDLINEENABLE,
+    D3DRS_BLENDFACTOR,
+    D3DRS_BLENDOP,
+    D3DRS_BLENDOPALPHA,
+    D3DRS_CCW_STENCILFAIL,
+    D3DRS_CCW_STENCILPASS,
+    D3DRS_CCW_STENCILZFAIL,
+    D3DRS_COLORWRITEENABLE,
+    D3DRS_COLORWRITEENABLE1,
+    D3DRS_COLORWRITEENABLE2,
+    D3DRS_COLORWRITEENABLE3,
+    D3DRS_DEPTHBIAS,
+    D3DRS_DESTBLEND,
+    D3DRS_DESTBLENDALPHA,
+    D3DRS_DITHERENABLE,
+    D3DRS_FILLMODE,
+    D3DRS_FOGDENSITY,
+    D3DRS_FOGEND,
+    D3DRS_FOGSTART,
+    D3DRS_LASTPIXEL,
+    D3DRS_SCISSORTESTENABLE,
+    D3DRS_SEPARATEALPHABLENDENABLE,
+    D3DRS_SHADEMODE,
+    D3DRS_SLOPESCALEDEPTHBIAS,
+    D3DRS_SRCBLEND,
+    D3DRS_SRCBLENDALPHA,
+    D3DRS_SRGBWRITEENABLE,
+    D3DRS_STENCILENABLE,
+    D3DRS_STENCILFAIL,
+    D3DRS_STENCILFUNC,
+    D3DRS_STENCILMASK,
+    D3DRS_STENCILPASS,
+    D3DRS_STENCILREF,
+    D3DRS_STENCILWRITEMASK,
+    D3DRS_STENCILZFAIL,
+    D3DRS_TEXTUREFACTOR,
+    D3DRS_TWOSIDEDSTENCILMODE,
+    D3DRS_WRAP0,
+    D3DRS_WRAP1,
+    D3DRS_WRAP10,
+    D3DRS_WRAP11,
+    D3DRS_WRAP12,
+    D3DRS_WRAP13,
+    D3DRS_WRAP14,
+    D3DRS_WRAP15,
+    D3DRS_WRAP2,
+    D3DRS_WRAP3,
+    D3DRS_WRAP4,
+    D3DRS_WRAP5,
+    D3DRS_WRAP6,
+    D3DRS_WRAP7,
+    D3DRS_WRAP8,
+    D3DRS_WRAP9,
+    D3DRS_ZENABLE,
+    D3DRS_ZFUNC,
+    D3DRS_ZWRITEENABLE
+};
+*/
+const uint32_t nine_render_states_pixel[(NINED3DRS_LAST + 31) / 32] =
+{
+    0x0f99c380, 0x1ff00070, 0x00000000, 0x00000000,
+    0x000000ff, 0xde01c900, 0x0003ffcf
+};
+
+/*
+static const DWORD nine_render_states_vertex[] =
+{
+    D3DRS_ADAPTIVETESS_W,
+    D3DRS_ADAPTIVETESS_X,
+    D3DRS_ADAPTIVETESS_Y,
+    D3DRS_ADAPTIVETESS_Z,
+    D3DRS_AMBIENT,
+    D3DRS_AMBIENTMATERIALSOURCE,
+    D3DRS_CLIPPING,
+    D3DRS_CLIPPLANEENABLE,
+    D3DRS_COLORVERTEX,
+    D3DRS_CULLMODE,
+    D3DRS_DIFFUSEMATERIALSOURCE,
+    D3DRS_EMISSIVEMATERIALSOURCE,
+    D3DRS_ENABLEADAPTIVETESSELLATION,
+    D3DRS_FOGCOLOR,
+    D3DRS_FOGDENSITY,
+    D3DRS_FOGENABLE,
+    D3DRS_FOGEND,
+    D3DRS_FOGSTART,
+    D3DRS_FOGTABLEMODE,
+    D3DRS_FOGVERTEXMODE,
+    D3DRS_INDEXEDVERTEXBLENDENABLE,
+    D3DRS_LIGHTING,
+    D3DRS_LOCALVIEWER,
+    D3DRS_MAXTESSELLATIONLEVEL,
+    D3DRS_MINTESSELLATIONLEVEL,
+    D3DRS_MULTISAMPLEANTIALIAS,
+    D3DRS_MULTISAMPLEMASK,
+    D3DRS_NORMALDEGREE,
+    D3DRS_NORMALIZENORMALS,
+    D3DRS_PATCHEDGESTYLE,
+    D3DRS_POINTSCALE_A,
+    D3DRS_POINTSCALE_B,
+    D3DRS_POINTSCALE_C,
+    D3DRS_POINTSCALEENABLE,
+    D3DRS_POINTSIZE,
+    D3DRS_POINTSIZE_MAX,
+    D3DRS_POINTSIZE_MIN,
+    D3DRS_POINTSPRITEENABLE,
+    D3DRS_POSITIONDEGREE,
+    D3DRS_RANGEFOGENABLE,
+    D3DRS_SHADEMODE,
+    D3DRS_SPECULARENABLE,
+    D3DRS_SPECULARMATERIALSOURCE,
+    D3DRS_TWEENFACTOR,
+    D3DRS_VERTEXBLEND
+};
+*/
+const uint32_t nine_render_states_vertex[(NINED3DRS_LAST + 31) / 32] =
+{
+    0x30400200, 0x0001007c, 0x00000000, 0x00000000,
+    0xfd9efb00, 0x01fc34cf, 0x00000000
+};
+
+/* TODO: put in the right values */
+const uint32_t nine_render_state_group[NINED3DRS_LAST + 1] =
+{
+    [D3DRS_ZENABLE] = NINE_STATE_DSA,
+    [D3DRS_FILLMODE] = NINE_STATE_RASTERIZER,
+    [D3DRS_SHADEMODE] = NINE_STATE_RASTERIZER,
+    [D3DRS_ZWRITEENABLE] = NINE_STATE_DSA,
+    [D3DRS_ALPHATESTENABLE] = NINE_STATE_DSA,
+    [D3DRS_LASTPIXEL] = NINE_STATE_RASTERIZER,
+    [D3DRS_SRCBLEND] = NINE_STATE_BLEND,
+    [D3DRS_DESTBLEND] = NINE_STATE_BLEND,
+    [D3DRS_CULLMODE] = NINE_STATE_RASTERIZER,
+    [D3DRS_ZFUNC] = NINE_STATE_DSA,
+    [D3DRS_ALPHAREF] = NINE_STATE_DSA,
+    [D3DRS_ALPHAFUNC] = NINE_STATE_DSA,
+    [D3DRS_DITHERENABLE] = NINE_STATE_RASTERIZER,
+    [D3DRS_ALPHABLENDENABLE] = NINE_STATE_BLEND,
+    [D3DRS_FOGENABLE] = NINE_STATE_FF_OTHER,
+    [D3DRS_SPECULARENABLE] = NINE_STATE_FF_LIGHTING,
+    [D3DRS_FOGCOLOR] = NINE_STATE_FF_OTHER,
+    [D3DRS_FOGTABLEMODE] = NINE_STATE_FF_OTHER,
+    [D3DRS_FOGSTART] = NINE_STATE_FF_OTHER,
+    [D3DRS_FOGEND] = NINE_STATE_FF_OTHER,
+    [D3DRS_FOGDENSITY] = NINE_STATE_FF_OTHER,
+    [D3DRS_RANGEFOGENABLE] = NINE_STATE_FF_OTHER,
+    [D3DRS_STENCILENABLE] = NINE_STATE_DSA,
+    [D3DRS_STENCILFAIL] = NINE_STATE_DSA,
+    [D3DRS_STENCILZFAIL] = NINE_STATE_DSA,
+    [D3DRS_STENCILPASS] = NINE_STATE_DSA,
+    [D3DRS_STENCILFUNC] = NINE_STATE_DSA,
+    [D3DRS_STENCILREF] = NINE_STATE_STENCIL_REF,
+    [D3DRS_STENCILMASK] = NINE_STATE_DSA,
+    [D3DRS_STENCILWRITEMASK] = NINE_STATE_DSA,
+    [D3DRS_TEXTUREFACTOR] = NINE_STATE_FF_PSSTAGES,
+    [D3DRS_WRAP0] = NINE_STATE_UNHANDLED, /* cylindrical wrap is crazy */
+    [D3DRS_WRAP1] = NINE_STATE_UNHANDLED,
+    [D3DRS_WRAP2] = NINE_STATE_UNHANDLED,
+    [D3DRS_WRAP3] = NINE_STATE_UNHANDLED,
+    [D3DRS_WRAP4] = NINE_STATE_UNHANDLED,
+    [D3DRS_WRAP5] = NINE_STATE_UNHANDLED,
+    [D3DRS_WRAP6] = NINE_STATE_UNHANDLED,
+    [D3DRS_WRAP7] = NINE_STATE_UNHANDLED,
+    [D3DRS_CLIPPING] = 0, /* software vertex processing only */
+    [D3DRS_LIGHTING] = NINE_STATE_FF_LIGHTING,
+    [D3DRS_AMBIENT] = NINE_STATE_FF_LIGHTING | NINE_STATE_FF_MATERIAL,
+    [D3DRS_FOGVERTEXMODE] = NINE_STATE_FF_OTHER,
+    [D3DRS_COLORVERTEX] = NINE_STATE_FF_LIGHTING,
+    [D3DRS_LOCALVIEWER] = NINE_STATE_FF_LIGHTING,
+    [D3DRS_NORMALIZENORMALS] = NINE_STATE_FF_OTHER,
+    [D3DRS_DIFFUSEMATERIALSOURCE] = NINE_STATE_FF_LIGHTING,
+    [D3DRS_SPECULARMATERIALSOURCE] = NINE_STATE_FF_LIGHTING,
+    [D3DRS_AMBIENTMATERIALSOURCE] = NINE_STATE_FF_LIGHTING,
+    [D3DRS_EMISSIVEMATERIALSOURCE] = NINE_STATE_FF_LIGHTING,
+    [D3DRS_VERTEXBLEND] = NINE_STATE_FF_OTHER,
+    [D3DRS_CLIPPLANEENABLE] = NINE_STATE_RASTERIZER,
+    [D3DRS_POINTSIZE] = NINE_STATE_RASTERIZER,
+    [D3DRS_POINTSIZE_MIN] = NINE_STATE_MISC_CONST,
+    [D3DRS_POINTSPRITEENABLE] = NINE_STATE_RASTERIZER,
+    [D3DRS_POINTSCALEENABLE] = NINE_STATE_FF_OTHER,
+    [D3DRS_POINTSCALE_A] = NINE_STATE_FF_OTHER,
+    [D3DRS_POINTSCALE_B] = NINE_STATE_FF_OTHER,
+    [D3DRS_POINTSCALE_C] = NINE_STATE_FF_OTHER,
+    [D3DRS_MULTISAMPLEANTIALIAS] = NINE_STATE_RASTERIZER,
+    [D3DRS_MULTISAMPLEMASK] = NINE_STATE_SAMPLE_MASK,
+    [D3DRS_PATCHEDGESTYLE] = NINE_STATE_UNHANDLED,
+    [D3DRS_DEBUGMONITORTOKEN] = NINE_STATE_UNHANDLED,
+    [D3DRS_POINTSIZE_MAX] = NINE_STATE_MISC_CONST,
+    [D3DRS_INDEXEDVERTEXBLENDENABLE] = NINE_STATE_FF_OTHER,
+    [D3DRS_COLORWRITEENABLE] = NINE_STATE_BLEND,
+    [D3DRS_TWEENFACTOR] = NINE_STATE_FF_OTHER,
+    [D3DRS_BLENDOP] = NINE_STATE_BLEND,
+    [D3DRS_POSITIONDEGREE] = NINE_STATE_UNHANDLED,
+    [D3DRS_NORMALDEGREE] = NINE_STATE_UNHANDLED,
+    [D3DRS_SCISSORTESTENABLE] = NINE_STATE_RASTERIZER,
+    [D3DRS_SLOPESCALEDEPTHBIAS] = NINE_STATE_RASTERIZER,
+    [D3DRS_ANTIALIASEDLINEENABLE] = NINE_STATE_RASTERIZER,
+    [D3DRS_MINTESSELLATIONLEVEL] = NINE_STATE_UNHANDLED,
+    [D3DRS_MAXTESSELLATIONLEVEL] = NINE_STATE_UNHANDLED,
+    [D3DRS_ADAPTIVETESS_X] = NINE_STATE_UNHANDLED,
+    [D3DRS_ADAPTIVETESS_Y] = NINE_STATE_UNHANDLED,
+    [D3DRS_ADAPTIVETESS_Z] = NINE_STATE_UNHANDLED,
+    [D3DRS_ADAPTIVETESS_W] = NINE_STATE_UNHANDLED,
+    [D3DRS_ENABLEADAPTIVETESSELLATION] = NINE_STATE_UNHANDLED,
+    [D3DRS_TWOSIDEDSTENCILMODE] = NINE_STATE_DSA,
+    [D3DRS_CCW_STENCILFAIL] = NINE_STATE_DSA,
+    [D3DRS_CCW_STENCILZFAIL] = NINE_STATE_DSA,
+    [D3DRS_CCW_STENCILPASS] = NINE_STATE_DSA,
+    [D3DRS_CCW_STENCILFUNC] = NINE_STATE_DSA,
+    [D3DRS_COLORWRITEENABLE1] = NINE_STATE_BLEND,
+    [D3DRS_COLORWRITEENABLE2] = NINE_STATE_BLEND,
+    [D3DRS_COLORWRITEENABLE3] = NINE_STATE_BLEND,
+    [D3DRS_BLENDFACTOR] = NINE_STATE_BLEND_COLOR,
+    [D3DRS_SRGBWRITEENABLE] = NINE_STATE_FB,
+    [D3DRS_DEPTHBIAS] = NINE_STATE_RASTERIZER,
+    [D3DRS_WRAP8] = NINE_STATE_UNHANDLED, /* cylwrap has to be done via GP */
+    [D3DRS_WRAP9] = NINE_STATE_UNHANDLED,
+    [D3DRS_WRAP10] = NINE_STATE_UNHANDLED,
+    [D3DRS_WRAP11] = NINE_STATE_UNHANDLED,
+    [D3DRS_WRAP12] = NINE_STATE_UNHANDLED,
+    [D3DRS_WRAP13] = NINE_STATE_UNHANDLED,
+    [D3DRS_WRAP14] = NINE_STATE_UNHANDLED,
+    [D3DRS_WRAP15] = NINE_STATE_UNHANDLED,
+    [D3DRS_SEPARATEALPHABLENDENABLE] = NINE_STATE_BLEND,
+    [D3DRS_SRCBLENDALPHA] = NINE_STATE_BLEND,
+    [D3DRS_DESTBLENDALPHA] = NINE_STATE_BLEND,
+    [D3DRS_BLENDOPALPHA] = NINE_STATE_BLEND
+};
+
+D3DMATRIX *
+nine_state_access_transform(struct nine_state *state, D3DTRANSFORMSTATETYPE t,
+                            boolean alloc)
+{
+    static D3DMATRIX Identity = { .m[0] = { 1, 0, 0, 0 },
+                                  .m[1] = { 0, 1, 0, 0 },
+                                  .m[2] = { 0, 0, 1, 0 },
+                                  .m[3] = { 0, 0, 0, 1 } };
+    unsigned index;
+
+    switch (t) {
+    case D3DTS_VIEW: index = 0; break;
+    case D3DTS_PROJECTION: index = 1; break;
+    case D3DTS_TEXTURE0: index = 2; break;
+    case D3DTS_TEXTURE1: index = 3; break;
+    case D3DTS_TEXTURE2: index = 4; break;
+    case D3DTS_TEXTURE3: index = 5; break;
+    case D3DTS_TEXTURE4: index = 6; break;
+    case D3DTS_TEXTURE5: index = 7; break;
+    case D3DTS_TEXTURE6: index = 8; break;
+    case D3DTS_TEXTURE7: index = 9; break;
+    default:
+        if (!(t >= D3DTS_WORLDMATRIX(0) && t <= D3DTS_WORLDMATRIX(255)))
+            return NULL;
+        index = 10 + (t - D3DTS_WORLDMATRIX(0));
+        break;
+    }
+
+    if (index >= state->ff.num_transforms) {
+        unsigned N = index + 1;
+        unsigned n = state->ff.num_transforms;
+
+        if (!alloc)
+            return &Identity;
+        state->ff.transform = REALLOC(state->ff.transform,
+                                      n * sizeof(D3DMATRIX),
+                                      N * sizeof(D3DMATRIX));
+        for (; n < N; ++n)
+            state->ff.transform[n] = Identity;
+        state->ff.num_transforms = N;
+    }
+    return &state->ff.transform[index];
+}
+
+#define D3DRS_TO_STRING_CASE(n) case D3DRS_##n: return "D3DRS_"#n
+const char *nine_d3drs_to_string(DWORD State)
+{
+    switch (State) {
+    D3DRS_TO_STRING_CASE(ZENABLE);
+    D3DRS_TO_STRING_CASE(FILLMODE);
+    D3DRS_TO_STRING_CASE(SHADEMODE);
+    D3DRS_TO_STRING_CASE(ZWRITEENABLE);
+    D3DRS_TO_STRING_CASE(ALPHATESTENABLE);
+    D3DRS_TO_STRING_CASE(LASTPIXEL);
+    D3DRS_TO_STRING_CASE(SRCBLEND);
+    D3DRS_TO_STRING_CASE(DESTBLEND);
+    D3DRS_TO_STRING_CASE(CULLMODE);
+    D3DRS_TO_STRING_CASE(ZFUNC);
+    D3DRS_TO_STRING_CASE(ALPHAREF);
+    D3DRS_TO_STRING_CASE(ALPHAFUNC);
+    D3DRS_TO_STRING_CASE(DITHERENABLE);
+    D3DRS_TO_STRING_CASE(ALPHABLENDENABLE);
+    D3DRS_TO_STRING_CASE(FOGENABLE);
+    D3DRS_TO_STRING_CASE(SPECULARENABLE);
+    D3DRS_TO_STRING_CASE(FOGCOLOR);
+    D3DRS_TO_STRING_CASE(FOGTABLEMODE);
+    D3DRS_TO_STRING_CASE(FOGSTART);
+    D3DRS_TO_STRING_CASE(FOGEND);
+    D3DRS_TO_STRING_CASE(FOGDENSITY);
+    D3DRS_TO_STRING_CASE(RANGEFOGENABLE);
+    D3DRS_TO_STRING_CASE(STENCILENABLE);
+    D3DRS_TO_STRING_CASE(STENCILFAIL);
+    D3DRS_TO_STRING_CASE(STENCILZFAIL);
+    D3DRS_TO_STRING_CASE(STENCILPASS);
+    D3DRS_TO_STRING_CASE(STENCILFUNC);
+    D3DRS_TO_STRING_CASE(STENCILREF);
+    D3DRS_TO_STRING_CASE(STENCILMASK);
+    D3DRS_TO_STRING_CASE(STENCILWRITEMASK);
+    D3DRS_TO_STRING_CASE(TEXTUREFACTOR);
+    D3DRS_TO_STRING_CASE(WRAP0);
+    D3DRS_TO_STRING_CASE(WRAP1);
+    D3DRS_TO_STRING_CASE(WRAP2);
+    D3DRS_TO_STRING_CASE(WRAP3);
+    D3DRS_TO_STRING_CASE(WRAP4);
+    D3DRS_TO_STRING_CASE(WRAP5);
+    D3DRS_TO_STRING_CASE(WRAP6);
+    D3DRS_TO_STRING_CASE(WRAP7);
+    D3DRS_TO_STRING_CASE(CLIPPING);
+    D3DRS_TO_STRING_CASE(LIGHTING);
+    D3DRS_TO_STRING_CASE(AMBIENT);
+    D3DRS_TO_STRING_CASE(FOGVERTEXMODE);
+    D3DRS_TO_STRING_CASE(COLORVERTEX);
+    D3DRS_TO_STRING_CASE(LOCALVIEWER);
+    D3DRS_TO_STRING_CASE(NORMALIZENORMALS);
+    D3DRS_TO_STRING_CASE(DIFFUSEMATERIALSOURCE);
+    D3DRS_TO_STRING_CASE(SPECULARMATERIALSOURCE);
+    D3DRS_TO_STRING_CASE(AMBIENTMATERIALSOURCE);
+    D3DRS_TO_STRING_CASE(EMISSIVEMATERIALSOURCE);
+    D3DRS_TO_STRING_CASE(VERTEXBLEND);
+    D3DRS_TO_STRING_CASE(CLIPPLANEENABLE);
+    D3DRS_TO_STRING_CASE(POINTSIZE);
+    D3DRS_TO_STRING_CASE(POINTSIZE_MIN);
+    D3DRS_TO_STRING_CASE(POINTSPRITEENABLE);
+    D3DRS_TO_STRING_CASE(POINTSCALEENABLE);
+    D3DRS_TO_STRING_CASE(POINTSCALE_A);
+    D3DRS_TO_STRING_CASE(POINTSCALE_B);
+    D3DRS_TO_STRING_CASE(POINTSCALE_C);
+    D3DRS_TO_STRING_CASE(MULTISAMPLEANTIALIAS);
+    D3DRS_TO_STRING_CASE(MULTISAMPLEMASK);
+    D3DRS_TO_STRING_CASE(PATCHEDGESTYLE);
+    D3DRS_TO_STRING_CASE(DEBUGMONITORTOKEN);
+    D3DRS_TO_STRING_CASE(POINTSIZE_MAX);
+    D3DRS_TO_STRING_CASE(INDEXEDVERTEXBLENDENABLE);
+    D3DRS_TO_STRING_CASE(COLORWRITEENABLE);
+    D3DRS_TO_STRING_CASE(TWEENFACTOR);
+    D3DRS_TO_STRING_CASE(BLENDOP);
+    D3DRS_TO_STRING_CASE(POSITIONDEGREE);
+    D3DRS_TO_STRING_CASE(NORMALDEGREE);
+    D3DRS_TO_STRING_CASE(SCISSORTESTENABLE);
+    D3DRS_TO_STRING_CASE(SLOPESCALEDEPTHBIAS);
+    D3DRS_TO_STRING_CASE(ANTIALIASEDLINEENABLE);
+    D3DRS_TO_STRING_CASE(MINTESSELLATIONLEVEL);
+    D3DRS_TO_STRING_CASE(MAXTESSELLATIONLEVEL);
+    D3DRS_TO_STRING_CASE(ADAPTIVETESS_X);
+    D3DRS_TO_STRING_CASE(ADAPTIVETESS_Y);
+    D3DRS_TO_STRING_CASE(ADAPTIVETESS_Z);
+    D3DRS_TO_STRING_CASE(ADAPTIVETESS_W);
+    D3DRS_TO_STRING_CASE(ENABLEADAPTIVETESSELLATION);
+    D3DRS_TO_STRING_CASE(TWOSIDEDSTENCILMODE);
+    D3DRS_TO_STRING_CASE(CCW_STENCILFAIL);
+    D3DRS_TO_STRING_CASE(CCW_STENCILZFAIL);
+    D3DRS_TO_STRING_CASE(CCW_STENCILPASS);
+    D3DRS_TO_STRING_CASE(CCW_STENCILFUNC);
+    D3DRS_TO_STRING_CASE(COLORWRITEENABLE1);
+    D3DRS_TO_STRING_CASE(COLORWRITEENABLE2);
+    D3DRS_TO_STRING_CASE(COLORWRITEENABLE3);
+    D3DRS_TO_STRING_CASE(BLENDFACTOR);
+    D3DRS_TO_STRING_CASE(SRGBWRITEENABLE);
+    D3DRS_TO_STRING_CASE(DEPTHBIAS);
+    D3DRS_TO_STRING_CASE(WRAP8);
+    D3DRS_TO_STRING_CASE(WRAP9);
+    D3DRS_TO_STRING_CASE(WRAP10);
+    D3DRS_TO_STRING_CASE(WRAP11);
+    D3DRS_TO_STRING_CASE(WRAP12);
+    D3DRS_TO_STRING_CASE(WRAP13);
+    D3DRS_TO_STRING_CASE(WRAP14);
+    D3DRS_TO_STRING_CASE(WRAP15);
+    D3DRS_TO_STRING_CASE(SEPARATEALPHABLENDENABLE);
+    D3DRS_TO_STRING_CASE(SRCBLENDALPHA);
+    D3DRS_TO_STRING_CASE(DESTBLENDALPHA);
+    D3DRS_TO_STRING_CASE(BLENDOPALPHA);
+    default:
+        return "(invalid)";
+    }
+}
+
diff --git a/src/gallium/state_trackers/nine/nine_state.h b/src/gallium/state_trackers/nine/nine_state.h
new file mode 100644 (file)
index 0000000..3e0162c
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _NINE_STATE_H_
+#define _NINE_STATE_H_
+
+#include "d3d9.h"
+#include "nine_defines.h"
+#include "pipe/p_state.h"
+#include "util/u_double_list.h"
+
+#define NINED3DSAMP_MINLOD (D3DSAMP_DMAPOFFSET + 1)
+#define NINED3DSAMP_SHADOW (D3DSAMP_DMAPOFFSET + 2)
+
+#define NINED3DRS_VSPOINTSIZE (D3DRS_BLENDOPALPHA + 1)
+#define NINED3DRS_RTMASK      (D3DRS_BLENDOPALPHA + 2)
+#define NINED3DRS_ZBIASSCALE  (D3DRS_BLENDOPALPHA + 3)
+
+#define D3DRS_LAST       D3DRS_BLENDOPALPHA
+#define NINED3DRS_LAST   NINED3DRS_ZBIASSCALE /* 212 */
+#define NINED3DSAMP_LAST NINED3DSAMP_SHADOW /* 15 */
+#define NINED3DTSS_LAST  D3DTSS_CONSTANT
+#define NINED3DTS_LAST   D3DTS_WORLDMATRIX(255)
+
+#define D3DRS_COUNT       (D3DRS_LAST + 1)
+#define NINED3DRS_COUNT   (NINED3DRS_LAST + 1)
+#define NINED3DSAMP_COUNT (NINED3DSAMP_LAST + 1)
+#define NINED3DTSS_COUNT  (NINED3DTSS_LAST + 1)
+#define NINED3DTS_COUNT   (NINED3DTS_LAST + 1)
+
+#define NINE_STATE_FB          (1 <<  0)
+#define NINE_STATE_VIEWPORT    (1 <<  1)
+#define NINE_STATE_SCISSOR     (1 <<  2)
+#define NINE_STATE_RASTERIZER  (1 <<  3)
+#define NINE_STATE_BLEND       (1 <<  4)
+#define NINE_STATE_DSA         (1 <<  5)
+#define NINE_STATE_VS          (1 <<  6)
+#define NINE_STATE_VS_CONST    (1 <<  7)
+#define NINE_STATE_PS          (1 <<  8)
+#define NINE_STATE_PS_CONST    (1 <<  9)
+#define NINE_STATE_TEXTURE     (1 << 10)
+#define NINE_STATE_SAMPLER     (1 << 11)
+#define NINE_STATE_VDECL       (1 << 12)
+#define NINE_STATE_IDXBUF      (1 << 13)
+#define NINE_STATE_PRIM        (1 << 14)
+#define NINE_STATE_MATERIAL    (1 << 15)
+#define NINE_STATE_BLEND_COLOR (1 << 16)
+#define NINE_STATE_STENCIL_REF (1 << 17)
+#define NINE_STATE_SAMPLE_MASK (1 << 18)
+#define NINE_STATE_MISC_CONST  (1 << 19)
+#define NINE_STATE_FF          (0x1f << 20)
+#define NINE_STATE_FF_VS       (0x17 << 20)
+#define NINE_STATE_FF_PS       (0x18 << 20)
+#define NINE_STATE_FF_LIGHTING (1 << 20)
+#define NINE_STATE_FF_MATERIAL (1 << 21)
+#define NINE_STATE_FF_VSTRANSF (1 << 22)
+#define NINE_STATE_FF_PSSTAGES (1 << 23)
+#define NINE_STATE_FF_OTHER    (1 << 24)
+#define NINE_STATE_ALL          0x1ffffff
+#define NINE_STATE_UNHANDLED   (1 << 25)
+
+
+#define NINE_MAX_SIMULTANEOUS_RENDERTARGETS 4
+#define NINE_MAX_CONST_F   256
+#define NINE_MAX_CONST_I   16
+#define NINE_MAX_CONST_B   16
+#define NINE_MAX_CONST_ALL 276 /* B consts count only 1/4 th */
+
+#define NINE_CONST_I_BASE(nconstf) \
+    ((nconstf)        * 4 * sizeof(float))
+#define NINE_CONST_B_BASE(nconstf) \
+    ((nconstf)        * 4 * sizeof(float) + \
+     NINE_MAX_CONST_I * 4 * sizeof(int))
+
+#define NINE_CONSTBUF_SIZE(nconstf)         \
+    ((nconstf)        * 4 * sizeof(float) + \
+     NINE_MAX_CONST_I * 4 * sizeof(int) + \
+     NINE_MAX_CONST_B * 1 * sizeof(float))
+
+
+#define NINE_MAX_LIGHTS        65536
+#define NINE_MAX_LIGHTS_ACTIVE 8
+
+#define NINED3DLIGHT_INVALID (D3DLIGHT_DIRECTIONAL + 1)
+
+#define NINE_MAX_SAMPLERS_PS 16
+#define NINE_MAX_SAMPLERS_VS  4
+#define NINE_MAX_SAMPLERS    21 /* PS + DMAP + VS */
+#define NINE_SAMPLER_PS(s)  ( 0 + (s))
+#define NINE_SAMPLER_DMAP    16
+#define NINE_SAMPLER_VS(s)  (17 + (s))
+#define NINE_PS_SAMPLERS_MASK 0x00ffff
+#define NINE_VS_SAMPLERS_MASK 0x1e0000
+
+struct nine_state
+{
+    struct {
+        uint32_t group;
+        uint32_t rs[(NINED3DRS_COUNT + 31) / 32];
+        uint32_t vtxbuf;
+        uint32_t stream_freq;
+        uint32_t texture;
+        uint16_t sampler[NINE_MAX_SAMPLERS];
+        struct nine_range *vs_const_f;
+        struct nine_range *ps_const_f;
+        uint16_t vs_const_i; /* NINE_MAX_CONST_I == 16 */
+        uint16_t ps_const_i;
+        uint16_t vs_const_b; /* NINE_MAX_CONST_B == 16 */
+        uint16_t ps_const_b;
+        uint8_t ucp;
+    } changed;
+
+    struct NineSurface9 *rt[NINE_MAX_SIMULTANEOUS_RENDERTARGETS];
+    struct NineSurface9 *ds;
+
+    D3DVIEWPORT9 viewport;
+
+    struct pipe_scissor_state scissor;
+
+    /* NOTE: vs, ps will be NULL for FF and are set in device->ff.vs,ps instead
+     *  (XXX: or is it better to reference FF shaders here, too ?)
+     * NOTE: const_f contains extra space for const_i,b to use as user constbuf
+     */
+    struct NineVertexShader9 *vs;
+    float *vs_const_f;
+    int    vs_const_i[NINE_MAX_CONST_I][4];
+    BOOL   vs_const_b[NINE_MAX_CONST_B];
+    uint32_t vs_key;
+
+    struct NinePixelShader9 *ps;
+    float *ps_const_f;
+    int    ps_const_i[NINE_MAX_CONST_I][4];
+    BOOL   ps_const_b[NINE_MAX_CONST_B];
+    uint32_t ps_key;
+
+    struct {
+        void *vs;
+        void *ps;
+    } cso;
+
+    struct NineVertexDeclaration9 *vdecl;
+
+    struct NineIndexBuffer9   *idxbuf;
+    struct NineVertexBuffer9  *stream[PIPE_MAX_ATTRIBS];
+    struct pipe_vertex_buffer  vtxbuf[PIPE_MAX_ATTRIBS];
+    UINT stream_freq[PIPE_MAX_ATTRIBS];
+    uint32_t stream_instancedata_mask; /* derived from stream_freq */
+    uint32_t stream_usage_mask; /* derived from VS and vdecl */
+
+    struct pipe_clip_state clip;
+    struct pipe_framebuffer_state fb;
+    uint8_t rt_mask;
+
+    DWORD rs[NINED3DRS_COUNT];
+
+    struct NineBaseTexture9 *texture[NINE_MAX_SAMPLERS]; /* PS, DMAP, VS */
+
+    DWORD samp[NINE_MAX_SAMPLERS][NINED3DSAMP_COUNT];
+    uint32_t samplers_shadow;
+
+    struct {
+        struct {
+            uint32_t group;
+            uint32_t tex_stage[NINE_MAX_SAMPLERS][(NINED3DTSS_COUNT + 31) / 32];
+            uint32_t transform[(NINED3DTS_COUNT + 31) / 32];
+        } changed;
+        struct {
+            boolean vs_const;
+            boolean ps_const;
+        } clobber;
+
+        D3DMATRIX *transform; /* access only via nine_state_access_transform */
+        unsigned num_transforms;
+
+        /* XXX: Do state blocks just change the set of active lights or do we
+         * have to store which lights have been disabled, too ?
+         */
+        D3DLIGHT9 *light;
+        uint16_t active_light[NINE_MAX_LIGHTS_ACTIVE]; /* 8 */
+        unsigned num_lights;
+        unsigned num_lights_active;
+
+        D3DMATERIAL9 material;
+
+        DWORD tex_stage[NINE_MAX_SAMPLERS][NINED3DTSS_COUNT];
+    } ff;
+};
+
+/* map D3DRS -> NINE_STATE_x
+ */
+extern const uint32_t nine_render_state_group[NINED3DRS_COUNT];
+
+/* for D3DSBT_PIXEL/VERTEX:
+ */
+extern const uint32_t nine_render_states_pixel[(NINED3DRS_COUNT + 31) / 32];
+extern const uint32_t nine_render_states_vertex[(NINED3DRS_COUNT + 31) / 32];
+
+struct NineDevice9;
+
+boolean nine_update_state(struct NineDevice9 *, uint32_t group_mask);
+
+void nine_state_set_defaults(struct nine_state *, const D3DCAPS9 *,
+                             boolean is_reset);
+void nine_state_clear(struct nine_state *, const boolean device);
+
+/* If @alloc is FALSE, the return value may be a const identity matrix.
+ * Therefore, do not modify if you set alloc to FALSE !
+ */
+D3DMATRIX *
+nine_state_access_transform(struct nine_state *, D3DTRANSFORMSTATETYPE,
+                            boolean alloc);
+
+const char *nine_d3drs_to_string(DWORD State);
+
+#endif /* _NINE_STATE_H_ */
diff --git a/src/gallium/state_trackers/nine/nineexoverlayextension.c b/src/gallium/state_trackers/nine/nineexoverlayextension.c
new file mode 100644 (file)
index 0000000..2253f8d
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "nineexoverlayextension.h"
+
+#define DBG_CHANNEL DBG_OVERLAYEXTENSION
+
+HRESULT WINAPI
+Nine9ExOverlayExtension_CheckDeviceOverlayType( struct Nine9ExOverlayExtension *This,
+                                                UINT Adapter,
+                                                D3DDEVTYPE DevType,
+                                                UINT OverlayWidth,
+                                                UINT OverlayHeight,
+                                                D3DFORMAT OverlayFormat,
+                                                D3DDISPLAYMODEEX *pDisplayMode,
+                                                D3DDISPLAYROTATION DisplayRotation,
+                                                D3DOVERLAYCAPS *pOverlayCaps )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+IDirect3D9ExOverlayExtensionVtbl Nine9ExOverlayExtension_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)Nine9ExOverlayExtension_CheckDeviceOverlayType
+};
diff --git a/src/gallium/state_trackers/nine/nineexoverlayextension.h b/src/gallium/state_trackers/nine/nineexoverlayextension.h
new file mode 100644 (file)
index 0000000..a16d690
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _NINE_NINEEXOVERLAYEXTENSION_H_
+#define _NINE_NINEEXOVERLAYEXTENSION_H_
+
+#include "iunknown.h"
+
+struct Nine9ExOverlayExtension
+{
+    struct NineUnknown base;
+};
+static INLINE struct Nine9ExOverlayExtension *
+Nine9ExOverlayExtension( void *data )
+{
+    return (struct Nine9ExOverlayExtension *)data;
+}
+
+HRESULT WINAPI
+Nine9ExOverlayExtension_CheckDeviceOverlayType( struct Nine9ExOverlayExtension *This,
+                                                UINT Adapter,
+                                                D3DDEVTYPE DevType,
+                                                UINT OverlayWidth,
+                                                UINT OverlayHeight,
+                                                D3DFORMAT OverlayFormat,
+                                                D3DDISPLAYMODEEX *pDisplayMode,
+                                                D3DDISPLAYROTATION DisplayRotation,
+                                                D3DOVERLAYCAPS *pOverlayCaps );
+
+#endif /* _NINE_NINEEXOVERLAYEXTENSION_H_ */
diff --git a/src/gallium/state_trackers/nine/pixelshader9.c b/src/gallium/state_trackers/nine/pixelshader9.c
new file mode 100644 (file)
index 0000000..3d68274
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "nine_helpers.h"
+#include "nine_shader.h"
+
+#include "pixelshader9.h"
+
+#include "device9.h"
+#include "pipe/p_context.h"
+
+#define DBG_CHANNEL DBG_PIXELSHADER
+
+HRESULT
+NinePixelShader9_ctor( struct NinePixelShader9 *This,
+                       struct NineUnknownParams *pParams,
+                       const DWORD *pFunction, void *cso )
+{
+    struct NineDevice9 *device;
+    struct nine_shader_info info;
+    HRESULT hr;
+
+    hr = NineUnknown_ctor(&This->base, pParams);
+    if (FAILED(hr))
+        return hr;
+
+    if (cso) {
+        This->variant.cso = cso;
+        return D3D_OK;
+    }
+    device = This->base.device;
+
+    info.type = PIPE_SHADER_FRAGMENT;
+    info.byte_code = pFunction;
+    info.const_i_base = NINE_CONST_I_BASE(device->max_ps_const_f) / 16;
+    info.const_b_base = NINE_CONST_B_BASE(device->max_ps_const_f) / 16;
+    info.sampler_mask_shadow = 0x0;
+    info.sampler_ps1xtypes = 0x0;
+
+    hr = nine_translate_shader(device, &info);
+    if (FAILED(hr))
+        return hr;
+    This->byte_code.version = info.version;
+
+    This->byte_code.tokens = mem_dup(pFunction, info.byte_size);
+    if (!This->byte_code.tokens)
+        return E_OUTOFMEMORY;
+    This->byte_code.size = info.byte_size;
+
+    This->variant.cso = info.cso;
+    This->sampler_mask = info.sampler_mask;
+    This->rt_mask = info.rt_mask;
+    This->const_used_size = info.const_used_size;
+    if (info.const_used_size == ~0)
+        This->const_used_size = NINE_CONSTBUF_SIZE(device->max_ps_const_f);
+    This->lconstf = info.lconstf;
+
+    return D3D_OK;
+}
+
+void
+NinePixelShader9_dtor( struct NinePixelShader9 *This )
+{
+    DBG("This=%p cso=%p\n", This, This->variant.cso);
+
+    if (This->base.device) {
+        struct pipe_context *pipe = This->base.device->pipe;
+        struct nine_shader_variant *var = &This->variant;
+        do {
+            if (var->cso) {
+                if (This->base.device->state.cso.ps == var->cso)
+                    pipe->bind_fs_state(pipe, NULL);
+                pipe->delete_fs_state(pipe, var->cso);
+            }
+            var = var->next;
+        } while (var);
+    }
+    nine_shader_variants_free(&This->variant);
+
+    if (This->byte_code.tokens)
+        FREE((void *)This->byte_code.tokens); /* const_cast */
+
+    FREE(This->lconstf.data);
+    FREE(This->lconstf.ranges);
+
+    NineUnknown_dtor(&This->base);
+}
+
+HRESULT WINAPI
+NinePixelShader9_GetFunction( struct NinePixelShader9 *This,
+                              void *pData,
+                              UINT *pSizeOfData )
+{
+    user_assert(pSizeOfData, D3DERR_INVALIDCALL);
+
+    if (!pData) {
+        *pSizeOfData = This->byte_code.size;
+        return D3D_OK;
+    }
+    user_assert(*pSizeOfData >= This->byte_code.size, D3DERR_INVALIDCALL);
+
+    memcpy(pData, This->byte_code.tokens, This->byte_code.size);
+
+    return D3D_OK;
+}
+
+void *
+NinePixelShader9_GetVariant( struct NinePixelShader9 *This,
+                             uint32_t key )
+{
+    void *cso = nine_shader_variant_get(&This->variant, key);
+    if (!cso) {
+        struct NineDevice9 *device = This->base.device;
+        struct nine_shader_info info;
+        HRESULT hr;
+
+        info.type = PIPE_SHADER_FRAGMENT;
+        info.const_i_base = NINE_CONST_I_BASE(device->max_ps_const_f) / 16;
+        info.const_b_base = NINE_CONST_B_BASE(device->max_ps_const_f) / 16;
+        info.byte_code = This->byte_code.tokens;
+        info.sampler_mask_shadow = key & 0xffff;
+        info.sampler_ps1xtypes = key;
+
+        hr = nine_translate_shader(This->base.device, &info);
+        if (FAILED(hr))
+            return NULL;
+        nine_shader_variant_add(&This->variant, key, info.cso);
+        cso = info.cso;
+    }
+    return cso;
+}
+
+IDirect3DPixelShader9Vtbl NinePixelShader9_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)NineUnknown_GetDevice,
+    (void *)NinePixelShader9_GetFunction
+};
+
+static const GUID *NinePixelShader9_IIDs[] = {
+    &IID_IDirect3DPixelShader9,
+    &IID_IUnknown,
+    NULL
+};
+
+HRESULT
+NinePixelShader9_new( struct NineDevice9 *pDevice,
+                      struct NinePixelShader9 **ppOut,
+                      const DWORD *pFunction, void *cso )
+{
+    NINE_DEVICE_CHILD_NEW(PixelShader9, ppOut, pDevice, pFunction, cso);
+}
diff --git a/src/gallium/state_trackers/nine/pixelshader9.h b/src/gallium/state_trackers/nine/pixelshader9.h
new file mode 100644 (file)
index 0000000..5e00b46
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _NINE_PIXELSHADER9_H_
+#define _NINE_PIXELSHADER9_H_
+
+#include "iunknown.h"
+#include "nine_shader.h"
+
+struct nine_lconstf;
+
+struct NinePixelShader9
+{
+    struct NineUnknown base;
+    struct nine_shader_variant variant;
+
+    struct {
+        const DWORD *tokens;
+        DWORD size;
+        uint8_t version; /* (major << 4) | minor */
+    } byte_code;
+
+    unsigned const_used_size; /* in bytes */
+
+    struct nine_lconstf lconstf;
+
+    uint16_t sampler_mask;
+    uint16_t sampler_mask_shadow;
+    uint8_t rt_mask;
+
+    uint64_t ff_key[6];
+};
+static INLINE struct NinePixelShader9 *
+NinePixelShader9( void *data )
+{
+    return (struct NinePixelShader9 *)data;
+}
+
+void *
+NinePixelShader9_GetVariant( struct NinePixelShader9 *vs,
+                             uint32_t key );
+
+/*** public ***/
+
+HRESULT
+NinePixelShader9_new( struct NineDevice9 *pDevice,
+                      struct NinePixelShader9 **ppOut,
+                      const DWORD *pFunction, void *cso );
+
+HRESULT
+NinePixelShader9_ctor( struct NinePixelShader9 *,
+                       struct NineUnknownParams *pParams,
+                       const DWORD *pFunction, void *cso );
+
+void
+NinePixelShader9_dtor( struct NinePixelShader9 * );
+
+HRESULT WINAPI
+NinePixelShader9_GetFunction( struct NinePixelShader9 *This,
+                              void *pData,
+                              UINT *pSizeOfData );
+
+#endif /* _NINE_PIXELSHADER9_H_ */
diff --git a/src/gallium/state_trackers/nine/query9.c b/src/gallium/state_trackers/nine/query9.c
new file mode 100644 (file)
index 0000000..86762d2
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "device9.h"
+#include "query9.h"
+#include "nine_helpers.h"
+#include "pipe/p_context.h"
+#include "util/u_math.h"
+#include "nine_dump.h"
+
+#define DBG_CHANNEL DBG_QUERY
+
+#define QUERY_TYPE_MAP_CASE(a, b) case D3DQUERYTYPE_##a: return PIPE_QUERY_##b
+static inline unsigned
+d3dquerytype_to_pipe_query(D3DQUERYTYPE type)
+{
+    switch (type) {
+    QUERY_TYPE_MAP_CASE(EVENT, GPU_FINISHED);
+    QUERY_TYPE_MAP_CASE(OCCLUSION, OCCLUSION_COUNTER);
+    QUERY_TYPE_MAP_CASE(TIMESTAMP, TIMESTAMP);
+    QUERY_TYPE_MAP_CASE(TIMESTAMPDISJOINT, TIMESTAMP_DISJOINT);
+    QUERY_TYPE_MAP_CASE(TIMESTAMPFREQ, TIMESTAMP_DISJOINT);
+    QUERY_TYPE_MAP_CASE(VERTEXSTATS, PIPELINE_STATISTICS);
+    case D3DQUERYTYPE_VCACHE:
+    case D3DQUERYTYPE_RESOURCEMANAGER:
+    case D3DQUERYTYPE_PIPELINETIMINGS:
+    case D3DQUERYTYPE_INTERFACETIMINGS:
+    case D3DQUERYTYPE_VERTEXTIMINGS:
+    case D3DQUERYTYPE_PIXELTIMINGS:
+    case D3DQUERYTYPE_BANDWIDTHTIMINGS:
+    case D3DQUERYTYPE_CACHEUTILIZATION:
+       return PIPE_QUERY_TYPES;
+    default:
+        return ~0;
+    }
+}
+
+#define GET_DATA_SIZE_CASE9(a)    case D3DQUERYTYPE_##a: return sizeof(D3DDEVINFO_D3D9##a)
+#define GET_DATA_SIZE_CASE1(a)    case D3DQUERYTYPE_##a: return sizeof(D3DDEVINFO_##a)
+#define GET_DATA_SIZE_CASE2(a, b) case D3DQUERYTYPE_##a: return sizeof(D3DDEVINFO_##b)
+#define GET_DATA_SIZE_CASET(a, b) case D3DQUERYTYPE_##a: return sizeof(b)
+static INLINE DWORD
+nine_query_result_size(D3DQUERYTYPE type)
+{
+    switch (type) {
+    GET_DATA_SIZE_CASE1(VCACHE);
+    GET_DATA_SIZE_CASE1(RESOURCEMANAGER);
+    GET_DATA_SIZE_CASE2(VERTEXSTATS, D3DVERTEXSTATS);
+    GET_DATA_SIZE_CASET(EVENT, BOOL);
+    GET_DATA_SIZE_CASET(OCCLUSION, DWORD);
+    GET_DATA_SIZE_CASET(TIMESTAMP, UINT64);
+    GET_DATA_SIZE_CASET(TIMESTAMPDISJOINT, BOOL);
+    GET_DATA_SIZE_CASET(TIMESTAMPFREQ, UINT64);
+    GET_DATA_SIZE_CASE9(PIPELINETIMINGS);
+    GET_DATA_SIZE_CASE9(INTERFACETIMINGS);
+    GET_DATA_SIZE_CASE2(VERTEXTIMINGS, D3D9STAGETIMINGS);
+    GET_DATA_SIZE_CASE2(PIXELTIMINGS, D3D9STAGETIMINGS);
+    GET_DATA_SIZE_CASE9(BANDWIDTHTIMINGS);
+    GET_DATA_SIZE_CASE9(CACHEUTILIZATION);
+    /* GET_DATA_SIZE_CASE1(MEMORYPRESSURE); Win7 only */
+    default:
+        assert(0);
+        return 0;
+    }
+}
+
+HRESULT
+nine_is_query_supported(D3DQUERYTYPE type)
+{
+    const unsigned ptype = d3dquerytype_to_pipe_query(type);
+
+    user_assert(ptype != ~0, D3DERR_INVALIDCALL);
+
+    if (ptype == PIPE_QUERY_TYPES) {
+        DBG("Query type %u (%s) not supported.\n",
+            type, nine_D3DQUERYTYPE_to_str(type));
+        return D3DERR_NOTAVAILABLE;
+    }
+    return D3D_OK;
+}
+
+HRESULT
+NineQuery9_ctor( struct NineQuery9 *This,
+                 struct NineUnknownParams *pParams,
+                 D3DQUERYTYPE Type )
+{
+    struct pipe_context *pipe = pParams->device->pipe;
+    const unsigned ptype = d3dquerytype_to_pipe_query(Type);
+    HRESULT hr;
+
+    hr = NineUnknown_ctor(&This->base, pParams);
+    if (FAILED(hr))
+        return hr;
+
+    This->state = NINE_QUERY_STATE_FRESH;
+    This->type = Type;
+
+    user_assert(ptype != ~0, D3DERR_INVALIDCALL);
+
+    if (ptype < PIPE_QUERY_TYPES) {
+        This->pq = pipe->create_query(pipe, ptype, 0);
+        if (!This->pq)
+            return E_OUTOFMEMORY;
+    } else {
+        DBG("Returning dummy NineQuery9 for %s.\n",
+            nine_D3DQUERYTYPE_to_str(Type));
+    }
+
+    This->instant =
+        Type == D3DQUERYTYPE_EVENT ||
+        Type == D3DQUERYTYPE_RESOURCEMANAGER ||
+        Type == D3DQUERYTYPE_TIMESTAMP ||
+        Type == D3DQUERYTYPE_TIMESTAMPFREQ ||
+        Type == D3DQUERYTYPE_VCACHE ||
+        Type == D3DQUERYTYPE_VERTEXSTATS;
+
+    This->result_size = nine_query_result_size(Type);
+
+    return D3D_OK;
+}
+
+void
+NineQuery9_dtor( struct NineQuery9 *This )
+{
+    struct pipe_context *pipe = This->base.device->pipe;
+
+    if (This->pq) {
+        if (This->state == NINE_QUERY_STATE_RUNNING)
+            pipe->end_query(pipe, This->pq);
+        pipe->destroy_query(pipe, This->pq);
+    }
+
+    NineUnknown_dtor(&This->base);
+}
+
+D3DQUERYTYPE WINAPI
+NineQuery9_GetType( struct NineQuery9 *This )
+{
+    return This->type;
+}
+
+DWORD WINAPI
+NineQuery9_GetDataSize( struct NineQuery9 *This )
+{
+    return This->result_size;
+}
+
+HRESULT WINAPI
+NineQuery9_Issue( struct NineQuery9 *This,
+                  DWORD dwIssueFlags )
+{
+    struct pipe_context *pipe = This->base.device->pipe;
+
+    user_assert((dwIssueFlags == D3DISSUE_BEGIN && !This->instant) ||
+                (dwIssueFlags == 0) ||
+                (dwIssueFlags == D3DISSUE_END), D3DERR_INVALIDCALL);
+
+    if (!This->pq) {
+        DBG("Issued dummy query.\n");
+        return D3D_OK;
+    }
+
+    if (dwIssueFlags == D3DISSUE_BEGIN) {
+        if (This->state == NINE_QUERY_STATE_RUNNING) {
+           pipe->end_query(pipe, This->pq);
+       }
+        pipe->begin_query(pipe, This->pq);
+        This->state = NINE_QUERY_STATE_RUNNING;
+    } else {
+        if (This->state == NINE_QUERY_STATE_RUNNING) {
+            pipe->end_query(pipe, This->pq);
+            This->state = NINE_QUERY_STATE_ENDED;
+       }
+    }
+    return D3D_OK;
+}
+
+union nine_query_result
+{
+    D3DDEVINFO_D3DVERTEXSTATS vertexstats;
+    D3DDEVINFO_D3D9BANDWIDTHTIMINGS bandwidth;
+    D3DDEVINFO_VCACHE vcache;
+    D3DDEVINFO_RESOURCEMANAGER rm;
+    D3DDEVINFO_D3D9PIPELINETIMINGS pipe;
+    D3DDEVINFO_D3D9STAGETIMINGS stage;
+    D3DDEVINFO_D3D9INTERFACETIMINGS iface;
+    D3DDEVINFO_D3D9CACHEUTILIZATION cacheu;
+    DWORD dw;
+    BOOL b;
+    UINT64 u64;
+};
+
+HRESULT WINAPI
+NineQuery9_GetData( struct NineQuery9 *This,
+                    void *pData,
+                    DWORD dwSize,
+                    DWORD dwGetDataFlags )
+{
+    struct pipe_context *pipe = This->base.device->pipe;
+    boolean ok = !This->pq;
+    unsigned i;
+    union pipe_query_result presult;
+    union nine_query_result nresult;
+
+    user_assert(This->state != NINE_QUERY_STATE_RUNNING, D3DERR_INVALIDCALL);
+    user_assert(dwSize == 0 || pData, D3DERR_INVALIDCALL);
+    user_assert(dwGetDataFlags == 0 ||
+                dwGetDataFlags == D3DGETDATA_FLUSH, D3DERR_INVALIDCALL);
+
+    if (!This->pq) {
+        DBG("No pipe query available.\n");
+        if (!dwSize)
+           return S_OK;
+    }
+    if (This->state == NINE_QUERY_STATE_FRESH)
+        return S_OK;
+
+    if (!ok) {
+        ok = pipe->get_query_result(pipe, This->pq, FALSE, &presult);
+        if (!ok) {
+            if (dwGetDataFlags) {
+                if (This->state != NINE_QUERY_STATE_FLUSHED)
+                    pipe->flush(pipe, NULL, 0);
+                This->state = NINE_QUERY_STATE_FLUSHED;
+            }
+            return S_FALSE;
+        }
+    }
+    if (!dwSize)
+        return S_OK;
+
+    switch (This->type) {
+    case D3DQUERYTYPE_EVENT:
+        nresult.b = presult.b;
+        break;
+    case D3DQUERYTYPE_OCCLUSION:
+        nresult.dw = presult.u64;
+        break;
+    case D3DQUERYTYPE_TIMESTAMP:
+        nresult.u64 = presult.u64;
+        break;
+    case D3DQUERYTYPE_TIMESTAMPDISJOINT:
+        nresult.b = presult.timestamp_disjoint.disjoint;
+        break;
+    case D3DQUERYTYPE_TIMESTAMPFREQ:
+        nresult.u64 = presult.timestamp_disjoint.frequency;
+        break;
+    case D3DQUERYTYPE_VERTEXSTATS:
+        nresult.vertexstats.NumRenderedTriangles =
+            presult.pipeline_statistics.c_invocations;
+        nresult.vertexstats.NumExtraClippingTriangles =
+            presult.pipeline_statistics.c_primitives;
+        break;
+    /* Thse might be doable with driver-specific queries; dummy for now. */
+    case D3DQUERYTYPE_BANDWIDTHTIMINGS:
+        nresult.bandwidth.MaxBandwidthUtilized = 1.0f;
+        nresult.bandwidth.FrontEndUploadMemoryUtilizedPercent = 0.5f;
+        nresult.bandwidth.VertexRateUtilizedPercent = 0.75f;
+        nresult.bandwidth.TriangleSetupRateUtilizedPercent = 0.75f;
+        nresult.bandwidth.FillRateUtilizedPercent = 1.0f;
+        break;
+    case D3DQUERYTYPE_VERTEXTIMINGS:
+    case D3DQUERYTYPE_PIXELTIMINGS:
+        nresult.stage.MemoryProcessingPercent = 0.5f;
+        nresult.stage.ComputationProcessingPercent = 0.5f;
+        break;
+    case D3DQUERYTYPE_VCACHE:
+        /* Are we supposed to fill this in ? */
+        nresult.vcache.Pattern = MAKEFOURCC('C', 'A', 'C', 'H');
+        nresult.vcache.OptMethod = 1;
+        nresult.vcache.CacheSize = 32 << 10;
+        nresult.vcache.MagicNumber = 0xdeadcafe;
+        break;
+    case D3DQUERYTYPE_RESOURCEMANAGER:
+        /* We could record some of these in the device ... */
+        for (i = 0; i < D3DRTYPECOUNT; ++i) {
+            nresult.rm.stats[i].bThrashing = FALSE;
+            nresult.rm.stats[i].ApproxBytesDownloaded = 0;
+            nresult.rm.stats[i].NumEvicts = 0;
+            nresult.rm.stats[i].NumVidCreates = 0;
+            nresult.rm.stats[i].LastPri = 0;
+            nresult.rm.stats[i].NumUsed = 1;
+            nresult.rm.stats[i].NumUsedInVidMem = 1;
+            nresult.rm.stats[i].WorkingSet = 1;
+            nresult.rm.stats[i].WorkingSetBytes = 1 << 20;
+            nresult.rm.stats[i].TotalManaged = 1;
+            nresult.rm.stats[i].TotalBytes = 1 << 20;
+        }
+        break;
+    case D3DQUERYTYPE_PIPELINETIMINGS:
+        nresult.pipe.VertexProcessingTimePercent = 0.4f;
+        nresult.pipe.PixelProcessingTimePercent = 0.4f;
+        nresult.pipe.OtherGPUProcessingTimePercent = 0.15f;
+        nresult.pipe.GPUIdleTimePercent = 0.05f;
+        break;
+    case D3DQUERYTYPE_INTERFACETIMINGS:
+        nresult.iface.WaitingForGPUToUseApplicationResourceTimePercent = 0.0f;
+        nresult.iface.WaitingForGPUToAcceptMoreCommandsTimePercent = 0.0f;
+        nresult.iface.WaitingForGPUToStayWithinLatencyTimePercent = 0.0f;
+        nresult.iface.WaitingForGPUExclusiveResourceTimePercent = 0.0f;
+        nresult.iface.WaitingForGPUOtherTimePercent = 0.0f;
+        break;
+    case D3DQUERYTYPE_CACHEUTILIZATION:
+        nresult.cacheu.TextureCacheHitRate = 0.9f;
+        nresult.cacheu.PostTransformVertexCacheHitRate = 0.3f;
+        break;
+    default:
+        assert(0);
+        break;
+    }
+    memcpy(pData, &nresult, MIN2(sizeof(nresult), dwSize));
+
+    return S_OK;
+}
+
+IDirect3DQuery9Vtbl NineQuery9_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)NineUnknown_GetDevice, /* actually part of Query9 iface */
+    (void *)NineQuery9_GetType,
+    (void *)NineQuery9_GetDataSize,
+    (void *)NineQuery9_Issue,
+    (void *)NineQuery9_GetData
+};
+
+static const GUID *NineQuery9_IIDs[] = {
+    &IID_IDirect3DQuery9,
+    &IID_IUnknown,
+    NULL
+};
+
+HRESULT
+NineQuery9_new( struct NineDevice9 *pDevice,
+                struct NineQuery9 **ppOut,
+                D3DQUERYTYPE Type )
+{
+    NINE_DEVICE_CHILD_NEW(Query9, ppOut, pDevice, Type);
+}
diff --git a/src/gallium/state_trackers/nine/query9.h b/src/gallium/state_trackers/nine/query9.h
new file mode 100644 (file)
index 0000000..f08393f
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _NINE_QUERY9_H_
+#define _NINE_QUERY9_H_
+
+#include "iunknown.h"
+
+enum nine_query_state
+{
+    NINE_QUERY_STATE_FRESH = 0,
+    NINE_QUERY_STATE_RUNNING,
+    NINE_QUERY_STATE_ENDED,
+    NINE_QUERY_STATE_FLUSHED
+};
+
+struct NineQuery9
+{
+    struct NineUnknown base;
+    struct pipe_query *pq;
+    DWORD result_size;
+    D3DQUERYTYPE type;
+    enum nine_query_state state;
+    boolean instant; /* true if D3DISSUE_BEGIN is not needed / invalid */
+};
+static INLINE struct NineQuery9 *
+NineQuery9( void *data )
+{
+    return (struct NineQuery9 *)data;
+}
+
+HRESULT
+nine_is_query_supported(D3DQUERYTYPE);
+
+HRESULT
+NineQuery9_new( struct NineDevice9 *Device,
+                struct NineQuery9 **ppOut,
+                D3DQUERYTYPE);
+
+HRESULT
+NineQuery9_ctor( struct NineQuery9 *,
+                 struct NineUnknownParams *pParams,
+                 D3DQUERYTYPE Type );
+
+void
+NineQuery9_dtor( struct NineQuery9 * );
+
+D3DQUERYTYPE WINAPI
+NineQuery9_GetType( struct NineQuery9 *This );
+
+DWORD WINAPI
+NineQuery9_GetDataSize( struct NineQuery9 *This );
+
+HRESULT WINAPI
+NineQuery9_Issue( struct NineQuery9 *This,
+                  DWORD dwIssueFlags );
+
+HRESULT WINAPI
+NineQuery9_GetData( struct NineQuery9 *This,
+                    void *pData,
+                    DWORD dwSize,
+                    DWORD dwGetDataFlags );
+
+#endif /* _NINE_QUERY9_H_ */
diff --git a/src/gallium/state_trackers/nine/resource9.c b/src/gallium/state_trackers/nine/resource9.c
new file mode 100644 (file)
index 0000000..8f53558
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "resource9.h"
+#include "device9.h"
+#include "nine_helpers.h"
+#include "nine_defines.h"
+
+#include "pipe/p_screen.h"
+
+#include "util/u_hash_table.h"
+#include "util/u_inlines.h"
+
+#include "nine_pdata.h"
+
+#define DBG_CHANNEL DBG_RESOURCE
+
+
+HRESULT
+NineResource9_ctor( struct NineResource9 *This,
+                    struct NineUnknownParams *pParams,
+                    BOOL Allocate,
+                    D3DRESOURCETYPE Type,
+                    D3DPOOL Pool )
+{
+    struct pipe_screen *screen;
+    HRESULT hr;
+
+    hr = NineUnknown_ctor(&This->base, pParams);
+    if (FAILED(hr))
+        return hr;
+
+    This->info.screen = screen = This->base.device->screen;
+
+    if (Allocate) {
+        DBG("(%p) Creating pipe_resource.\n", This);
+        This->resource = screen->resource_create(screen, &This->info);
+        if (!This->resource)
+            return D3DERR_OUTOFVIDEOMEMORY;
+    }
+
+    This->data = NULL; /* FIXME remove, rather set it to null in surface9.c*/
+    This->type = Type;
+    This->pool = Pool;
+    This->priority = 0;
+
+    This->pdata = util_hash_table_create(ht_guid_hash, ht_guid_compare);
+    if (!This->pdata)
+        return E_OUTOFMEMORY;
+
+    return D3D_OK;
+}
+
+void
+NineResource9_dtor( struct NineResource9 *This )
+{
+    if (This->pdata) {
+        util_hash_table_foreach(This->pdata, ht_guid_delete, NULL);
+        util_hash_table_destroy(This->pdata);
+    }
+
+    /* NOTE: We do have to use refcounting, the driver might
+     * still hold a reference. */
+    pipe_resource_reference(&This->resource, NULL);
+
+    /* release allocated system memory for non-D3DPOOL_DEFAULT resources */
+    if (This->data)
+        FREE(This->data);
+
+    NineUnknown_dtor(&This->base);
+}
+
+struct pipe_resource *
+NineResource9_GetResource( struct NineResource9 *This )
+{
+    return This->resource;
+}
+
+D3DPOOL
+NineResource9_GetPool( struct NineResource9 *This )
+{
+    return This->pool;
+}
+
+HRESULT WINAPI
+NineResource9_SetPrivateData( struct NineResource9 *This,
+                              REFGUID refguid,
+                              const void *pData,
+                              DWORD SizeOfData,
+                              DWORD Flags )
+{
+    enum pipe_error err;
+    struct pheader *header;
+    const void *user_data = pData;
+
+    DBG("This=%p refguid=%p pData=%p SizeOfData=%u Flags=%x\n",
+        This, refguid, pData, SizeOfData, Flags);
+
+    if (Flags & D3DSPD_IUNKNOWN)
+        user_assert(SizeOfData == sizeof(IUnknown *), D3DERR_INVALIDCALL);
+
+    /* data consists of a header and the actual data. avoiding 2 mallocs */
+    header = CALLOC_VARIANT_LENGTH_STRUCT(pheader, SizeOfData-1);
+    if (!header) { return E_OUTOFMEMORY; }
+    header->unknown = (Flags & D3DSPD_IUNKNOWN) ? TRUE : FALSE;
+
+    /* if the refguid already exists, delete it */
+    NineResource9_FreePrivateData(This, refguid);
+
+    /* IUnknown special case */
+    if (header->unknown) {
+        /* here the pointer doesn't point to the data we want, so point at the
+         * pointer making what we eventually copy is the pointer itself */
+        user_data = &pData;
+    }
+
+    header->size = SizeOfData;
+    memcpy(header->data, user_data, header->size);
+
+    err = util_hash_table_set(This->pdata, refguid, header);
+    if (err == PIPE_OK) {
+        if (header->unknown) { IUnknown_AddRef(*(IUnknown **)header->data); }
+        return D3D_OK;
+    }
+
+    FREE(header);
+    if (err == PIPE_ERROR_OUT_OF_MEMORY) { return E_OUTOFMEMORY; }
+
+    return D3DERR_DRIVERINTERNALERROR;
+}
+
+HRESULT WINAPI
+NineResource9_GetPrivateData( struct NineResource9 *This,
+                              REFGUID refguid,
+                              void *pData,
+                              DWORD *pSizeOfData )
+{
+    struct pheader *header;
+
+    DBG("This=%p refguid=%p pData=%p pSizeOfData=%p\n",
+        This, refguid, pData, pSizeOfData);
+
+    user_assert(pSizeOfData, E_POINTER);
+
+    header = util_hash_table_get(This->pdata, refguid);
+    if (!header) { return D3DERR_NOTFOUND; }
+
+    if (!pData) {
+        *pSizeOfData = header->size;
+        return D3D_OK;
+    }
+    if (*pSizeOfData < header->size) {
+        return D3DERR_MOREDATA;
+    }
+
+    if (header->unknown) { IUnknown_AddRef(*(IUnknown **)header->data); }
+    memcpy(pData, header->data, header->size);
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineResource9_FreePrivateData( struct NineResource9 *This,
+                               REFGUID refguid )
+{
+    struct pheader *header;
+
+    DBG("This=%p refguid=%p\n", This, refguid);
+
+    header = util_hash_table_get(This->pdata, refguid);
+    if (!header)
+        return D3DERR_NOTFOUND;
+
+    ht_guid_delete(NULL, header, NULL);
+    util_hash_table_remove(This->pdata, refguid);
+
+    return D3D_OK;
+}
+
+DWORD WINAPI
+NineResource9_SetPriority( struct NineResource9 *This,
+                           DWORD PriorityNew )
+{
+    DWORD prev = This->priority;
+    This->priority = PriorityNew;
+    return prev;
+}
+
+DWORD WINAPI
+NineResource9_GetPriority( struct NineResource9 *This )
+{
+    return This->priority;
+}
+
+/* NOTE: Don't forget to adjust locked vtable if you change this ! */
+void WINAPI
+NineResource9_PreLoad( struct NineResource9 *This )
+{
+    if (This->pool != D3DPOOL_MANAGED)
+        return;
+    /* We don't treat managed vertex or index buffers different from
+     * default ones (are managed vertex buffers even allowed ?), and
+     * the PreLoad for textures is overridden by superclass.
+     */
+}
+
+D3DRESOURCETYPE WINAPI
+NineResource9_GetType( struct NineResource9 *This )
+{
+    return This->type;
+}
diff --git a/src/gallium/state_trackers/nine/resource9.h b/src/gallium/state_trackers/nine/resource9.h
new file mode 100644 (file)
index 0000000..0451498
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _NINE_RESOURCE9_H_
+#define _NINE_RESOURCE9_H_
+
+#include "iunknown.h"
+#include "pipe/p_state.h"
+
+struct pipe_screen;
+struct util_hash_table;
+struct NineDevice9;
+
+struct NineResource9
+{
+    struct NineUnknown base;
+
+    struct pipe_resource *resource; /* device resource */
+
+    uint8_t *data; /* system memory backing */
+
+    D3DRESOURCETYPE type;
+    D3DPOOL pool;
+    DWORD priority;
+    DWORD usage;
+
+    struct pipe_resource info; /* resource configuration */
+
+    /* for [GS]etPrivateData/FreePrivateData */
+    struct util_hash_table *pdata;
+};
+static INLINE struct NineResource9 *
+NineResource9( void *data )
+{
+    return (struct NineResource9 *)data;
+}
+
+HRESULT
+NineResource9_ctor( struct NineResource9 *This,
+                    struct NineUnknownParams *pParams,
+                    BOOL Allocate,
+                    D3DRESOURCETYPE Type,
+                    D3DPOOL Pool );
+
+void
+NineResource9_dtor( struct NineResource9 *This );
+
+/*** Nine private methods ***/
+
+struct pipe_resource *
+NineResource9_GetResource( struct NineResource9 *This );
+
+D3DPOOL
+NineResource9_GetPool( struct NineResource9 *This );
+
+/*** Direct3D public methods ***/
+
+HRESULT WINAPI
+NineResource9_SetPrivateData( struct NineResource9 *This,
+                              REFGUID refguid,
+                              const void *pData,
+                              DWORD SizeOfData,
+                              DWORD Flags );
+
+HRESULT WINAPI
+NineResource9_GetPrivateData( struct NineResource9 *This,
+                              REFGUID refguid,
+                              void *pData,
+                              DWORD *pSizeOfData );
+
+HRESULT WINAPI
+NineResource9_FreePrivateData( struct NineResource9 *This,
+                               REFGUID refguid );
+
+DWORD WINAPI
+NineResource9_SetPriority( struct NineResource9 *This,
+                           DWORD PriorityNew );
+
+DWORD WINAPI
+NineResource9_GetPriority( struct NineResource9 *This );
+
+void WINAPI
+NineResource9_PreLoad( struct NineResource9 *This );
+
+D3DRESOURCETYPE WINAPI
+NineResource9_GetType( struct NineResource9 *This );
+
+#endif /* _NINE_RESOURCE9_H_ */
diff --git a/src/gallium/state_trackers/nine/stateblock9.c b/src/gallium/state_trackers/nine/stateblock9.c
new file mode 100644 (file)
index 0000000..ffe4ab2
--- /dev/null
@@ -0,0 +1,533 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "stateblock9.h"
+#include "device9.h"
+#include "basetexture9.h"
+#include "nine_helpers.h"
+
+#define DBG_CHANNEL DBG_STATEBLOCK
+
+/* XXX TODO: handling of lights is broken */
+
+HRESULT
+NineStateBlock9_ctor( struct NineStateBlock9 *This,
+                      struct NineUnknownParams *pParams,
+                      enum nine_stateblock_type type )
+{
+    HRESULT hr = NineUnknown_ctor(&This->base, pParams);
+    if (FAILED(hr))
+        return hr;
+
+    This->type = type;
+
+    This->state.vs_const_f = MALLOC(pParams->device->constbuf_vs->width0);
+    This->state.ps_const_f = MALLOC(pParams->device->constbuf_ps->width0);
+    if (!This->state.vs_const_f || !This->state.ps_const_f)
+        return E_OUTOFMEMORY;
+
+    return D3D_OK;
+}
+
+void
+NineStateBlock9_dtor( struct NineStateBlock9 *This )
+{
+    struct nine_state *state = &This->state;
+    struct nine_range *r;
+    struct nine_range_pool *pool = &This->base.device->range_pool;
+
+    nine_state_clear(state, FALSE);
+
+    if (state->vs_const_f) FREE(state->vs_const_f);
+    if (state->ps_const_f) FREE(state->ps_const_f);
+
+    if (state->ff.light) FREE(state->ff.light);
+
+    if (state->ff.transform) FREE(state->ff.transform);
+
+    if (This->state.changed.ps_const_f) {
+        for (r = This->state.changed.ps_const_f; r->next; r = r->next);
+        nine_range_pool_put_chain(pool, This->state.changed.ps_const_f, r);
+    }
+    if (This->state.changed.vs_const_f) {
+        for (r = This->state.changed.vs_const_f; r->next; r = r->next);
+        nine_range_pool_put_chain(pool, This->state.changed.vs_const_f, r);
+    }
+
+    NineUnknown_dtor(&This->base);
+}
+
+/* Copy state marked changed in @mask from @src to @dst.
+ * If @apply is false, updating dst->changed can be omitted.
+ * TODO: compare ?
+ */
+static void
+nine_state_copy_common(struct nine_state *dst,
+                       const struct nine_state *src,
+                       struct nine_state *mask, /* aliases either src or dst */
+                       const boolean apply,
+                       struct nine_range_pool *pool)
+{
+    unsigned i, s;
+
+    if (apply)
+       dst->changed.group |= mask->changed.group;
+
+    if (mask->changed.group & NINE_STATE_VIEWPORT)
+        dst->viewport = src->viewport;
+    if (mask->changed.group & NINE_STATE_SCISSOR)
+        dst->scissor = src->scissor;
+
+    if (mask->changed.group & NINE_STATE_VS)
+        nine_bind(&dst->vs, src->vs);
+    if (mask->changed.group & NINE_STATE_PS)
+        nine_bind(&dst->ps, src->ps);
+
+    /* Vertex constants.
+     *
+     * Various possibilities for optimization here, like creating a per-SB
+     * constant buffer, or memcmp'ing for changes.
+     * Will do that later depending on what works best for specific apps.
+     */
+    if (mask->changed.group & NINE_STATE_VS_CONST) {
+        struct nine_range *r;
+        for (r = mask->changed.vs_const_f; r; r = r->next) {
+            memcpy(&dst->vs_const_f[r->bgn * 4],
+                   &src->vs_const_f[r->bgn * 4],
+                   (r->end - r->bgn) * 4 * sizeof(float));
+            if (apply)
+                nine_ranges_insert(&dst->changed.vs_const_f, r->bgn, r->end,
+                                   pool);
+        }
+        if (mask->changed.vs_const_i) {
+            uint16_t m = mask->changed.vs_const_i;
+            for (i = ffs(m) - 1, m >>= i; m; ++i, m >>= 1)
+                if (m & 1)
+                    memcpy(dst->vs_const_i[i], src->vs_const_i[i], 4 * sizeof(int));
+            if (apply)
+                dst->changed.vs_const_i |= mask->changed.vs_const_i;
+        }
+        if (mask->changed.vs_const_b) {
+            uint16_t m = mask->changed.vs_const_b;
+            for (i = ffs(m) - 1, m >>= i; m; ++i, m >>= 1)
+                if (m & 1)
+                    dst->vs_const_b[i] = src->vs_const_b[i];
+            if (apply)
+                dst->changed.vs_const_b |= mask->changed.vs_const_b;
+        }
+    }
+
+    /* Pixel constants. */
+    if (mask->changed.group & NINE_STATE_PS_CONST) {
+        struct nine_range *r;
+        for (r = mask->changed.ps_const_f; r; r = r->next) {
+            memcpy(&dst->ps_const_f[r->bgn * 4],
+                   &src->ps_const_f[r->bgn * 4],
+                   (r->end - r->bgn) * 4 * sizeof(float));
+            if (apply)
+                nine_ranges_insert(&dst->changed.ps_const_f, r->bgn, r->end,
+                                   pool);
+        }
+        if (mask->changed.ps_const_i) {
+            uint16_t m = mask->changed.ps_const_i;
+            for (i = ffs(m) - 1, m >>= i; m; ++i, m >>= 1)
+                if (m & 1)
+                    memcpy(dst->ps_const_i[i], src->ps_const_i[i], 4 * sizeof(int));
+            if (apply)
+                dst->changed.ps_const_i |= mask->changed.ps_const_i;
+        }
+        if (mask->changed.ps_const_b) {
+            uint16_t m = mask->changed.ps_const_b;
+            for (i = ffs(m) - 1, m >>= i; m; ++i, m >>= 1)
+                if (m & 1)
+                    dst->ps_const_b[i] = src->ps_const_b[i];
+            if (apply)
+                dst->changed.ps_const_b |= mask->changed.ps_const_b;
+        }
+    }
+
+    /* Render states.
+     * TODO: Maybe build a list ?
+     */
+    for (i = 0; i < Elements(dst->changed.rs); ++i) {
+        uint32_t m = mask->changed.rs[i];
+        if (apply)
+            dst->changed.rs[i] |= m;
+        while (m) {
+            const int r = ffs(m) - 1;
+            m &= ~(1 << r);
+            dst->rs[i * 32 + r] = src->rs[i * 32 + r];
+        }
+    }
+
+
+    /* Clip planes. */
+    if (mask->changed.ucp) {
+        for (i = 0; i < PIPE_MAX_CLIP_PLANES; ++i)
+            if (mask->changed.ucp & (1 << i))
+                memcpy(dst->clip.ucp[i],
+                       src->clip.ucp[i], sizeof(src->clip.ucp[0]));
+        if (apply)
+           dst->changed.ucp |= mask->changed.ucp;
+    }
+
+    /* Sampler state. */
+    if (mask->changed.group & NINE_STATE_SAMPLER) {
+        for (s = 0; s < NINE_MAX_SAMPLERS; ++s) {
+            if (mask->changed.sampler[s] == 0x3ffe) {
+                memcpy(&dst->samp[s], &src->samp[s], sizeof(dst->samp[s]));
+            } else {
+                uint32_t m = mask->changed.sampler[s];
+                while (m) {
+                    const int i = ffs(m) - 1;
+                    m &= ~(1 << i);
+                    dst->samp[s][i] = src->samp[s][i];
+                }
+            }
+            if (apply)
+                dst->changed.sampler[s] |= mask->changed.sampler[s];
+        }
+    }
+
+    /* Index buffer. */
+    if (mask->changed.group & NINE_STATE_IDXBUF)
+        nine_bind(&dst->idxbuf, src->idxbuf);
+
+    /* Vertex streams. */
+    if (mask->changed.vtxbuf | mask->changed.stream_freq) {
+        uint32_t m = mask->changed.vtxbuf | mask->changed.stream_freq;
+        for (i = 0; m; ++i, m >>= 1) {
+            if (mask->changed.vtxbuf & (1 << i)) {
+                nine_bind(&dst->stream[i], src->stream[i]);
+                if (src->stream[i]) {
+                    dst->vtxbuf[i].buffer_offset = src->vtxbuf[i].buffer_offset;
+                    dst->vtxbuf[i].buffer = src->vtxbuf[i].buffer;
+                    dst->vtxbuf[i].stride = src->vtxbuf[i].stride;
+                }
+            }
+            if (mask->changed.stream_freq & (1 << i))
+                dst->stream_freq[i] = src->stream_freq[i];
+        }
+        dst->stream_instancedata_mask &= ~mask->changed.stream_freq;
+        dst->stream_instancedata_mask |=
+            src->stream_instancedata_mask & mask->changed.stream_freq;
+        if (apply) {
+            dst->changed.vtxbuf |= mask->changed.vtxbuf;
+            dst->changed.stream_freq |= mask->changed.stream_freq;
+        }
+    }
+
+    if (!(mask->changed.group & NINE_STATE_FF))
+        return;
+    WARN_ONCE("Fixed function state not handled properly by StateBlocks.\n");
+
+    /* Fixed function state. */
+    if (apply)
+        dst->ff.changed.group |= src->ff.changed.group;
+
+    if (mask->changed.group & NINE_STATE_FF_MATERIAL)
+        dst->ff.material = src->ff.material;
+
+    if (mask->changed.group & NINE_STATE_FF_PSSTAGES) {
+        for (s = 0; s < NINE_MAX_SAMPLERS; ++s) {
+            for (i = 0; i < NINED3DTSS_COUNT; ++i)
+                if (mask->ff.changed.tex_stage[s][i / 32] & (1 << (i % 32)))
+                    dst->ff.tex_stage[s][i] = src->ff.tex_stage[s][i];
+            if (apply) {
+                /* TODO: it's 32 exactly, just offset by 1 as 0 is unused */
+                dst->ff.changed.tex_stage[s][0] |=
+                    mask->ff.changed.tex_stage[s][0];
+                dst->ff.changed.tex_stage[s][1] |=
+                    mask->ff.changed.tex_stage[s][1];
+            }
+        }
+    }
+    if (mask->changed.group & NINE_STATE_FF_LIGHTING) {
+        if (dst->ff.num_lights < mask->ff.num_lights) {
+            dst->ff.light = REALLOC(dst->ff.light,
+                                    dst->ff.num_lights * sizeof(D3DLIGHT9),
+                                    mask->ff.num_lights * sizeof(D3DLIGHT9));
+            dst->ff.num_lights = mask->ff.num_lights;
+        }
+        for (i = 0; i < mask->ff.num_lights; ++i)
+            if (mask->ff.light[i].Type != NINED3DLIGHT_INVALID)
+                dst->ff.light[i] = src->ff.light[i];
+
+        DBG("TODO: active lights\n");
+    }
+    if (mask->changed.group & NINE_STATE_FF_VSTRANSF) {
+        for (i = 0; i < Elements(mask->ff.changed.transform); ++i) {
+            if (!mask->ff.changed.transform[i])
+                continue;
+            for (s = i * 32; s < (i * 32 + 32); ++s) {
+                if (!(mask->ff.changed.transform[i] & (1 << (s % 32))))
+                    continue;
+                *nine_state_access_transform(dst, s, TRUE) =
+                    *nine_state_access_transform( /* const because !alloc */
+                        (struct nine_state *)src, s, FALSE);
+            }
+            if (apply)
+                dst->ff.changed.transform[i] |= mask->ff.changed.transform[i];
+        }
+    }
+}
+
+static void
+nine_state_copy_common_all(struct nine_state *dst,
+                           const struct nine_state *src,
+                           struct nine_state *help,
+                           const boolean apply,
+                           struct nine_range_pool *pool,
+                           const int MaxStreams)
+{
+    unsigned i;
+
+    if (apply)
+       dst->changed.group |= src->changed.group;
+
+    dst->viewport = src->viewport;
+    dst->scissor = src->scissor;
+
+    nine_bind(&dst->vs, src->vs);
+    nine_bind(&dst->ps, src->ps);
+
+    /* Vertex constants.
+     *
+     * Various possibilities for optimization here, like creating a per-SB
+     * constant buffer, or memcmp'ing for changes.
+     * Will do that later depending on what works best for specific apps.
+     */
+    if (1) {
+        struct nine_range *r = help->changed.vs_const_f;
+        memcpy(&dst->vs_const_f[0],
+               &src->vs_const_f[0], (r->end - r->bgn) * 4 * sizeof(float));
+        if (apply)
+            nine_ranges_insert(&dst->changed.vs_const_f, r->bgn, r->end, pool);
+
+        memcpy(dst->vs_const_i, src->vs_const_i, sizeof(dst->vs_const_i));
+        memcpy(dst->vs_const_b, src->vs_const_b, sizeof(dst->vs_const_b));
+        if (apply) {
+            dst->changed.vs_const_i |= src->changed.vs_const_i;
+            dst->changed.vs_const_b |= src->changed.vs_const_b;
+        }
+    }
+
+    /* Pixel constants. */
+    if (1) {
+        struct nine_range *r = help->changed.ps_const_f;
+        memcpy(&dst->ps_const_f[0],
+               &src->ps_const_f[0], (r->end - r->bgn) * 4 * sizeof(float));
+        if (apply)
+            nine_ranges_insert(&dst->changed.ps_const_f, r->bgn, r->end, pool);
+
+        memcpy(dst->ps_const_i, src->ps_const_i, sizeof(dst->ps_const_i));
+        memcpy(dst->ps_const_b, src->ps_const_b, sizeof(dst->ps_const_b));
+        if (apply) {
+            dst->changed.ps_const_i |= src->changed.ps_const_i;
+            dst->changed.ps_const_b |= src->changed.ps_const_b;
+        }
+    }
+
+    /* Render states. */
+    memcpy(dst->rs, src->rs, sizeof(dst->rs));
+    if (apply)
+        memcpy(dst->changed.rs, src->changed.rs, sizeof(dst->changed.rs));
+
+
+    /* Clip planes. */
+    memcpy(&dst->clip, &src->clip, sizeof(dst->clip));
+    if (apply)
+        dst->changed.ucp = src->changed.ucp;
+
+    /* Sampler state. */
+    memcpy(dst->samp, src->samp, sizeof(dst->samp));
+    if (apply)
+        memcpy(dst->changed.sampler,
+               src->changed.sampler, sizeof(dst->changed.sampler));
+
+    /* Index buffer. */
+    nine_bind(&dst->idxbuf, src->idxbuf);
+
+    /* Vertex streams. */
+    if (1) {
+        for (i = 0; i < Elements(dst->stream); ++i) {
+            nine_bind(&dst->stream[i], src->stream[i]);
+            if (src->stream[i]) {
+                dst->vtxbuf[i].buffer_offset = src->vtxbuf[i].buffer_offset;
+                dst->vtxbuf[i].buffer = src->vtxbuf[i].buffer;
+                dst->vtxbuf[i].stride = src->vtxbuf[i].stride;
+            }
+            dst->stream_freq[i] = src->stream_freq[i];
+        }
+        dst->stream_instancedata_mask = src->stream_instancedata_mask;
+        if (apply) {
+            dst->changed.vtxbuf = (1ULL << MaxStreams) - 1;
+            dst->changed.stream_freq = (1ULL << MaxStreams) - 1;
+        }
+    }
+
+    /* keep this check in case we want to disable FF */
+    if (!(help->changed.group & NINE_STATE_FF))
+        return;
+    WARN_ONCE("Fixed function state not handled properly by StateBlocks.\n");
+
+    /* Fixed function state. */
+    if (apply)
+        dst->ff.changed.group = src->ff.changed.group;
+
+    dst->ff.material = src->ff.material;
+
+    memcpy(dst->ff.tex_stage, src->ff.tex_stage, sizeof(dst->ff.tex_stage));
+    if (apply) /* TODO: memset */
+        memcpy(dst->ff.changed.tex_stage,
+               src->ff.changed.tex_stage, sizeof(dst->ff.changed.tex_stage));
+
+    /* Lights. */
+    if (1) {
+        if (dst->ff.num_lights < src->ff.num_lights) {
+            dst->ff.light = REALLOC(dst->ff.light,
+                                    dst->ff.num_lights * sizeof(D3DLIGHT9),
+                                    src->ff.num_lights * sizeof(D3DLIGHT9));
+            dst->ff.num_lights = src->ff.num_lights;
+        }
+        memcpy(dst->ff.light,
+               src->ff.light, src->ff.num_lights * sizeof(dst->ff.light[0]));
+
+        DBG("TODO: active lights\n");
+    }
+
+    /* Transforms. */
+    if (1) {
+        if (dst->ff.num_transforms < src->ff.num_transforms) {
+            dst->ff.transform = REALLOC(dst->ff.transform,
+                dst->ff.num_transforms * sizeof(dst->ff.transform[0]),
+                src->ff.num_transforms * sizeof(src->ff.transform[0]));
+            dst->ff.num_transforms = src->ff.num_transforms;
+        }
+        memcpy(dst->ff.transform,
+               src->ff.transform, src->ff.num_transforms * sizeof(D3DMATRIX));
+        if (apply) /* TODO: memset */
+            memcpy(dst->ff.changed.transform,
+                   src->ff.changed.transform, sizeof(dst->ff.changed.transform));
+    }
+}
+
+/* Capture those bits of current device state that have been changed between
+ * BeginStateBlock and EndStateBlock.
+ */
+HRESULT WINAPI
+NineStateBlock9_Capture( struct NineStateBlock9 *This )
+{
+    struct nine_state *dst = &This->state;
+    struct nine_state *src = &This->base.device->state;
+    const int MaxStreams = This->base.device->caps.MaxStreams;
+    unsigned s;
+
+    DBG("This=%p\n", This);
+
+    if (This->type == NINESBT_ALL)
+        nine_state_copy_common_all(dst, src, dst, FALSE, NULL, MaxStreams);
+    else
+        nine_state_copy_common(dst, src, dst, FALSE, NULL);
+
+    if (dst->changed.group & NINE_STATE_VDECL)
+        nine_bind(&dst->vdecl, src->vdecl);
+
+    /* Textures */
+    if (dst->changed.texture) {
+        uint32_t m = dst->changed.texture;
+        for (s = 0; m; ++s, m >>= 1)
+            if (m & 1)
+                nine_bind(&dst->texture[s], src->texture[s]);
+    }
+
+    return D3D_OK;
+}
+
+/* Set state managed by this StateBlock as current device state. */
+HRESULT WINAPI
+NineStateBlock9_Apply( struct NineStateBlock9 *This )
+{
+    struct nine_state *dst = &This->base.device->state;
+    struct nine_state *src = &This->state;
+    struct nine_range_pool *pool = &This->base.device->range_pool;
+    const int MaxStreams = This->base.device->caps.MaxStreams;
+    unsigned s;
+
+    DBG("This=%p\n", This);
+
+    if (This->type == NINESBT_ALL)
+        nine_state_copy_common_all(dst, src, src, TRUE, pool, MaxStreams);
+    else
+        nine_state_copy_common(dst, src, src, TRUE, pool);
+
+    if ((src->changed.group & NINE_STATE_VDECL) && src->vdecl)
+        nine_bind(&dst->vdecl, src->vdecl);
+
+    /* Textures */
+    if (src->changed.texture) {
+        uint32_t m = src->changed.texture;
+        dst->changed.texture |= m;
+
+        dst->samplers_shadow &= ~m;
+
+        for (s = 0; m; ++s, m >>= 1) {
+            struct NineBaseTexture9 *tex = src->texture[s];
+            if (!(m & 1))
+                continue;
+            if (tex) {
+                tex->bind_count++;
+                if ((tex->dirty | tex->dirty_mip) && LIST_IS_EMPTY(&tex->list))
+                    list_add(&tex->list, &This->base.device->update_textures);
+                dst->samplers_shadow |= tex->shadow << s;
+            }
+            if (src->texture[s])
+                src->texture[s]->bind_count--;
+            nine_bind(&dst->texture[s], src->texture[s]);
+        }
+    }
+
+    return D3D_OK;
+}
+
+IDirect3DStateBlock9Vtbl NineStateBlock9_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)NineUnknown_GetDevice, /* actually part of StateBlock9 iface */
+    (void *)NineStateBlock9_Capture,
+    (void *)NineStateBlock9_Apply
+};
+
+static const GUID *NineStateBlock9_IIDs[] = {
+    &IID_IDirect3DStateBlock9,
+    &IID_IUnknown,
+    NULL
+};
+
+HRESULT
+NineStateBlock9_new( struct NineDevice9 *pDevice,
+                     struct NineStateBlock9 **ppOut,
+                     enum nine_stateblock_type type)
+{
+    NINE_DEVICE_CHILD_NEW(StateBlock9, ppOut, pDevice, type);
+}
diff --git a/src/gallium/state_trackers/nine/stateblock9.h b/src/gallium/state_trackers/nine/stateblock9.h
new file mode 100644 (file)
index 0000000..bcaf634
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _NINE_STATEBLOCK9_H_
+#define _NINE_STATEBLOCK9_H_
+
+#include "iunknown.h"
+
+#include "nine_state.h"
+
+enum nine_stateblock_type
+{
+   NINESBT_ALL,
+   NINESBT_VERTEXSTATE,
+   NINESBT_PIXELSTATE,
+   NINESBT_CUSTOM
+};
+
+struct NineStateBlock9
+{
+    struct NineUnknown base;
+
+    struct nine_state state;
+
+    enum nine_stateblock_type type;
+};
+static INLINE struct NineStateBlock9 *
+NineStateBlock9( void *data )
+{
+    return (struct NineStateBlock9 *)data;
+}
+
+HRESULT
+NineStateBlock9_new( struct NineDevice9 *,
+                     struct NineStateBlock9 **ppOut,
+                     enum nine_stateblock_type);
+
+HRESULT
+NineStateBlock9_ctor( struct NineStateBlock9 *,
+                      struct NineUnknownParams *pParams,
+                      enum nine_stateblock_type type );
+
+void
+NineStateBlock9_dtor( struct NineStateBlock9 * );
+
+HRESULT WINAPI
+NineStateBlock9_Capture( struct NineStateBlock9 *This );
+
+HRESULT WINAPI
+NineStateBlock9_Apply( struct NineStateBlock9 *This );
+
+#endif /* _NINE_STATEBLOCK9_H_ */
diff --git a/src/gallium/state_trackers/nine/surface9.c b/src/gallium/state_trackers/nine/surface9.c
new file mode 100644 (file)
index 0000000..42a9e05
--- /dev/null
@@ -0,0 +1,711 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "surface9.h"
+#include "device9.h"
+#include "basetexture9.h" /* for marking dirty */
+
+#include "nine_helpers.h"
+#include "nine_pipe.h"
+#include "nine_dump.h"
+
+#include "pipe/p_context.h"
+#include "pipe/p_screen.h"
+#include "pipe/p_state.h"
+
+#include "util/u_math.h"
+#include "util/u_inlines.h"
+#include "util/u_surface.h"
+
+#define DBG_CHANNEL DBG_SURFACE
+
+HRESULT
+NineSurface9_ctor( struct NineSurface9 *This,
+                   struct NineUnknownParams *pParams,
+                   struct NineUnknown *pContainer,
+                   struct pipe_resource *pResource,
+                   uint8_t TextureType,
+                   unsigned Level,
+                   unsigned Layer,
+                   D3DSURFACE_DESC *pDesc )
+{
+    HRESULT hr;
+
+    DBG("This=%p pDevice=%p pResource=%p Level=%u Layer=%u pDesc=%p\n",
+        This, pParams->device, pResource, Level, Layer, pDesc);
+
+    /* Mark this as a special surface held by another internal resource. */
+    pParams->container = pContainer;
+
+    user_assert(!(pDesc->Usage & D3DUSAGE_DYNAMIC) ||
+                (pDesc->Pool != D3DPOOL_MANAGED), D3DERR_INVALIDCALL);
+
+    assert(pResource ||
+           pDesc->Pool != D3DPOOL_DEFAULT || pDesc->Format == D3DFMT_NULL);
+
+    This->base.info.screen = pParams->device->screen;
+    This->base.info.target = PIPE_TEXTURE_2D;
+    This->base.info.format = d3d9_to_pipe_format(pDesc->Format);
+    This->base.info.width0 = pDesc->Width;
+    This->base.info.height0 = pDesc->Height;
+    This->base.info.depth0 = 1;
+    This->base.info.last_level = 0;
+    This->base.info.array_size = 1;
+    This->base.info.nr_samples = pDesc->MultiSampleType;
+    This->base.info.usage = PIPE_USAGE_DEFAULT;
+    This->base.info.bind = PIPE_BIND_SAMPLER_VIEW;
+    This->base.info.flags = 0;
+
+    if (pDesc->Usage & D3DUSAGE_RENDERTARGET)
+        This->base.info.bind |= PIPE_BIND_RENDER_TARGET;
+    if (pDesc->Usage & D3DUSAGE_DEPTHSTENCIL)
+        This->base.info.bind |= PIPE_BIND_DEPTH_STENCIL;
+
+    if (pDesc->Pool == D3DPOOL_SYSTEMMEM) {
+        This->base.info.usage = PIPE_USAGE_STAGING;
+        if (pResource)
+            This->base.data = (uint8_t *)pResource; /* this is *pSharedHandle */
+        pResource = NULL;
+    } else {
+        if (pResource && (pDesc->Usage & D3DUSAGE_DYNAMIC))
+            pResource->flags |= NINE_RESOURCE_FLAG_LOCKABLE;
+        pipe_resource_reference(&This->base.resource, pResource);
+    }
+
+    hr = NineResource9_ctor(&This->base, pParams, FALSE, D3DRTYPE_SURFACE,
+                            pDesc->Pool);
+    if (FAILED(hr))
+        return hr;
+    This->base.usage = pDesc->Usage;
+
+    This->pipe = This->base.base.device->pipe;
+    This->transfer = NULL;
+
+    This->texture = TextureType;
+    This->level = Level;
+    This->level_actual = Level;
+    This->layer = Layer;
+    This->desc = *pDesc;
+
+    This->stride = util_format_get_stride(This->base.info.format, pDesc->Width);
+    This->stride = align(This->stride, 4);
+
+    if (!pResource && !This->base.data) {
+        hr = NineSurface9_AllocateData(This);
+        if (FAILED(hr))
+            return hr;
+    } else {
+        if (pResource && NineSurface9_IsOffscreenPlain(This))
+            pResource->flags |= NINE_RESOURCE_FLAG_LOCKABLE;
+    }
+
+    NineSurface9_Dump(This);
+
+    return D3D_OK;
+}
+
+void
+NineSurface9_dtor( struct NineSurface9 *This )
+{
+    if (This->transfer)
+        NineSurface9_UnlockRect(This);
+    NineSurface9_ClearDirtyRects(This);
+
+    pipe_surface_reference(&This->surface[0], NULL);
+    pipe_surface_reference(&This->surface[1], NULL);
+
+    NineResource9_dtor(&This->base);
+}
+
+struct pipe_surface *
+NineSurface9_CreatePipeSurface( struct NineSurface9 *This, const int sRGB )
+{
+    struct pipe_context *pipe = This->pipe;
+    struct pipe_resource *resource = This->base.resource;
+    struct pipe_surface templ;
+
+    assert(This->desc.Pool == D3DPOOL_DEFAULT ||
+           This->desc.Pool == D3DPOOL_MANAGED);
+    assert(resource);
+
+    templ.format = sRGB ? util_format_srgb(resource->format) : resource->format;
+    templ.u.tex.level = This->level;
+    templ.u.tex.first_layer = This->layer;
+    templ.u.tex.last_layer = This->layer;
+
+    This->surface[sRGB] = pipe->create_surface(pipe, resource, &templ);
+    assert(This->surface[sRGB]);
+    return This->surface[sRGB];
+}
+
+#ifdef DEBUG
+void
+NineSurface9_Dump( struct NineSurface9 *This )
+{
+    struct NineBaseTexture9 *tex;
+    GUID id = IID_IDirect3DBaseTexture9;
+    REFIID ref = &id;
+
+    DBG("\nNineSurface9(%p->%p/%p): Pool=%s Type=%s Usage=%s\n"
+        "Dims=%ux%u Format=%s Stride=%u Lockable=%i\n"
+        "Level=%u(%u), Layer=%u\n", This, This->base.resource, This->base.data,
+        nine_D3DPOOL_to_str(This->desc.Pool),
+        nine_D3DRTYPE_to_str(This->desc.Type),
+        nine_D3DUSAGE_to_str(This->desc.Usage),
+        This->desc.Width, This->desc.Height,
+        d3dformat_to_string(This->desc.Format), This->stride,
+        This->base.resource &&
+        (This->base.resource->flags & NINE_RESOURCE_FLAG_LOCKABLE),
+        This->level, This->level_actual, This->layer);
+
+    if (!This->base.base.container)
+        return;
+    NineUnknown_QueryInterface(This->base.base.container, ref, (void **)&tex);
+    if (tex) {
+        NineBaseTexture9_Dump(tex);
+        NineUnknown_Release(NineUnknown(tex));
+    }
+}
+#endif /* DEBUG */
+
+HRESULT WINAPI
+NineSurface9_GetContainer( struct NineSurface9 *This,
+                           REFIID riid,
+                           void **ppContainer )
+{
+    HRESULT hr;
+    if (!NineUnknown(This)->container)
+        return E_NOINTERFACE;
+    hr = NineUnknown_QueryInterface(NineUnknown(This)->container, riid, ppContainer);
+    if (FAILED(hr))
+        DBG("QueryInterface FAILED!\n");
+    return hr;
+}
+
+static INLINE void
+NineSurface9_MarkContainerDirty( struct NineSurface9 *This )
+{
+    if (This->texture) {
+        struct NineBaseTexture9 *tex =
+            NineBaseTexture9(This->base.base.container);
+        assert(tex);
+        assert(This->texture == D3DRTYPE_TEXTURE ||
+               This->texture == D3DRTYPE_CUBETEXTURE);
+        if (This->base.pool == D3DPOOL_MANAGED)
+            tex->dirty = TRUE;
+        else
+        if (This->base.usage & D3DUSAGE_AUTOGENMIPMAP)
+            tex->dirty_mip = TRUE;
+
+        BASETEX_REGISTER_UPDATE(tex);
+    }
+}
+
+HRESULT WINAPI
+NineSurface9_GetDesc( struct NineSurface9 *This,
+                      D3DSURFACE_DESC *pDesc )
+{
+    user_assert(pDesc != NULL, E_POINTER);
+    *pDesc = This->desc;
+    return D3D_OK;
+}
+
+/* Wine just keeps a single directy rect and expands it to cover all
+ * the dirty rects ever added.
+ * We'll keep 2, and expand the one that fits better, just for fun.
+ */
+INLINE void
+NineSurface9_AddDirtyRect( struct NineSurface9 *This,
+                           const struct pipe_box *box )
+{
+    float area[2];
+    struct u_rect rect, cover_a, cover_b;
+
+    if (!box) {
+        This->dirty_rects[0].x0 = 0;
+        This->dirty_rects[0].y0 = 0;
+        This->dirty_rects[0].x1 = This->desc.Width;
+        This->dirty_rects[0].y1 = This->desc.Height;
+
+        memset(&This->dirty_rects[1], 0, sizeof(This->dirty_rects[1]));
+        return;
+    }
+    rect.x0 = box->x;
+    rect.y0 = box->y;
+    rect.x1 = box->x + box->width;
+    rect.y1 = box->y + box->height;
+
+    if (This->dirty_rects[0].x1 == 0) {
+        This->dirty_rects[0] = rect;
+        return;
+    }
+
+    u_rect_union(&cover_a, &This->dirty_rects[0], &rect);
+    area[0] = u_rect_area(&cover_a);
+
+    if (This->dirty_rects[1].x1 == 0) {
+        area[1] = u_rect_area(&This->dirty_rects[0]);
+        if (area[0] > (area[1] * 1.25f))
+            This->dirty_rects[1] = rect;
+        else
+            This->dirty_rects[0] = cover_a;
+    } else {
+        u_rect_union(&cover_b, &This->dirty_rects[1], &rect);
+        area[1] = u_rect_area(&cover_b);
+
+        if (area[0] > area[1])
+            This->dirty_rects[1] = cover_b;
+        else
+            This->dirty_rects[0] = cover_a;
+    }
+}
+
+static INLINE uint8_t *
+NineSurface9_GetSystemMemPointer(struct NineSurface9 *This, int x, int y)
+{
+    unsigned x_offset = util_format_get_stride(This->base.info.format, x);
+
+    y = util_format_get_nblocksy(This->base.info.format, y);
+
+    assert(This->base.data);
+    return This->base.data + (y * This->stride + x_offset);
+}
+
+HRESULT WINAPI
+NineSurface9_LockRect( struct NineSurface9 *This,
+                       D3DLOCKED_RECT *pLockedRect,
+                       const RECT *pRect,
+                       DWORD Flags )
+{
+    struct pipe_resource *resource = This->base.resource;
+    struct pipe_box box;
+    unsigned usage;
+
+    DBG("This=%p pLockedRect=%p pRect=%p[%u..%u,%u..%u] Flags=%s\n", This,
+        pLockedRect, pRect,
+        pRect ? pRect->left : 0, pRect ? pRect->right : 0,
+        pRect ? pRect->top : 0, pRect ? pRect->bottom : 0,
+        nine_D3DLOCK_to_str(Flags));
+    NineSurface9_Dump(This);
+
+#ifdef NINE_STRICT
+    user_assert(This->base.pool != D3DPOOL_DEFAULT ||
+                (resource && (resource->flags & NINE_RESOURCE_FLAG_LOCKABLE)),
+                D3DERR_INVALIDCALL);
+#endif
+    user_assert(!(Flags & ~(D3DLOCK_DISCARD |
+                            D3DLOCK_DONOTWAIT |
+                            D3DLOCK_NO_DIRTY_UPDATE |
+                            D3DLOCK_NOOVERWRITE |
+                            D3DLOCK_NOSYSLOCK | /* ignored */
+                            D3DLOCK_READONLY)), D3DERR_INVALIDCALL);
+    user_assert(!((Flags & D3DLOCK_DISCARD) && (Flags & D3DLOCK_READONLY)),
+                D3DERR_INVALIDCALL);
+
+    /* check if it's already locked */
+    user_assert(This->lock_count == 0, D3DERR_INVALIDCALL);
+    user_assert(pLockedRect, E_POINTER);
+
+    user_assert(This->desc.MultiSampleType == D3DMULTISAMPLE_NONE,
+                D3DERR_INVALIDCALL);
+
+    if (pRect && This->base.pool == D3DPOOL_DEFAULT &&
+        util_format_is_compressed(This->base.info.format)) {
+        const unsigned w = util_format_get_blockwidth(This->base.info.format);
+        const unsigned h = util_format_get_blockheight(This->base.info.format);
+        user_assert(!(pRect->left % w) && !(pRect->right % w) &&
+                    !(pRect->top % h) && !(pRect->bottom % h),
+                    D3DERR_INVALIDCALL);
+    }
+
+    if (Flags & D3DLOCK_DISCARD) {
+        usage = PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_RANGE;
+    } else {
+        usage = (Flags & D3DLOCK_READONLY) ?
+            PIPE_TRANSFER_READ : PIPE_TRANSFER_READ_WRITE;
+    }
+    if (Flags & D3DLOCK_DONOTWAIT)
+        usage |= PIPE_TRANSFER_DONTBLOCK;
+
+    if (pRect) {
+        rect_to_pipe_box(&box, pRect);
+        if (u_box_clip_2d(&box, &box, This->desc.Width,
+                          This->desc.Height) < 0) {
+            DBG("pRect clipped by Width=%u Height=%u\n",
+                This->desc.Width, This->desc.Height);
+            return D3DERR_INVALIDCALL;
+        }
+    } else {
+        u_box_origin_2d(This->desc.Width, This->desc.Height, &box);
+    }
+
+    user_warn(This->desc.Format == D3DFMT_NULL);
+
+    if (This->base.data) {
+        DBG("returning system memory\n");
+
+        pLockedRect->Pitch = This->stride;
+        pLockedRect->pBits = NineSurface9_GetSystemMemPointer(This,
+                                                              box.x, box.y);
+    } else {
+        DBG("mapping pipe_resource %p (level=%u usage=%x)\n",
+            resource, This->level, usage);
+
+        pLockedRect->pBits = This->pipe->transfer_map(This->pipe, resource,
+                                                      This->level, usage, &box,
+                                                      &This->transfer);
+        if (!This->transfer) {
+            DBG("transfer_map failed\n");
+            if (Flags & D3DLOCK_DONOTWAIT)
+                return D3DERR_WASSTILLDRAWING;
+            return D3DERR_INVALIDCALL;
+        }
+        pLockedRect->Pitch = This->transfer->stride;
+    }
+
+    if (!(Flags & (D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_READONLY))) {
+        NineSurface9_MarkContainerDirty(This);
+        if (This->base.pool == D3DPOOL_MANAGED)
+            NineSurface9_AddDirtyRect(This, &box);
+    }
+
+    ++This->lock_count;
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineSurface9_UnlockRect( struct NineSurface9 *This )
+{
+    DBG("This=%p lock_count=%u\n", This, This->lock_count);
+    user_assert(This->lock_count, D3DERR_INVALIDCALL);
+    if (This->transfer) {
+        This->pipe->transfer_unmap(This->pipe, This->transfer);
+        This->transfer = NULL;
+    }
+    --This->lock_count;
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineSurface9_GetDC( struct NineSurface9 *This,
+                    HDC *phdc )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineSurface9_ReleaseDC( struct NineSurface9 *This,
+                        HDC hdc )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+/* nine private */
+
+HRESULT
+NineSurface9_AllocateData( struct NineSurface9 *This )
+{
+#if 0
+    struct pipe_screen *screen = This->base.info.screen;
+    /* XXX: Can't use staging resource because apparently apps expect
+     * memory offsets to be the same across locks.
+     * NV50 doesn't support direct mapping yet so only enable this if
+     * everything else works.
+     */
+    if (This->base.pool == D3DPOOL_SYSTEMMEM) {
+        /* Allocate a staging resource to save a copy:
+         * user -> staging resource
+         * staging resource -> (blit) -> video memory
+         *
+         * Instead of:
+         * user -> system memory
+         * system memory -> transfer staging area
+         * transfer -> video memory
+         *
+         * Does this work if we "lose" the device ?
+         */
+        struct pipe_resource *resource;
+        struct pipe_resource templ;
+
+        templ.target = PIPE_TEXTURE_2D;
+        templ.format = This->base.info.format;
+        templ.width0 = This->desc.Width;
+        templ.height0 = This->desc.Height;
+        templ.depth0 = 1;
+        templ.array_size = 1;
+        templ.last_level = 0;
+        templ.nr_samples = 0;
+        templ.usage = PIPE_USAGE_STAGING;
+        templ.bind =
+            PIPE_BIND_SAMPLER_VIEW |
+            PIPE_BIND_TRANSFER_WRITE |
+            PIPE_BIND_TRANSFER_READ;
+        templ.flags = 0;
+
+        DBG("(%p(This=%p),level=%u) Allocating staging resource.\n",
+            This->base.base.container, This, This->level);
+
+        resource = screen->resource_create(screen, &templ);
+        if (!resource)
+            DBG("Failed to allocate staging resource.\n");
+
+        /* Also deallocate old staging resource. */
+        pipe_resource_reference(&This->base.resource, resource);
+    }
+#endif
+    if (!This->base.resource) {
+        const unsigned size = This->stride *
+            util_format_get_nblocksy(This->base.info.format, This->desc.Height);
+
+        DBG("(%p(This=%p),level=%u) Allocating 0x%x bytes of system memory.\n",
+            This->base.base.container, This, This->level, size);
+
+        This->base.data = (uint8_t *)MALLOC(size);
+        if (!This->base.data)
+            return E_OUTOFMEMORY;
+    }
+    return D3D_OK;
+}
+
+IDirect3DSurface9Vtbl NineSurface9_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */
+    (void *)NineResource9_SetPrivateData,
+    (void *)NineResource9_GetPrivateData,
+    (void *)NineResource9_FreePrivateData,
+    (void *)NineResource9_SetPriority,
+    (void *)NineResource9_GetPriority,
+    (void *)NineResource9_PreLoad,
+    (void *)NineResource9_GetType,
+    (void *)NineSurface9_GetContainer,
+    (void *)NineSurface9_GetDesc,
+    (void *)NineSurface9_LockRect,
+    (void *)NineSurface9_UnlockRect,
+    (void *)NineSurface9_GetDC,
+    (void *)NineSurface9_ReleaseDC
+};
+
+
+static INLINE boolean
+NineSurface9_IsDirty(struct NineSurface9 *This)
+{
+    return This->dirty_rects[0].x1 != 0;
+}
+
+HRESULT
+NineSurface9_CopySurface( struct NineSurface9 *This,
+                          struct NineSurface9 *From,
+                          const POINT *pDestPoint,
+                          const RECT *pSourceRect )
+{
+    struct pipe_context *pipe = This->pipe;
+    struct pipe_resource *r_dst = This->base.resource;
+    struct pipe_resource *r_src = From->base.resource;
+    struct pipe_transfer *transfer;
+    struct pipe_box src_box;
+    struct pipe_box dst_box;
+    uint8_t *p_dst;
+    const uint8_t *p_src;
+
+    user_assert(This->desc.Format == From->desc.Format, D3DERR_INVALIDCALL);
+
+    dst_box.x = pDestPoint ? pDestPoint->x : 0;
+    dst_box.y = pDestPoint ? pDestPoint->y : 0;
+
+    user_assert(dst_box.x >= 0 &&
+                dst_box.y >= 0, D3DERR_INVALIDCALL);
+
+    dst_box.z = This->layer;
+    src_box.z = From->layer;
+
+    dst_box.depth = 1;
+    src_box.depth = 1;
+
+    if (pSourceRect) {
+        /* make sure it doesn't range outside the source surface */
+        user_assert(pSourceRect->left >= 0 &&
+                    pSourceRect->right <= From->desc.Width &&
+                    pSourceRect->top >= 0 &&
+                    pSourceRect->bottom <= From->desc.Height,
+                    D3DERR_INVALIDCALL);
+        if (rect_to_pipe_box_xy_only_clamp(&src_box, pSourceRect))
+            return D3D_OK;
+    } else {
+        src_box.x = 0;
+        src_box.y = 0;
+        src_box.width = From->desc.Width;
+        src_box.height = From->desc.Height;
+    }
+
+    /* limits */
+    dst_box.width = This->desc.Width - dst_box.x;
+    dst_box.height = This->desc.Height - dst_box.y;
+
+    user_assert(src_box.width <= dst_box.width &&
+                src_box.height <= dst_box.height, D3DERR_INVALIDCALL);
+
+    dst_box.width = src_box.width;
+    dst_box.height = src_box.height;
+
+    /* Don't copy to device memory of managed resources.
+     * We don't want to download it back again later.
+     */
+    if (This->base.pool == D3DPOOL_MANAGED)
+        r_dst = NULL;
+
+    /* Don't copy from stale device memory of managed resources.
+     * Also, don't copy between system and device if we don't have to.
+     */
+    if (From->base.pool == D3DPOOL_MANAGED) {
+        if (!r_dst || NineSurface9_IsDirty(From))
+            r_src = NULL;
+    }
+
+    if (r_dst && r_src) {
+        pipe->resource_copy_region(pipe,
+                                   r_dst, This->level,
+                                   dst_box.x, dst_box.y, dst_box.z,
+                                   r_src, From->level,
+                                   &src_box);
+    } else
+    if (r_dst) {
+        p_src = NineSurface9_GetSystemMemPointer(From, src_box.x, src_box.y);
+
+        pipe->transfer_inline_write(pipe, r_dst, This->level,
+                                    0, /* WRITE|DISCARD are implicit */
+                                    &dst_box, p_src, From->stride, 0);
+    } else
+    if (r_src) {
+        p_dst = NineSurface9_GetSystemMemPointer(This, 0, 0);
+
+        p_src = pipe->transfer_map(pipe, r_src, From->level,
+                                   PIPE_TRANSFER_READ,
+                                   &src_box, &transfer);
+        if (!p_src)
+            return D3DERR_DRIVERINTERNALERROR;
+
+        util_copy_rect(p_dst, This->base.info.format,
+                       This->stride, dst_box.x, dst_box.y,
+                       dst_box.width, dst_box.height,
+                       p_src,
+                       transfer->stride, src_box.x, src_box.y);
+
+        pipe->transfer_unmap(pipe, transfer);
+    } else {
+        p_dst = NineSurface9_GetSystemMemPointer(This, 0, 0);
+        p_src = NineSurface9_GetSystemMemPointer(From, 0, 0);
+
+        util_copy_rect(p_dst, This->base.info.format,
+                       This->stride, dst_box.x, dst_box.y,
+                       dst_box.width, dst_box.height,
+                       p_src,
+                       From->stride, src_box.x, src_box.y);
+    }
+
+    if (This->base.pool == D3DPOOL_DEFAULT ||
+        This->base.pool == D3DPOOL_MANAGED)
+        NineSurface9_MarkContainerDirty(This);
+    if (!r_dst && This->base.resource)
+        NineSurface9_AddDirtyRect(This, &dst_box);
+
+    return D3D_OK;
+}
+
+/* Gladly, rendering to a MANAGED surface is not permitted, so we will
+ * never have to do the reverse, i.e. download the surface.
+ */
+HRESULT
+NineSurface9_UploadSelf( struct NineSurface9 *This )
+{
+    struct pipe_context *pipe = This->pipe;
+    struct pipe_resource *res = This->base.resource;
+    uint8_t *ptr;
+    unsigned i;
+
+    assert(This->base.pool == D3DPOOL_MANAGED);
+
+    if (!NineSurface9_IsDirty(This))
+        return D3D_OK;
+
+    for (i = 0; i < Elements(This->dirty_rects); ++i) {
+        struct pipe_box box;
+        nine_u_rect_to_pipe_box(&box, &This->dirty_rects[i], This->layer);
+
+        if (box.width == 0)
+            break;
+        ptr = NineSurface9_GetSystemMemPointer(This, box.x, box.y);
+
+        pipe->transfer_inline_write(pipe, res, This->level,
+                                    0,
+                                    &box, ptr, This->stride, 0);
+    }
+    NineSurface9_ClearDirtyRects(This);
+
+    return D3D_OK;
+}
+
+void
+NineSurface9_SetResourceResize( struct NineSurface9 *This,
+                                struct pipe_resource *resource )
+{
+    assert(This->level == 0 && This->level_actual == 0);
+    assert(!This->lock_count);
+    assert(This->desc.Pool == D3DPOOL_DEFAULT);
+    assert(!This->texture);
+
+    pipe_resource_reference(&This->base.resource, resource);
+
+    This->desc.Width = This->base.info.width0 = resource->width0;
+    This->desc.Height = This->base.info.height0 = resource->height0;
+
+    This->stride = util_format_get_stride(This->base.info.format,
+                                          This->desc.Width);
+    This->stride = align(This->stride, 4);
+
+    pipe_surface_reference(&This->surface[0], NULL);
+    pipe_surface_reference(&This->surface[1], NULL);
+}
+
+
+static const GUID *NineSurface9_IIDs[] = {
+    &IID_IDirect3DSurface9,
+    &IID_IDirect3DResource9,
+    &IID_IUnknown,
+    NULL
+};
+
+HRESULT
+NineSurface9_new( struct NineDevice9 *pDevice,
+                  struct NineUnknown *pContainer,
+                  struct pipe_resource *pResource,
+                  uint8_t TextureType,
+                  unsigned Level,
+                  unsigned Layer,
+                  D3DSURFACE_DESC *pDesc,
+                  struct NineSurface9 **ppOut )
+{
+    NINE_DEVICE_CHILD_NEW(Surface9, ppOut, pDevice, /* args */
+                          pContainer, pResource,
+                          TextureType, Level, Layer, pDesc);
+}
diff --git a/src/gallium/state_trackers/nine/surface9.h b/src/gallium/state_trackers/nine/surface9.h
new file mode 100644 (file)
index 0000000..4a9db25
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _NINE_SURFACE9_H_
+#define _NINE_SURFACE9_H_
+
+#include "resource9.h"
+
+#include "pipe/p_state.h"
+#include "util/u_double_list.h"
+#include "util/u_rect.h"
+#include "util/u_inlines.h"
+
+struct NineSurface9
+{
+    struct NineResource9 base;
+
+    /* G3D state */
+    struct pipe_context *pipe;
+    struct pipe_transfer *transfer;
+    struct pipe_surface *surface[2]; /* created on-demand (linear, sRGB) */
+    int lock_count;
+    uint8_t texture; /* rtype of container BaseTex or 0 */
+
+    /* resource description */
+    unsigned level;        /* refers to the pipe_resource (SetLOD !) */
+    unsigned level_actual; /* refers to the NineTexture */
+    unsigned layer;
+    D3DSURFACE_DESC desc;
+
+    unsigned stride; /* for system memory backing */
+
+    /* wine doesn't even use these, 2 will be enough */
+    struct u_rect dirty_rects[2];
+};
+static INLINE struct NineSurface9 *
+NineSurface9( void *data )
+{
+    return (struct NineSurface9 *)data;
+}
+
+HRESULT
+NineSurface9_new( struct NineDevice9 *pDevice,
+                  struct NineUnknown *pContainer,
+                  struct pipe_resource *pResource,
+                  uint8_t TextureType, /* 0 if pContainer isn't BaseTexure9 */
+                  unsigned Level,
+                  unsigned Layer,
+                  D3DSURFACE_DESC *pDesc,
+                  struct NineSurface9 **ppOut );
+
+HRESULT
+NineSurface9_ctor( struct NineSurface9 *This,
+                   struct NineUnknownParams *pParams,
+                   struct NineUnknown *pContainer,
+                   struct pipe_resource *pResource,
+                   uint8_t TextureType,
+                   unsigned Level,
+                   unsigned Layer,
+                   D3DSURFACE_DESC *pDesc );
+
+void
+NineSurface9_dtor( struct NineSurface9 *This );
+
+/*** Nine private ***/
+
+struct pipe_surface *
+NineSurface9_CreatePipeSurface( struct NineSurface9 *This, const int sRGB );
+
+static INLINE struct pipe_surface *
+NineSurface9_GetSurface( struct NineSurface9 *This, int sRGB )
+{
+    if (This->surface[sRGB])
+        return This->surface[sRGB];
+    return NineSurface9_CreatePipeSurface(This, sRGB);
+}
+
+static INLINE struct pipe_resource *
+NineSurface9_GetResource( struct NineSurface9 *This )
+{
+    return This->base.resource;
+}
+
+static INLINE void
+NineSurface9_SetResource( struct NineSurface9 *This,
+                          struct pipe_resource *resource, unsigned level )
+{
+    This->level = level;
+    pipe_resource_reference(&This->base.resource, resource);
+    pipe_surface_reference(&This->surface[0], NULL);
+    pipe_surface_reference(&This->surface[1], NULL);
+}
+
+void
+NineSurface9_SetResourceResize( struct NineSurface9 *This,
+                                struct pipe_resource *resource );
+
+void
+NineSurface9_AddDirtyRect( struct NineSurface9 *This,
+                           const struct pipe_box *box );
+
+static INLINE void
+NineSurface9_ClearDirtyRects( struct NineSurface9 *This )
+{
+    memset(&This->dirty_rects, 0, sizeof(This->dirty_rects));
+}
+
+HRESULT
+NineSurface9_AllocateData( struct NineSurface9 *This );
+
+HRESULT
+NineSurface9_UploadSelf( struct NineSurface9 *This );
+
+HRESULT
+NineSurface9_CopySurface( struct NineSurface9 *This,
+                          struct NineSurface9 *From,
+                          const POINT *pDestPoint,
+                          const RECT *pSourceRect );
+
+static INLINE boolean
+NineSurface9_IsOffscreenPlain (struct NineSurface9 *This )
+{
+    return This->base.usage == 0 && !This->texture;
+}
+
+#ifdef DEBUG
+void
+NineSurface9_Dump( struct NineSurface9 *This );
+#else
+static INLINE void
+NineSurface9_Dump( struct NineSurface9 *This ) { }
+#endif
+
+/*** Direct3D public ***/
+
+HRESULT WINAPI
+NineSurface9_GetContainer( struct NineSurface9 *This,
+                           REFIID riid,
+                           void **ppContainer );
+
+HRESULT WINAPI
+NineSurface9_GetDesc( struct NineSurface9 *This,
+                      D3DSURFACE_DESC *pDesc );
+
+HRESULT WINAPI
+NineSurface9_LockRect( struct NineSurface9 *This,
+                       D3DLOCKED_RECT *pLockedRect,
+                       const RECT *pRect,
+                       DWORD Flags );
+
+HRESULT WINAPI
+NineSurface9_UnlockRect( struct NineSurface9 *This );
+
+HRESULT WINAPI
+NineSurface9_GetDC( struct NineSurface9 *This,
+                    HDC *phdc );
+
+HRESULT WINAPI
+NineSurface9_ReleaseDC( struct NineSurface9 *This,
+                        HDC hdc );
+
+#endif /* _NINE_SURFACE9_H_ */
diff --git a/src/gallium/state_trackers/nine/swapchain9.c b/src/gallium/state_trackers/nine/swapchain9.c
new file mode 100644 (file)
index 0000000..b6e8125
--- /dev/null
@@ -0,0 +1,871 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "swapchain9.h"
+#include "surface9.h"
+#include "device9.h"
+
+#include "nine_helpers.h"
+#include "nine_pipe.h"
+#include "nine_dump.h"
+
+#include "util/u_inlines.h"
+#include "util/u_surface.h"
+#include "hud/hud_context.h"
+#include "state_tracker/drm_driver.h"
+
+#define DBG_CHANNEL DBG_SWAPCHAIN
+
+#define UNTESTED(n) DBG("UNTESTED point %d. Please tell if it worked\n", n)
+
+HRESULT
+NineSwapChain9_ctor( struct NineSwapChain9 *This,
+                     struct NineUnknownParams *pParams,
+                     BOOL implicit,
+                     ID3DPresent *pPresent,
+                     D3DPRESENT_PARAMETERS *pPresentationParameters,
+                     struct d3dadapter9_context *pCTX,
+                     HWND hFocusWindow,
+                     D3DDISPLAYMODEEX *mode )
+{
+    HRESULT hr;
+
+    DBG("This=%p pDevice=%p pPresent=%p pCTX=%p hFocusWindow=%p\n",
+        This, pParams->device, pPresent, pCTX, hFocusWindow);
+
+    hr = NineUnknown_ctor(&This->base, pParams);
+    if (FAILED(hr))
+        return hr;
+
+    This->screen = NineDevice9_GetScreen(This->base.device);
+    This->pipe = NineDevice9_GetPipe(This->base.device);
+    This->cso = NineDevice9_GetCSO(This->base.device);
+    This->implicit = implicit;
+    This->actx = pCTX;
+    This->present = pPresent;
+    This->mode = NULL;
+
+    ID3DPresent_AddRef(pPresent);
+
+    if (!pPresentationParameters->hDeviceWindow)
+        pPresentationParameters->hDeviceWindow = hFocusWindow;
+
+    This->rendering_done = FALSE;
+    return NineSwapChain9_Resize(This, pPresentationParameters, mode);
+}
+
+static D3DWindowBuffer *
+D3DWindowBuffer_create(struct NineSwapChain9 *This,
+                       struct pipe_resource *resource,
+                       int depth)
+{
+    D3DWindowBuffer *ret;
+    struct winsys_handle whandle;
+    int stride, dmaBufFd;
+
+    memset(&whandle, 0, sizeof(whandle));
+    whandle.type = DRM_API_HANDLE_TYPE_FD;
+    This->screen->resource_get_handle(This->screen, resource, &whandle);
+    stride = whandle.stride;
+    dmaBufFd = whandle.handle;
+    ID3DPresent_NewD3DWindowBufferFromDmaBuf(This->present,
+                                             dmaBufFd,
+                                             resource->width0,
+                                             resource->height0,
+                                             stride,
+                                             depth,
+                                             32,
+                                             &ret);
+    return ret;
+}
+
+HRESULT
+NineSwapChain9_Resize( struct NineSwapChain9 *This,
+                       D3DPRESENT_PARAMETERS *pParams,
+                       D3DDISPLAYMODEEX *mode )
+{
+    struct NineDevice9 *pDevice = This->base.device;
+    struct NineSurface9 **bufs;
+    D3DSURFACE_DESC desc;
+    HRESULT hr;
+    struct pipe_resource *resource, tmplt;
+    enum pipe_format pf;
+    BOOL has_present_buffers = FALSE;
+    int depth;
+    unsigned i, oldBufferCount, newBufferCount;
+
+    DBG("This=%p pParams=%p\n", This, pParams);
+    user_assert(pParams != NULL, E_POINTER);
+
+    DBG("pParams(%p):\n"
+        "BackBufferWidth: %u\n"
+        "BackBufferHeight: %u\n"
+        "BackBufferFormat: %s\n"
+        "BackBufferCount: %u\n"
+        "MultiSampleType: %u\n"
+        "MultiSampleQuality: %u\n"
+        "SwapEffect: %u\n"
+        "hDeviceWindow: %p\n"
+        "Windowed: %i\n"
+        "EnableAutoDepthStencil: %i\n"
+        "AutoDepthStencilFormat: %s\n"
+        "Flags: %s\n"
+        "FullScreen_RefreshRateInHz: %u\n"
+        "PresentationInterval: %x\n", pParams,
+        pParams->BackBufferWidth, pParams->BackBufferHeight,
+        d3dformat_to_string(pParams->BackBufferFormat),
+        pParams->BackBufferCount,
+        pParams->MultiSampleType, pParams->MultiSampleQuality,
+        pParams->SwapEffect, pParams->hDeviceWindow, pParams->Windowed,
+        pParams->EnableAutoDepthStencil,
+        d3dformat_to_string(pParams->AutoDepthStencilFormat),
+        nine_D3DPRESENTFLAG_to_str(pParams->Flags),
+        pParams->FullScreen_RefreshRateInHz,
+        pParams->PresentationInterval);
+
+    if (pParams->SwapEffect == D3DSWAPEFFECT_COPY &&
+        pParams->BackBufferCount > 1) {
+        pParams->BackBufferCount = 1;
+    }
+
+    if (pParams->BackBufferCount > 3) {
+        pParams->BackBufferCount = 3;
+    }
+
+    if (pParams->BackBufferCount == 0) {
+        pParams->BackBufferCount = 1;
+    }
+
+    if (pParams->BackBufferFormat == D3DFMT_UNKNOWN) {
+        pParams->BackBufferFormat = D3DFMT_A8R8G8B8;
+    }
+
+    This->desired_fences = This->actx->throttling ? This->actx->throttling_value + 1 : 0;
+    /* +1 because we add the fence of the current buffer before popping an old one */
+    if (This->desired_fences > DRI_SWAP_FENCES_MAX)
+        This->desired_fences = DRI_SWAP_FENCES_MAX;
+
+    if (mode && This->mode) {
+        *(This->mode) = *mode;
+    } else if (mode) {
+        This->mode = malloc(sizeof(D3DDISPLAYMODEEX));
+        memcpy(This->mode, mode, sizeof(D3DDISPLAYMODEEX));
+    } else if (This->mode) {
+        free(This->mode);
+        This->mode = NULL;
+    }
+
+    /* Note: It is the role of the backend to fill if neccessary
+     * BackBufferWidth and BackBufferHeight */
+    ID3DPresent_SetPresentParameters(This->present, pParams, This->mode);
+
+    /* When we have flip behaviour, d3d9 expects we get back the screen buffer when we flip.
+     * Here we don't get back the initial content of the screen. To emulate the behaviour
+     * we allocate an additional buffer */
+    oldBufferCount = This->params.BackBufferCount ?
+                     (This->params.BackBufferCount +
+                      (This->params.SwapEffect != D3DSWAPEFFECT_COPY)) : 0;
+    newBufferCount = pParams->BackBufferCount +
+                     (pParams->SwapEffect != D3DSWAPEFFECT_COPY);
+
+    pf = d3d9_to_pipe_format(pParams->BackBufferFormat);
+    if (This->actx->linear_framebuffer ||
+        (pf != PIPE_FORMAT_B8G8R8X8_UNORM &&
+        pf != PIPE_FORMAT_B8G8R8A8_UNORM) ||
+        pParams->SwapEffect != D3DSWAPEFFECT_DISCARD ||
+        pParams->MultiSampleType >= 2 ||
+        (This->actx->ref && This->actx->ref == This->screen))
+        has_present_buffers = TRUE;
+
+    /* Note: the buffer depth has to match the window depth.
+     * In practice, ARGB buffers can be used with windows
+     * of depth 24. Windows of depth 32 are extremely rare.
+     * So even if the buffer is ARGB, say it is depth 24.
+     * It is common practice, for example that's how
+     * glamor implements depth 24.
+     * TODO: handle windows with other depths. Not possible in the short term.
+     * For example 16 bits.*/
+    depth = 24;
+
+    tmplt.target = PIPE_TEXTURE_2D;
+    tmplt.width0 = pParams->BackBufferWidth;
+    tmplt.height0 = pParams->BackBufferHeight;
+    tmplt.depth0 = 1;
+    tmplt.last_level = 0;
+    tmplt.array_size = 1;
+    tmplt.usage = PIPE_USAGE_DEFAULT;
+    tmplt.flags = 0;
+
+    desc.Type = D3DRTYPE_SURFACE;
+    desc.Pool = D3DPOOL_DEFAULT;
+    desc.MultiSampleType = pParams->MultiSampleType;
+    desc.MultiSampleQuality = 0;
+    desc.Width = pParams->BackBufferWidth;
+    desc.Height = pParams->BackBufferHeight;
+
+    for (i = 0; i < oldBufferCount; i++) {
+        ID3DPresent_DestroyD3DWindowBuffer(This->present, This->present_handles[i]);
+        This->present_handles[i] = NULL;
+        if (This->present_buffers)
+            pipe_resource_reference(&(This->present_buffers[i]), NULL);
+    }
+
+    if (!has_present_buffers && This->present_buffers) {
+        FREE(This->present_buffers);
+        This->present_buffers = NULL;
+    }
+
+    if (newBufferCount != oldBufferCount) {
+        for (i = newBufferCount; i < oldBufferCount;
+             ++i)
+            NineUnknown_Detach(NineUnknown(This->buffers[i]));
+
+        bufs = REALLOC(This->buffers,
+                       oldBufferCount * sizeof(This->buffers[0]),
+                       newBufferCount * sizeof(This->buffers[0]));
+        if (!bufs)
+            return E_OUTOFMEMORY;
+        This->buffers = bufs;
+        if (has_present_buffers) {
+            This->present_buffers = REALLOC(This->present_buffers,
+                                            This->present_buffers == NULL ? 0 : oldBufferCount * sizeof(struct pipe_resource *),
+                                            newBufferCount * sizeof(struct pipe_resource *));
+            memset(This->present_buffers, 0, newBufferCount * sizeof(struct pipe_resource *));
+        }
+        This->present_handles = REALLOC(This->present_handles,
+                                        oldBufferCount * sizeof(D3DWindowBuffer *),
+                                        newBufferCount * sizeof(D3DWindowBuffer *));
+        for (i = oldBufferCount; i < newBufferCount; ++i) {
+            This->buffers[i] = NULL;
+            This->present_handles[i] = NULL;
+        }
+    }
+
+    for (i = 0; i < newBufferCount; ++i) {
+        tmplt.format = d3d9_to_pipe_format(pParams->BackBufferFormat);
+        tmplt.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_TRANSFER_READ |
+                     PIPE_BIND_TRANSFER_WRITE | PIPE_BIND_RENDER_TARGET;
+        tmplt.nr_samples = pParams->MultiSampleType;
+        if (!has_present_buffers)
+            tmplt.bind |= PIPE_BIND_SHARED | PIPE_BIND_SCANOUT | PIPE_BIND_DISPLAY_TARGET;
+        resource = This->screen->resource_create(This->screen, &tmplt);
+        if (!resource) {
+            DBG("Failed to create pipe_resource.\n");
+            return D3DERR_OUTOFVIDEOMEMORY;
+        }
+        if (pParams->Flags & D3DPRESENTFLAG_LOCKABLE_BACKBUFFER)
+            resource->flags |= NINE_RESOURCE_FLAG_LOCKABLE;
+        if (This->buffers[i]) {
+            NineSurface9_SetResourceResize(This->buffers[i], resource);
+            if (has_present_buffers)
+                pipe_resource_reference(&resource, NULL);
+        } else {
+            desc.Format = pParams->BackBufferFormat;
+            desc.Usage = D3DUSAGE_RENDERTARGET;
+            hr = NineSurface9_new(pDevice, NineUnknown(This), resource, 0,
+                                  0, 0, &desc, &This->buffers[i]);
+            if (has_present_buffers)
+                pipe_resource_reference(&resource, NULL);
+            if (FAILED(hr)) {
+                DBG("Failed to create RT surface.\n");
+                return hr;
+            }
+            This->buffers[i]->base.base.forward = FALSE;
+        }
+        if (has_present_buffers) {
+            tmplt.format = PIPE_FORMAT_B8G8R8X8_UNORM;
+            tmplt.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_SHARED | PIPE_BIND_SCANOUT | PIPE_BIND_DISPLAY_TARGET;
+            tmplt.nr_samples = 0;
+            if (This->actx->linear_framebuffer)
+                tmplt.bind |= PIPE_BIND_LINEAR;
+            if (pParams->SwapEffect != D3DSWAPEFFECT_DISCARD)
+                tmplt.bind |= PIPE_BIND_RENDER_TARGET;
+            resource = This->screen->resource_create(This->screen, &tmplt);
+            pipe_resource_reference(&(This->present_buffers[i]), resource);
+        }
+        This->present_handles[i] = D3DWindowBuffer_create(This, resource, depth);
+        if (!has_present_buffers)
+            pipe_resource_reference(&resource, NULL);
+    }
+    if (pParams->EnableAutoDepthStencil) {
+        tmplt.format = d3d9_to_pipe_format(pParams->AutoDepthStencilFormat);
+        tmplt.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_TRANSFER_READ |
+                     PIPE_BIND_TRANSFER_WRITE | PIPE_BIND_DEPTH_STENCIL;
+        tmplt.nr_samples = pParams->MultiSampleType;
+
+        resource = This->screen->resource_create(This->screen, &tmplt);
+        if (!resource) {
+            DBG("Failed to create pipe_resource for depth buffer.\n");
+            return D3DERR_OUTOFVIDEOMEMORY;
+        }
+        if (This->zsbuf) {
+            NineSurface9_SetResourceResize(This->zsbuf, resource);
+            pipe_resource_reference(&resource, NULL);
+        } else {
+            /* XXX wine thinks the container of this should be the device */
+            desc.Format = pParams->AutoDepthStencilFormat;
+            desc.Usage = D3DUSAGE_DEPTHSTENCIL;
+            hr = NineSurface9_new(pDevice, NineUnknown(pDevice), resource, 0,
+                                  0, 0, &desc, &This->zsbuf);
+            pipe_resource_reference(&resource, NULL);
+            if (FAILED(hr)) {
+                DBG("Failed to create ZS surface.\n");
+                return hr;
+            }
+            This->zsbuf->base.base.forward = FALSE;
+        }
+    }
+
+    This->params = *pParams;
+
+    return D3D_OK;
+}
+
+/* Throttling: code adapted from the dri state tracker */
+
+/**
+ * swap_fences_pop_front - pull a fence from the throttle queue
+ *
+ * If the throttle queue is filled to the desired number of fences,
+ * pull fences off the queue until the number is less than the desired
+ * number of fences, and return the last fence pulled.
+ */
+static struct pipe_fence_handle *
+swap_fences_pop_front(struct NineSwapChain9 *This)
+{
+    struct pipe_screen *screen = This->screen;
+    struct pipe_fence_handle *fence = NULL;
+
+    if (This->desired_fences == 0)
+        return NULL;
+
+    if (This->cur_fences >= This->desired_fences) {
+        screen->fence_reference(screen, &fence, This->swap_fences[This->tail]);
+        screen->fence_reference(screen, &This->swap_fences[This->tail++], NULL);
+        This->tail &= DRI_SWAP_FENCES_MASK;
+        --This->cur_fences;
+    }
+    return fence;
+}
+
+
+/**
+ * swap_fences_see_front - same than swap_fences_pop_front without
+ * pulling
+ *
+ */
+
+static struct pipe_fence_handle *
+swap_fences_see_front(struct NineSwapChain9 *This)
+{
+    struct pipe_screen *screen = This->screen;
+    struct pipe_fence_handle *fence = NULL;
+
+    if (This->desired_fences == 0)
+        return NULL;
+
+    if (This->cur_fences >= This->desired_fences) {
+        screen->fence_reference(screen, &fence, This->swap_fences[This->tail]);
+    }
+    return fence;
+}
+
+
+/**
+ * swap_fences_push_back - push a fence onto the throttle queue at the back
+ *
+ * push a fence onto the throttle queue and pull fences of the queue
+ * so that the desired number of fences are on the queue.
+ */
+static void
+swap_fences_push_back(struct NineSwapChain9 *This,
+                      struct pipe_fence_handle *fence)
+{
+    struct pipe_screen *screen = This->screen;
+
+    if (!fence || This->desired_fences == 0)
+        return;
+
+    while(This->cur_fences == This->desired_fences)
+        swap_fences_pop_front(This);
+
+    This->cur_fences++;
+    screen->fence_reference(screen, &This->swap_fences[This->head++],
+                            fence);
+    This->head &= DRI_SWAP_FENCES_MASK;
+}
+
+
+/**
+ * swap_fences_unref - empty the throttle queue
+ *
+ * pulls fences of the throttle queue until it is empty.
+ */
+static void
+swap_fences_unref(struct NineSwapChain9 *This)
+{
+    struct pipe_screen *screen = This->screen;
+
+    while(This->cur_fences) {
+        screen->fence_reference(screen, &This->swap_fences[This->tail++], NULL);
+        This->tail &= DRI_SWAP_FENCES_MASK;
+        --This->cur_fences;
+    }
+}
+
+void
+NineSwapChain9_dtor( struct NineSwapChain9 *This )
+{
+    unsigned i;
+
+    DBG("This=%p\n", This);
+
+    if (This->buffers) {
+        for (i = 0; i < This->params.BackBufferCount; i++) {
+            NineUnknown_Destroy(NineUnknown(This->buffers[i]));
+            ID3DPresent_DestroyD3DWindowBuffer(This->present, This->present_handles[i]);
+            if (This->present_buffers)
+                pipe_resource_reference(&(This->present_buffers[i]), NULL);
+        }
+        FREE(This->buffers);
+        FREE(This->present_buffers);
+    }
+    if (This->zsbuf)
+        NineUnknown_Destroy(NineUnknown(This->zsbuf));
+
+    if (This->present)
+        ID3DPresent_Release(This->present);
+
+    swap_fences_unref(This);
+    NineUnknown_dtor(&This->base);
+}
+
+static void
+create_present_buffer( struct NineSwapChain9 *This,
+                       unsigned int width, unsigned int height,
+                       struct pipe_resource **resource,
+                       D3DWindowBuffer **present_handle)
+{
+    struct pipe_resource tmplt;
+
+    tmplt.target = PIPE_TEXTURE_2D;
+    tmplt.width0 = width;
+    tmplt.height0 = height;
+    tmplt.depth0 = 1;
+    tmplt.last_level = 0;
+    tmplt.array_size = 1;
+    tmplt.usage = PIPE_USAGE_DEFAULT;
+    tmplt.flags = 0;
+    tmplt.format = PIPE_FORMAT_B8G8R8X8_UNORM;
+    tmplt.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_TRANSFER_READ |
+                 PIPE_BIND_TRANSFER_WRITE | PIPE_BIND_RENDER_TARGET |
+                 PIPE_BIND_SHARED | PIPE_BIND_SCANOUT | PIPE_BIND_DISPLAY_TARGET;
+    tmplt.nr_samples = 0;
+    if (This->actx->linear_framebuffer)
+        tmplt.bind |= PIPE_BIND_LINEAR;
+    *resource = This->screen->resource_create(This->screen, &tmplt);
+
+    *present_handle = D3DWindowBuffer_create(This, *resource, 24);
+}
+
+static void
+handle_draw_cursor_and_hud( struct NineSwapChain9 *This, struct pipe_resource *resource)
+{
+    struct NineDevice9 *device = This->base.device;
+    struct pipe_blit_info blit;
+
+    if (device->cursor.software && device->cursor.visible && device->cursor.w) {
+        blit.src.resource = device->cursor.image;
+        blit.src.level = 0;
+        blit.src.format = device->cursor.image->format;
+        blit.src.box.x = 0;
+        blit.src.box.y = 0;
+        blit.src.box.z = 0;
+        blit.src.box.depth = 1;
+        blit.src.box.width = device->cursor.w;
+        blit.src.box.height = device->cursor.h;
+
+        blit.dst.resource = resource;
+        blit.dst.level = 0;
+        blit.dst.format = resource->format;
+        blit.dst.box.z = 0;
+        blit.dst.box.depth = 1;
+
+        blit.mask = PIPE_MASK_RGBA;
+        blit.filter = PIPE_TEX_FILTER_NEAREST;
+        blit.scissor_enable = FALSE;
+
+        ID3DPresent_GetCursorPos(This->present, &device->cursor.pos);
+
+        /* NOTE: blit messes up when box.x + box.width < 0, fix driver */
+        blit.dst.box.x = MAX2(device->cursor.pos.x, 0) - device->cursor.hotspot.x;
+        blit.dst.box.y = MAX2(device->cursor.pos.y, 0) - device->cursor.hotspot.y;
+        blit.dst.box.width = blit.src.box.width;
+        blit.dst.box.height = blit.src.box.height;
+
+        DBG("Blitting cursor(%ux%u) to (%i,%i).\n",
+            blit.src.box.width, blit.src.box.height,
+            blit.dst.box.x, blit.dst.box.y);
+
+        This->pipe->blit(This->pipe, &blit);
+    }
+
+    if (device->hud && resource) {
+        hud_draw(device->hud, resource); /* XXX: no offset */
+        /* HUD doesn't clobber stipple */
+        NineDevice9_RestoreNonCSOState(device, ~0x2);
+    }
+}
+
+static INLINE HRESULT
+present( struct NineSwapChain9 *This,
+         const RECT *pSourceRect,
+         const RECT *pDestRect,
+         HWND hDestWindowOverride,
+         const RGNDATA *pDirtyRegion,
+         DWORD dwFlags )
+{
+    struct pipe_resource *resource;
+    struct pipe_fence_handle *fence;
+    HRESULT hr;
+    struct pipe_blit_info blit;
+
+    DBG("present: This=%p pSourceRect=%p pDestRect=%p "
+        "pDirtyRegion=%p hDestWindowOverride=%p"
+        "dwFlags=%d resource=%p\n",
+        This, pSourceRect, pDestRect, pDirtyRegion,
+        hDestWindowOverride, (int)dwFlags, This->buffers[0]->base.resource);
+
+    if (pSourceRect)
+        DBG("pSourceRect = (%u..%u)x(%u..%u)\n",
+            pSourceRect->left, pSourceRect->right,
+            pSourceRect->top, pSourceRect->bottom);
+    if (pDestRect)
+        DBG("pDestRect = (%u..%u)x(%u..%u)\n",
+            pDestRect->left, pDestRect->right,
+            pDestRect->top, pDestRect->bottom);
+
+    /* TODO: in the case the source and destination rect have different size:
+     * We need to allocate a new buffer, and do a blit to it to resize.
+     * We can't use the present_buffer for that since when we created it,
+     * we couldn't guess which size would have been needed.
+     * If pDestRect or pSourceRect is null, we have to check the sizes
+     * from the source size, and the destination window size.
+     * In this case, either resize rngdata, or pass NULL instead
+     */
+    /* Note: This->buffers[0]->level should always be 0 */
+
+    if (This->rendering_done)
+        goto bypass_rendering;
+
+    resource = This->buffers[0]->base.resource;
+
+    if (This->params.SwapEffect == D3DSWAPEFFECT_DISCARD)
+        handle_draw_cursor_and_hud(This, resource);
+
+    if (This->present_buffers) {
+        blit.src.resource = resource;
+        blit.src.level = 0;
+        blit.src.format = resource->format;
+        blit.src.box.z = 0;
+        blit.src.box.depth = 1;
+        blit.src.box.x = 0;
+        blit.src.box.y = 0;
+        blit.src.box.width = resource->width0;
+        blit.src.box.height = resource->height0;
+
+        resource = This->present_buffers[0];
+
+        blit.dst.resource = resource;
+        blit.dst.level = 0;
+        blit.dst.format = resource->format;
+        blit.dst.box.z = 0;
+        blit.dst.box.depth = 1;
+        blit.dst.box.x = 0;
+        blit.dst.box.y = 0;
+        blit.dst.box.width = resource->width0;
+        blit.dst.box.height = resource->height0;
+
+        blit.mask = PIPE_MASK_RGBA;
+        blit.filter = PIPE_TEX_FILTER_NEAREST;
+        blit.scissor_enable = FALSE;
+
+        This->pipe->blit(This->pipe, &blit);
+    }
+
+    if (This->params.SwapEffect != D3DSWAPEFFECT_DISCARD)
+        handle_draw_cursor_and_hud(This, resource);
+
+    fence = NULL;
+    This->pipe->flush(This->pipe, &fence, PIPE_FLUSH_END_OF_FRAME);
+    if (fence) {
+        swap_fences_push_back(This, fence);
+        This->screen->fence_reference(This->screen, &fence, NULL);
+    }
+
+    This->rendering_done = TRUE;
+bypass_rendering:
+
+    if (dwFlags & D3DPRESENT_DONOTWAIT) {
+        UNTESTED(2);
+        BOOL still_draw = FALSE;
+        fence = swap_fences_see_front(This);
+        if (fence) {
+            still_draw = !This->screen->fence_signalled(This->screen, fence);
+            This->screen->fence_reference(This->screen, &fence, NULL);
+        }
+        if (still_draw)
+            return D3DERR_WASSTILLDRAWING;
+    }
+
+    fence = swap_fences_pop_front(This);
+    if (fence) {
+        (void) This->screen->fence_finish(This->screen, fence, PIPE_TIMEOUT_INFINITE);
+        This->screen->fence_reference(This->screen, &fence, NULL);
+    }
+
+    if (This->present_buffers)
+        resource = This->present_buffers[0];
+    else
+        resource = This->buffers[0]->base.resource;
+    This->pipe->flush_resource(This->pipe, resource);
+    hr = ID3DPresent_PresentBuffer(This->present, This->present_handles[0], hDestWindowOverride, pSourceRect, pDestRect, pDirtyRegion, dwFlags);
+
+    if (FAILED(hr)) { UNTESTED(3);return hr; }
+
+    This->rendering_done = FALSE;
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineSwapChain9_Present( struct NineSwapChain9 *This,
+                        const RECT *pSourceRect,
+                        const RECT *pDestRect,
+                        HWND hDestWindowOverride,
+                        const RGNDATA *pDirtyRegion,
+                        DWORD dwFlags )
+{
+    struct pipe_resource *res = NULL;
+    D3DWindowBuffer *handle_temp;
+    int i;
+    BOOL released;
+    HRESULT hr = present(This, pSourceRect, pDestRect,
+                         hDestWindowOverride, pDirtyRegion, dwFlags);
+
+    if (hr == D3DERR_WASSTILLDRAWING)
+        return hr;
+
+    switch (This->params.SwapEffect) {
+        case D3DSWAPEFFECT_FLIP:
+            UNTESTED(4);
+        case D3DSWAPEFFECT_DISCARD:
+            /* rotate the queue */;
+            pipe_resource_reference(&res, This->buffers[0]->base.resource);
+            for (i = 1; i <= This->params.BackBufferCount; i++) {
+                NineSurface9_SetResourceResize(This->buffers[i - 1],
+                                               This->buffers[i]->base.resource);
+            }
+            NineSurface9_SetResourceResize(
+                This->buffers[This->params.BackBufferCount], res);
+            pipe_resource_reference(&res, NULL);
+
+            if (This->present_buffers) {
+                pipe_resource_reference(&res, This->present_buffers[0]);
+                for (i = 1; i <= This->params.BackBufferCount; i++)
+                    pipe_resource_reference(&(This->present_buffers[i-1]), This->present_buffers[i]);
+                pipe_resource_reference(&(This->present_buffers[This->params.BackBufferCount]), res);
+                pipe_resource_reference(&res, NULL);
+            }
+
+            handle_temp = This->present_handles[0];
+            for (i = 1; i <= This->params.BackBufferCount; i++) {
+                This->present_handles[i-1] = This->present_handles[i];
+            }
+            This->present_handles[This->params.BackBufferCount] = handle_temp;
+            break;
+
+        case D3DSWAPEFFECT_COPY:
+            UNTESTED(5);
+            /* do nothing */
+            break;
+
+        case D3DSWAPEFFECT_OVERLAY:
+            /* XXX not implemented */
+            break;
+
+        case D3DSWAPEFFECT_FLIPEX:
+            /* XXX not implemented */
+            break;
+    }
+
+    ID3DPresent_WaitBufferReleased(This->present, This->present_handles[0]);
+
+    This->base.device->state.changed.group |= NINE_STATE_FB;
+    nine_update_state(This->base.device, NINE_STATE_FB);
+
+    return hr;
+}
+
+HRESULT WINAPI
+NineSwapChain9_GetFrontBufferData( struct NineSwapChain9 *This,
+                                   IDirect3DSurface9 *pDestSurface )
+{
+    struct NineSurface9 *dest_surface = NineSurface9(pDestSurface);
+    struct NineDevice9 *pDevice = This->base.device;
+    unsigned int width, height;
+    struct pipe_resource *temp_resource;
+    struct NineSurface9 *temp_surface;
+    D3DWindowBuffer *temp_handle;
+    D3DSURFACE_DESC desc;
+    HRESULT hr;
+
+    DBG("GetFrontBufferData: This=%p pDestSurface=%p\n",
+        This, pDestSurface);
+
+    width = dest_surface->desc.Width;
+    height = dest_surface->desc.Height;
+
+    /* Note: front window size and destination size are supposed
+     * to match. However it's not very clear what should get taken in Windowed
+     * mode. It may need a fix */
+    create_present_buffer(This, width, height, &temp_resource, &temp_handle);
+
+    desc.Type = D3DRTYPE_SURFACE;
+    desc.Pool = D3DPOOL_DEFAULT;
+    desc.MultiSampleType = D3DMULTISAMPLE_NONE;
+    desc.MultiSampleQuality = 0;
+    desc.Width = width;
+    desc.Height = height;
+    /* NineSurface9_CopySurface needs same format. */
+    desc.Format = dest_surface->desc.Format;
+    desc.Usage = D3DUSAGE_RENDERTARGET;
+    hr = NineSurface9_new(pDevice, NineUnknown(This), temp_resource, 0,
+                          0, 0, &desc, &temp_surface);
+    pipe_resource_reference(&temp_resource, NULL);
+    if (FAILED(hr)) {
+        DBG("Failed to create temp FrontBuffer surface.\n");
+        return hr;
+    }
+
+    ID3DPresent_FrontBufferCopy(This->present, temp_handle);
+
+    NineSurface9_CopySurface(dest_surface, temp_surface, NULL, NULL);
+
+    ID3DPresent_DestroyD3DWindowBuffer(This->present, temp_handle);
+    NineUnknown_Destroy(NineUnknown(temp_surface));
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineSwapChain9_GetBackBuffer( struct NineSwapChain9 *This,
+                              UINT iBackBuffer,
+                              D3DBACKBUFFER_TYPE Type,
+                              IDirect3DSurface9 **ppBackBuffer )
+{
+    DBG("GetBackBuffer: This=%p iBackBuffer=%d Type=%d ppBackBuffer=%p\n",
+        This, iBackBuffer, Type, ppBackBuffer);
+    (void)user_error(Type == D3DBACKBUFFER_TYPE_MONO);
+    user_assert(iBackBuffer < This->params.BackBufferCount, D3DERR_INVALIDCALL);
+    user_assert(ppBackBuffer != NULL, E_POINTER);
+
+    NineUnknown_AddRef(NineUnknown(This->buffers[iBackBuffer]));
+    *ppBackBuffer = (IDirect3DSurface9 *)This->buffers[iBackBuffer];
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineSwapChain9_GetRasterStatus( struct NineSwapChain9 *This,
+                                D3DRASTER_STATUS *pRasterStatus )
+{
+    DBG("GetRasterStatus: This=%p pRasterStatus=%p\n",
+        This, pRasterStatus);
+    user_assert(pRasterStatus != NULL, E_POINTER);
+    return ID3DPresent_GetRasterStatus(This->present, pRasterStatus);
+}
+
+HRESULT WINAPI
+NineSwapChain9_GetDisplayMode( struct NineSwapChain9 *This,
+                               D3DDISPLAYMODE *pMode )
+{
+    D3DDISPLAYMODEEX mode;
+    D3DDISPLAYROTATION rot;
+    HRESULT hr;
+
+    DBG("GetDisplayMode: This=%p pMode=%p\n",
+        This, pMode);
+    user_assert(pMode != NULL, E_POINTER);
+
+    hr = ID3DPresent_GetDisplayMode(This->present, &mode, &rot);
+    if (SUCCEEDED(hr)) {
+        pMode->Width = mode.Width;
+        pMode->Height = mode.Height;
+        pMode->RefreshRate = mode.RefreshRate;
+        pMode->Format = mode.Format;
+    }
+    return hr;
+}
+
+HRESULT WINAPI
+NineSwapChain9_GetPresentParameters( struct NineSwapChain9 *This,
+                                     D3DPRESENT_PARAMETERS *pPresentationParameters )
+{
+    DBG("GetPresentParameters: This=%p pPresentationParameters=%p\n",
+        This, pPresentationParameters);
+    user_assert(pPresentationParameters != NULL, E_POINTER);
+    *pPresentationParameters = This->params;
+    return D3D_OK;
+}
+
+IDirect3DSwapChain9Vtbl NineSwapChain9_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)NineSwapChain9_Present,
+    (void *)NineSwapChain9_GetFrontBufferData,
+    (void *)NineSwapChain9_GetBackBuffer,
+    (void *)NineSwapChain9_GetRasterStatus,
+    (void *)NineSwapChain9_GetDisplayMode,
+    (void *)NineUnknown_GetDevice, /* actually part of SwapChain9 iface */
+    (void *)NineSwapChain9_GetPresentParameters
+};
+
+static const GUID *NineSwapChain9_IIDs[] = {
+    &IID_IDirect3DSwapChain9,
+    &IID_IUnknown,
+    NULL
+};
+
+HRESULT
+NineSwapChain9_new( struct NineDevice9 *pDevice,
+                    BOOL implicit,
+                    ID3DPresent *pPresent,
+                    D3DPRESENT_PARAMETERS *pPresentationParameters,
+                    struct d3dadapter9_context *pCTX,
+                    HWND hFocusWindow,
+                    struct NineSwapChain9 **ppOut )
+{
+    NINE_DEVICE_CHILD_NEW(SwapChain9, ppOut, pDevice, /* args */
+                          implicit, pPresent, pPresentationParameters,
+                          pCTX, hFocusWindow, NULL);
+}
diff --git a/src/gallium/state_trackers/nine/swapchain9.h b/src/gallium/state_trackers/nine/swapchain9.h
new file mode 100644 (file)
index 0000000..566f78a
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _NINE_SWAPCHAIN9_H_
+#define _NINE_SWAPCHAIN9_H_
+
+#include "iunknown.h"
+#include "adapter9.h"
+
+#include "d3dadapter/d3dadapter9.h"
+
+struct NineDevice9;
+struct NineSurface9;
+struct nine_winsys_swapchain;
+struct blit_state;
+
+#define DRI_SWAP_FENCES_MAX 4
+#define DRI_SWAP_FENCES_MASK 3
+
+struct NineSwapChain9
+{
+    struct NineUnknown base;
+
+    /* G3D stuff */
+    struct pipe_screen *screen;
+    struct pipe_context *pipe;
+    struct cso_context *cso;
+
+    /* presentation backend */
+    ID3DPresent *present;
+    D3DPRESENT_PARAMETERS params;
+    D3DDISPLAYMODEEX *mode;
+    struct d3dadapter9_context *actx;
+    BOOL implicit;
+
+    /* buffer handles */
+    struct NineSurface9 **buffers; /* 0 to BackBufferCount-1 : the back buffers. BackBufferCount : additional buffer */
+    struct pipe_resource **present_buffers;
+    D3DWindowBuffer **present_handles;
+
+    struct pipe_fence_handle *swap_fences[DRI_SWAP_FENCES_MAX];
+    unsigned int cur_fences;
+    unsigned int head;
+    unsigned int tail;
+    unsigned int desired_fences;
+
+    BOOL rendering_done;
+
+    struct NineSurface9 *zsbuf;
+
+    D3DGAMMARAMP gamma;
+};
+static INLINE struct NineSwapChain9 *
+NineSwapChain9( void *data )
+{
+    return (struct NineSwapChain9 *)data;
+}
+
+HRESULT
+NineSwapChain9_new( struct NineDevice9 *pDevice,
+                    BOOL implicit,
+                    ID3DPresent *pPresent,
+                    D3DPRESENT_PARAMETERS *pPresentationParameters,
+                    struct d3dadapter9_context *pCTX,
+                    HWND hFocusWindow,
+                    struct NineSwapChain9 **ppOut );
+
+HRESULT
+NineSwapChain9_ctor( struct NineSwapChain9 *This,
+                     struct NineUnknownParams *pParams,
+                     BOOL implicit,
+                     ID3DPresent *pPresent,
+                     D3DPRESENT_PARAMETERS *pPresentationParameters,
+                     struct d3dadapter9_context *pCTX,
+                     HWND hFocusWindow,
+                     D3DDISPLAYMODEEX *mode );
+
+void
+NineSwapChain9_dtor( struct NineSwapChain9 *This );
+
+HRESULT
+NineSwapChain9_Resize( struct NineSwapChain9 *This,
+                       D3DPRESENT_PARAMETERS *pParams,
+                       D3DDISPLAYMODEEX *mode );
+
+HRESULT WINAPI
+NineSwapChain9_Present( struct NineSwapChain9 *This,
+                        const RECT *pSourceRect,
+                        const RECT *pDestRect,
+                        HWND hDestWindowOverride,
+                        const RGNDATA *pDirtyRegion,
+                        DWORD dwFlags );
+
+HRESULT WINAPI
+NineSwapChain9_GetFrontBufferData( struct NineSwapChain9 *This,
+                                   IDirect3DSurface9 *pDestSurface );
+
+HRESULT WINAPI
+NineSwapChain9_GetBackBuffer( struct NineSwapChain9 *This,
+                              UINT iBackBuffer,
+                              D3DBACKBUFFER_TYPE Type,
+                              IDirect3DSurface9 **ppBackBuffer );
+
+HRESULT WINAPI
+NineSwapChain9_GetRasterStatus( struct NineSwapChain9 *This,
+                                D3DRASTER_STATUS *pRasterStatus );
+
+HRESULT WINAPI
+NineSwapChain9_GetDisplayMode( struct NineSwapChain9 *This,
+                               D3DDISPLAYMODE *pMode );
+
+HRESULT WINAPI
+NineSwapChain9_GetPresentParameters( struct NineSwapChain9 *This,
+                                     D3DPRESENT_PARAMETERS *pPresentationParameters );
+
+#endif /* _NINE_SWAPCHAIN9_H_ */
diff --git a/src/gallium/state_trackers/nine/swapchain9ex.c b/src/gallium/state_trackers/nine/swapchain9ex.c
new file mode 100644 (file)
index 0000000..7207b58
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "swapchain9ex.h"
+#include "device9.h"
+
+#include "nine_helpers.h"
+
+#define DBG_CHANNEL DBG_SWAPCHAIN
+
+static HRESULT
+NineSwapChain9Ex_ctor( struct NineSwapChain9Ex *This,
+                       struct NineUnknownParams *pParams,
+                       BOOL implicit,
+                       ID3DPresent *pPresent,
+                       D3DPRESENT_PARAMETERS *pPresentationParameters,
+                       struct d3dadapter9_context *pCTX,
+                       HWND hFocusWindow,
+                       D3DDISPLAYMODEEX *mode )
+{
+    return NineSwapChain9_ctor(&This->base, pParams, implicit, pPresent,
+                               pPresentationParameters, pCTX, hFocusWindow, mode);
+}
+
+static void
+NineSwapChain9Ex_dtor( struct NineSwapChain9Ex *This )
+{
+    NineSwapChain9_dtor(&This->base);
+}
+
+HRESULT WINAPI
+NineSwapChain9Ex_GetLastPresentCount( struct NineSwapChain9Ex *This,
+                                      UINT *pLastPresentCount )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineSwapChain9Ex_GetPresentStats( struct NineSwapChain9Ex *This,
+                                  D3DPRESENTSTATS *pPresentationStatistics )
+{
+    STUB(D3DERR_INVALIDCALL);
+}
+
+HRESULT WINAPI
+NineSwapChain9Ex_GetDisplayModeEx( struct NineSwapChain9Ex *This,
+                                   D3DDISPLAYMODEEX *pMode,
+                                   D3DDISPLAYROTATION *pRotation )
+{
+    D3DDISPLAYROTATION rot;
+
+    user_assert(pMode != NULL, E_POINTER);
+    if (!pRotation) { pRotation = &rot; }
+
+    return ID3DPresent_GetDisplayMode(This->base.present, pMode, pRotation);
+}
+
+IDirect3DSwapChain9ExVtbl NineSwapChain9Ex_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)NineSwapChain9_Present,
+    (void *)NineSwapChain9_GetFrontBufferData,
+    (void *)NineSwapChain9_GetBackBuffer,
+    (void *)NineSwapChain9_GetRasterStatus,
+    (void *)NineSwapChain9_GetDisplayMode,
+    (void *)NineUnknown_GetDevice, /* actually part of NineSwapChain9 iface */
+    (void *)NineSwapChain9_GetPresentParameters,
+    (void *)NineSwapChain9Ex_GetLastPresentCount,
+    (void *)NineSwapChain9Ex_GetPresentStats,
+    (void *)NineSwapChain9Ex_GetDisplayModeEx
+};
+
+static const GUID *NineSwapChain9Ex_IIDs[] = {
+    &IID_IDirect3DSwapChain9Ex,
+    &IID_IDirect3DSwapChain9,
+    &IID_IUnknown,
+    NULL
+};
+
+HRESULT
+NineSwapChain9Ex_new( struct NineDevice9 *pDevice,
+                      BOOL implicit,
+                      ID3DPresent *pPresent,
+                      D3DPRESENT_PARAMETERS *pPresentationParameters,
+                      struct d3dadapter9_context *pCTX,
+                      HWND hFocusWindow,
+                      D3DDISPLAYMODEEX *mode,
+                      struct NineSwapChain9Ex **ppOut )
+{
+    NINE_DEVICE_CHILD_NEW(SwapChain9Ex, ppOut, pDevice, /* args */
+                          implicit, pPresent, pPresentationParameters,
+                          pCTX, hFocusWindow, mode);
+}
diff --git a/src/gallium/state_trackers/nine/swapchain9ex.h b/src/gallium/state_trackers/nine/swapchain9ex.h
new file mode 100644 (file)
index 0000000..bf40783
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _NINE_SWAPCHAIN9EX_H_
+#define _NINE_SWAPCHAIN9EX_H_
+
+#include "swapchain9.h"
+
+struct NineSwapChain9Ex
+{
+    struct NineSwapChain9 base;
+};
+static INLINE struct NineSwapChain9Ex *
+NineSwapChain9Ex( void *data )
+{
+    return (struct NineSwapChain9Ex *)data;
+}
+
+HRESULT
+NineSwapChain9Ex_new( struct NineDevice9 *pDevice,
+                      BOOL implicit,
+                      ID3DPresent *pPresent,
+                      D3DPRESENT_PARAMETERS *pPresentationParameters,
+                      struct d3dadapter9_context *pCTX,
+                      HWND hFocusWindow,
+                      D3DDISPLAYMODEEX *mode,
+                      struct NineSwapChain9Ex **ppOut );
+
+HRESULT WINAPI
+NineSwapChain9Ex_GetLastPresentCount( struct NineSwapChain9Ex *This,
+                                      UINT *pLastPresentCount );
+
+HRESULT WINAPI
+NineSwapChain9Ex_GetPresentStats( struct NineSwapChain9Ex *This,
+                                  D3DPRESENTSTATS *pPresentationStatistics );
+
+HRESULT WINAPI
+NineSwapChain9Ex_GetDisplayModeEx( struct NineSwapChain9Ex *This,
+                                   D3DDISPLAYMODEEX *pMode,
+                                   D3DDISPLAYROTATION *pRotation );
+
+#endif /* _NINE_SWAPCHAIN9EX_H_ */
diff --git a/src/gallium/state_trackers/nine/texture9.c b/src/gallium/state_trackers/nine/texture9.c
new file mode 100644 (file)
index 0000000..c13268d
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "device9.h"
+#include "surface9.h"
+#include "texture9.h"
+#include "nine_helpers.h"
+#include "nine_pipe.h"
+#include "nine_dump.h"
+
+#include "pipe/p_state.h"
+#include "pipe/p_context.h"
+#include "pipe/p_screen.h"
+#include "util/u_inlines.h"
+#include "util/u_resource.h"
+
+#define DBG_CHANNEL DBG_TEXTURE
+
+static HRESULT
+NineTexture9_ctor( struct NineTexture9 *This,
+                   struct NineUnknownParams *pParams,
+                   UINT Width, UINT Height, UINT Levels,
+                   DWORD Usage,
+                   D3DFORMAT Format,
+                   D3DPOOL Pool,
+                   HANDLE *pSharedHandle )
+{
+    struct pipe_screen *screen = pParams->device->screen;
+    struct pipe_resource *info = &This->base.base.info;
+    unsigned l;
+    D3DSURFACE_DESC sfdesc;
+    HRESULT hr;
+    const boolean shared_create = pSharedHandle && !*pSharedHandle;
+
+    DBG("(%p) Width=%u Height=%u Levels=%u Usage=%s Format=%s Pool=%s "
+        "pSharedHandle=%p\n", This, Width, Height, Levels,
+        nine_D3DUSAGE_to_str(Usage),
+        d3dformat_to_string(Format), nine_D3DPOOL_to_str(Pool), pSharedHandle);
+
+    user_assert(!(Usage & D3DUSAGE_AUTOGENMIPMAP) ||
+                (Pool != D3DPOOL_SYSTEMMEM && Levels <= 1), D3DERR_INVALIDCALL);
+
+    /* TODO: implement buffer sharing (should work with cross process too)
+     *
+     * Gem names may have fit but they're depreciated and won't work on render-nodes.
+     * One solution is to use shm buffers. We would use a /dev/shm file, fill the first
+     * values to tell it is a nine buffer, the size, which function created it, etc,
+     * and then it would contain the data. The handle would be a number, corresponding to
+     * the file to read (/dev/shm/nine-share-4 for example would be 4).
+     *
+     * Wine just ignores the argument, which works only if the app creates the handle
+     * and won't use it. Instead of failing, we support that situation by putting an
+     * invalid handle, that we would fail to import. Please note that we don't advertise
+     * the flag indicating the support for that feature, but apps seem to not care.
+     */
+    user_assert(!pSharedHandle ||
+                Pool == D3DPOOL_SYSTEMMEM ||
+                Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL);
+
+    if (pSharedHandle && Pool == D3DPOOL_DEFAULT) {
+        /* Note: Below there is some implementation to support buffer sharing in
+         * this case, but it won't work for cross-process. Thus just ignore
+         * that code. */
+        if (shared_create) {
+            DBG("Creating Texture with invalid handle. Importing will fail\n.");
+            *pSharedHandle = (HANDLE)1; /* Wine would keep it NULL */
+            pSharedHandle = NULL;
+        } else {
+            ERR("Application tries to use cross-process sharing feature. Nine "
+                "doesn't support it");
+            return D3DERR_INVALIDCALL;
+        }
+    }
+
+    if (Usage & D3DUSAGE_AUTOGENMIPMAP)
+        Levels = 0;
+
+    This->base.format = Format;
+    This->base.base.usage = Usage;
+
+    info->screen = screen;
+    info->target = PIPE_TEXTURE_2D;
+    info->format = d3d9_to_pipe_format(Format);
+    info->width0 = Width;
+    info->height0 = Height;
+    info->depth0 = 1;
+    if (Levels)
+        info->last_level = Levels - 1;
+    else
+        info->last_level = util_logbase2(MAX2(Width, Height));
+    info->array_size = 1;
+    info->nr_samples = 0;
+    info->bind = PIPE_BIND_SAMPLER_VIEW;
+    info->usage = PIPE_USAGE_DEFAULT;
+    info->flags = 0;
+
+    if (Usage & D3DUSAGE_RENDERTARGET)
+        info->bind |= PIPE_BIND_RENDER_TARGET;
+    if (Usage & D3DUSAGE_DEPTHSTENCIL)
+        info->bind |= PIPE_BIND_DEPTH_STENCIL;
+
+    if (Usage & D3DUSAGE_DYNAMIC) {
+        info->usage = PIPE_USAGE_DYNAMIC;
+        info->bind |=
+            PIPE_BIND_TRANSFER_READ |
+            PIPE_BIND_TRANSFER_WRITE;
+    }
+    if (pSharedHandle)
+        info->bind |= PIPE_BIND_SHARED;
+
+    if (Pool == D3DPOOL_SYSTEMMEM)
+        info->usage = PIPE_USAGE_STAGING;
+
+    if (pSharedHandle && !shared_create) {
+        if (Pool == D3DPOOL_SYSTEMMEM) {
+            /* Hack for surface creation. */
+            This->base.base.resource = (struct pipe_resource *)*pSharedHandle;
+        } else {
+            struct pipe_resource *res;
+            res = screen->resource_from_handle(screen, info,
+                                      (struct winsys_handle *)pSharedHandle);
+            if (!res)
+                return D3DERR_NOTFOUND;
+            This->base.base.resource = res;
+        }
+    }
+
+    This->surfaces = CALLOC(info->last_level + 1, sizeof(*This->surfaces));
+    if (!This->surfaces)
+        return E_OUTOFMEMORY;
+
+    hr = NineBaseTexture9_ctor(&This->base, pParams, D3DRTYPE_TEXTURE, Pool);
+    if (FAILED(hr))
+        return hr;
+    This->base.pstype = (Height == 1) ? 1 : 0;
+
+    /* Create all the surfaces right away.
+     * They manage backing storage, and transfers (LockRect) are deferred
+     * to them.
+     */
+    sfdesc.Format = Format;
+    sfdesc.Type = D3DRTYPE_SURFACE;
+    sfdesc.Usage = Usage;
+    sfdesc.Pool = Pool;
+    sfdesc.MultiSampleType = D3DMULTISAMPLE_NONE;
+    sfdesc.MultiSampleQuality = 0;
+    for (l = 0; l <= info->last_level; ++l) {
+        sfdesc.Width = u_minify(Width, l);
+        sfdesc.Height = u_minify(Height, l);
+
+        hr = NineSurface9_new(This->base.base.base.device, NineUnknown(This),
+                              This->base.base.resource, D3DRTYPE_TEXTURE, l, 0,
+                              &sfdesc, &This->surfaces[l]);
+        if (FAILED(hr))
+            return hr;
+    }
+
+    This->dirty_rect.depth = 1; /* widht == 0 means empty, depth stays 1 */
+
+    if (pSharedHandle) {
+        if (Pool == D3DPOOL_SYSTEMMEM) {
+            This->base.base.resource = NULL;
+            if (shared_create)
+                *pSharedHandle = This->surfaces[0]->base.data;
+        } else
+        if (shared_create) {
+            boolean ok;
+            ok = screen->resource_get_handle(screen, This->base.base.resource,
+                                         (struct winsys_handle *)pSharedHandle);
+            if (!ok)
+                return D3DERR_DRIVERINTERNALERROR;
+        }
+    }
+
+    return D3D_OK;
+}
+
+static void
+NineTexture9_dtor( struct NineTexture9 *This )
+{
+    unsigned l;
+
+    if (This->surfaces) {
+        /* The surfaces should have 0 references and be unbound now. */
+        for (l = 0; l <= This->base.base.info.last_level; ++l)
+            NineUnknown_Destroy(&This->surfaces[l]->base.base);
+        FREE(This->surfaces);
+    }
+
+    NineBaseTexture9_dtor(&This->base);
+}
+
+HRESULT WINAPI
+NineTexture9_GetLevelDesc( struct NineTexture9 *This,
+                           UINT Level,
+                           D3DSURFACE_DESC *pDesc )
+{
+    user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL);
+    user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP),
+                D3DERR_INVALIDCALL);
+
+    *pDesc = This->surfaces[Level]->desc;
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineTexture9_GetSurfaceLevel( struct NineTexture9 *This,
+                              UINT Level,
+                              IDirect3DSurface9 **ppSurfaceLevel )
+{
+    user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL);
+    user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP),
+                D3DERR_INVALIDCALL);
+
+    NineUnknown_AddRef(NineUnknown(This->surfaces[Level]));
+    *ppSurfaceLevel = (IDirect3DSurface9 *)This->surfaces[Level];
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineTexture9_LockRect( struct NineTexture9 *This,
+                       UINT Level,
+                       D3DLOCKED_RECT *pLockedRect,
+                       const RECT *pRect,
+                       DWORD Flags )
+{
+    user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL);
+    user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP),
+                D3DERR_INVALIDCALL);
+
+    return NineSurface9_LockRect(This->surfaces[Level], pLockedRect,
+                                 pRect, Flags);
+}
+
+HRESULT WINAPI
+NineTexture9_UnlockRect( struct NineTexture9 *This,
+                         UINT Level )
+{
+    user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL);
+
+    return NineSurface9_UnlockRect(This->surfaces[Level]);
+}
+
+HRESULT WINAPI
+NineTexture9_AddDirtyRect( struct NineTexture9 *This,
+                           const RECT *pDirtyRect )
+{
+    DBG("This=%p pDirtyRect=%p[(%u,%u)-(%u,%u)]\n", This, pDirtyRect,
+        pDirtyRect ? pDirtyRect->left : 0, pDirtyRect ? pDirtyRect->top : 0,
+        pDirtyRect ? pDirtyRect->right : 0, pDirtyRect ? pDirtyRect->bottom : 0);
+
+    /* Tracking dirty regions on DEFAULT or SYSTEMMEM resources is pointless,
+     * because we always write to the final storage. Just marked it dirty in
+     * case we need to generate mip maps.
+     */
+    if (This->base.base.pool != D3DPOOL_MANAGED) {
+        if (This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP)
+            This->base.dirty_mip = TRUE;
+        return D3D_OK;
+    }
+    This->base.dirty = TRUE;
+
+    BASETEX_REGISTER_UPDATE(&This->base);
+
+    if (!pDirtyRect) {
+        u_box_origin_2d(This->base.base.info.width0,
+                        This->base.base.info.height0, &This->dirty_rect);
+    } else {
+        struct pipe_box box;
+        rect_to_pipe_box_clamp(&box, pDirtyRect);
+        u_box_union_2d(&This->dirty_rect, &This->dirty_rect, &box);
+    }
+    return D3D_OK;
+}
+
+IDirect3DTexture9Vtbl NineTexture9_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */
+    (void *)NineResource9_SetPrivateData,
+    (void *)NineResource9_GetPrivateData,
+    (void *)NineResource9_FreePrivateData,
+    (void *)NineResource9_SetPriority,
+    (void *)NineResource9_GetPriority,
+    (void *)NineBaseTexture9_PreLoad,
+    (void *)NineResource9_GetType,
+    (void *)NineBaseTexture9_SetLOD,
+    (void *)NineBaseTexture9_GetLOD,
+    (void *)NineBaseTexture9_GetLevelCount,
+    (void *)NineBaseTexture9_SetAutoGenFilterType,
+    (void *)NineBaseTexture9_GetAutoGenFilterType,
+    (void *)NineBaseTexture9_GenerateMipSubLevels,
+    (void *)NineTexture9_GetLevelDesc,
+    (void *)NineTexture9_GetSurfaceLevel,
+    (void *)NineTexture9_LockRect,
+    (void *)NineTexture9_UnlockRect,
+    (void *)NineTexture9_AddDirtyRect
+};
+
+static const GUID *NineTexture9_IIDs[] = {
+    &IID_IDirect3DTexture9,
+    &IID_IDirect3DBaseTexture9,
+    &IID_IDirect3DResource9,
+    &IID_IUnknown,
+    NULL
+};
+
+HRESULT
+NineTexture9_new( struct NineDevice9 *pDevice,
+                  UINT Width, UINT Height, UINT Levels,
+                  DWORD Usage,
+                  D3DFORMAT Format,
+                  D3DPOOL Pool,
+                  struct NineTexture9 **ppOut,
+                  HANDLE *pSharedHandle )
+{
+    NINE_DEVICE_CHILD_NEW(Texture9, ppOut, pDevice,
+                          Width, Height, Levels,
+                          Usage, Format, Pool, pSharedHandle);
+}
diff --git a/src/gallium/state_trackers/nine/texture9.h b/src/gallium/state_trackers/nine/texture9.h
new file mode 100644 (file)
index 0000000..5e37a12
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _NINE_TEXTURE9_H_
+#define _NINE_TEXTURE9_H_
+
+#include "basetexture9.h"
+#include "surface9.h"
+
+struct NineTexture9
+{
+    struct NineBaseTexture9 base;
+    struct NineSurface9 **surfaces;
+    struct pipe_box dirty_rect; /* covers all mip levels */
+};
+static INLINE struct NineTexture9 *
+NineTexture9( void *data )
+{
+    return (struct NineTexture9 *)data;
+}
+
+HRESULT
+NineTexture9_new( struct NineDevice9 *pDevice,
+                  UINT Width, UINT Height, UINT Levels,
+                  DWORD Usage,
+                  D3DFORMAT Format,
+                  D3DPOOL Pool,
+                  struct NineTexture9 **ppOut,
+                  HANDLE *pSharedHandle );
+
+HRESULT WINAPI
+NineTexture9_GetLevelDesc( struct NineTexture9 *This,
+                           UINT Level,
+                           D3DSURFACE_DESC *pDesc );
+
+HRESULT WINAPI
+NineTexture9_GetSurfaceLevel( struct NineTexture9 *This,
+                              UINT Level,
+                              IDirect3DSurface9 **ppSurfaceLevel );
+
+HRESULT WINAPI
+NineTexture9_LockRect( struct NineTexture9 *This,
+                       UINT Level,
+                       D3DLOCKED_RECT *pLockedRect,
+                       const RECT *pRect,
+                       DWORD Flags );
+
+HRESULT WINAPI
+NineTexture9_UnlockRect( struct NineTexture9 *This,
+                         UINT Level );
+
+HRESULT WINAPI
+NineTexture9_AddDirtyRect( struct NineTexture9 *This,
+                           const RECT *pDirtyRect );
+
+#endif /* _NINE_TEXTURE9_H_ */
diff --git a/src/gallium/state_trackers/nine/vertexbuffer9.c b/src/gallium/state_trackers/nine/vertexbuffer9.c
new file mode 100644 (file)
index 0000000..6a57349
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "vertexbuffer9.h"
+#include "device9.h"
+#include "nine_helpers.h"
+#include "nine_pipe.h"
+
+#include "pipe/p_screen.h"
+#include "pipe/p_context.h"
+#include "pipe/p_state.h"
+#include "pipe/p_defines.h"
+#include "pipe/p_format.h"
+#include "util/u_box.h"
+
+#define DBG_CHANNEL DBG_VERTEXBUFFER
+
+HRESULT
+NineVertexBuffer9_ctor( struct NineVertexBuffer9 *This,
+                        struct NineUnknownParams *pParams,
+                        D3DVERTEXBUFFER_DESC *pDesc )
+{
+    struct pipe_resource *info = &This->base.info;
+    HRESULT hr;
+
+    DBG("This=%p Size=0x%x Usage=%x Pool=%u\n", This,
+        pDesc->Size, pDesc->Usage, pDesc->Pool);
+
+    user_assert(pDesc->Pool != D3DPOOL_SCRATCH, D3DERR_INVALIDCALL);
+
+    This->maps = MALLOC(sizeof(struct pipe_transfer *));
+    if (!This->maps)
+        return E_OUTOFMEMORY;
+    This->nmaps = 0;
+    This->maxmaps = 1;
+
+    This->pipe = pParams->device->pipe;
+
+    info->screen = pParams->device->screen;
+    info->target = PIPE_BUFFER;
+    info->format = PIPE_FORMAT_R8_UNORM;
+    info->width0 = pDesc->Size;
+    info->flags = 0;
+
+    info->bind = PIPE_BIND_VERTEX_BUFFER | PIPE_BIND_TRANSFER_WRITE;
+    if (!(pDesc->Usage & D3DUSAGE_WRITEONLY))
+        info->bind |= PIPE_BIND_TRANSFER_READ;
+
+    info->usage = PIPE_USAGE_DEFAULT;
+    if (pDesc->Usage & D3DUSAGE_DYNAMIC)
+        info->usage = PIPE_USAGE_STREAM;
+    if (pDesc->Pool == D3DPOOL_SYSTEMMEM)
+        info->usage = PIPE_USAGE_STAGING;
+
+    /* if (pDesc->Usage & D3DUSAGE_DONOTCLIP) { } */
+    /* if (pDesc->Usage & D3DUSAGE_NONSECURE) { } */
+    /* if (pDesc->Usage & D3DUSAGE_NPATCHES) { } */
+    /* if (pDesc->Usage & D3DUSAGE_POINTS) { } */
+    /* if (pDesc->Usage & D3DUSAGE_RTPATCHES) { } */
+    /* if (pDesc->Usage & D3DUSAGE_SOFTWAREPROCESSING) { } */
+    /* if (pDesc->Usage & D3DUSAGE_TEXTAPI) { } */
+
+    info->height0 = 1;
+    info->depth0 = 1;
+    info->array_size = 1;
+    info->last_level = 0;
+    info->nr_samples = 0;
+
+    hr = NineResource9_ctor(&This->base, pParams, TRUE, D3DRTYPE_VERTEXBUFFER,
+                            pDesc->Pool);
+    if (FAILED(hr))
+        return hr;
+
+    pDesc->Type = D3DRTYPE_VERTEXBUFFER;
+    pDesc->Format = D3DFMT_VERTEXDATA;
+    This->desc = *pDesc;
+
+    return D3D_OK;
+}
+
+void
+NineVertexBuffer9_dtor( struct NineVertexBuffer9 *This )
+{
+    if (This->maps) {
+        while (This->nmaps) {
+            NineVertexBuffer9_Unlock(This);
+        }
+        FREE(This->maps);
+    }
+
+    NineResource9_dtor(&This->base);
+}
+
+HRESULT WINAPI
+NineVertexBuffer9_Lock( struct NineVertexBuffer9 *This,
+                        UINT OffsetToLock,
+                        UINT SizeToLock,
+                        void **ppbData,
+                        DWORD Flags )
+{
+    struct pipe_box box;
+    void *data;
+    const unsigned usage = d3dlock_buffer_to_pipe_transfer_usage(Flags);
+
+    DBG("This=%p(pipe=%p) OffsetToLock=0x%x, SizeToLock=0x%x, Flags=0x%x\n",
+        This, This->base.resource,
+        OffsetToLock, SizeToLock, Flags);
+
+    user_assert(ppbData, E_POINTER);
+    user_assert(!(Flags & ~(D3DLOCK_DISCARD |
+                            D3DLOCK_DONOTWAIT |
+                            D3DLOCK_NO_DIRTY_UPDATE |
+                            D3DLOCK_NOSYSLOCK |
+                            D3DLOCK_READONLY |
+                            D3DLOCK_NOOVERWRITE)), D3DERR_INVALIDCALL);
+
+    if (This->nmaps == This->maxmaps) {
+        struct pipe_transfer **newmaps =
+            REALLOC(This->maps, sizeof(struct pipe_transfer *)*This->maxmaps,
+                    sizeof(struct pipe_transfer *)*(This->maxmaps << 1));
+        if (newmaps == NULL)
+            return E_OUTOFMEMORY;
+
+        This->maxmaps <<= 1;
+        This->maps = newmaps;
+    }
+
+    if (SizeToLock == 0) {
+        SizeToLock = This->desc.Size - OffsetToLock;
+        user_warn(OffsetToLock != 0);
+    }
+
+    u_box_1d(OffsetToLock, SizeToLock, &box);
+
+    data = This->pipe->transfer_map(This->pipe, This->base.resource, 0,
+                                    usage, &box, &This->maps[This->nmaps]);
+    if (!data) {
+        DBG("pipe::transfer_map failed\n"
+            " usage = %x\n"
+            " box.x = %u\n"
+            " box.width = %u\n",
+            usage, box.x, box.width);
+        /* not sure what to return, msdn suggests this */
+        if (Flags & D3DLOCK_DONOTWAIT)
+            return D3DERR_WASSTILLDRAWING;
+        return D3DERR_INVALIDCALL;
+    }
+
+    This->nmaps++;
+    *ppbData = data;
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineVertexBuffer9_Unlock( struct NineVertexBuffer9 *This )
+{
+    DBG("This=%p\n", This);
+
+    user_assert(This->nmaps > 0, D3DERR_INVALIDCALL);
+    This->pipe->transfer_unmap(This->pipe, This->maps[--(This->nmaps)]);
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineVertexBuffer9_GetDesc( struct NineVertexBuffer9 *This,
+                           D3DVERTEXBUFFER_DESC *pDesc )
+{
+    user_assert(pDesc, E_POINTER);
+    *pDesc = This->desc;
+    return D3D_OK;
+}
+
+IDirect3DVertexBuffer9Vtbl NineVertexBuffer9_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */
+    (void *)NineResource9_SetPrivateData,
+    (void *)NineResource9_GetPrivateData,
+    (void *)NineResource9_FreePrivateData,
+    (void *)NineResource9_SetPriority,
+    (void *)NineResource9_GetPriority,
+    (void *)NineResource9_PreLoad,
+    (void *)NineResource9_GetType,
+    (void *)NineVertexBuffer9_Lock,
+    (void *)NineVertexBuffer9_Unlock,
+    (void *)NineVertexBuffer9_GetDesc
+};
+
+static const GUID *NineVertexBuffer9_IIDs[] = {
+    &IID_IDirect3DVertexBuffer9,
+    &IID_IDirect3DResource9,
+    &IID_IUnknown,
+    NULL
+};
+
+HRESULT
+NineVertexBuffer9_new( struct NineDevice9 *pDevice,
+                       D3DVERTEXBUFFER_DESC *pDesc,
+                       struct NineVertexBuffer9 **ppOut )
+{
+    NINE_DEVICE_CHILD_NEW(VertexBuffer9, ppOut, /* args */ pDevice, pDesc);
+}
diff --git a/src/gallium/state_trackers/nine/vertexbuffer9.h b/src/gallium/state_trackers/nine/vertexbuffer9.h
new file mode 100644 (file)
index 0000000..0d88b83
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _NINE_VERTEXBUFFER9_H_
+#define _NINE_VERTEXBUFFER9_H_
+
+#include "resource9.h"
+
+struct pipe_screen;
+struct pipe_context;
+struct pipe_transfer;
+
+struct NineVertexBuffer9
+{
+    struct NineResource9 base;
+
+    /* G3D */
+    struct pipe_context *pipe;
+    struct pipe_transfer **maps;
+    int nmaps, maxmaps;
+
+    D3DVERTEXBUFFER_DESC desc;
+};
+static INLINE struct NineVertexBuffer9 *
+NineVertexBuffer9( void *data )
+{
+    return (struct NineVertexBuffer9 *)data;
+}
+
+HRESULT
+NineVertexBuffer9_new( struct NineDevice9 *pDevice,
+                       D3DVERTEXBUFFER_DESC *pDesc,
+                       struct NineVertexBuffer9 **ppOut );
+
+HRESULT
+NineVertexBuffer9_ctor( struct NineVertexBuffer9 *This,
+                        struct NineUnknownParams *pParams,
+                        D3DVERTEXBUFFER_DESC *pDesc );
+
+void
+NineVertexBuffer9_dtor( struct NineVertexBuffer9 *This );
+
+HRESULT WINAPI
+NineVertexBuffer9_Lock( struct NineVertexBuffer9 *This,
+                        UINT OffsetToLock,
+                        UINT SizeToLock,
+                        void **ppbData,
+                        DWORD Flags );
+
+HRESULT WINAPI
+NineVertexBuffer9_Unlock( struct NineVertexBuffer9 *This );
+
+HRESULT WINAPI
+NineVertexBuffer9_GetDesc( struct NineVertexBuffer9 *This,
+                           D3DVERTEXBUFFER_DESC *pDesc );
+
+#endif /* _NINE_VERTEXBUFFER9_H_ */
diff --git a/src/gallium/state_trackers/nine/vertexdeclaration9.c b/src/gallium/state_trackers/nine/vertexdeclaration9.c
new file mode 100644 (file)
index 0000000..1a33e93
--- /dev/null
@@ -0,0 +1,518 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "vertexdeclaration9.h"
+#include "vertexbuffer9.h"
+#include "device9.h"
+#include "nine_helpers.h"
+
+#include "pipe/p_format.h"
+#include "pipe/p_context.h"
+#include "util/u_math.h"
+#include "util/u_format.h"
+#include "util/u_box.h"
+#include "translate/translate.h"
+
+#define DBG_CHANNEL DBG_VERTEXDECLARATION
+
+static INLINE enum pipe_format decltype_format(BYTE type)
+{
+    switch (type) {
+    case D3DDECLTYPE_FLOAT1:    return PIPE_FORMAT_R32_FLOAT;
+    case D3DDECLTYPE_FLOAT2:    return PIPE_FORMAT_R32G32_FLOAT;
+    case D3DDECLTYPE_FLOAT3:    return PIPE_FORMAT_R32G32B32_FLOAT;
+    case D3DDECLTYPE_FLOAT4:    return PIPE_FORMAT_R32G32B32A32_FLOAT;
+    case D3DDECLTYPE_D3DCOLOR:  return PIPE_FORMAT_B8G8R8A8_UNORM;
+    case D3DDECLTYPE_UBYTE4:    return PIPE_FORMAT_R8G8B8A8_USCALED;
+    case D3DDECLTYPE_SHORT2:    return PIPE_FORMAT_R16G16_SSCALED;
+    case D3DDECLTYPE_SHORT4:    return PIPE_FORMAT_R16G16B16A16_SSCALED;
+    case D3DDECLTYPE_UBYTE4N:   return PIPE_FORMAT_R8G8B8A8_UNORM;
+    case D3DDECLTYPE_SHORT2N:   return PIPE_FORMAT_R16G16_SNORM;
+    case D3DDECLTYPE_SHORT4N:   return PIPE_FORMAT_R16G16B16A16_SNORM;
+    case D3DDECLTYPE_USHORT2N:  return PIPE_FORMAT_R16G16_UNORM;
+    case D3DDECLTYPE_USHORT4N:  return PIPE_FORMAT_R16G16B16A16_UNORM;
+    case D3DDECLTYPE_UDEC3:     return PIPE_FORMAT_R10G10B10X2_USCALED;
+    case D3DDECLTYPE_DEC3N:     return PIPE_FORMAT_R10G10B10X2_SNORM;
+    case D3DDECLTYPE_FLOAT16_2: return PIPE_FORMAT_R16G16_FLOAT;
+    case D3DDECLTYPE_FLOAT16_4: return PIPE_FORMAT_R16G16B16A16_FLOAT;
+    default:
+        assert(!"Implementation error !");
+    }
+    return PIPE_FORMAT_NONE;
+}
+
+static INLINE unsigned decltype_size(BYTE type)
+{
+    switch (type) {
+    case D3DDECLTYPE_FLOAT1: return 1 * sizeof(float);
+    case D3DDECLTYPE_FLOAT2: return 2 * sizeof(float);
+    case D3DDECLTYPE_FLOAT3: return 3 * sizeof(float);
+    case D3DDECLTYPE_FLOAT4: return 4 * sizeof(float);
+    case D3DDECLTYPE_D3DCOLOR: return 1 * sizeof(DWORD);
+    case D3DDECLTYPE_UBYTE4: return 4 * sizeof(BYTE);
+    case D3DDECLTYPE_SHORT2: return 2 * sizeof(short);
+    case D3DDECLTYPE_SHORT4: return 4 * sizeof(short);
+    case D3DDECLTYPE_UBYTE4N: return 4 * sizeof(BYTE);
+    case D3DDECLTYPE_SHORT2N: return 2 * sizeof(short);
+    case D3DDECLTYPE_SHORT4N: return 4 * sizeof(short);
+    case D3DDECLTYPE_USHORT2N: return 2 * sizeof(short);
+    case D3DDECLTYPE_USHORT4N: return 4 * sizeof(short);
+    case D3DDECLTYPE_UDEC3: return 4;
+    case D3DDECLTYPE_DEC3N: return 4;
+    case D3DDECLTYPE_FLOAT16_2: return 2 * 2;
+    case D3DDECLTYPE_FLOAT16_4: return 4 * 2;
+    default:
+        assert(!"Implementation error !");
+    }
+    return 0;
+}
+
+/* Actually, arbitrary usage index values are permitted, but a
+ * simple lookup table won't work in that case. Let's just wait
+ * with making this more generic until we need it.
+ */
+static INLINE boolean
+nine_d3ddeclusage_check(unsigned usage, unsigned usage_idx)
+{
+    switch (usage) {
+    case D3DDECLUSAGE_POSITIONT:
+    case D3DDECLUSAGE_PSIZE:
+    case D3DDECLUSAGE_TESSFACTOR:
+    case D3DDECLUSAGE_DEPTH:
+    case D3DDECLUSAGE_FOG:
+    case D3DDECLUSAGE_SAMPLE:
+        return usage_idx <= 0;
+    case D3DDECLUSAGE_NORMAL:
+    case D3DDECLUSAGE_TANGENT:
+    case D3DDECLUSAGE_BINORMAL:
+        return usage_idx <= 1;
+    case D3DDECLUSAGE_POSITION:
+    case D3DDECLUSAGE_BLENDWEIGHT:
+    case D3DDECLUSAGE_BLENDINDICES:
+    case D3DDECLUSAGE_COLOR:
+        return usage_idx <= 4;
+    case D3DDECLUSAGE_TEXCOORD:
+        return usage_idx <= 15;
+    default:
+        return FALSE;
+    }
+}
+
+#define NINE_DECLUSAGE_CASE0(n) case D3DDECLUSAGE_##n: return NINE_DECLUSAGE_##n
+#define NINE_DECLUSAGE_CASEi(n) case D3DDECLUSAGE_##n: return NINE_DECLUSAGE_##n(usage_idx)
+INLINE unsigned
+nine_d3d9_to_nine_declusage(unsigned usage, unsigned usage_idx)
+{
+    if (!nine_d3ddeclusage_check(usage, usage_idx))
+        ERR("D3DDECLUSAGE_%u[%u]\n",usage,usage_idx);
+    assert(nine_d3ddeclusage_check(usage, usage_idx));
+    switch (usage) {
+    NINE_DECLUSAGE_CASEi(POSITION);
+    NINE_DECLUSAGE_CASEi(BLENDWEIGHT);
+    NINE_DECLUSAGE_CASEi(BLENDINDICES);
+    NINE_DECLUSAGE_CASEi(NORMAL);
+    NINE_DECLUSAGE_CASE0(PSIZE);
+    NINE_DECLUSAGE_CASEi(TEXCOORD);
+    NINE_DECLUSAGE_CASEi(TANGENT);
+    NINE_DECLUSAGE_CASEi(BINORMAL);
+    NINE_DECLUSAGE_CASE0(TESSFACTOR);
+    NINE_DECLUSAGE_CASE0(POSITIONT);
+    NINE_DECLUSAGE_CASEi(COLOR);
+    NINE_DECLUSAGE_CASE0(DEPTH);
+    NINE_DECLUSAGE_CASE0(FOG);
+    NINE_DECLUSAGE_CASE0(SAMPLE);
+    default:
+        assert(!"Invalid DECLUSAGE.");
+        return NINE_DECLUSAGE_NONE;
+    }
+}
+
+static const char *nine_declusage_names[] =
+{
+    [NINE_DECLUSAGE_POSITION(0)]     = "POSITION",
+    [NINE_DECLUSAGE_POSITION(1)]     = "POSITION1",
+    [NINE_DECLUSAGE_POSITION(2)]     = "POSITION2",
+    [NINE_DECLUSAGE_POSITION(3)]     = "POSITION3",
+    [NINE_DECLUSAGE_POSITION(4)]     = "POSITION4",
+    [NINE_DECLUSAGE_BLENDWEIGHT(0)]  = "BLENDWEIGHT",
+    [NINE_DECLUSAGE_BLENDWEIGHT(1)]  = "BLENDWEIGHT1",
+    [NINE_DECLUSAGE_BLENDWEIGHT(2)]  = "BLENDWEIGHT2",
+    [NINE_DECLUSAGE_BLENDWEIGHT(3)]  = "BLENDWEIGHT3",
+    [NINE_DECLUSAGE_BLENDINDICES(0)] = "BLENDINDICES",
+    [NINE_DECLUSAGE_BLENDINDICES(1)] = "BLENDINDICES1",
+    [NINE_DECLUSAGE_BLENDINDICES(2)] = "BLENDINDICES2",
+    [NINE_DECLUSAGE_BLENDINDICES(3)] = "BLENDINDICES3",
+    [NINE_DECLUSAGE_NORMAL(0)]       = "NORMAL",
+    [NINE_DECLUSAGE_NORMAL(1)]       = "NORMAL1",
+    [NINE_DECLUSAGE_PSIZE]           = "PSIZE",
+    [NINE_DECLUSAGE_TEXCOORD(0)]     = "TEXCOORD0",
+    [NINE_DECLUSAGE_TEXCOORD(1)]     = "TEXCOORD1",
+    [NINE_DECLUSAGE_TEXCOORD(2)]     = "TEXCOORD2",
+    [NINE_DECLUSAGE_TEXCOORD(3)]     = "TEXCOORD3",
+    [NINE_DECLUSAGE_TEXCOORD(4)]     = "TEXCOORD4",
+    [NINE_DECLUSAGE_TEXCOORD(5)]     = "TEXCOORD5",
+    [NINE_DECLUSAGE_TEXCOORD(6)]     = "TEXCOORD6",
+    [NINE_DECLUSAGE_TEXCOORD(7)]     = "TEXCOORD7",
+    [NINE_DECLUSAGE_TEXCOORD(8)]     = "TEXCOORD8",
+    [NINE_DECLUSAGE_TEXCOORD(9)]     = "TEXCOORD9",
+    [NINE_DECLUSAGE_TEXCOORD(10)]    = "TEXCOORD10",
+    [NINE_DECLUSAGE_TEXCOORD(11)]    = "TEXCOORD11",
+    [NINE_DECLUSAGE_TEXCOORD(12)]    = "TEXCOORD12",
+    [NINE_DECLUSAGE_TEXCOORD(13)]    = "TEXCOORD13",
+    [NINE_DECLUSAGE_TEXCOORD(14)]    = "TEXCOORD14",
+    [NINE_DECLUSAGE_TEXCOORD(15)]    = "TEXCOORD15",
+    [NINE_DECLUSAGE_TANGENT(0)]      = "TANGENT",
+    [NINE_DECLUSAGE_TANGENT(1)]      = "TANGENT1",
+    [NINE_DECLUSAGE_BINORMAL(0)]     = "BINORMAL",
+    [NINE_DECLUSAGE_BINORMAL(1)]     = "BINORMAL1",
+    [NINE_DECLUSAGE_TESSFACTOR]      = "TESSFACTOR",
+    [NINE_DECLUSAGE_POSITIONT]       = "POSITIONT",
+    [NINE_DECLUSAGE_COLOR(0)]        = "DIFFUSE",
+    [NINE_DECLUSAGE_COLOR(1)]        = "SPECULAR",
+    [NINE_DECLUSAGE_COLOR(2)]        = "COLOR2",
+    [NINE_DECLUSAGE_COLOR(3)]        = "COLOR3",
+    [NINE_DECLUSAGE_COLOR(4)]        = "COLOR4",
+    [NINE_DECLUSAGE_DEPTH]           = "DEPTH",
+    [NINE_DECLUSAGE_FOG]             = "FOG",
+    [NINE_DECLUSAGE_NONE]            = "(NONE)",
+    [NINE_DECLUSAGE_COUNT]           = "(OOB)"
+};
+static INLINE const char *
+nine_declusage_name(unsigned ndcl)
+{
+    return nine_declusage_names[MIN2(ndcl, Elements(nine_declusage_names) - 1)];
+}
+
+HRESULT
+NineVertexDeclaration9_ctor( struct NineVertexDeclaration9 *This,
+                             struct NineUnknownParams *pParams,
+                             const D3DVERTEXELEMENT9 *pElements )
+{
+    const D3DCAPS9 *caps;
+    unsigned i;
+
+    HRESULT hr = NineUnknown_ctor(&This->base, pParams);
+    if (FAILED(hr)) { return hr; }
+
+    for (This->nelems = 0;
+         pElements[This->nelems].Type != D3DDECLTYPE_UNUSED &&
+         pElements[This->nelems].Stream != 0xFF; /* wine */
+         ++This->nelems);
+
+    caps = NineDevice9_GetCaps(This->base.device);
+    user_assert(This->nelems <= caps->MaxStreams, D3DERR_INVALIDCALL);
+
+    This->decls = CALLOC(This->nelems+1, sizeof(D3DVERTEXELEMENT9));
+    This->elems = CALLOC(This->nelems, sizeof(struct pipe_vertex_element));
+    if (!This->decls || !This->elems) { return E_OUTOFMEMORY; }
+    memcpy(This->decls, pElements, sizeof(D3DVERTEXELEMENT9)*(This->nelems+1));
+
+    memset(This->usage_map, 0xff, sizeof(This->usage_map));
+
+    for (i = 0; i < This->nelems; ++i) {
+        uint8_t usage = nine_d3d9_to_nine_declusage(This->decls[i].Usage,
+                                                    This->decls[i].UsageIndex);
+        This->usage_map[usage] = i;
+
+        This->elems[i].src_offset = This->decls[i].Offset;
+        This->elems[i].instance_divisor = 0;
+        This->elems[i].vertex_buffer_index = This->decls[i].Stream;
+        This->elems[i].src_format = decltype_format(This->decls[i].Type);
+        /* XXX Remember Method (tesselation), Usage, UsageIndex */
+
+        DBG("VERTEXELEMENT[%u]: Stream=%u Offset=%u Type=%s DeclUsage=%s\n", i,
+            This->decls[i].Stream,
+            This->decls[i].Offset,
+            util_format_name(This->elems[i].src_format),
+            nine_declusage_name(usage));
+    }
+
+    return D3D_OK;
+}
+
+void
+NineVertexDeclaration9_dtor( struct NineVertexDeclaration9 *This )
+{
+    if (This->decls)
+        FREE(This->decls);
+    if (This->elems)
+        FREE(This->elems);
+
+    NineUnknown_dtor(&This->base);
+}
+
+HRESULT WINAPI
+NineVertexDeclaration9_GetDeclaration( struct NineVertexDeclaration9 *This,
+                                       D3DVERTEXELEMENT9 *pElement,
+                                       UINT *pNumElements )
+{
+    if (!pElement) {
+        user_assert(pNumElements, D3DERR_INVALIDCALL);
+        *pNumElements = This->nelems+1;
+        return D3D_OK;
+    }
+    if (pNumElements) { *pNumElements = This->nelems+1; }
+    memcpy(pElement, This->decls, sizeof(D3DVERTEXELEMENT9)*(This->nelems+1));
+    return D3D_OK;
+}
+
+IDirect3DVertexDeclaration9Vtbl NineVertexDeclaration9_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)NineUnknown_GetDevice, /* actually part of VertexDecl9 iface */
+    (void *)NineVertexDeclaration9_GetDeclaration
+};
+
+static const GUID *NineVertexDeclaration9_IIDs[] = {
+    &IID_IDirect3DVertexDeclaration9,
+    &IID_IUnknown,
+    NULL
+};
+
+HRESULT
+NineVertexDeclaration9_new( struct NineDevice9 *pDevice,
+                            const D3DVERTEXELEMENT9 *pElements,
+                            struct NineVertexDeclaration9 **ppOut )
+{
+    NINE_DEVICE_CHILD_NEW(VertexDeclaration9, ppOut, /* args */ pDevice, pElements);
+}
+
+HRESULT
+NineVertexDeclaration9_new_from_fvf( struct NineDevice9 *pDevice,
+                                     DWORD FVF,
+                                     struct NineVertexDeclaration9 **ppOut )
+{
+    D3DVERTEXELEMENT9 elems[16], decl_end = D3DDECL_END();
+    unsigned texcount, i, betas, nelems = 0;
+    BYTE beta_index = 0xFF;
+
+    switch (FVF & D3DFVF_POSITION_MASK) {
+        case D3DFVF_XYZ: /* simple XYZ */
+        case D3DFVF_XYZB1:
+        case D3DFVF_XYZB2:
+        case D3DFVF_XYZB3:
+        case D3DFVF_XYZB4:
+        case D3DFVF_XYZB5: /* XYZ with beta values */
+            elems[nelems].Type = D3DDECLTYPE_FLOAT3;
+            elems[nelems].Usage = D3DDECLUSAGE_POSITION;
+            elems[nelems].UsageIndex = 0;
+            ++nelems;
+            /* simple XYZ has no beta values. break. */
+            if ((FVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) { break; }
+
+            betas = (((FVF & D3DFVF_XYZB5)-D3DFVF_XYZB1)>>1)+1;
+            if (FVF & D3DFVF_LASTBETA_D3DCOLOR) {
+                beta_index = D3DDECLTYPE_D3DCOLOR;
+            } else if (FVF & D3DFVF_LASTBETA_UBYTE4) {
+                beta_index = D3DDECLTYPE_UBYTE4;
+            } else if ((FVF & D3DFVF_XYZB5) == D3DFVF_XYZB5) {
+                beta_index = D3DDECLTYPE_FLOAT1;
+            }
+            if (beta_index != 0xFF) { --betas; }
+
+            if (betas > 0) {
+                switch (betas) {
+                    case 1: elems[nelems].Type = D3DDECLTYPE_FLOAT1; break;
+                    case 2: elems[nelems].Type = D3DDECLTYPE_FLOAT2; break;
+                    case 3: elems[nelems].Type = D3DDECLTYPE_FLOAT3; break;
+                    case 4: elems[nelems].Type = D3DDECLTYPE_FLOAT4; break;
+                    default:
+                        assert(!"Implementation error!");
+                }
+                elems[nelems].Usage = D3DDECLUSAGE_BLENDWEIGHT;
+                elems[nelems].UsageIndex = 0;
+                ++nelems;
+            }
+
+            if (beta_index != 0xFF) {
+                elems[nelems].Type = beta_index;
+                elems[nelems].Usage = D3DDECLUSAGE_BLENDINDICES;
+                elems[nelems].UsageIndex = 0;
+                ++nelems;
+            }
+            break;
+
+        case D3DFVF_XYZW: /* simple XYZW */
+        case D3DFVF_XYZRHW: /* pretransformed XYZW */
+            elems[nelems].Type = D3DDECLTYPE_FLOAT4;
+            elems[nelems].Usage =
+                ((FVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZW) ?
+                D3DDECLUSAGE_POSITION : D3DDECLUSAGE_POSITIONT;
+            elems[nelems].UsageIndex = 0;
+            ++nelems;
+            break;
+
+        default:
+            (void)user_error(!"Position doesn't match any known combination");
+    }
+
+    /* normals, psize and colors */
+    if (FVF & D3DFVF_NORMAL) {
+        elems[nelems].Type = D3DDECLTYPE_FLOAT3;
+        elems[nelems].Usage = D3DDECLUSAGE_NORMAL;
+        elems[nelems].UsageIndex = 0;
+        ++nelems;
+    }
+    if (FVF & D3DFVF_PSIZE) {
+        elems[nelems].Type = D3DDECLTYPE_FLOAT1;
+        elems[nelems].Usage = D3DDECLUSAGE_PSIZE;
+        elems[nelems].UsageIndex = 0;
+        ++nelems;
+    }
+    if (FVF & D3DFVF_DIFFUSE) {
+        elems[nelems].Type = D3DDECLTYPE_D3DCOLOR;
+        elems[nelems].Usage = D3DDECLUSAGE_COLOR;
+        elems[nelems].UsageIndex = 0;
+        ++nelems;
+    }
+    if (FVF & D3DFVF_SPECULAR) {
+        elems[nelems].Type = D3DDECLTYPE_D3DCOLOR;
+        elems[nelems].Usage = D3DDECLUSAGE_COLOR;
+        elems[nelems].UsageIndex = 1;
+        ++nelems;
+    }
+
+    /* textures */
+    texcount = (FVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
+    if (user_error(texcount <= 8)) { texcount = 8; }
+
+    for (i = 0; i < texcount; ++i) {
+        switch ((FVF >> (16+i*2)) & 0x3) {
+            case D3DFVF_TEXTUREFORMAT1:
+                elems[nelems].Type = D3DDECLTYPE_FLOAT1;
+                break;
+
+            case D3DFVF_TEXTUREFORMAT2:
+                elems[nelems].Type = D3DDECLTYPE_FLOAT2;
+                break;
+
+            case D3DFVF_TEXTUREFORMAT3:
+                elems[nelems].Type = D3DDECLTYPE_FLOAT3;
+                break;
+
+            case D3DFVF_TEXTUREFORMAT4:
+                elems[nelems].Type = D3DDECLTYPE_FLOAT4;
+                break;
+
+            default:
+                assert(!"Implementation error!");
+        }
+        elems[nelems].Usage = D3DDECLUSAGE_TEXCOORD;
+        elems[nelems].UsageIndex = i;
+        ++nelems;
+    }
+
+    /* fill out remaining data */
+    for (i = 0; i < nelems; ++i) {
+        elems[i].Stream = 0;
+        elems[i].Offset = (i == 0) ? 0 : (elems[i-1].Offset +
+                                          decltype_size(elems[i-1].Type));
+        elems[i].Method = D3DDECLMETHOD_DEFAULT;
+    }
+    elems[nelems++] = decl_end;
+
+    NINE_DEVICE_CHILD_NEW(VertexDeclaration9, ppOut, /* args */ pDevice, elems);
+}
+
+/* ProcessVertices runs stream output into a temporary buffer to capture
+ * all outputs.
+ * Now we have to convert them to the format and order set by the vertex
+ * declaration, for which we use u_translate.
+ * This is necessary if the vertex declaration contains elements using a
+ * non float32 format, because stream output only supports f32/u32/s32.
+ */
+HRESULT
+NineVertexDeclaration9_ConvertStreamOutput(
+    struct NineVertexDeclaration9 *This,
+    struct NineVertexBuffer9 *pDstBuf,
+    UINT DestIndex,
+    UINT VertexCount,
+    struct pipe_resource *pSrcBuf,
+    const struct pipe_stream_output_info *so )
+{
+    struct pipe_context *pipe = This->base.device->pipe;
+    struct pipe_transfer *transfer = NULL;
+    struct translate *translate;
+    struct translate_key transkey;
+    struct pipe_box box;
+    HRESULT hr;
+    unsigned i;
+    void *src_map;
+    void *dst_map;
+
+    transkey.output_stride = 0;
+    for (i = 0; i < This->nelems; ++i) {
+        enum pipe_format format;
+
+        switch (so->output[i].num_components) {
+        case 1: format = PIPE_FORMAT_R32_FLOAT; break;
+        case 2: format = PIPE_FORMAT_R32G32_FLOAT; break;
+        case 3: format = PIPE_FORMAT_R32G32B32_FLOAT; break;
+        default:
+            assert(so->output[i].num_components == 4);
+            format = PIPE_FORMAT_R32G32B32A32_FLOAT;
+            break;
+        }
+        transkey.element[i].type = TRANSLATE_ELEMENT_NORMAL;
+        transkey.element[i].input_format = format;
+        transkey.element[i].input_buffer = 0;
+        transkey.element[i].input_offset = so->output[i].dst_offset * 4;
+        transkey.element[i].instance_divisor = 0;
+
+        transkey.element[i].output_format = This->elems[i].src_format;
+        transkey.element[i].output_offset = This->elems[i].src_offset;
+        transkey.output_stride +=
+            util_format_get_blocksize(This->elems[i].src_format);
+
+        assert(!(transkey.output_stride & 3));
+    }
+    transkey.nr_elements = This->nelems;
+
+    translate = translate_create(&transkey);
+    if (!translate)
+        return E_OUTOFMEMORY;
+
+    hr = NineVertexBuffer9_Lock(pDstBuf,
+                                transkey.output_stride * DestIndex,
+                                transkey.output_stride * VertexCount,
+                                &dst_map, D3DLOCK_DISCARD);
+    if (FAILED(hr))
+        goto out;
+
+    src_map = pipe->transfer_map(pipe, pSrcBuf, 0, PIPE_TRANSFER_READ, &box,
+                                 &transfer);
+    if (!src_map) {
+        hr = D3DERR_DRIVERINTERNALERROR;
+        goto out;
+    }
+    translate->set_buffer(translate, 0, src_map, so->stride[0], ~0);
+
+    translate->run(translate, 0, VertexCount, 0, 0, dst_map);
+
+    NineVertexBuffer9_Unlock(pDstBuf);
+out:
+    if (transfer)
+        pipe->transfer_unmap(pipe, transfer);
+    translate->release(translate); /* TODO: cache these */
+    return hr;
+}
diff --git a/src/gallium/state_trackers/nine/vertexdeclaration9.h b/src/gallium/state_trackers/nine/vertexdeclaration9.h
new file mode 100644 (file)
index 0000000..6590f46
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _NINE_VERTEXDECLARATION9_H_
+#define _NINE_VERTEXDECLARATION9_H_
+
+#include "nine_defines.h"
+#include "iunknown.h"
+
+struct pipe_resource;
+struct pipe_vertex_element;
+struct pipe_stream_output_info;
+struct NineDevice9;
+struct NineVertexBuffer9;
+
+struct NineVertexDeclaration9
+{
+    struct NineUnknown base;
+
+    /* G3D state */
+    struct pipe_vertex_element *elems;
+    unsigned nelems;
+
+    /* DECLUSAGE -> element index, for selecting the vertex element
+     * for each VS input */
+    uint8_t usage_map[NINE_DECLUSAGE_COUNT];
+
+    D3DVERTEXELEMENT9 *decls;
+    DWORD fvf;
+};
+static INLINE struct NineVertexDeclaration9 *
+NineVertexDeclaration9( void *data )
+{
+    return (struct NineVertexDeclaration9 *)data;
+}
+
+HRESULT
+NineVertexDeclaration9_new( struct NineDevice9 *pDevice,
+                            const D3DVERTEXELEMENT9 *pElements,
+                            struct NineVertexDeclaration9 **ppOut );
+
+HRESULT
+NineVertexDeclaration9_new_from_fvf( struct NineDevice9 *pDevice,
+                                     DWORD FVF,
+                                     struct NineVertexDeclaration9 **ppOut );
+
+HRESULT
+NineVertexDeclaration9_ctor( struct NineVertexDeclaration9 *This,
+                             struct NineUnknownParams *pParams,
+                             const D3DVERTEXELEMENT9 *pElements );
+
+void
+NineVertexDeclaration9_dtor( struct NineVertexDeclaration9 *This );
+
+HRESULT WINAPI
+NineVertexDeclaration9_GetDeclaration( struct NineVertexDeclaration9 *This,
+                                       D3DVERTEXELEMENT9 *pElement,
+                                       UINT *pNumElements );
+
+/* Convert stream output data to the vertex declaration's format. */
+HRESULT
+NineVertexDeclaration9_ConvertStreamOutput(
+    struct NineVertexDeclaration9 *This,
+    struct NineVertexBuffer9 *pDstBuf,
+    UINT DestIndex,
+    UINT VertexCount,
+    struct pipe_resource *pSrcBuf,
+    const struct pipe_stream_output_info *so );
+
+#endif /* _NINE_VERTEXDECLARATION9_H_ */
diff --git a/src/gallium/state_trackers/nine/vertexshader9.c b/src/gallium/state_trackers/nine/vertexshader9.c
new file mode 100644 (file)
index 0000000..e04f3a5
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "nine_helpers.h"
+#include "nine_shader.h"
+
+#include "vertexshader9.h"
+
+#include "device9.h"
+#include "pipe/p_context.h"
+
+#define DBG_CHANNEL DBG_VERTEXSHADER
+
+HRESULT
+NineVertexShader9_ctor( struct NineVertexShader9 *This,
+                        struct NineUnknownParams *pParams,
+                        const DWORD *pFunction, void *cso )
+{
+    struct NineDevice9 *device;
+    struct nine_shader_info info;
+    HRESULT hr;
+    unsigned i;
+
+    hr = NineUnknown_ctor(&This->base, pParams);
+    if (FAILED(hr))
+        return hr;
+
+    if (cso) {
+        This->variant.cso = cso;
+        return D3D_OK;
+    }
+    device = This->base.device;
+
+    info.type = PIPE_SHADER_VERTEX;
+    info.byte_code = pFunction;
+    info.const_i_base = NINE_CONST_I_BASE(device->max_vs_const_f) / 16;
+    info.const_b_base = NINE_CONST_B_BASE(device->max_vs_const_f) / 16;
+    info.sampler_mask_shadow = 0x0;
+    info.sampler_ps1xtypes = 0x0;
+
+    hr = nine_translate_shader(device, &info);
+    if (FAILED(hr))
+        return hr;
+    This->byte_code.version = info.version;
+
+    This->byte_code.tokens = mem_dup(pFunction, info.byte_size);
+    if (!This->byte_code.tokens)
+        return E_OUTOFMEMORY;
+    This->byte_code.size = info.byte_size;
+
+    This->variant.cso = info.cso;
+    This->const_used_size = info.const_used_size;
+    if (info.const_used_size == ~0)
+        This->const_used_size = NINE_CONSTBUF_SIZE(device->max_vs_const_f);
+    This->lconstf = info.lconstf;
+    This->sampler_mask = info.sampler_mask;
+    This->position_t = info.position_t;
+    This->point_size = info.point_size;
+
+    for (i = 0; i < info.num_inputs && i < Elements(This->input_map); ++i)
+        This->input_map[i].ndecl = info.input_map[i];
+    This->num_inputs = i;
+
+    return D3D_OK;
+}
+
+void
+NineVertexShader9_dtor( struct NineVertexShader9 *This )
+{
+    DBG("This=%p cso=%p\n", This, This->variant.cso);
+
+    if (This->base.device) {
+        struct pipe_context *pipe = This->base.device->pipe;
+        struct nine_shader_variant *var = &This->variant;
+        do {
+            if (var->cso) {
+                if (This->base.device->state.cso.vs == var->cso)
+                    pipe->bind_vs_state(pipe, NULL);
+                pipe->delete_vs_state(pipe, var->cso);
+            }
+            var = var->next;
+        } while (var);
+    }
+    nine_shader_variants_free(&This->variant);
+
+    if (This->byte_code.tokens)
+        FREE((void *)This->byte_code.tokens); /* const_cast */
+
+    FREE(This->lconstf.data);
+    FREE(This->lconstf.ranges);
+
+    NineUnknown_dtor(&This->base);
+}
+
+HRESULT WINAPI
+NineVertexShader9_GetFunction( struct NineVertexShader9 *This,
+                               void *pData,
+                               UINT *pSizeOfData )
+{
+    user_assert(pSizeOfData, D3DERR_INVALIDCALL);
+
+    if (!pData) {
+        *pSizeOfData = This->byte_code.size;
+        return D3D_OK;
+    }
+    user_assert(*pSizeOfData >= This->byte_code.size, D3DERR_INVALIDCALL);
+
+    memcpy(pData, This->byte_code.tokens, This->byte_code.size);
+
+    return D3D_OK;
+}
+
+void *
+NineVertexShader9_GetVariant( struct NineVertexShader9 *This,
+                              uint32_t key )
+{
+    void *cso = nine_shader_variant_get(&This->variant, key);
+    if (!cso) {
+        struct NineDevice9 *device = This->base.device;
+        struct nine_shader_info info;
+        HRESULT hr;
+
+        info.type = PIPE_SHADER_VERTEX;
+        info.const_i_base = NINE_CONST_I_BASE(device->max_vs_const_f) / 16;
+        info.const_b_base = NINE_CONST_B_BASE(device->max_vs_const_f) / 16;
+        info.byte_code = This->byte_code.tokens;
+        info.sampler_mask_shadow = key & 0xf;
+
+        hr = nine_translate_shader(This->base.device, &info);
+        if (FAILED(hr))
+            return NULL;
+        nine_shader_variant_add(&This->variant, key, info.cso);
+        cso = info.cso;
+    }
+    return cso;
+}
+
+IDirect3DVertexShader9Vtbl NineVertexShader9_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)NineUnknown_GetDevice,
+    (void *)NineVertexShader9_GetFunction
+};
+
+static const GUID *NineVertexShader9_IIDs[] = {
+    &IID_IDirect3DVertexShader9,
+    &IID_IUnknown,
+    NULL
+};
+
+HRESULT
+NineVertexShader9_new( struct NineDevice9 *pDevice,
+                       struct NineVertexShader9 **ppOut,
+                       const DWORD *pFunction, void *cso )
+{
+    NINE_DEVICE_CHILD_NEW(VertexShader9, ppOut, pDevice, pFunction, cso);
+}
diff --git a/src/gallium/state_trackers/nine/vertexshader9.h b/src/gallium/state_trackers/nine/vertexshader9.h
new file mode 100644 (file)
index 0000000..a7d750d
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _NINE_VERTEXSHADER9_H_
+#define _NINE_VERTEXSHADER9_H_
+
+#include "iunknown.h"
+#include "nine_shader.h"
+
+struct NineVertexShader9
+{
+    struct NineUnknown base;
+    struct nine_shader_variant variant;
+
+    struct {
+        uint8_t ndecl; /* NINE_DECLUSAGE_x */
+    } input_map[PIPE_MAX_ATTRIBS];
+    unsigned num_inputs;
+
+    struct {
+        const DWORD *tokens;
+        DWORD size;
+        uint8_t version; /* (major << 4) | minor */
+    } byte_code;
+
+    uint8_t sampler_mask;
+    uint8_t sampler_mask_shadow;
+
+    boolean position_t; /* if true, disable vport transform */
+    boolean point_size; /* if true, set rasterizer.point_size_per_vertex to 1 */
+
+    unsigned const_used_size; /* in bytes */
+
+    struct nine_lconstf lconstf;
+
+    const struct pipe_stream_output_info *so;
+
+    uint64_t ff_key[2];
+};
+static INLINE struct NineVertexShader9 *
+NineVertexShader9( void *data )
+{
+    return (struct NineVertexShader9 *)data;
+}
+
+void *
+NineVertexShader9_GetVariant( struct NineVertexShader9 *vs,
+                              uint32_t key );
+
+/*** public ***/
+
+HRESULT
+NineVertexShader9_new( struct NineDevice9 *pDevice,
+                       struct NineVertexShader9 **ppOut,
+                       const DWORD *pFunction, void *cso );
+
+HRESULT
+NineVertexShader9_ctor( struct NineVertexShader9 *,
+                        struct NineUnknownParams *pParams,
+                        const DWORD *pFunction, void *cso );
+
+void
+NineVertexShader9_dtor( struct NineVertexShader9 * );
+
+HRESULT WINAPI
+NineVertexShader9_GetFunction( struct NineVertexShader9 *This,
+                               void *pData,
+                               UINT *pSizeOfData );
+
+#endif /* _NINE_VERTEXSHADER9_H_ */
diff --git a/src/gallium/state_trackers/nine/volume9.c b/src/gallium/state_trackers/nine/volume9.c
new file mode 100644 (file)
index 0000000..c46a9d1
--- /dev/null
@@ -0,0 +1,604 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "device9.h"
+#include "volume9.h"
+#include "basetexture9.h" /* for marking dirty */
+#include "nine_helpers.h"
+#include "nine_pipe.h"
+#include "nine_dump.h"
+
+#include "util/u_hash_table.h"
+#include "util/u_format.h"
+#include "util/u_surface.h"
+#include "nine_pdata.h"
+
+#define DBG_CHANNEL DBG_VOLUME
+
+
+static HRESULT
+NineVolume9_AllocateData( struct NineVolume9 *This )
+{
+    unsigned size = This->layer_stride * This->desc.Depth;
+
+    DBG("(%p(This=%p),level=%u) Allocating 0x%x bytes of system memory.\n",
+        This->base.container, This, This->level, size);
+
+    This->data = (uint8_t *)MALLOC(size);
+    if (!This->data)
+        return E_OUTOFMEMORY;
+    return D3D_OK;
+}
+
+static HRESULT
+NineVolume9_ctor( struct NineVolume9 *This,
+                  struct NineUnknownParams *pParams,
+                  struct NineUnknown *pContainer,
+                  struct pipe_resource *pResource,
+                  unsigned Level,
+                  D3DVOLUME_DESC *pDesc )
+{
+    HRESULT hr;
+
+    assert(pContainer); /* stand-alone volumes can't be created */
+
+    DBG("This=%p pContainer=%p pDevice=%p pResource=%p Level=%u pDesc=%p\n",
+        This, pContainer, pParams->device, pResource, Level, pDesc);
+
+    /* Mark this as a special surface held by another internal resource. */
+    pParams->container = pContainer;
+
+    user_assert(!(pDesc->Usage & D3DUSAGE_DYNAMIC) ||
+                (pDesc->Pool != D3DPOOL_MANAGED), D3DERR_INVALIDCALL);
+
+    assert(pResource || pDesc->Pool != D3DPOOL_DEFAULT);
+
+    hr = NineUnknown_ctor(&This->base, pParams);
+    if (FAILED(hr))
+        return hr;
+
+    This->pdata = util_hash_table_create(ht_guid_hash, ht_guid_compare);
+    if (!This->pdata)
+        return E_OUTOFMEMORY;
+
+    pipe_resource_reference(&This->resource, pResource);
+
+    This->pipe = pParams->device->pipe;
+    This->transfer = NULL;
+    This->lock_count = 0;
+
+    This->level = Level;
+    This->level_actual = Level;
+    This->desc = *pDesc;
+
+    This->info.screen = pParams->device->screen;
+    This->info.target = PIPE_TEXTURE_3D;
+    This->info.format = d3d9_to_pipe_format(pDesc->Format);
+    This->info.width0 = pDesc->Width;
+    This->info.height0 = pDesc->Height;
+    This->info.depth0 = pDesc->Depth;
+    This->info.last_level = 0;
+    This->info.array_size = 1;
+    This->info.nr_samples = 0;
+    This->info.usage = PIPE_USAGE_DEFAULT;
+    This->info.bind = PIPE_BIND_SAMPLER_VIEW;
+    This->info.flags = 0;
+
+    This->stride = util_format_get_stride(This->info.format, pDesc->Width);
+    This->stride = align(This->stride, 4);
+    This->layer_stride = util_format_get_2d_size(This->info.format,
+                                                 This->stride, pDesc->Height);
+
+    if (pDesc->Pool == D3DPOOL_SYSTEMMEM)
+        This->info.usage = PIPE_USAGE_STAGING;
+
+    if (!This->resource) {
+        hr = NineVolume9_AllocateData(This);
+        if (FAILED(hr))
+            return hr;
+    }
+    return D3D_OK;
+}
+
+static void
+NineVolume9_dtor( struct NineVolume9 *This )
+{
+    DBG("This=%p\n", This);
+
+    if (This->transfer)
+        NineVolume9_UnlockBox(This);
+
+    pipe_resource_reference(&This->resource, NULL);
+
+    NineUnknown_dtor(&This->base);
+}
+
+HRESULT WINAPI
+NineVolume9_GetContainer( struct NineVolume9 *This,
+                          REFIID riid,
+                          void **ppContainer )
+{
+    if (!NineUnknown(This)->container)
+        return E_NOINTERFACE;
+    return NineUnknown_QueryInterface(NineUnknown(This)->container, riid, ppContainer);
+}
+
+static INLINE void
+NineVolume9_MarkContainerDirty( struct NineVolume9 *This )
+{
+    struct NineBaseTexture9 *tex;
+#ifdef DEBUG
+    /* This is always contained by a NineVolumeTexture9. */
+    GUID id = IID_IDirect3DVolumeTexture9;
+    REFIID ref = &id;
+    assert(NineUnknown_QueryInterface(This->base.container, ref, (void **)&tex)
+           == S_OK);
+    assert(NineUnknown_Release(NineUnknown(tex)) != 0);
+#endif
+
+    tex = NineBaseTexture9(This->base.container);
+    assert(tex);
+    if (This->desc.Pool == D3DPOOL_MANAGED)
+        tex->dirty = TRUE;
+    else
+    if (This->desc.Usage & D3DUSAGE_AUTOGENMIPMAP)
+        tex->dirty_mip = TRUE;
+
+    BASETEX_REGISTER_UPDATE(tex);
+}
+
+HRESULT WINAPI
+NineVolume9_GetDesc( struct NineVolume9 *This,
+                     D3DVOLUME_DESC *pDesc )
+{
+    user_assert(pDesc != NULL, E_POINTER);
+    *pDesc = This->desc;
+    return D3D_OK;
+}
+
+static INLINE boolean
+NineVolume9_IsDirty(struct NineVolume9 *This)
+{
+    return This->dirty_box[0].width != 0;
+}
+
+INLINE void
+NineVolume9_AddDirtyRegion( struct NineVolume9 *This,
+                            const struct pipe_box *box )
+{
+    struct pipe_box cover_a, cover_b;
+    float vol[2];
+
+    if (!box) {
+        u_box_3d(0, 0, 0, This->desc.Width, This->desc.Height,
+                 This->desc.Depth, &This->dirty_box[0]);
+        memset(&This->dirty_box[1], 0, sizeof(This->dirty_box[1]));
+        return;
+    }
+    if (!This->dirty_box[0].width) {
+        This->dirty_box[0] = *box;
+        return;
+    }
+
+    u_box_union_3d(&cover_a, &This->dirty_box[0], box);
+    vol[0] = u_box_volume_3d(&cover_a);
+
+    if (This->dirty_box[1].width == 0) {
+        vol[1] = u_box_volume_3d(&This->dirty_box[0]);
+        if (vol[0] > (vol[1] * 1.5f))
+            This->dirty_box[1] = *box;
+        else
+            This->dirty_box[0] = cover_a;
+    } else {
+        u_box_union_3d(&cover_b, &This->dirty_box[1], box);
+        vol[1] = u_box_volume_3d(&cover_b);
+
+        if (vol[0] > vol[1])
+            This->dirty_box[1] = cover_b;
+        else
+            This->dirty_box[0] = cover_a;
+    }
+}
+
+static INLINE uint8_t *
+NineVolume9_GetSystemMemPointer(struct NineVolume9 *This, int x, int y, int z)
+{
+    unsigned x_offset = util_format_get_stride(This->info.format, x);
+
+    y = util_format_get_nblocksy(This->info.format, y);
+
+    assert(This->data);
+    return This->data + (z * This->layer_stride + y * This->stride + x_offset);
+}
+
+HRESULT WINAPI
+NineVolume9_LockBox( struct NineVolume9 *This,
+                     D3DLOCKED_BOX *pLockedVolume,
+                     const D3DBOX *pBox,
+                     DWORD Flags )
+{
+    struct pipe_resource *resource = This->resource;
+    struct pipe_box box;
+    unsigned usage;
+
+    DBG("This=%p(%p) pLockedVolume=%p pBox=%p[%u..%u,%u..%u,%u..%u] Flags=%s\n",
+        This, This->base.container, pLockedVolume, pBox,
+        pBox ? pBox->Left : 0, pBox ? pBox->Right : 0,
+        pBox ? pBox->Top : 0, pBox ? pBox->Bottom : 0,
+        pBox ? pBox->Front : 0, pBox ? pBox->Back : 0,
+        nine_D3DLOCK_to_str(Flags));
+
+    user_assert(This->desc.Pool != D3DPOOL_DEFAULT ||
+                (This->desc.Usage & D3DUSAGE_DYNAMIC), D3DERR_INVALIDCALL);
+
+    user_assert(!((Flags & D3DLOCK_DISCARD) && (Flags & D3DLOCK_READONLY)),
+                D3DERR_INVALIDCALL);
+
+    user_assert(This->lock_count == 0, D3DERR_INVALIDCALL);
+    user_assert(pLockedVolume, E_POINTER);
+
+    if (pBox && This->desc.Pool == D3DPOOL_DEFAULT &&
+        util_format_is_compressed(This->info.format)) {
+        const unsigned w = util_format_get_blockwidth(This->info.format);
+        const unsigned h = util_format_get_blockheight(This->info.format);
+        user_assert(!(pBox->Left % w) && !(pBox->Right % w) &&
+                    !(pBox->Top % h) && !(pBox->Bottom % h),
+                    D3DERR_INVALIDCALL);
+    }
+
+    if (Flags & D3DLOCK_DISCARD) {
+        usage = PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_RANGE;
+    } else {
+        usage = (Flags & D3DLOCK_READONLY) ?
+            PIPE_TRANSFER_READ : PIPE_TRANSFER_READ_WRITE;
+    }
+    if (Flags & D3DLOCK_DONOTWAIT)
+        usage |= PIPE_TRANSFER_DONTBLOCK;
+
+    if (pBox) {
+        d3dbox_to_pipe_box(&box, pBox);
+        if (u_box_clip_2d(&box, &box, This->desc.Width, This->desc.Height) < 0) {
+            DBG("Locked volume intersection empty.\n");
+            return D3DERR_INVALIDCALL;
+        }
+    } else {
+        u_box_3d(0, 0, 0, This->desc.Width, This->desc.Height, This->desc.Depth,
+                 &box);
+    }
+
+    if (This->data) {
+        pLockedVolume->RowPitch = This->stride;
+        pLockedVolume->SlicePitch = This->layer_stride;
+        pLockedVolume->pBits =
+            NineVolume9_GetSystemMemPointer(This, box.x, box.y, box.z);
+    } else {
+        pLockedVolume->pBits =
+            This->pipe->transfer_map(This->pipe, resource, This->level, usage,
+                                     &box, &This->transfer);
+        if (!This->transfer) {
+            if (Flags & D3DLOCK_DONOTWAIT)
+                return D3DERR_WASSTILLDRAWING;
+            return D3DERR_DRIVERINTERNALERROR;
+        }
+        pLockedVolume->RowPitch = This->transfer->stride;
+        pLockedVolume->SlicePitch = This->transfer->layer_stride;
+    }
+
+    if (!(Flags & (D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_READONLY))) {
+        NineVolume9_MarkContainerDirty(This);
+        if (This->desc.Pool == D3DPOOL_MANAGED)
+            NineVolume9_AddDirtyRegion(This, &box);
+    }
+
+    ++This->lock_count;
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineVolume9_UnlockBox( struct NineVolume9 *This )
+{
+    DBG("This=%p lock_count=%u\n", This, This->lock_count);
+    user_assert(This->lock_count, D3DERR_INVALIDCALL);
+    if (This->transfer) {
+        This->pipe->transfer_unmap(This->pipe, This->transfer);
+        This->transfer = NULL;
+    }
+    --This->lock_count;
+    return D3D_OK;
+}
+
+
+HRESULT
+NineVolume9_CopyVolume( struct NineVolume9 *This,
+                        struct NineVolume9 *From,
+                        unsigned dstx, unsigned dsty, unsigned dstz,
+                        struct pipe_box *pSrcBox )
+{
+    struct pipe_context *pipe = This->pipe;
+    struct pipe_resource *r_dst = This->resource;
+    struct pipe_resource *r_src = From->resource;
+    struct pipe_transfer *transfer;
+    struct pipe_box src_box;
+    struct pipe_box dst_box;
+    uint8_t *p_dst;
+    const uint8_t *p_src;
+
+    user_assert(This->desc.Format == From->desc.Format, D3DERR_INVALIDCALL);
+
+    dst_box.x = dstx;
+    dst_box.y = dsty;
+    dst_box.z = dstz;
+
+    if (pSrcBox) {
+        /* make sure it doesn't range outside the source volume */
+        user_assert(pSrcBox->x >= 0 &&
+                    (pSrcBox->width - pSrcBox->x) <= From->desc.Width &&
+                    pSrcBox->y >= 0 &&
+                    (pSrcBox->height - pSrcBox->y) <= From->desc.Height &&
+                    pSrcBox->z >= 0 &&
+                    (pSrcBox->depth - pSrcBox->z) <= From->desc.Depth,
+                    D3DERR_INVALIDCALL);
+        src_box = *pSrcBox;
+    } else {
+        src_box.x = 0;
+        src_box.y = 0;
+        src_box.z = 0;
+        src_box.width = From->desc.Width;
+        src_box.height = From->desc.Height;
+        src_box.depth = From->desc.Depth;
+    }
+    /* limits */
+    dst_box.width = This->desc.Width - dst_box.x;
+    dst_box.height = This->desc.Height - dst_box.y;
+    dst_box.depth = This->desc.Depth - dst_box.z;
+
+    user_assert(src_box.width <= dst_box.width &&
+                src_box.height <= dst_box.height &&
+                src_box.depth <= dst_box.depth, D3DERR_INVALIDCALL);
+
+    dst_box.width = src_box.width;
+    dst_box.height = src_box.height;
+    dst_box.depth = src_box.depth;
+
+    /* Don't copy to device memory of managed resources.
+     * We don't want to download it back again later.
+     */
+    if (This->desc.Pool == D3DPOOL_MANAGED)
+        r_dst = NULL;
+
+    /* Don't copy from stale device memory of managed resources.
+     * Also, don't copy between system and device if we don't have to.
+     */
+    if (From->desc.Pool == D3DPOOL_MANAGED) {
+        if (!r_dst || NineVolume9_IsDirty(From))
+            r_src = NULL;
+    }
+
+    if (r_dst && r_src) {
+        pipe->resource_copy_region(pipe,
+                                   r_dst, This->level,
+                                   dst_box.x, dst_box.y, dst_box.z,
+                                   r_src, From->level,
+                                   &src_box);
+    } else
+    if (r_dst) {
+        p_src = NineVolume9_GetSystemMemPointer(From,
+            src_box.x, src_box.y, src_box.z);
+
+        pipe->transfer_inline_write(pipe, r_dst, This->level,
+                                    0, /* WRITE|DISCARD are implicit */
+                                    &dst_box, p_src,
+                                    From->stride, From->layer_stride);
+    } else
+    if (r_src) {
+        p_dst = NineVolume9_GetSystemMemPointer(This, 0, 0, 0);
+        p_src = pipe->transfer_map(pipe, r_src, From->level,
+                                   PIPE_TRANSFER_READ,
+                                   &src_box, &transfer);
+        if (!p_src)
+            return D3DERR_DRIVERINTERNALERROR;
+
+        util_copy_box(p_dst, This->info.format,
+                      This->stride, This->layer_stride,
+                      dst_box.x, dst_box.y, dst_box.z,
+                      dst_box.width, dst_box.height, dst_box.depth,
+                      p_src,
+                      transfer->stride, transfer->layer_stride,
+                      src_box.x, src_box.y, src_box.z);
+
+        pipe->transfer_unmap(pipe, transfer);
+    } else {
+        p_dst = NineVolume9_GetSystemMemPointer(This, 0, 0, 0);
+        p_src = NineVolume9_GetSystemMemPointer(From, 0, 0, 0);
+
+        util_copy_box(p_dst, This->info.format,
+                      This->stride, This->layer_stride,
+                      dst_box.x, dst_box.y, dst_box.z,
+                      dst_box.width, dst_box.height, dst_box.depth,
+                      p_src,
+                      From->stride, From->layer_stride,
+                      src_box.x, src_box.y, src_box.z);
+    }
+
+    if (This->desc.Pool == D3DPOOL_DEFAULT ||
+        This->desc.Pool == D3DPOOL_MANAGED)
+        NineVolume9_MarkContainerDirty(This);
+    if (!r_dst && This->resource)
+        NineVolume9_AddDirtyRegion(This, &dst_box);
+
+    return D3D_OK;
+}
+
+HRESULT
+NineVolume9_UploadSelf( struct NineVolume9 *This )
+{
+    struct pipe_context *pipe = This->pipe;
+    struct pipe_resource *res = This->resource;
+    uint8_t *ptr;
+    unsigned i;
+
+    DBG("This=%p dirty=%i data=%p res=%p\n", This, NineVolume9_IsDirty(This),
+        This->data, res);
+
+    assert(This->desc.Pool == D3DPOOL_MANAGED);
+
+    if (!NineVolume9_IsDirty(This))
+        return D3D_OK;
+    assert(res);
+
+    for (i = 0; i < Elements(This->dirty_box); ++i) {
+        const struct pipe_box *box = &This->dirty_box[i];
+        if (box->width == 0)
+            break;
+        ptr = NineVolume9_GetSystemMemPointer(This, box->x, box->y, box->z);
+
+        pipe->transfer_inline_write(pipe, res, This->level,
+                                    0,
+                                    box, ptr, This->stride, This->layer_stride);
+    }
+    NineVolume9_ClearDirtyRegion(This);
+
+    return D3D_OK;
+}
+
+
+IDirect3DVolume9Vtbl NineVolume9_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)NineUnknown_GetDevice, /* actually part of Volume9 iface */
+    (void *)NineVolume9_SetPrivateData,
+    (void *)NineVolume9_GetPrivateData,
+    (void *)NineVolume9_FreePrivateData,
+    (void *)NineVolume9_GetContainer,
+    (void *)NineVolume9_GetDesc,
+    (void *)NineVolume9_LockBox,
+    (void *)NineVolume9_UnlockBox
+};
+
+static const GUID *NineVolume9_IIDs[] = {
+    &IID_IDirect3DVolume9,
+    &IID_IUnknown,
+    NULL
+};
+
+HRESULT
+NineVolume9_new( struct NineDevice9 *pDevice,
+                 struct NineUnknown *pContainer,
+                 struct pipe_resource *pResource,
+                 unsigned Level,
+                 D3DVOLUME_DESC *pDesc,
+                 struct NineVolume9 **ppOut )
+{
+    NINE_DEVICE_CHILD_NEW(Volume9, ppOut, pDevice, /* args */
+                          pContainer, pResource, Level, pDesc);
+}
+
+
+/*** The boring stuff. TODO: Unify with Resource. ***/
+
+HRESULT WINAPI
+NineVolume9_SetPrivateData( struct NineVolume9 *This,
+                            REFGUID refguid,
+                            const void *pData,
+                            DWORD SizeOfData,
+                            DWORD Flags )
+{
+    enum pipe_error err;
+    struct pheader *header;
+    const void *user_data = pData;
+
+    if (Flags & D3DSPD_IUNKNOWN)
+        user_assert(SizeOfData == sizeof(IUnknown *), D3DERR_INVALIDCALL);
+
+    /* data consists of a header and the actual data. avoiding 2 mallocs */
+    header = CALLOC_VARIANT_LENGTH_STRUCT(pheader, SizeOfData-1);
+    if (!header) { return E_OUTOFMEMORY; }
+    header->unknown = (Flags & D3DSPD_IUNKNOWN) ? TRUE : FALSE;
+
+    /* if the refguid already exists, delete it */
+    NineVolume9_FreePrivateData(This, refguid);
+
+    /* IUnknown special case */
+    if (header->unknown) {
+        /* here the pointer doesn't point to the data we want, so point at the
+         * pointer making what we eventually copy is the pointer itself */
+        user_data = &pData;
+    }
+
+    header->size = SizeOfData;
+    memcpy(header->data, user_data, header->size);
+
+    err = util_hash_table_set(This->pdata, refguid, header);
+    if (err == PIPE_OK) {
+        if (header->unknown) { IUnknown_AddRef(*(IUnknown **)header->data); }
+        return D3D_OK;
+    }
+
+    FREE(header);
+    if (err == PIPE_ERROR_OUT_OF_MEMORY) { return E_OUTOFMEMORY; }
+
+    return D3DERR_DRIVERINTERNALERROR;
+}
+
+HRESULT WINAPI
+NineVolume9_GetPrivateData( struct NineVolume9 *This,
+                            REFGUID refguid,
+                            void *pData,
+                            DWORD *pSizeOfData )
+{
+    struct pheader *header;
+
+    user_assert(pSizeOfData, E_POINTER);
+
+    header = util_hash_table_get(This->pdata, refguid);
+    if (!header) { return D3DERR_NOTFOUND; }
+
+    if (!pData) {
+        *pSizeOfData = header->size;
+        return D3D_OK;
+    }
+    if (*pSizeOfData < header->size) {
+        return D3DERR_MOREDATA;
+    }
+
+    if (header->unknown) { IUnknown_AddRef(*(IUnknown **)header->data); }
+    memcpy(pData, header->data, header->size);
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineVolume9_FreePrivateData( struct NineVolume9 *This,
+                             REFGUID refguid )
+{
+    struct pheader *header;
+
+    header = util_hash_table_get(This->pdata, refguid);
+    if (!header) { return D3DERR_NOTFOUND; }
+
+    ht_guid_delete(NULL, header, NULL);
+    util_hash_table_remove(This->pdata, refguid);
+
+    return D3D_OK;
+}
+
diff --git a/src/gallium/state_trackers/nine/volume9.h b/src/gallium/state_trackers/nine/volume9.h
new file mode 100644 (file)
index 0000000..8028366
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _NINE_VOLUME9_H_
+#define _NINE_VOLUME9_H_
+
+#include "iunknown.h"
+
+#include "pipe/p_state.h"
+#include "util/u_inlines.h"
+
+struct util_hash_table;
+
+struct NineDevice9;
+
+struct NineVolume9
+{
+    struct NineUnknown base;
+
+    struct pipe_resource *resource;
+    unsigned level;
+    unsigned level_actual;
+
+    uint8_t *data; /* system memory backing */
+
+    D3DVOLUME_DESC desc;
+    struct pipe_resource info;
+    unsigned stride;
+    unsigned layer_stride;
+
+    struct pipe_transfer *transfer;
+    unsigned lock_count;
+
+    struct pipe_box dirty_box[2];
+
+    struct pipe_context *pipe;
+
+    /* for [GS]etPrivateData/FreePrivateData */
+    struct util_hash_table *pdata;
+};
+static INLINE struct NineVolume9 *
+NineVolume9( void *data )
+{
+    return (struct NineVolume9 *)data;
+}
+
+HRESULT
+NineVolume9_new( struct NineDevice9 *pDevice,
+                 struct NineUnknown *pContainer,
+                 struct pipe_resource *pResource,
+                 unsigned Level,
+                 D3DVOLUME_DESC *pDesc,
+                 struct NineVolume9 **ppOut );
+
+/*** Nine private ***/
+
+static INLINE void
+NineVolume9_SetResource( struct NineVolume9 *This,
+                         struct pipe_resource *resource, unsigned level )
+{
+    This->level = level;
+    pipe_resource_reference(&This->resource, resource);
+}
+
+void
+NineVolume9_AddDirtyRegion( struct NineVolume9 *This,
+                            const struct pipe_box *box );
+
+static INLINE void
+NineVolume9_ClearDirtyRegion( struct NineVolume9 *This )
+{
+    memset(&This->dirty_box, 0, sizeof(This->dirty_box));
+}
+
+HRESULT
+NineVolume9_CopyVolume( struct NineVolume9 *This,
+                        struct NineVolume9 *From,
+                        unsigned dstx, unsigned dsty, unsigned dstz,
+                        struct pipe_box *pSrcBox );
+
+HRESULT
+NineVolume9_UploadSelf( struct NineVolume9 *This );
+
+
+/*** Direct3D public ***/
+
+HRESULT WINAPI
+NineVolume9_SetPrivateData( struct NineVolume9 *This,
+                            REFGUID refguid,
+                            const void *pData,
+                            DWORD SizeOfData,
+                            DWORD Flags );
+
+HRESULT WINAPI
+NineVolume9_GetPrivateData( struct NineVolume9 *This,
+                            REFGUID refguid,
+                            void *pData,
+                            DWORD *pSizeOfData );
+
+HRESULT WINAPI
+NineVolume9_FreePrivateData( struct NineVolume9 *This,
+                             REFGUID refguid );
+
+HRESULT WINAPI
+NineVolume9_GetContainer( struct NineVolume9 *This,
+                          REFIID riid,
+                          void **ppContainer );
+
+HRESULT WINAPI
+NineVolume9_GetDesc( struct NineVolume9 *This,
+                     D3DVOLUME_DESC *pDesc );
+
+HRESULT WINAPI
+NineVolume9_LockBox( struct NineVolume9 *This,
+                     D3DLOCKED_BOX *pLockedVolume,
+                     const D3DBOX *pBox,
+                     DWORD Flags );
+
+HRESULT WINAPI
+NineVolume9_UnlockBox( struct NineVolume9 *This );
+
+#endif /* _NINE_VOLUME9_H_ */
diff --git a/src/gallium/state_trackers/nine/volumetexture9.c b/src/gallium/state_trackers/nine/volumetexture9.c
new file mode 100644 (file)
index 0000000..65d320c
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "device9.h"
+#include "volumetexture9.h"
+#include "nine_helpers.h"
+#include "nine_pipe.h"
+
+#define DBG_CHANNEL DBG_VOLUMETEXTURE
+
+static HRESULT
+NineVolumeTexture9_ctor( struct NineVolumeTexture9 *This,
+                         struct NineUnknownParams *pParams,
+                         UINT Width, UINT Height, UINT Depth, UINT Levels,
+                         DWORD Usage,
+                         D3DFORMAT Format,
+                         D3DPOOL Pool,
+                         HANDLE *pSharedHandle )
+{
+    struct pipe_resource *info = &This->base.base.info;
+    unsigned l;
+    D3DVOLUME_DESC voldesc;
+    HRESULT hr;
+
+    /* An IDirect3DVolume9 cannot be bound as a render target can it ? */
+    user_assert(!(Usage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)),
+                D3DERR_INVALIDCALL);
+    user_assert(!(Usage & D3DUSAGE_AUTOGENMIPMAP) ||
+                (Pool != D3DPOOL_SYSTEMMEM && Levels <= 1), D3DERR_INVALIDCALL);
+
+    user_assert(!pSharedHandle, D3DERR_INVALIDCALL); /* TODO */
+
+    if (Usage & D3DUSAGE_AUTOGENMIPMAP)
+        Levels = 0;
+
+    This->base.format = Format;
+    This->base.base.usage = Usage;
+
+    info->screen = pParams->device->screen;
+    info->target = PIPE_TEXTURE_3D;
+    info->format = d3d9_to_pipe_format(Format);
+    info->width0 = Width;
+    info->height0 = Height;
+    info->depth0 = Depth;
+    if (Levels)
+        info->last_level = Levels - 1;
+    else
+        info->last_level = util_logbase2(MAX2(MAX2(Width, Height), Depth));
+    info->array_size = 1;
+    info->nr_samples = 0;
+    info->bind = PIPE_BIND_SAMPLER_VIEW;
+    info->usage = PIPE_USAGE_DEFAULT;
+    info->flags = 0;
+
+    if (Usage & D3DUSAGE_DYNAMIC) {
+        info->usage = PIPE_USAGE_DYNAMIC;
+        info->bind |=
+            PIPE_BIND_TRANSFER_READ |
+            PIPE_BIND_TRANSFER_WRITE;
+    }
+
+    This->volumes = CALLOC(info->last_level + 1, sizeof(*This->volumes));
+    if (!This->volumes)
+        return E_OUTOFMEMORY;
+    This->base.pstype = 3;
+
+    hr = NineBaseTexture9_ctor(&This->base, pParams,
+                               D3DRTYPE_VOLUMETEXTURE, Pool);
+    if (FAILED(hr))
+        return hr;
+
+    voldesc.Format = Format;
+    voldesc.Type = D3DRTYPE_VOLUME;
+    voldesc.Usage = Usage;
+    voldesc.Pool = Pool;
+    for (l = 0; l <= info->last_level; ++l) {
+        voldesc.Width = u_minify(Width, l);
+        voldesc.Height = u_minify(Height, l);
+        voldesc.Depth = u_minify(Depth, l);
+
+        hr = NineVolume9_new(This->base.base.base.device, NineUnknown(This),
+                             This->base.base.resource, l,
+                             &voldesc, &This->volumes[l]);
+        if (FAILED(hr))
+            return hr;
+    }
+
+    return D3D_OK;
+}
+
+static void
+NineVolumeTexture9_dtor( struct NineVolumeTexture9 *This )
+{
+    unsigned l;
+
+    DBG("This=%p\n", This);
+
+    if (This->volumes) {
+        for (l = 0; l < This->base.base.info.last_level; ++l)
+            NineUnknown_Destroy(&This->volumes[l]->base);
+        FREE(This->volumes);
+    }
+
+    NineBaseTexture9_dtor(&This->base);
+}
+
+HRESULT WINAPI
+NineVolumeTexture9_GetLevelDesc( struct NineVolumeTexture9 *This,
+                                 UINT Level,
+                                 D3DVOLUME_DESC *pDesc )
+{
+    user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL);
+    user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP),
+                D3DERR_INVALIDCALL);
+
+    *pDesc = This->volumes[Level]->desc;
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineVolumeTexture9_GetVolumeLevel( struct NineVolumeTexture9 *This,
+                                   UINT Level,
+                                   IDirect3DVolume9 **ppVolumeLevel )
+{
+    user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL);
+    user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP),
+                D3DERR_INVALIDCALL);
+
+    NineUnknown_AddRef(NineUnknown(This->volumes[Level]));
+    *ppVolumeLevel = (IDirect3DVolume9 *)This->volumes[Level];
+
+    return D3D_OK;
+}
+
+HRESULT WINAPI
+NineVolumeTexture9_LockBox( struct NineVolumeTexture9 *This,
+                            UINT Level,
+                            D3DLOCKED_BOX *pLockedVolume,
+                            const D3DBOX *pBox,
+                            DWORD Flags )
+{
+    user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL);
+    user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP),
+                D3DERR_INVALIDCALL);
+
+    return NineVolume9_LockBox(This->volumes[Level], pLockedVolume, pBox,
+                               Flags);
+}
+
+HRESULT WINAPI
+NineVolumeTexture9_UnlockBox( struct NineVolumeTexture9 *This,
+                              UINT Level )
+{
+    user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL);
+
+    return NineVolume9_UnlockBox(This->volumes[Level]);
+}
+
+HRESULT WINAPI
+NineVolumeTexture9_AddDirtyBox( struct NineVolumeTexture9 *This,
+                                const D3DBOX *pDirtyBox )
+{
+    if (This->base.base.pool != D3DPOOL_MANAGED) {
+        if (This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP)
+            This->base.dirty_mip = TRUE;
+        return D3D_OK;
+    }
+    This->base.dirty = TRUE;
+
+    BASETEX_REGISTER_UPDATE(&This->base);
+
+    if (!pDirtyBox) {
+        This->dirty_box.x = 0;
+        This->dirty_box.y = 0;
+        This->dirty_box.z = 0;
+        This->dirty_box.width = This->base.base.info.width0;
+        This->dirty_box.height = This->base.base.info.height0;
+        This->dirty_box.depth = This->base.base.info.depth0;
+    } else {
+        struct pipe_box box;
+        d3dbox_to_pipe_box(&box, pDirtyBox);
+        u_box_union_3d(&This->dirty_box, &This->dirty_box, &box);
+    }
+    return D3D_OK;
+}
+
+IDirect3DVolumeTexture9Vtbl NineVolumeTexture9_vtable = {
+    (void *)NineUnknown_QueryInterface,
+    (void *)NineUnknown_AddRef,
+    (void *)NineUnknown_Release,
+    (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */
+    (void *)NineResource9_SetPrivateData,
+    (void *)NineResource9_GetPrivateData,
+    (void *)NineResource9_FreePrivateData,
+    (void *)NineResource9_SetPriority,
+    (void *)NineResource9_GetPriority,
+    (void *)NineBaseTexture9_PreLoad,
+    (void *)NineResource9_GetType,
+    (void *)NineBaseTexture9_SetLOD,
+    (void *)NineBaseTexture9_GetLOD,
+    (void *)NineBaseTexture9_GetLevelCount,
+    (void *)NineBaseTexture9_SetAutoGenFilterType,
+    (void *)NineBaseTexture9_GetAutoGenFilterType,
+    (void *)NineBaseTexture9_GenerateMipSubLevels,
+    (void *)NineVolumeTexture9_GetLevelDesc,
+    (void *)NineVolumeTexture9_GetVolumeLevel,
+    (void *)NineVolumeTexture9_LockBox,
+    (void *)NineVolumeTexture9_UnlockBox,
+    (void *)NineVolumeTexture9_AddDirtyBox
+};
+
+static const GUID *NineVolumeTexture9_IIDs[] = {
+    &IID_IDirect3DVolumeTexture9,
+    &IID_IDirect3DBaseTexture9,
+    &IID_IDirect3DResource9,
+    &IID_IUnknown,
+    NULL
+};
+
+HRESULT
+NineVolumeTexture9_new( struct NineDevice9 *pDevice,
+                        UINT Width, UINT Height, UINT Depth, UINT Levels,
+                        DWORD Usage,
+                        D3DFORMAT Format,
+                        D3DPOOL Pool,
+                        struct NineVolumeTexture9 **ppOut,
+                        HANDLE *pSharedHandle )
+{
+    NINE_DEVICE_CHILD_NEW(VolumeTexture9, ppOut, pDevice,
+                          Width, Height, Depth, Levels,
+                          Usage, Format, Pool, pSharedHandle);
+}
+
diff --git a/src/gallium/state_trackers/nine/volumetexture9.h b/src/gallium/state_trackers/nine/volumetexture9.h
new file mode 100644 (file)
index 0000000..313fa1a
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _NINE_VOLUMETEXTURE9_H_
+#define _NINE_VOLUMETEXTURE9_H_
+
+#include "basetexture9.h"
+#include "volume9.h"
+
+struct NineVolumeTexture9
+{
+    struct NineBaseTexture9 base;
+    struct NineVolume9 **volumes;
+    struct pipe_box dirty_box;
+};
+static INLINE struct NineVolumeTexture9 *
+NineVolumeTexture9( void *data )
+{
+    return (struct NineVolumeTexture9 *)data;
+}
+
+HRESULT
+NineVolumeTexture9_new( struct NineDevice9 *pDevice,
+                        UINT Width, UINT Height, UINT Depth, UINT Levels,
+                        DWORD Usage,
+                        D3DFORMAT Format,
+                        D3DPOOL Pool,
+                        struct NineVolumeTexture9 **ppOut,
+                        HANDLE *pSharedHandle );
+
+HRESULT WINAPI
+NineVolumeTexture9_GetLevelDesc( struct NineVolumeTexture9 *This,
+                                 UINT Level,
+                                 D3DVOLUME_DESC *pDesc );
+
+HRESULT WINAPI
+NineVolumeTexture9_GetVolumeLevel( struct NineVolumeTexture9 *This,
+                                   UINT Level,
+                                   IDirect3DVolume9 **ppVolumeLevel );
+
+HRESULT WINAPI
+NineVolumeTexture9_LockBox( struct NineVolumeTexture9 *This,
+                            UINT Level,
+                            D3DLOCKED_BOX *pLockedVolume,
+                            const D3DBOX *pBox,
+                            DWORD Flags );
+
+HRESULT WINAPI
+NineVolumeTexture9_UnlockBox( struct NineVolumeTexture9 *This,
+                              UINT Level );
+
+HRESULT WINAPI
+NineVolumeTexture9_AddDirtyBox( struct NineVolumeTexture9 *This,
+                                const D3DBOX *pDirtyBox );
+
+#endif /* _NINE_VOLUMETEXTURE9_H_ */
diff --git a/src/gallium/targets/d3dadapter9/Makefile.am b/src/gallium/targets/d3dadapter9/Makefile.am
new file mode 100644 (file)
index 0000000..6231236
--- /dev/null
@@ -0,0 +1,131 @@
+# Copyright © 2012 Intel Corporation
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+
+include $(top_srcdir)/src/gallium/Automake.inc
+
+AM_CFLAGS = \
+       -I$(top_srcdir)/include/D3D9 \
+       -I$(top_srcdir)/src/loader \
+       -I$(top_srcdir)/src/mapi/ \
+       -I$(top_srcdir)/src/mesa/ \
+       -I$(top_srcdir)/src/mesa/drivers/dri/common/ \
+       -I$(top_builddir)/src/mesa/drivers/dri/common/ \
+       -I$(top_srcdir)/src/gallium/winsys \
+       -I$(top_srcdir)/src/gallium/state_trackers/nine \
+       $(GALLIUM_TARGET_CFLAGS) \
+       $(VISIBILITY_CFLAGS)
+
+if HAVE_GALLIUM_STATIC_TARGETS
+AM_CPPFLAGS = \
+       -DNINE_TARGET \
+       -DGALLIUM_STATIC_TARGETS=1
+
+else
+
+AM_CPPFLAGS = \
+       -DPIPE_SEARCH_DIR=\"$(libdir)/gallium-pipe\" \
+       $(GALLIUM_PIPE_LOADER_DEFINES)
+
+endif
+
+ninedir = $(D3D_DRIVER_INSTALL_DIR)
+nine_LTLIBRARIES = d3dadapter9.la
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = d3d.pc
+
+d3dadapter9_la_SOURCES = \
+       getproc.c \
+       drm.c
+
+d3dadapter9_la_LDFLAGS = \
+       -shared \
+       -shrext .so \
+       -module \
+       -no-undefined \
+       -version-number $(NINE_MAJOR):$(NINE_MINOR) \
+       $(GC_SECTIONS) \
+       $(LD_NO_UNDEFINED)
+
+if HAVE_LD_VERSION_SCRIPT
+d3dadapter9_la_LDFLAGS += \
+       -Wl,--version-script=$(top_srcdir)/src/gallium/targets/d3dadapter9/d3dadapter9.sym
+endif # HAVE_LD_VERSION_SCRIPT
+
+d3dadapter9_la_LIBADD = \
+       $(top_builddir)/src/gallium/auxiliary/libgallium.la \
+       $(top_builddir)/src/gallium/state_trackers/nine/libninetracker.la \
+       $(top_builddir)/src/util/libmesautil.la \
+       $(top_builddir)/src/gallium/winsys/sw/wrapper/libwsw.la \
+       $(EXPAT_LIBS) \
+       $(GALLIUM_COMMON_LIB_DEPS)
+
+
+TARGET_DRIVERS =
+TARGET_CPPFLAGS =
+TARGET_LIB_DEPS = $(top_builddir)/src/loader/libloader.la
+
+include $(top_srcdir)/src/gallium/drivers/i915/Automake.inc
+
+include $(top_srcdir)/src/gallium/drivers/ilo/Automake.inc
+
+include $(top_srcdir)/src/gallium/drivers/nouveau/Automake.inc
+
+include $(top_srcdir)/src/gallium/drivers/r300/Automake.inc
+include $(top_srcdir)/src/gallium/drivers/r600/Automake.inc
+include $(top_srcdir)/src/gallium/drivers/radeonsi/Automake.inc
+
+include $(top_srcdir)/src/gallium/drivers/svga/Automake.inc
+
+include $(top_srcdir)/src/gallium/drivers/freedreno/Automake.inc
+
+include $(top_srcdir)/src/gallium/drivers/vc4/Automake.inc
+
+include $(top_srcdir)/src/gallium/drivers/softpipe/Automake.inc
+include $(top_srcdir)/src/gallium/drivers/llvmpipe/Automake.inc
+
+if HAVE_GALLIUM_STATIC_TARGETS
+
+d3dadapter9_la_CPPFLAGS = $(AM_CPPFLAGS) $(TARGET_CPPFLAGS)
+d3dadapter9_la_LIBADD += $(TARGET_LIB_DEPS) \
+       $(TARGET_RADEON_WINSYS) $(TARGET_RADEON_COMMON)
+
+else # HAVE_GALLIUM_STATIC_TARGETS
+
+d3dadapter9_la_LIBADD += \
+       $(top_builddir)/src/gallium/auxiliary/pipe-loader/libpipe_loader.la \
+       $(GALLIUM_PIPE_LOADER_WINSYS_LIBS) \
+       $(GALLIUM_PIPE_LOADER_LIBS)
+
+endif # HAVE_GALLIUM_STATIC_TARGETS
+
+if HAVE_MESA_LLVM
+nodist_EXTRA_d3dadapter9_la_SOURCES = dummy.cpp
+d3dadapter9_la_LDFLAGS += $(LLVM_LDFLAGS)
+d3dadapter9_la_LIBADD += $(LLVM_LIBS)
+endif
+
+d3dadapterdir = $(includedir)/d3dadapter
+d3dadapter_HEADERS = \
+       $(top_srcdir)/include/d3dadapter/d3dadapter9.h \
+       $(top_srcdir)/include/d3dadapter/drm.h \
+       $(top_srcdir)/include/d3dadapter/present.h
diff --git a/src/gallium/targets/d3dadapter9/d3d.pc.in b/src/gallium/targets/d3dadapter9/d3d.pc.in
new file mode 100644 (file)
index 0000000..9a18a5c
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+moduledir=@D3D_DRIVER_INSTALL_DIR@
+
+Name: d3d
+Description: Native D3D driver modules
+Version: @VERSION@
+Requires.private: @DRI_PC_REQ_PRIV@
+Cflags: -I${includedir}
diff --git a/src/gallium/targets/d3dadapter9/d3dadapter9.sym b/src/gallium/targets/d3dadapter9/d3dadapter9.sym
new file mode 100644 (file)
index 0000000..2290dae
--- /dev/null
@@ -0,0 +1,6 @@
+{
+       global:
+               D3DAdapter9GetProc;
+       local:
+               *;
+};
diff --git a/src/gallium/targets/d3dadapter9/drm.c b/src/gallium/targets/d3dadapter9/drm.c
new file mode 100644 (file)
index 0000000..d0b72e0
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "loader.h"
+
+#include "adapter9.h"
+
+#include "pipe-loader/pipe_loader.h"
+
+#include "pipe/p_screen.h"
+#include "pipe/p_state.h"
+
+#include "target-helpers/inline_drm_helper.h"
+#include "target-helpers/inline_sw_helper.h"
+#include "state_tracker/drm_driver.h"
+
+#include "d3dadapter/d3dadapter9.h"
+#include "d3dadapter/drm.h"
+
+#include <libdrm/drm.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#define DBG_CHANNEL DBG_ADAPTER
+
+#define VERSION_DWORD(hi, lo) \
+    ((DWORD)( \
+        ((DWORD)((hi) & 0xFFFF) << 16) | \
+         (DWORD)((lo) & 0xFFFF) \
+    ))
+
+/* Regarding os versions, we should not define our own as that would simply be
+ * weird. Defaulting to Win2k/XP seems sane considering the origin of D3D9. The
+ * driver also defaults to being a generic D3D9 driver, which of course only
+ * matters if you're actually using the DDI. */
+#define VERSION_HIGH    VERSION_DWORD(0x0006, 0x000E) /* winxp, d3d9 */
+#define VERSION_LOW     VERSION_DWORD(0x0000, 0x0001) /* version, build */
+
+struct d3dadapter9drm_context
+{
+    struct d3dadapter9_context base;
+    struct pipe_loader_device *dev, *swdev;
+};
+
+static void
+drm_destroy( struct d3dadapter9_context *ctx )
+{
+#if !GALLIUM_STATIC_TARGETS
+    struct d3dadapter9drm_context *drm = (struct d3dadapter9drm_context *)ctx;
+
+    /* pipe_loader_sw destroys the context */
+    if (drm->swdev)
+        pipe_loader_release(&drm->swdev, 1);
+    if (drm->dev)
+        pipe_loader_release(&drm->dev, 1);
+#endif
+
+    FREE(ctx);
+}
+
+/* read a DWORD in the form 0xnnnnnnnn, which is how sysfs pci id stuff is
+ * formatted. */
+static INLINE DWORD
+read_file_dword( const char *name )
+{
+    char buf[32];
+    int fd, r;
+
+    fd = open(name, O_RDONLY);
+    if (fd < 0) {
+        DBG("Unable to get PCI information from `%s'\n", name);
+        return 0;
+    }
+
+    r = read(fd, buf, 32);
+    close(fd);
+
+    return (r > 0) ? (DWORD)strtol(buf, NULL, 0) : 0;
+}
+
+/* sysfs doesn't expose the revision as its own file, so this function grabs a
+ * dword at an offset in the raw PCI header. The reason this isn't used for all
+ * data is that the kernel will make corrections but not expose them in the raw
+ * header bytes. */
+static INLINE DWORD
+read_config_dword( int fd,
+                   unsigned offset )
+{
+    DWORD r = 0;
+
+    if (lseek(fd, offset, SEEK_SET) != offset) { return 0; }
+    if (read(fd, &r, 4) != 4) { return 0; }
+
+    return r;
+}
+
+static INLINE void
+get_bus_info( int fd,
+              DWORD *vendorid,
+              DWORD *deviceid,
+              DWORD *subsysid,
+              DWORD *revision )
+{
+    drm_unique_t u;
+
+    u.unique_len = 0;
+    u.unique = NULL;
+
+    if (ioctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) { return; }
+    u.unique = CALLOC(u.unique_len+1, 1);
+
+    if (ioctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) { return; }
+    u.unique[u.unique_len] = '\0';
+
+    DBG("DRM Device BusID: %s\n", u.unique);
+    if (strncmp("pci:", u.unique, 4) == 0) {
+        char fname[512]; /* this ought to be enough */
+        int l = snprintf(fname, 512, "/sys/bus/pci/devices/%s/", u.unique+4);
+
+        /* VendorId */
+        snprintf(fname+l, 512-l, "vendor");
+        *vendorid = read_file_dword(fname);
+        /* DeviceId */
+        snprintf(fname+l, 512-l, "device");
+        *deviceid = read_file_dword(fname);
+        /* SubSysId */
+        snprintf(fname+l, 512-l, "subsystem_device");
+        *subsysid = (read_file_dword(fname) << 16) & 0xFFFF0000;
+        snprintf(fname+l, 512-l, "subsystem_vendor");
+        *subsysid |= read_file_dword(fname) & 0x0000FFFF;
+        /* Revision */
+        {
+            int cfgfd;
+
+            snprintf(fname+l, 512-l, "config");
+            cfgfd = open(fname, O_RDONLY);
+            if (cfgfd >= 0) {
+                *revision = read_config_dword(cfgfd, 0x8) & 0x000000FF;
+                close(cfgfd);
+            } else {
+                DBG("Unable to get raw PCI information from `%s'\n", fname);
+            }
+        }
+        DBG("PCI info: vendor=0x%04x, device=0x%04x, subsys=0x%08x, rev=%d\n",
+            *vendorid, *deviceid, *subsysid, *revision);
+    } else {
+        DBG("Unsupported BusID type.\n");
+    }
+
+    FREE(u.unique);
+}
+
+static INLINE void
+read_descriptor( struct d3dadapter9_context *ctx,
+                 int fd )
+{
+    D3DADAPTER_IDENTIFIER9 *drvid = &ctx->identifier;
+
+    memset(drvid, 0, sizeof(*drvid));
+    get_bus_info(fd, &drvid->VendorId, &drvid->DeviceId,
+                 &drvid->SubSysId, &drvid->Revision);
+
+    strncpy(drvid->Driver, "libd3dadapter9.so", sizeof(drvid->Driver));
+    strncpy(drvid->DeviceName, ctx->hal->get_name(ctx->hal), 32);
+    snprintf(drvid->Description, sizeof(drvid->Description),
+             "Gallium 0.4 with %s", ctx->hal->get_vendor(ctx->hal));
+
+    drvid->DriverVersionLowPart = VERSION_LOW;
+    drvid->DriverVersionHighPart = VERSION_HIGH;
+
+    /* To make a pseudo-real GUID we use the PCI bus data and some string */
+    drvid->DeviceIdentifier.Data1 = drvid->VendorId;
+    drvid->DeviceIdentifier.Data2 = drvid->DeviceId;
+    drvid->DeviceIdentifier.Data3 = drvid->SubSysId;
+    memcpy(drvid->DeviceIdentifier.Data4, "Gallium3D", 8);
+
+    drvid->WHQLLevel = 1; /* This fakes WHQL validaion */
+
+    /* XXX Fake NVIDIA binary driver on Windows.
+     *
+     * OS version: 4=95/98/NT4, 5=2000, 6=2000/XP, 7=Vista, 8=Win7
+     */
+    strncpy(drvid->Driver, "nvd3dum.dll", sizeof(drvid->Driver));
+    strncpy(drvid->Description, "NVIDIA GeForce GTX 680", sizeof(drvid->Description));
+    drvid->DriverVersionLowPart = VERSION_DWORD(12, 6658); /* minor, build */
+    drvid->DriverVersionHighPart = VERSION_DWORD(6, 15); /* OS, major */
+    drvid->SubSysId = 0;
+    drvid->Revision = 0;
+    drvid->DeviceIdentifier.Data1 = 0xaeb2cdd4;
+    drvid->DeviceIdentifier.Data2 = 0x6e41;
+    drvid->DeviceIdentifier.Data3 = 0x43ea;
+    drvid->DeviceIdentifier.Data4[0] = 0x94;
+    drvid->DeviceIdentifier.Data4[1] = 0x1c;
+    drvid->DeviceIdentifier.Data4[2] = 0x83;
+    drvid->DeviceIdentifier.Data4[3] = 0x61;
+    drvid->DeviceIdentifier.Data4[4] = 0xcc;
+    drvid->DeviceIdentifier.Data4[5] = 0x76;
+    drvid->DeviceIdentifier.Data4[6] = 0x07;
+    drvid->DeviceIdentifier.Data4[7] = 0x81;
+    drvid->WHQLLevel = 0;
+}
+
+static HRESULT WINAPI
+drm_create_adapter( int fd,
+                    ID3DAdapter9 **ppAdapter )
+{
+    struct d3dadapter9drm_context *ctx = CALLOC_STRUCT(d3dadapter9drm_context);
+    HRESULT hr;
+    int i, different_device;
+    const struct drm_conf_ret *throttle_ret = NULL;
+    const struct drm_conf_ret *dmabuf_ret = NULL;
+
+#if !GALLIUM_STATIC_TARGETS
+    const char *paths[] = {
+        getenv("D3D9_DRIVERS_PATH"),
+        getenv("D3D9_DRIVERS_DIR"),
+        PIPE_SEARCH_DIR
+    };
+#endif
+
+    if (!ctx) { return E_OUTOFMEMORY; }
+
+    ctx->base.destroy = drm_destroy;
+
+    fd = loader_get_user_preferred_fd(fd, &different_device);
+    ctx->base.linear_framebuffer = !!different_device;
+
+#if GALLIUM_STATIC_TARGETS
+    ctx->base.hal = dd_create_screen(fd);
+#else
+    /* use pipe-loader to dlopen appropriate drm driver */
+    if (!pipe_loader_drm_probe_fd(&ctx->dev, fd, FALSE)) {
+        ERR("Failed to probe drm fd %d.\n", fd);
+        FREE(ctx);
+        close(fd);
+        return D3DERR_DRIVERINTERNALERROR;
+    }
+
+    /* use pipe-loader to create a drm screen (hal) */
+    ctx->base.hal = NULL;
+    for (i = 0; !ctx->base.hal && i < Elements(paths); ++i) {
+        if (!paths[i]) { continue; }
+        ctx->base.hal = pipe_loader_create_screen(ctx->dev, paths[i]);
+    }
+#endif
+    if (!ctx->base.hal) {
+        ERR("Unable to load requested driver.\n");
+        drm_destroy(&ctx->base);
+        return D3DERR_DRIVERINTERNALERROR;
+    }
+
+#if GALLIUM_STATIC_TARGETS
+    dmabuf_ret = dd_configuration(DRM_CONF_SHARE_FD);
+    throttle_ret = dd_configuration(DRM_CONF_THROTTLE);
+#else
+    dmabuf_ret = pipe_loader_configuration(ctx->dev, DRM_CONF_SHARE_FD);
+    throttle_ret = pipe_loader_configuration(ctx->dev, DRM_CONF_THROTTLE);
+#endif // GALLIUM_STATIC_TARGETS
+    if (!dmabuf_ret || !dmabuf_ret->val.val_bool) {
+        ERR("The driver is not capable of dma-buf sharing."
+            "Abandon to load nine state tracker\n");
+        drm_destroy(&ctx->base);
+        return D3DERR_DRIVERINTERNALERROR;
+    }
+
+    if (throttle_ret && throttle_ret->val.val_int != -1) {
+        ctx->base.throttling = TRUE;
+        ctx->base.throttling_value = throttle_ret->val.val_int;
+    } else
+        ctx->base.throttling = FALSE;
+
+
+#if GALLIUM_STATIC_TARGETS
+    ctx->base.ref = ninesw_create_screen(ctx->base.hal);
+#else
+    /* wrap it to create a software screen that can share resources */
+    if (pipe_loader_sw_probe_wrapped(&ctx->swdev, ctx->base.hal)) {
+        ctx->base.ref = NULL;
+        for (i = 0; !ctx->base.ref && i < Elements(paths); ++i) {
+            if (!paths[i]) { continue; }
+            ctx->base.ref = pipe_loader_create_screen(ctx->swdev, paths[i]);
+        }
+    }
+#endif
+    if (!ctx->base.ref) {
+        ERR("Couldn't wrap drm screen to swrast screen. Software devices "
+            "will be unavailable.\n");
+    }
+
+    /* read out PCI info */
+    read_descriptor(&ctx->base, fd);
+
+    /* create and return new ID3DAdapter9 */
+    hr = NineAdapter9_new(&ctx->base, (struct NineAdapter9 **)ppAdapter);
+    if (FAILED(hr)) {
+        drm_destroy(&ctx->base);
+        return hr;
+    }
+
+    return D3D_OK;
+}
+
+const struct D3DAdapter9DRM drm9_desc = {
+    .major_version = D3DADAPTER9DRM_MAJOR,
+    .minor_version = D3DADAPTER9DRM_MINOR,
+    .create_adapter = drm_create_adapter
+};
diff --git a/src/gallium/targets/d3dadapter9/getproc.c b/src/gallium/targets/d3dadapter9/getproc.c
new file mode 100644 (file)
index 0000000..2aa79a4
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2013 Joakim Sindholt <opensource@zhasha.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include <string.h>
+
+#include "util/u_memory.h"
+
+#include "d3dadapter/drm.h"
+extern const struct D3DAdapter9DRM drm9_desc;
+
+struct {
+    const char *name;
+    const void *desc;
+} drivers[] = {
+    { D3DADAPTER9DRM_NAME, &drm9_desc },
+};
+
+PUBLIC const void * WINAPI
+D3DAdapter9GetProc( const char *name )
+{
+    int i;
+    for (i = 0; i < Elements(drivers); ++i) {
+        if (strcmp(name, drivers[i].name) == 0) {
+            return drivers[i].desc;
+        }
+    }
+    return NULL;
+}